Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
f738602
wip
SeregPie May 6, 2024
1481020
+
SeregPie May 6, 2024
d9a9025
+
SeregPie May 6, 2024
7f87217
+
SeregPie May 8, 2024
b9f96a5
+
SeregPie May 8, 2024
808a110
+
SeregPie May 9, 2024
045369f
+
SeregPie May 9, 2024
17861cd
+
SeregPie May 9, 2024
cc11664
+
SeregPie May 13, 2024
d59d5ff
+
SeregPie May 13, 2024
3a33730
+
SeregPie May 15, 2024
e7995dc
+
SeregPie May 15, 2024
693e32d
+
SeregPie May 15, 2024
16c294c
+
SeregPie May 16, 2024
f84194d
+
SeregPie May 17, 2024
350a7a0
+
SeregPie May 18, 2024
331e301
+
SeregPie May 18, 2024
1d715e7
+
SeregPie May 22, 2024
dfd09f1
+
SeregPie May 28, 2024
8d8ad93
+
SeregPie Jun 2, 2024
a6f0ba1
+
SeregPie Jun 4, 2024
588cfb1
+
SeregPie Jun 12, 2024
871091e
+
s-sintschilin Aug 14, 2024
493094c
+
s-sintschilin Aug 14, 2024
119bbdb
+
s-sintschilin Aug 14, 2024
ae4fa58
+
s-sintschilin Aug 16, 2024
de376c7
+
s-sintschilin Aug 16, 2024
cc4d78f
+
s-sintschilin Aug 19, 2024
96db7a3
+
s-sintschilin Aug 19, 2024
6cac1ff
+
s-sintschilin Aug 20, 2024
0e60765
+
s-sintschilin Aug 22, 2024
3d2fc99
+
s-sintschilin Aug 22, 2024
ddb9409
+
s-sintschilin Oct 16, 2024
c5569d1
+
s-sintschilin Oct 21, 2024
38cd8fc
+
s-sintschilin Oct 30, 2024
f37b775
+
s-sintschilin Nov 4, 2024
eaaa2c4
+
s-sintschilin Nov 4, 2024
6f2cde4
+
s-sintschilin Nov 4, 2024
d5a0c25
+
s-sintschilin Dec 16, 2024
90d0296
+
s-sintschilin Dec 17, 2024
4098608
+
s-sintschilin Dec 18, 2024
54840b6
+
s-sintschilin Dec 18, 2024
256a55b
+
s-sintschilin Jan 21, 2025
2a7a9d5
+
s-sintschilin Jan 21, 2025
1e65313
+
s-sintschilin Jan 27, 2025
966e549
+
Aug 8, 2025
1271306
+
Aug 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
/dist
/public

/bun.lockb
/bun.lock
/bun.lockb
7 changes: 2 additions & 5 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
/dist

/src/core/basics/form-reactivity
/src/core/basics/provider-compitibility
/src/core/basics/validator-customization
/src/core/composables/form-fallthrough
/src/core/composables/media-query
-/src/core/basics/provider-compitibility
-/src/core/basics/validator-customization
53 changes: 51 additions & 2 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,64 @@
}
},
"test": {
"builder": "@angular-devkit/build-angular:jest",
"builder": "@angular-builders/jest:run",
"options": {
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "./src/tsconfig.spec.json"
}
}
},
"projectType": "library",
"root": "."
},
"docs": {
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"configurations": {
"development": {
"extractLicenses": false,
"optimization": false,
"sourceMap": true
},
"production": {
"outputHashing": "all"
}
},
"defaultConfiguration": "production",
"options": {
"allowedCommonJsDependencies": ["@messageformat/core"],
"assets": ["./src/docs/favicon.ico", "./src/docs/assets"],
"browser": "./src/docs/main.ts",
"index": "./src/docs/index.html",
"inlineStyleLanguage": "scss",
"outputPath": {
"base": "./docs",
"browser": ""
},
"polyfills": ["zone.js"],
"styles": ["./src/docs/styles.scss"],
"tsConfig": "./src/docs/tsconfig.json"
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"development": {
"buildTarget": "docs:build:development"
},
"production": {
"buildTarget": "docs:build:production"
}
},
"defaultConfiguration": "development",
"options": {
"open": true
}
}
},
"projectType": "application",
"root": ".",
"sourceRoot": "./src/docs"
}
},
"version": 1
Expand Down
Empty file modified ng-package.json
100755 → 100644
Empty file.
59 changes: 31 additions & 28 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"url": "https://github.com/SeregPie/ngx-craft.git"
},
"scripts": {
"build": "ng build core",
"build": "ng build core && ng build docs",
"start": "ng serve",
"test": "ng test",
"format": "prettier --write ."
},
Expand All @@ -19,33 +20,35 @@
"@angular/forms": ">=17.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.4",
"@angular/animations": "^17.3.4",
"@angular/cli": "^17.3.4",
"@angular/common": "^17.3.4",
"@angular/compiler": "^17.3.4",
"@angular/compiler-cli": "^17.3.4",
"@angular/core": "^17.3.4",
"@angular/forms": "^17.3.4",
"@angular/platform-browser": "^17.3.4",
"@angular/platform-browser-dynamic": "^17.3.4",
"@angular/router": "^17.3.4",
"@faker-js/faker": "^8.4.1",
"@jsverse/transloco": "^7.4.0",
"@jsverse/transloco-messageformat": "^7.0.0",
"@messageformat/core": "^3.3.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"modern-normalize": "^2.0.0",
"ng-packagr": "^17.3.0",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"rxjs": "^7.8.1",
"tslib": "^2.6.2",
"typescript": "^5.4.5",
"zone.js": "^0.14.4"
"@angular-builders/jest": "^20.0.0",
"@angular-devkit/build-angular": "^20.1.5",
"@angular/animations": "^20.1.6",
"@angular/cli": "^20.1.5",
"@angular/common": "^20.1.6",
"@angular/compiler": "^20.1.6",
"@angular/compiler-cli": "^20.1.6",
"@angular/core": "^20.1.6",
"@angular/forms": "^20.1.6",
"@angular/platform-browser": "^20.1.6",
"@angular/platform-browser-dynamic": "^20.1.6",
"@angular/router": "^20.1.6",
"@faker-js/faker": "^9.9.0",
"@jsverse/transloco": "^7.6.1",
"@jsverse/transloco-messageformat": "^7.0.1",
"@messageformat/core": "^3.4.0",
"@primeng/themes": "^20.0.1",
"@types/jest": "^30.0.0",
"jest": "^30.0.5",
"jest-environment-jsdom": "^30.0.5",
"modern-normalize": "^3.0.1",
"ng-packagr": "^20.1.0",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.2.0",
"primeng": "^20.0.1",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"typescript": "<5.9.0",
"zone.js": "^0.15.1"
},
"keywords": [
"angular",
Expand Down
25 changes: 25 additions & 0 deletions src/core/basics/daowexhy/index.cTMunvUb.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {signal} from '@angular/core';
import {fakeAsync} from '@angular/core/testing';

import {unwrapSignal, wrapSignal} from '.';

// todo: better tests
// todo: better descriptions

describe('wrapSignal', () => {
it('...', fakeAsync(async () => {
const value = {};

expect(wrapSignal(value)()).toBe(value);
expect(wrapSignal(signal(value))()).toBe(value);
}));
});

describe('unwrapSignal', () => {
it('...', fakeAsync(async () => {
const value = {};

expect(unwrapSignal(value)).toBe(value);
expect(unwrapSignal(signal(value))).toBe(value);
}));
});
45 changes: 45 additions & 0 deletions src/core/basics/daowexhy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// @ts-nocheck
// todo: rename folder

import {isSignal, signal, Signal} from '@angular/core';

/**
* A type that can be either a value of type T or a Signal containing a value of type T.
*
* @template T The type of the value or signal.
*/
export type MaybeSignal<T> = T | Signal<T>;

/**
* Unwraps a MaybeSignal to extract the value. If the input is a Signal, it calls the signal function
* to retrieve the value. Otherwise, it returns the value directly.
*
* @template T The type of the value contained within the MaybeSignal.
* @param {MaybeSignal<T>} v The MaybeSignal value to unwrap.
* @returns {T} The value inside the Signal, or the value itself if it was not a Signal.
*/
export function unwrapSignal<const T>(
//
v: MaybeSignal<T>,
): T;

export function unwrapSignal(v) {
return isSignal(v) ? v() : v;
}

/**
* Wraps a value in a Signal. If the input is already a Signal, it is returned as is. Otherwise,
* it creates a new Signal wrapping the value.
*
* @template T The type of the value to be wrapped in a Signal.
* @param {MaybeSignal<T>} v The value or Signal to wrap.
* @returns {Signal<T>} A Signal wrapping the value.
*/
export function wrapSignal<const T>(
//
v: MaybeSignal<T>,
): Signal<T>;

export function wrapSignal(v) {
return isSignal(v) ? v : signal(v);
}
16 changes: 16 additions & 0 deletions src/core/basics/evvxribr/index.ts.draft
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {SIGNAL, WritableSignal} from '@angular/core';

export function signalDummy<const T>(vezfdfmx: {
//
get(): T;
set(v: T): void;
}): WritableSignal {
let {get, set} = vezfdfmx;
let edhyhsrd = () => get();
Object.assign(edhyhsrd, {
[SIGNAL]: true,
set: (v) => set(v),
update: (fn) => set(fn(get())),
asReadonly: () => {},
});
}
59 changes: 37 additions & 22 deletions src/core/basics/form-reactivity/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,49 @@
<!-- todo: better docs -->

# Form Reactivity

## Usage
`formi(control)`

```ts
const formResult = computed(() => {
if (formi(form).valid) {
return formi(form).value;
}
return null;
});
@Component({})
class MyComponent {
form = useFormFallthrough();

error = computed(() => {
let form = this.form();
if (form && formi(form).touched && formi(form).invalid) {
let errors = formi(form).errors;
if (errors) {
if (errors['required']) {
return 'The input is required.';
}
}
return 'The input is invalid.';
}
return null;
});
}
```

## Types

<!-- prettier-ignore -->
```ts
export const formi: {
<ControlT extends AbstractControl>(
control: ControlT,
): ReadonlyReactiveFormProxy<ControlT>;
};

export type ReadonlyReactiveFormProxy<
ControlT extends AbstractControl = AbstractControl,
> = (
& {
readonly control: ControlT;
}
& Readonly<Pick<ControlT, ReadonlyReactiveFormProp>>
);

export type ReadonlyReactiveFormProp = (
| 'status'
| 'valid'
Expand All @@ -28,19 +58,4 @@ export type ReadonlyReactiveFormProp = (
| 'value'
| 'errors'
);

export type ReadonlyReactiveFormProxy<
ControlT extends AbstractControl = AbstractControl,
> = (
& {
readonly control: ControlT;
}
& Readonly<Pick<ControlT, ReadonlyReactiveFormProp>>
);

export const formi: {
<ControlT extends AbstractControl>(
control: ControlT,
): ReadonlyReactiveFormProxy<ControlT>;
};
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import {FormControl, FormGroup, Validators} from '@angular/forms';

import {formi} from '.';

describe('formi', () => {
// todo: better tests
// todo: better descriptions

describe.skip('formi', () => {
it('should reflect actual state', fakeAsync(async () => {
let form = new FormGroup({
a: new FormControl<null | number>(null, {
Expand All @@ -15,6 +18,7 @@ describe('formi', () => {
}),
});

// todo
for await (let _ of (async function* () {
yield;
for (let fn of [
Expand Down Expand Up @@ -48,42 +52,43 @@ describe('formi', () => {
it('should trigger changes properly', fakeAsync(async () => {
let form = new FormControl(null);

// todo: rename
let effectFn = jest.fn(() => {
formi(form).disabled;
});
TestBed.runInInjectionContext(() => {
effect(effectFn);
});
TestBed.flushEffects();
jest.clearAllMocks()
jest.clearAllMocks();

form.disable();
form.markAsTouched();
TestBed.flushEffects();

expect(effectFn).toHaveBeenCalledTimes(1);
jest.clearAllMocks()
jest.clearAllMocks();

form.disable();
form.markAsUntouched();
TestBed.flushEffects();

expect(effectFn).not.toHaveBeenCalled();
jest.clearAllMocks()
jest.clearAllMocks();

form.enable();
form.markAsUntouched();
TestBed.flushEffects();

expect(effectFn).toHaveBeenCalledTimes(1);
jest.clearAllMocks()
jest.clearAllMocks();

form.enable();
form.markAsTouched();
TestBed.flushEffects();

expect(effectFn).not.toHaveBeenCalled();
jest.clearAllMocks()
jest.clearAllMocks();
}));

it('should have target control', fakeAsync(async () => {
Expand Down
Loading