@filip.mazev/blocks 1.4.15 → 1.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/styles/_a11y.scss +5 -0
- package/core/styles/_field-state.scss +12 -3
- package/core/styles/_helpers.scss +1 -0
- package/core/styles/_index.scss +1 -0
- package/core/styles/_slider.scss +116 -6
- package/core/styles/_text-overflow.scss +7 -0
- package/core/styles/_text.scss +5 -0
- package/core/styles/_validation.scss +48 -0
- package/fesm2022/filip.mazev-blocks-core.mjs +83 -18
- package/fesm2022/filip.mazev-blocks-core.mjs.map +1 -1
- package/fesm2022/filip.mazev-blocks-effects-runtime.mjs +14 -3
- package/fesm2022/filip.mazev-blocks-effects-runtime.mjs.map +1 -1
- package/fesm2022/filip.mazev-blocks-effects.mjs +16 -8
- package/fesm2022/filip.mazev-blocks-effects.mjs.map +1 -1
- package/fesm2022/filip.mazev-blocks-forms.mjs +5004 -1078
- package/fesm2022/filip.mazev-blocks-forms.mjs.map +1 -1
- package/fesm2022/filip.mazev-blocks-primitives.mjs +2373 -1294
- package/fesm2022/filip.mazev-blocks-primitives.mjs.map +1 -1
- package/fesm2022/filip.mazev-blocks.mjs +1 -1
- package/fesm2022/filip.mazev-blocks.mjs.map +1 -1
- package/forms/README.md +80 -0
- package/package.json +1 -1
- package/types/filip.mazev-blocks-core.d.ts +22 -2
- package/types/filip.mazev-blocks-effects.d.ts +1 -1
- package/types/filip.mazev-blocks-forms.d.ts +1216 -76
- package/types/filip.mazev-blocks-primitives.d.ts +304 -6
- package/types/filip.mazev-blocks.d.ts +1 -1
package/forms/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Forms
|
|
2
|
+
|
|
3
|
+
Blocks fields use Angular 22 native signal control contracts and support Signal Forms, Reactive Forms, Template-driven Forms and standalone models. The library supplies presentation, interaction and accessible feedback; Angular owns validation and submission.
|
|
4
|
+
|
|
5
|
+
## Import and basic usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { signal } from '@angular/core';
|
|
9
|
+
import { form, FormField as SignalFormField, FormRoot, required, email } from '@angular/forms/signals';
|
|
10
|
+
import { Button, InputField } from '@filip.mazev/blocks/forms';
|
|
11
|
+
|
|
12
|
+
readonly accountModel = signal({ email: '' });
|
|
13
|
+
readonly account = form(this.accountModel, (p) => {
|
|
14
|
+
required(p.email, { message: 'Email is required.' });
|
|
15
|
+
email(p.email, { message: 'Enter a valid email address.' });
|
|
16
|
+
}, {
|
|
17
|
+
submission: {
|
|
18
|
+
ignoreValidators: 'none',
|
|
19
|
+
action: async (field) => { await this.api.save(field().value()); }
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Import `SignalFormField`, `FormRoot`, and the used Blocks controls into the standalone component. Alias Angular's directive because Blocks also exports its frame component as `FormField`.
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<form [formRoot]="account">
|
|
28
|
+
<bx-input-field label="Email" type="email" [formField]="account.email" />
|
|
29
|
+
<button bx-button type="submit" [disabled]="!account().valid()" [loading]="account().submitting()">Save</button>
|
|
30
|
+
</form>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Validation and state
|
|
34
|
+
|
|
35
|
+
Schema validation supplies `required`, numeric and length limits, pattern metadata, errors, pending, disabled and readonly state to compatible controls. `valid()` is false while asynchronous validation is pending; `!invalid()` alone does not guarantee readiness.
|
|
36
|
+
|
|
37
|
+
Use `ignoreValidators: 'none'` to gate the submission handler as well as the visible button while async validation is pending. Submission marks interactive fields touched, prevents duplicate submissions, and applies returned server errors to their target fields.
|
|
38
|
+
|
|
39
|
+
Read field state through the Angular field tree. Derive UI with `computed()` and use `effect()` for side effects when validity or pending state changes. Cross-field validators belong in the schema and can read related values. Blocks does not implement a second validation engine.
|
|
40
|
+
|
|
41
|
+
## Custom messages and visibility
|
|
42
|
+
|
|
43
|
+
Shared inputs include `errorMessages`, `errorPriority`, `errorMode` (`first` or `all`), and `errorPolicy` (`touched`, `dirty`, `submitted`, `always`, or a function receiving `IErrorState`). The default reveals invalid fields after touch or submission. A function can include custom group or application state. The submitted policy tracks native form submission; when invoking submission programmatically outside the form element, pass the shared `submitted` input from application state.
|
|
44
|
+
|
|
45
|
+
Message resolution prefers projected `bx-error` content, then field message overrides, schema messages, and configured defaults. `minlength`/`maxlength` Reactive Forms keys and `minLength`/`maxLength` Signal Forms kinds are recognized. Resolvers receive the original error plus its parameter payload.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
readonly messages: ValidationMessages = {
|
|
49
|
+
minLength: ({ params }) => `Use at least ${params['minLength'] ?? params['requiredLength']} characters.`,
|
|
50
|
+
required: { key: 'validation.required' }
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Put this declaration in the appropriate constants or types-supporting module according to the house rules. Translation-key overrides receive error parameters through the existing adapter. Default messages can be replaced application-wide using `FormSettingsService.update()`; instance inputs take precedence. No error-message map is mandatory when the schema supplies messages.
|
|
55
|
+
|
|
56
|
+
Projected `bx-error` supports rich content. `bx-hint`, `hint`, `hintEnd`, `bxPrefix`, and `bxSuffix` provide composable support and adornments. Supporting text and errors are associated automatically through `aria-describedby`. Custom error regions announce changes politely.
|
|
57
|
+
|
|
58
|
+
## Compatibility and migration
|
|
59
|
+
|
|
60
|
+
Existing `[formControl]`, `formControlName`, and `[(ngModel)]` component bindings remain supported. Text edits honor Reactive Forms blur and submit update strategies. `reset()` on the owning field/form clears component interaction and parse state. Standalone value controls expose `[(value)]`; checkbox-style controls expose `[(checked)]`.
|
|
61
|
+
|
|
62
|
+
`BxBaseControl` remains available for existing external CVA subclasses; repeated touch reporting and schema error-message handling are corrected. New Blocks controls use native signal contracts, without implementing CVA on the same component. The legacy individually bound radio remains available, while new forms should bind a `RadioGroup` once around its options.
|
|
63
|
+
|
|
64
|
+
Native `input`, `textarea` and `select` elements can use `bxInput` inside `bx-form-field`. Consumer components can provide `BX_FORM_FIELD_CONTROL` with `IFormFieldControl` to integrate their own state and focus behavior.
|
|
65
|
+
|
|
66
|
+
## Asynchronous options
|
|
67
|
+
|
|
68
|
+
Single select and multiselect support application-owned requests, comparison, templates, incremental loading and error/retry behavior. Their scroll wrappers use `LoadMoreDirective`, which can also be used by future paginated components. See the [load-more guide](directives/load-more/README.md) and [multiselect guide](components/multi-select/README.md).
|
|
69
|
+
|
|
70
|
+
## Appearance and accessibility
|
|
71
|
+
|
|
72
|
+
Controls follow Blocks semantic tokens, global theme/appearance configuration, reduced motion through `BxA11yService`, and reactive text resolution through `BX_I18N`. Configuration supports filled/outlined appearance, label placement, required markers, floating-label behavior and supporting-text sizing. Readonly and disabled states remain distinct in form state. All applicable controls accept `readOnly` as well as Angular Signal Forms' lowercase `readonly` contract. Either true value prevents edits while retaining focusability. Readonly controls use the default cursor and suppress pointer hover/click highlights and interactive glass lighting while preserving their static appearance and keyboard focus styling. Focus origin uses the shared Angular CDK focus monitor. Changes to readonly state update mounted surfaces, including projected native controls and grouped radios. Native select integration prevents interaction without binding a nonexistent native readOnly property.
|
|
73
|
+
|
|
74
|
+
All existing form ellipsis and full-selection fit measurement use the public `TruncateDirective` from `@filip.mazev/blocks/primitives`. Set `[tooltipOnTruncate]="false"` on an input, search, select, or multiselect to retain truncation while supplying your own tooltip. `FormSettingsService.update({ tooltipOnTruncate: false })` changes the application default; instance inputs take precedence. Tag and menu controls expose the same opt-out. The public `TruncatedTextPipe` (`bxTruncatedText`) and `truncatedText()` helper support custom feedback. See the [shared truncation guide](../primitives/directives/truncate/README.md).
|
|
75
|
+
|
|
76
|
+
## Playground
|
|
77
|
+
|
|
78
|
+
Open `/components/signal-forms` for multiple controls, sync/async/cross-field rules, pending state, custom messages, server errors, disabled submission, dynamic disabled/readonly, reset and reactive validation status. Use Fill valid data to exercise submission, or an email containing `server-error` to see a server rejection.
|
|
79
|
+
|
|
80
|
+
The load-more and selection pages include fake APIs, failed requests, retry and small pages without scrollbars.
|
package/package.json
CHANGED
|
@@ -216,10 +216,13 @@ export declare class BxShortcutService {
|
|
|
216
216
|
static ɵprov: i0.ɵɵInjectableDeclaration<any>;
|
|
217
217
|
}
|
|
218
218
|
export declare abstract class BxBaseControl<T> implements ControlValueAccessor, OnInit {
|
|
219
|
-
|
|
219
|
+
private readonly focusMonitor;
|
|
220
|
+
private readonly focusElement;
|
|
221
|
+
private readonly destroyRef;
|
|
220
222
|
protected readonly internalValue: import("@angular/core").WritableSignal<T | null>;
|
|
221
223
|
protected readonly isTouched: import("@angular/core").WritableSignal<boolean>;
|
|
222
224
|
protected readonly isDisabled: import("@angular/core").WritableSignal<boolean>;
|
|
225
|
+
protected readonly keyboardFocused: import("@angular/core").WritableSignal<boolean>;
|
|
223
226
|
readonly ngControl: NgControl | null;
|
|
224
227
|
readonly label: import("@angular/core").InputSignal<ResolvableText | undefined>;
|
|
225
228
|
readonly placeholder: import("@angular/core").InputSignal<ResolvableText | undefined>;
|
|
@@ -228,6 +231,9 @@ export declare abstract class BxBaseControl<T> implements ControlValueAccessor,
|
|
|
228
231
|
readonly ariaLabel: import("@angular/core").InputSignal<string | undefined>;
|
|
229
232
|
readonly errorMessages: import("@angular/core").InputSignal<Partial<Record<ValidatorKey, ResolvableText>>>;
|
|
230
233
|
readonly required: import("@angular/core").InputSignal<boolean>;
|
|
234
|
+
readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
235
|
+
readonly readOnly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
236
|
+
readonly isReadonly: import("@angular/core").Signal<boolean>;
|
|
231
237
|
readonly loading: import("@angular/core").InputSignal<boolean>;
|
|
232
238
|
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
233
239
|
protected onChange: (value: T | null) => void;
|
|
@@ -240,6 +246,8 @@ export declare abstract class BxBaseControl<T> implements ControlValueAccessor,
|
|
|
240
246
|
setDisabledState(isDisabled: boolean): void;
|
|
241
247
|
protected updateValue(value: T | null): void;
|
|
242
248
|
protected markAsTouched(): void;
|
|
249
|
+
protected onControlPointerDown(): void;
|
|
250
|
+
protected isFieldRequired(): boolean;
|
|
243
251
|
protected get errorMessage(): ResolvableText | undefined;
|
|
244
252
|
static ɵfac: i0.ɵɵFactoryDeclaration<BxBaseControl<any>, never>;
|
|
245
253
|
static ɵdir: i0.ɵɵDirectiveDeclaration<BxBaseControl<any>, never, never, {
|
|
@@ -278,6 +286,16 @@ export declare abstract class BxBaseControl<T> implements ControlValueAccessor,
|
|
|
278
286
|
"required": false;
|
|
279
287
|
"isSignal": true;
|
|
280
288
|
};
|
|
289
|
+
"readonly": {
|
|
290
|
+
"alias": "readonly";
|
|
291
|
+
"required": false;
|
|
292
|
+
"isSignal": true;
|
|
293
|
+
};
|
|
294
|
+
"readOnly": {
|
|
295
|
+
"alias": "readOnly";
|
|
296
|
+
"required": false;
|
|
297
|
+
"isSignal": true;
|
|
298
|
+
};
|
|
281
299
|
"loading": {
|
|
282
300
|
"alias": "loading";
|
|
283
301
|
"required": false;
|
|
@@ -353,4 +371,6 @@ export declare function invertPaletteToken(token: Color): Color;
|
|
|
353
371
|
export declare function resolveThemeId(value: string | null | undefined): BxThemeId | undefined;
|
|
354
372
|
export declare function uuidv4(): string;
|
|
355
373
|
export declare function inheritOverlayTheme(source: HTMLElement, pane: HTMLElement): () => void;
|
|
356
|
-
export declare function trackOverlayOrigin(overlay: OverlayRef, origin: HTMLElement): () => void;
|
|
374
|
+
export declare function trackOverlayOrigin(overlay: OverlayRef, origin: HTMLElement): () => void;
|
|
375
|
+
/** Resolves text and tracks the adapter's language signal in the calling computation. */
|
|
376
|
+
export declare function resolveText(text: ResolvableText | undefined, adapter: IBxI18nAdapter | null, params?: Record<string, unknown>): string;
|
|
@@ -47,7 +47,7 @@ export declare class BxSurfaceDirective implements AfterViewInit {
|
|
|
47
47
|
}, {}, never, never, true, never>;
|
|
48
48
|
}
|
|
49
49
|
/** Internal component integration. An explicit bxSurface directive takes precedence. */
|
|
50
|
-
export declare function injectComponentSurface(options?: () => SurfaceOptions$1): void;
|
|
50
|
+
export declare function injectComponentSurface(options?: () => SurfaceOptions$1, enabled?: () => boolean): void;
|
|
51
51
|
export interface BxGlassLight {
|
|
52
52
|
update(light: GlassLight): void;
|
|
53
53
|
destroy(): void;
|