@modyra/angular 0.2.0 → 0.3.0
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/README.md +53 -40
- package/fesm2022/modyra-angular.mjs +28 -13
- package/package.json +3 -3
- package/types/modyra-angular.d.ts +19 -14
package/README.md
CHANGED
|
@@ -9,33 +9,37 @@
|
|
|
9
9
|
engine with native bindings for Angular, React, Vue and Lit — one shared
|
|
10
10
|
core, one shared headless widget layer, one shared theme package.
|
|
11
11
|
|
|
12
|
-
- No
|
|
13
|
-
- Compile-time checked field bindings: `
|
|
12
|
+
- No framework runtime, no RxJS — form state is plain signals and `computed`s
|
|
13
|
+
- Compile-time checked field bindings: `form.f.email` — typos don't compile
|
|
14
14
|
- Sync, async (debounced, cancellable, cross-field) and form-level validation
|
|
15
15
|
- Typed field arrays (`array()`) for repeatable rows — push/insert/remove/move
|
|
16
16
|
- Drafts (autosave/restore), undo/redo, minimal-patch change tracking, devtools
|
|
17
17
|
- Headless core or accessible ready-made controls — your design system or ours
|
|
18
|
-
- Incremental
|
|
18
|
+
- Incremental adoption paths — e.g. Reactive Forms interop (`mdyCva`) on Angular
|
|
19
19
|
|
|
20
20
|
[](https://github.com/modyra/modyra/actions/workflows/ci.yml)
|
|
21
|
-
[](https://github.com/modyra/modyra/actions/workflows/release.yml)
|
|
22
|
+
[](https://www.npmjs.com/package/@modyra/core)
|
|
23
23
|
[](https://www.typescriptlang.org)
|
|
24
24
|
[](LICENSE)
|
|
25
25
|
[](https://github.com/sponsors/lorenzomusche)
|
|
26
26
|
|
|
27
27
|
## Packages
|
|
28
28
|
|
|
29
|
-
| Package
|
|
30
|
-
|
|
|
31
|
-
| [`@modyra/core`](packages/core)
|
|
32
|
-
| [`@modyra/widgets`](packages/widgets)
|
|
33
|
-
| [`@modyra/angular`](packages/angular)
|
|
34
|
-
| [`@modyra/react`](packages/react)
|
|
35
|
-
| [`@modyra/vue`](packages/vue)
|
|
36
|
-
| [`@modyra/lit`](packages/lit)
|
|
37
|
-
| [`@modyra/zod`](packages/zod)
|
|
38
|
-
| [`@modyra/
|
|
29
|
+
| Package | What it is | UI layer | Peer deps |
|
|
30
|
+
| :---------------------------------------------------- | :------------------------------------------------------------------------------------------------------- | :------------------------------------------------------- | :--------------------- |
|
|
31
|
+
| [`@modyra/core`](packages/core) | Framework-agnostic form engine: typed field trees, arrays, validation, drafts, undo/redo, i18n utilities | headless | — |
|
|
32
|
+
| [`@modyra/widgets`](packages/widgets) | Headless widget controllers + universal interaction/accessibility contract | headless | — |
|
|
33
|
+
| [`@modyra/angular`](packages/angular) | Angular binding on native signals | full renderer catalog, themes, devtools, wizard, interop | `@angular/*` ≥21 |
|
|
34
|
+
| [`@modyra/react`](packages/react) | React binding via `useSyncExternalStore` | headless — bring your own UI | `react` ≥18 |
|
|
35
|
+
| [`@modyra/vue`](packages/vue) | Vue binding on `@vue/reactivity` | headless — bring your own UI | `@vue/reactivity` ≥3.4 |
|
|
36
|
+
| [`@modyra/lit`](packages/lit) | Lit binding — ReactiveController | themable form elements | `lit` ≥3 |
|
|
37
|
+
| [`@modyra/zod`](packages/zod) | Framework-agnostic Zod adapter — schema-first typed forms | — | `zod` ≥3.25 |
|
|
38
|
+
| [`@modyra/standard-schema`](packages/standard-schema) | Standard Schema adapter — one adapter for Zod, Valibot, ArkType and every v1 vendor | — | — |
|
|
39
|
+
| [`@modyra/styles`](packages/styles) | CSS themes (`default`, `material`, `ios`, `ionic`, `base`) for every adapter | themes | — |
|
|
40
|
+
|
|
41
|
+
Every binding is a first-class citizen over the same engine: pick the one
|
|
42
|
+
for your framework, keep everything else identical.
|
|
39
43
|
|
|
40
44
|
## The engine in 60 seconds (framework-agnostic)
|
|
41
45
|
|
|
@@ -57,7 +61,7 @@ form.getValue().address.city; // "Rome" — fully typed, typos don't compile
|
|
|
57
61
|
```
|
|
58
62
|
|
|
59
63
|
> **Validators are factories, not values:** write `required()`, not
|
|
60
|
-
> `required` (
|
|
64
|
+
> `required` (value-style-validator muscle memory trips here — the
|
|
61
65
|
> resulting TS error is easy to misread). Validation errors come back as
|
|
62
66
|
> **arrays of message strings** (`["Name taken"]`), not `{ required: true }`
|
|
63
67
|
> keyed objects. To stop at the first failing validator instead of
|
|
@@ -247,20 +251,15 @@ implemented end-to-end, side by side, in:
|
|
|
247
251
|
Adapter recipes, the four-primitive reactive contract and the Astro note:
|
|
248
252
|
[Multi-framework architecture](docs/guides/multi-framework.md).
|
|
249
253
|
|
|
250
|
-
##
|
|
254
|
+
## Coming from Angular Reactive Forms?
|
|
251
255
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
Observables in the public API, none used internally. The optional `/interop`
|
|
260
|
-
entry point is the single exception — it declares `@angular/forms` as an
|
|
261
|
-
_optional_ peer for CVA-based migration.
|
|
262
|
-
|
|
263
|
-
Full, honest comparison: [Compared with Reactive Forms](docs/guides/comparison-reactive-forms.md).
|
|
256
|
+
This library trades ecosystem maturity for compile-checked field paths,
|
|
257
|
+
signal-based state (zoneless-friendly, no RxJS — no runtime dependency, no
|
|
258
|
+
Observables in the public API, none used internally) and built-in
|
|
259
|
+
async/cross-field validation, typed arrays, drafts, undo/redo and devtools.
|
|
260
|
+
The `/interop` entry point (`mdyCva`, optional `@angular/forms` peer) covers
|
|
261
|
+
incremental adoption. Full, honest comparison:
|
|
262
|
+
[Compared with Reactive Forms](docs/guides/comparison-reactive-forms.md).
|
|
264
263
|
|
|
265
264
|
## Layers
|
|
266
265
|
|
|
@@ -300,8 +299,10 @@ The full index lives in [docs/README.md](docs/README.md). The shortlist:
|
|
|
300
299
|
|
|
301
300
|
- [Mental model](docs/guides/mental-model.md) — the state graph, field lifecycle, operation semantics
|
|
302
301
|
- [Typed forms](docs/guides/typed-forms.md) — schema, handles, `patch`/`getChanges`, async validation, field arrays, undo/redo, **drafts (read the security note)**, wizard, Zod
|
|
302
|
+
- [Schema adapters](docs/guides/schemas.md) — Zod vs Standard Schema (Valibot, ArkType, …): which model, which trade-offs
|
|
303
303
|
- [Usage modes](docs/guides/usage-modes.md) — declarative, explicit adapter, headless, validation semantics
|
|
304
304
|
- [UI toolkit](docs/guides/ui-toolkit.md) — renderer catalog, enterprise select, dynamic forms, CSS tokens
|
|
305
|
+
- [AI-generated forms](docs/guides/ai-generated-forms.md) — LLM output → `parseDynamicFields()` → render: the safe pipeline + system prompt template
|
|
305
306
|
- [DevTools](docs/guides/devtools.md) — hotkey overlay, masking, production notes
|
|
306
307
|
- [I18n](docs/guides/i18n.md) — UI strings (en/it/de/fr/es), date/time value models, localized parsing
|
|
307
308
|
- [Reactive Forms interop](docs/guides/interop.md) · [Comparison](docs/guides/comparison-reactive-forms.md) · [Troubleshooting](docs/guides/troubleshooting.md)
|
|
@@ -317,15 +318,28 @@ Project policies: [security](SECURITY.md) · [contributing](CONTRIBUTING.md) ·
|
|
|
317
318
|
own adapter package.
|
|
318
319
|
- TypeScript strict mode; the library compiles with `strict` and
|
|
319
320
|
`strictTemplates`.
|
|
320
|
-
- Status: young library, actively developed, single maintainer.
|
|
321
|
-
|
|
322
|
-
(`
|
|
323
|
-
`
|
|
324
|
-
(`npm run test:bundle`)
|
|
325
|
-
|
|
321
|
+
- Status: young library, actively developed, single maintainer. `npm test`
|
|
322
|
+
runs the whole matrix — core engine, every adapter, the widget layer and
|
|
323
|
+
the Angular package (`test:core`, `test:adapters`, `test:widgets`,
|
|
324
|
+
`test:angular` individually) — plus a tree-shaking bundle check
|
|
325
|
+
(`npm run test:bundle`), axe-core accessibility tests over the main
|
|
326
|
+
Angular renderers (jest + jsdom, inside `test:angular`) and a Playwright
|
|
327
|
+
browser smoke test over the packaged Angular demo (`npm run test:e2e`,
|
|
328
|
+
currently non-blocking in CI while it stabilizes); visual regression
|
|
329
|
+
tests are still planned. Pin your version and read release notes.
|
|
326
330
|
|
|
327
331
|
## Examples
|
|
328
332
|
|
|
333
|
+
[](https://stackblitz.com/github/modyra/modyra/tree/main/examples/stackblitz)
|
|
334
|
+
|
|
335
|
+
`examples/stackblitz` is a minimal Angular signup form that runs against the
|
|
336
|
+
**published** `@modyra/angular` package — the fastest way to try the library
|
|
337
|
+
without cloning anything.
|
|
338
|
+
|
|
339
|
+
`examples/angular` is the full Angular demo app (typed, declarative, dynamic
|
|
340
|
+
and Zod sections over the whole renderer catalog) — one demo app per
|
|
341
|
+
framework, same engine.
|
|
342
|
+
|
|
329
343
|
`examples/{react,vue,lit}` implement the **same signup form** (name +
|
|
330
344
|
email, shared validators, agnostic devtools panel) so the adapters can be
|
|
331
345
|
compared side by side, with a runtime switcher across the shipped themes
|
|
@@ -344,11 +358,10 @@ npm run demo:lit # http://localhost:4303
|
|
|
344
358
|
|
|
345
359
|
```bash
|
|
346
360
|
pnpm install # workspace deps use the workspace: protocol — use pnpm
|
|
347
|
-
npm run build:
|
|
348
|
-
npm run build:
|
|
349
|
-
npm
|
|
350
|
-
npm
|
|
351
|
-
npm run test:adapters # zod/vue/react/lit node tests
|
|
361
|
+
npm run build:packages # core + widgets + schema adapters + react/vue/lit + styles
|
|
362
|
+
npm run build:angular # the Angular package (kept as build:lib alias)
|
|
363
|
+
npm test # the whole matrix: core, adapters, widgets, Angular
|
|
364
|
+
npm run demo:angular # one demo per framework: demo:react / demo:vue / demo:lit
|
|
352
365
|
```
|
|
353
366
|
|
|
354
367
|
## Brand
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, untracked, effect, computed, signal, inject, Injector, DestroyRef, input, output, forwardRef, ChangeDetectionStrategy, Component, linkedSignal, contentChildren, booleanAttribute, ApplicationRef, EnvironmentInjector, createComponent, Injectable, ElementRef, Directive, TemplateRef, contentChild, viewChild, viewChildren, afterNextRender, Renderer2, numberAttribute, HostAttributeToken } from '@angular/core';
|
|
3
|
-
import { MDY_I18N_MESSAGES_DEFAULT,
|
|
3
|
+
import { MDY_I18N_MESSAGES_DEFAULT, MDY_I18N_PRESETS, MDY_I18N_DEFAULT_TAGS } from '@modyra/core/localization';
|
|
4
|
+
import { buildDateLocale } from '@modyra/core/datetime';
|
|
5
|
+
import { MdyFormEngine, field as field$1, group as group$1, array as array$1, MdyTypedFormBase, email, maxLength, max, minLength, min, pattern, required } from '@modyra/core';
|
|
4
6
|
import { mdyFormSerialize } from '@modyra/core/serialize';
|
|
5
|
-
import {
|
|
7
|
+
import { buildDynamicFieldValidators } from '@modyra/core/dynamic-config';
|
|
6
8
|
import { NgTemplateOutlet, NgClass, NgStyle } from '@angular/common';
|
|
7
9
|
import { today, buildMonthGrid, isSameDay, isDateInRange, daysInMonth, addMonths, parseIsoDate, formatIsoDate, parseLocalizedDate, orderDates, isDateBetween, compareDates } from '@modyra/core/date-utils';
|
|
8
10
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
@@ -148,9 +150,12 @@ function angularReactivity(injector) {
|
|
|
148
150
|
class MdyDeclarativeAdapter extends MdyFormEngine {
|
|
149
151
|
constructor(formValue, submitMode = signal("valid-only"),
|
|
150
152
|
/** Needed to run async validators, drafts and history. */
|
|
151
|
-
injector
|
|
153
|
+
injector,
|
|
154
|
+
/** Injection-prevention policy for field values (see `@modyra/core` security). */
|
|
155
|
+
security) {
|
|
152
156
|
super(angularReactivity(injector), formValue, submitMode, {
|
|
153
157
|
devWarnings: typeof ngDevMode !== "undefined" && !!ngDevMode,
|
|
158
|
+
...(security !== undefined && { security }),
|
|
154
159
|
});
|
|
155
160
|
}
|
|
156
161
|
getField(name) {
|
|
@@ -209,6 +214,7 @@ function mdyForm(schema, options) {
|
|
|
209
214
|
...(options?.validators !== undefined && { validators: options.validators }),
|
|
210
215
|
...(options?.history !== undefined && { history: options.history }),
|
|
211
216
|
...(options?.draft !== undefined && { draft: options.draft }),
|
|
217
|
+
...(options?.security !== undefined && { security: options.security }),
|
|
212
218
|
...(injector !== undefined && { injector }),
|
|
213
219
|
});
|
|
214
220
|
// Tie the form's resources (async runners, draft/history timers) to the
|
|
@@ -226,7 +232,7 @@ function mdyForm(schema, options) {
|
|
|
226
232
|
*/
|
|
227
233
|
class MdyTypedForm extends MdyTypedFormBase {
|
|
228
234
|
constructor(schema, options) {
|
|
229
|
-
const adapter = new MdyDeclarativeAdapter(signal(undefined), signal(options?.submitMode ?? "valid-only"), options?.injector);
|
|
235
|
+
const adapter = new MdyDeclarativeAdapter(signal(undefined), signal(options?.submitMode ?? "valid-only"), options?.injector, options?.security);
|
|
230
236
|
super(schema, adapter, options);
|
|
231
237
|
this.state = adapter.state;
|
|
232
238
|
this.value = computed(() => this._flatToValue(this._adapter.value()));
|
|
@@ -445,6 +451,9 @@ class MdyFormComponent {
|
|
|
445
451
|
setInitialValue(name, value) {
|
|
446
452
|
this._registry.setInitialValue(name, value);
|
|
447
453
|
}
|
|
454
|
+
setSanitizer(name, sanitizer) {
|
|
455
|
+
this._registry.setSanitizer(name, sanitizer);
|
|
456
|
+
}
|
|
448
457
|
setDisabled(name, disabled) {
|
|
449
458
|
this._registry.setDisabled(name, disabled);
|
|
450
459
|
}
|
|
@@ -3193,7 +3202,6 @@ class MdyDatePickerComponent extends MdyOverlayControl {
|
|
|
3193
3202
|
[disabled]="isDisabled()"
|
|
3194
3203
|
(change)="onInputChange($event)"
|
|
3195
3204
|
(blur)="onInputBlur($event)"
|
|
3196
|
-
[attr.aria-expanded]="open()"
|
|
3197
3205
|
[attr.aria-haspopup]="'dialog'"
|
|
3198
3206
|
[attr.aria-invalid]="hasErrors()"
|
|
3199
3207
|
[attr.aria-describedby]="hasErrors() ? fieldId + '-errors' : null"
|
|
@@ -3211,6 +3219,8 @@ class MdyDatePickerComponent extends MdyOverlayControl {
|
|
|
3211
3219
|
[disabled]="isDisabled()"
|
|
3212
3220
|
(click)="toggleOverlay($event)"
|
|
3213
3221
|
[attr.aria-label]="i18n.datepickerToggleLabel"
|
|
3222
|
+
[attr.aria-expanded]="open()"
|
|
3223
|
+
[attr.aria-haspopup]="'dialog'"
|
|
3214
3224
|
>
|
|
3215
3225
|
<mdy-icon name="CALENDAR" class="mdy-datepicker__icon" />
|
|
3216
3226
|
</button>
|
|
@@ -3311,7 +3321,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
3311
3321
|
[disabled]="isDisabled()"
|
|
3312
3322
|
(change)="onInputChange($event)"
|
|
3313
3323
|
(blur)="onInputBlur($event)"
|
|
3314
|
-
[attr.aria-expanded]="open()"
|
|
3315
3324
|
[attr.aria-haspopup]="'dialog'"
|
|
3316
3325
|
[attr.aria-invalid]="hasErrors()"
|
|
3317
3326
|
[attr.aria-describedby]="hasErrors() ? fieldId + '-errors' : null"
|
|
@@ -3329,6 +3338,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
3329
3338
|
[disabled]="isDisabled()"
|
|
3330
3339
|
(click)="toggleOverlay($event)"
|
|
3331
3340
|
[attr.aria-label]="i18n.datepickerToggleLabel"
|
|
3341
|
+
[attr.aria-expanded]="open()"
|
|
3342
|
+
[attr.aria-haspopup]="'dialog'"
|
|
3332
3343
|
>
|
|
3333
3344
|
<mdy-icon name="CALENDAR" class="mdy-datepicker__icon" />
|
|
3334
3345
|
</button>
|
|
@@ -6493,7 +6504,6 @@ class MdyTimepickerComponent extends MdyOverlayControl {
|
|
|
6493
6504
|
[attr.aria-required]="ariaRequired() || isRequired()"
|
|
6494
6505
|
[attr.aria-disabled]="effectiveAriaDisabled()"
|
|
6495
6506
|
[attr.aria-label]="label() || null"
|
|
6496
|
-
[attr.aria-expanded]="open()"
|
|
6497
6507
|
[attr.aria-haspopup]="'dialog'"
|
|
6498
6508
|
autocomplete="off"
|
|
6499
6509
|
/>
|
|
@@ -6506,6 +6516,8 @@ class MdyTimepickerComponent extends MdyOverlayControl {
|
|
|
6506
6516
|
class="mdy-timepicker__toggle"
|
|
6507
6517
|
[disabled]="isDisabled()"
|
|
6508
6518
|
[attr.aria-label]="i18n.timepickerOpenLabel"
|
|
6519
|
+
[attr.aria-expanded]="open()"
|
|
6520
|
+
[attr.aria-haspopup]="'dialog'"
|
|
6509
6521
|
tabindex="-1"
|
|
6510
6522
|
(click)="toggleOverlay($event)"
|
|
6511
6523
|
>
|
|
@@ -6595,7 +6607,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
6595
6607
|
[attr.aria-required]="ariaRequired() || isRequired()"
|
|
6596
6608
|
[attr.aria-disabled]="effectiveAriaDisabled()"
|
|
6597
6609
|
[attr.aria-label]="label() || null"
|
|
6598
|
-
[attr.aria-expanded]="open()"
|
|
6599
6610
|
[attr.aria-haspopup]="'dialog'"
|
|
6600
6611
|
autocomplete="off"
|
|
6601
6612
|
/>
|
|
@@ -6608,6 +6619,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
6608
6619
|
class="mdy-timepicker__toggle"
|
|
6609
6620
|
[disabled]="isDisabled()"
|
|
6610
6621
|
[attr.aria-label]="i18n.timepickerOpenLabel"
|
|
6622
|
+
[attr.aria-expanded]="open()"
|
|
6623
|
+
[attr.aria-haspopup]="'dialog'"
|
|
6611
6624
|
tabindex="-1"
|
|
6612
6625
|
(click)="toggleOverlay($event)"
|
|
6613
6626
|
>
|
|
@@ -6791,7 +6804,9 @@ class MdyDynamicFormComponent {
|
|
|
6791
6804
|
const form = this.form();
|
|
6792
6805
|
untracked(() => {
|
|
6793
6806
|
for (const f of fields) {
|
|
6794
|
-
|
|
6807
|
+
// buildDynamicFieldValidators includes the automatic option
|
|
6808
|
+
// whitelist (anti-tampering) for select/radio/segmented/multiselect.
|
|
6809
|
+
const { validators, marksRequired } = buildDynamicFieldValidators(f);
|
|
6795
6810
|
form.upsertValidators(f.name, "mdy-dynamic", validators, marksRequired);
|
|
6796
6811
|
}
|
|
6797
6812
|
});
|
|
@@ -8718,7 +8733,6 @@ class MdyDateRangePickerComponent extends MdyOverlayControl {
|
|
|
8718
8733
|
[attr.aria-required]="ariaRequired() || isRequired()"
|
|
8719
8734
|
[attr.aria-disabled]="effectiveAriaDisabled()"
|
|
8720
8735
|
[attr.aria-label]="(label() ? label() + ' — ' : '') + i18n.daterangeStartLabel"
|
|
8721
|
-
[attr.aria-expanded]="open()"
|
|
8722
8736
|
[attr.aria-haspopup]="'dialog'"
|
|
8723
8737
|
autocomplete="off"
|
|
8724
8738
|
/>
|
|
@@ -8742,7 +8756,6 @@ class MdyDateRangePickerComponent extends MdyOverlayControl {
|
|
|
8742
8756
|
[attr.aria-required]="ariaRequired() || isRequired()"
|
|
8743
8757
|
[attr.aria-disabled]="effectiveAriaDisabled()"
|
|
8744
8758
|
[attr.aria-label]="(label() ? label() + ' — ' : '') + i18n.daterangeEndLabel"
|
|
8745
|
-
[attr.aria-expanded]="open()"
|
|
8746
8759
|
[attr.aria-haspopup]="'dialog'"
|
|
8747
8760
|
autocomplete="off"
|
|
8748
8761
|
/>
|
|
@@ -8753,6 +8766,8 @@ class MdyDateRangePickerComponent extends MdyOverlayControl {
|
|
|
8753
8766
|
class="mdy-datepicker__toggle"
|
|
8754
8767
|
[disabled]="isDisabled()"
|
|
8755
8768
|
[attr.aria-label]="i18n.datepickerToggleLabel"
|
|
8769
|
+
[attr.aria-expanded]="open()"
|
|
8770
|
+
[attr.aria-haspopup]="'dialog'"
|
|
8756
8771
|
tabindex="-1"
|
|
8757
8772
|
(click)="toggleOverlay($event)"
|
|
8758
8773
|
>
|
|
@@ -8862,7 +8877,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
8862
8877
|
[attr.aria-required]="ariaRequired() || isRequired()"
|
|
8863
8878
|
[attr.aria-disabled]="effectiveAriaDisabled()"
|
|
8864
8879
|
[attr.aria-label]="(label() ? label() + ' — ' : '') + i18n.daterangeStartLabel"
|
|
8865
|
-
[attr.aria-expanded]="open()"
|
|
8866
8880
|
[attr.aria-haspopup]="'dialog'"
|
|
8867
8881
|
autocomplete="off"
|
|
8868
8882
|
/>
|
|
@@ -8886,7 +8900,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
8886
8900
|
[attr.aria-required]="ariaRequired() || isRequired()"
|
|
8887
8901
|
[attr.aria-disabled]="effectiveAriaDisabled()"
|
|
8888
8902
|
[attr.aria-label]="(label() ? label() + ' — ' : '') + i18n.daterangeEndLabel"
|
|
8889
|
-
[attr.aria-expanded]="open()"
|
|
8890
8903
|
[attr.aria-haspopup]="'dialog'"
|
|
8891
8904
|
autocomplete="off"
|
|
8892
8905
|
/>
|
|
@@ -8897,6 +8910,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
8897
8910
|
class="mdy-datepicker__toggle"
|
|
8898
8911
|
[disabled]="isDisabled()"
|
|
8899
8912
|
[attr.aria-label]="i18n.datepickerToggleLabel"
|
|
8913
|
+
[attr.aria-expanded]="open()"
|
|
8914
|
+
[attr.aria-haspopup]="'dialog'"
|
|
8900
8915
|
tabindex="-1"
|
|
8901
8916
|
(click)="toggleOverlay($event)"
|
|
8902
8917
|
>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modyra/angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Type-safe Angular forms built entirely on native Signals.",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "github",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"tslib": ">=2.3.0",
|
|
53
|
-
"@modyra/core": "^0.
|
|
54
|
-
"@modyra/widgets": "^0.
|
|
53
|
+
"@modyra/core": "^0.3.0",
|
|
54
|
+
"@modyra/widgets": "^0.3.0"
|
|
55
55
|
},
|
|
56
56
|
"exports": {
|
|
57
57
|
".": {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { Signal, WritableSignal, Injector, InjectionToken, Provider, TemplateRef, OnInit, ElementRef, InputSignal, OnDestroy, InputSignalWithTransform } from '@angular/core';
|
|
3
3
|
import * as _modyra_core from '@modyra/core';
|
|
4
|
-
import { MdyFormError, MdyFieldError, MdyFormSubmitEvent, MdyControlOption, ValidatorFn, MdySelectOption, MdyFormRegistry, MdyFormEngine, MdySubmitMode,
|
|
5
|
-
export { MdyAsyncValidatorFn, MdyAsyncValidatorOptions, MdyControlOption, MdyDateRange, MdyDraftOptions, MdyDraftStorage, MdyFieldError, MdyFormError, MdyFormSubmitEvent, MdyFormValidatorFn, MdySelectOption, MdySubmitMode, ValidatorFn } from '@modyra/core';
|
|
4
|
+
import { MdyFormError, MdyFieldError, MdyFormSubmitEvent, MdyControlOption, ValidatorFn, MdySelectOption, MdyFormRegistry, MdyFormEngine, MdySubmitMode, MdySecurityPolicy, MdyAnyArrayDescriptor as MdyAnyArrayDescriptor$1, MdyAnyFieldDescriptor as MdyAnyFieldDescriptor$1, MdyAnyGroupDescriptor as MdyAnyGroupDescriptor$1, MdyArrayDescriptor as MdyArrayDescriptor$1, MdyArrayItemValue as MdyArrayItemValue$1, MdyFieldDescriptor as MdyFieldDescriptor$1, MdyFormSchema as MdyFormSchema$1, MdyGroupDescriptor as MdyGroupDescriptor$1, MdyFieldOptions as MdyFieldOptions$1, MdyTypedFormBaseOptions, MdyFormPatch as MdyFormPatch$1, MdyFormValue as MdyFormValue$1, MdyTypedFormBase, MdyWiden as MdyWiden$1, MdyFormValidatorFn, MdyAsyncValidatorFn, MdyAsyncValidatorOptions, MdySanitizer, MdyDateRange, MdyReactivity } from '@modyra/core';
|
|
5
|
+
export { MdyAsyncValidatorFn, MdyAsyncValidatorOptions, MdyControlOption, MdyDateRange, MdyDraftOptions, MdyDraftStorage, MdyFieldError, MdyFormError, MdyFormSubmitEvent, MdyFormValidatorFn, MdySanitizeProfile, MdySanitizer, MdySecurityPolicy, MdySecurityViolation, MdySecurityViolationKind, MdySelectOption, MdySubmitMode, ValidatorFn } from '@modyra/core';
|
|
6
6
|
import * as _modyra_angular from '@modyra/angular';
|
|
7
|
+
import { MdyI18nMessages, MdyBuiltInLocale } from '@modyra/core/localization';
|
|
8
|
+
import { MdyDateLocale } from '@modyra/core/datetime';
|
|
7
9
|
import { MdyDynamicField } from '@modyra/core/dynamic-config';
|
|
8
|
-
import * as
|
|
10
|
+
import * as packages_core_dist_i18n from 'packages/core/dist/i18n';
|
|
9
11
|
import { OverlayPosition, OverlayAlignment, OverlayAnchor } from '@modyra/core/overlay-position';
|
|
10
12
|
import { CalendarCell, CalendarDate } from '@modyra/core/date-utils';
|
|
11
13
|
import * as _modyra_widgets from '@modyra/widgets';
|
|
@@ -122,7 +124,9 @@ type MdyDeclarativeRegistry = MdyFormRegistry<Signal<boolean>>;
|
|
|
122
124
|
declare class MdyDeclarativeAdapter extends MdyFormEngine implements MdyFormAdapter<Record<string, unknown>>, MdyDeclarativeRegistry {
|
|
123
125
|
constructor(formValue: Signal<Record<string, unknown> | undefined>, submitMode?: Signal<MdySubmitMode>,
|
|
124
126
|
/** Needed to run async validators, drafts and history. */
|
|
125
|
-
injector?: Injector
|
|
127
|
+
injector?: Injector,
|
|
128
|
+
/** Injection-prevention policy for field values (see `@modyra/core` security). */
|
|
129
|
+
security?: MdySecurityPolicy);
|
|
126
130
|
readonly state: MdyFormState;
|
|
127
131
|
readonly value: Signal<Record<string, unknown>>;
|
|
128
132
|
readonly fieldNames: Signal<readonly string[]>;
|
|
@@ -467,6 +471,7 @@ declare class MdyFormComponent<T extends Record<string, unknown>> implements Mdy
|
|
|
467
471
|
removeValidators(name: string, key: string): void;
|
|
468
472
|
upsertAsyncValidators<V>(name: string, key: string, validators: ReadonlyArray<MdyAsyncValidatorFn<V>>, options?: MdyAsyncValidatorOptions): void;
|
|
469
473
|
setInitialValue(name: string, value: unknown): void;
|
|
474
|
+
setSanitizer(name: string, sanitizer: MdySanitizer): void;
|
|
470
475
|
setDisabled(name: string, disabled: Signal<boolean>): void;
|
|
471
476
|
setReadonly(name: string, readonly: Signal<boolean>): void;
|
|
472
477
|
get state(): MdyFormState;
|
|
@@ -723,7 +728,7 @@ declare class MdyWizardStepComponent {
|
|
|
723
728
|
* `form.submit(...)` or submit the surrounding form there.
|
|
724
729
|
*/
|
|
725
730
|
declare class MdyFormWizardComponent {
|
|
726
|
-
protected readonly i18n:
|
|
731
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
727
732
|
private readonly adapter;
|
|
728
733
|
protected readonly steps: Signal<readonly MdyWizardStepComponent[]>;
|
|
729
734
|
private readonly _activeIndex;
|
|
@@ -1080,7 +1085,7 @@ declare class MdyGlassDirective {
|
|
|
1080
1085
|
/** Optional override for the blur amount (e.g., '10px' or 'blur(10px)') */
|
|
1081
1086
|
readonly blur: _angular_core.InputSignal<string | undefined>;
|
|
1082
1087
|
/** Intensity of the glass effect. Themes can use this to adjust blur/opacity. */
|
|
1083
|
-
readonly intensity: _angular_core.InputSignal<"
|
|
1088
|
+
readonly intensity: _angular_core.InputSignal<"high" | "low" | "medium">;
|
|
1084
1089
|
/** Optional background color override to tint the glass. */
|
|
1085
1090
|
readonly glassColor: _angular_core.InputSignal<string | undefined>;
|
|
1086
1091
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MdyGlassDirective, never>;
|
|
@@ -1341,7 +1346,7 @@ declare class MdyCheckboxComponent extends MdyBaseControl<boolean> {
|
|
|
1341
1346
|
* ```
|
|
1342
1347
|
*/
|
|
1343
1348
|
declare class MdyColorsComponent extends MdyOverlayControl<string> {
|
|
1344
|
-
protected readonly i18n:
|
|
1349
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
1345
1350
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
1346
1351
|
readonly presets: _angular_core.InputSignal<readonly string[]>;
|
|
1347
1352
|
protected readonly fieldId: string;
|
|
@@ -1463,7 +1468,7 @@ declare class MdyCalendarHeaderComponent {
|
|
|
1463
1468
|
readonly nextMonth: _angular_core.OutputEmitterRef<void>;
|
|
1464
1469
|
readonly toggleView: _angular_core.OutputEmitterRef<void>;
|
|
1465
1470
|
private readonly locale;
|
|
1466
|
-
protected readonly i18n:
|
|
1471
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
1467
1472
|
/** Localized month name (e.g. "March", "Marzo"). */
|
|
1468
1473
|
protected readonly monthLabel: _angular_core.Signal<string>;
|
|
1469
1474
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MdyCalendarHeaderComponent, never>;
|
|
@@ -1547,7 +1552,7 @@ declare class MdyDatePickerComponent extends MdyOverlayControl<string | null> {
|
|
|
1547
1552
|
readonly displayFormat: _angular_core.InputSignal<"iso" | "localized">;
|
|
1548
1553
|
protected readonly minSpace = 450;
|
|
1549
1554
|
protected readonly fieldId: string;
|
|
1550
|
-
protected readonly i18n:
|
|
1555
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
1551
1556
|
private readonly calendarRef;
|
|
1552
1557
|
private readonly locale;
|
|
1553
1558
|
private readonly injector;
|
|
@@ -1586,7 +1591,7 @@ declare class MdyDateRangePickerComponent extends MdyOverlayControl<MdyDateRange
|
|
|
1586
1591
|
private readonly calendarRef;
|
|
1587
1592
|
private readonly locale;
|
|
1588
1593
|
private readonly injector;
|
|
1589
|
-
protected readonly i18n:
|
|
1594
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
1590
1595
|
protected readonly tempStart: _angular_core.WritableSignal<CalendarDate | null>;
|
|
1591
1596
|
protected readonly tempEnd: _angular_core.WritableSignal<CalendarDate | null>;
|
|
1592
1597
|
protected readonly displayStart: _angular_core.Signal<string>;
|
|
@@ -1751,7 +1756,7 @@ declare class MdyFileComponent extends MdyBaseControl<File | File[] | null> {
|
|
|
1751
1756
|
readonly fileSelected: _angular_core.OutputEmitterRef<File | File[] | null>;
|
|
1752
1757
|
/** Emits the files rejected by accept/maxFileSize/maxFiles filtering. */
|
|
1753
1758
|
readonly filesRejected: _angular_core.OutputEmitterRef<readonly File[]>;
|
|
1754
|
-
protected readonly i18n:
|
|
1759
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
1755
1760
|
protected readonly fieldId: string;
|
|
1756
1761
|
protected readonly dragOver: _angular_core.WritableSignal<boolean>;
|
|
1757
1762
|
private readonly fileInput;
|
|
@@ -1779,7 +1784,7 @@ declare class MdyFileComponent extends MdyBaseControl<File | File[] | null> {
|
|
|
1779
1784
|
*/
|
|
1780
1785
|
declare abstract class MdyDropdownBase<TValue, TOptionValue = unknown> extends MdyOptionsOverlayControl<TValue, TOptionValue> implements MdyOptionsControl<TOptionValue> {
|
|
1781
1786
|
/** Internationalized strings used by dropdown UI. */
|
|
1782
|
-
protected readonly i18n:
|
|
1787
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
1783
1788
|
/** Injector for Angular effects and `afterNextRender` calls. */
|
|
1784
1789
|
protected readonly injector: Injector;
|
|
1785
1790
|
/** Minimum viewport space required to anchor the dropdown. */
|
|
@@ -1803,7 +1808,7 @@ declare abstract class MdyDropdownBase<TValue, TOptionValue = unknown> extends M
|
|
|
1803
1808
|
* Renders selectable filter chips and delivers ReadonlyArray<TValue>.
|
|
1804
1809
|
*/
|
|
1805
1810
|
declare class MdyMultiselectComponent<TValue = string> extends MdyDropdownBase<ReadonlyArray<TValue>, TValue> implements MdyOptionsControl<TValue> {
|
|
1806
|
-
readonly mode: _angular_core.InputSignal<"
|
|
1811
|
+
readonly mode: _angular_core.InputSignal<"multi" | "single">;
|
|
1807
1812
|
/**
|
|
1808
1813
|
* Optional filter predicate applied to options before display.
|
|
1809
1814
|
* Receives the option *value* and returns `true` to show the option.
|
|
@@ -2013,7 +2018,7 @@ declare class MdyToggleComponent extends MdyBaseControl<boolean> {
|
|
|
2013
2018
|
* Timepicker renderer — M3-style input with clock overlay.
|
|
2014
2019
|
*/
|
|
2015
2020
|
declare class MdyTimepickerComponent extends MdyOverlayControl<string | null> {
|
|
2016
|
-
protected readonly i18n:
|
|
2021
|
+
protected readonly i18n: packages_core_dist_i18n.MdyI18nMessages;
|
|
2017
2022
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
2018
2023
|
/**
|
|
2019
2024
|
* Value and display format: `"12h"` uses `"hh:mm AM/PM"` strings,
|