forty-cdk 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/accordion/README.md +122 -0
- package/aspect-ratio/README.md +76 -0
- package/avatar/README.md +100 -0
- package/breadcrumbs/README.md +49 -0
- package/breakpoints/README.md +81 -0
- package/button/README.md +49 -0
- package/calendar/README.md +458 -0
- package/carousel/README.md +358 -0
- package/checkbox/README.md +146 -0
- package/combobox/README.md +535 -0
- package/context-menu/README.md +139 -0
- package/date-field/README.md +184 -0
- package/date-picker/README.md +338 -0
- package/dialog/README.md +388 -0
- package/disclosure/README.md +114 -0
- package/drag-drop/README.md +359 -0
- package/drawer/README.md +560 -0
- package/dropdown-menu/README.md +176 -0
- package/fesm2022/forty-cdk-accordion.mjs +348 -0
- package/fesm2022/forty-cdk-accordion.mjs.map +1 -0
- package/fesm2022/forty-cdk-aspect-ratio.mjs +74 -0
- package/fesm2022/forty-cdk-aspect-ratio.mjs.map +1 -0
- package/fesm2022/forty-cdk-avatar.mjs +308 -0
- package/fesm2022/forty-cdk-avatar.mjs.map +1 -0
- package/fesm2022/forty-cdk-breadcrumbs.mjs +125 -0
- package/fesm2022/forty-cdk-breadcrumbs.mjs.map +1 -0
- package/fesm2022/forty-cdk-breakpoints.mjs +117 -0
- package/fesm2022/forty-cdk-breakpoints.mjs.map +1 -0
- package/fesm2022/forty-cdk-button.mjs +134 -0
- package/fesm2022/forty-cdk-button.mjs.map +1 -0
- package/fesm2022/forty-cdk-calendar.mjs +2034 -0
- package/fesm2022/forty-cdk-calendar.mjs.map +1 -0
- package/fesm2022/forty-cdk-carousel.mjs +968 -0
- package/fesm2022/forty-cdk-carousel.mjs.map +1 -0
- package/fesm2022/forty-cdk-checkbox.mjs +226 -0
- package/fesm2022/forty-cdk-checkbox.mjs.map +1 -0
- package/fesm2022/forty-cdk-combobox.mjs +2596 -0
- package/fesm2022/forty-cdk-combobox.mjs.map +1 -0
- package/fesm2022/forty-cdk-context-menu.mjs +413 -0
- package/fesm2022/forty-cdk-context-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-core.mjs +9022 -0
- package/fesm2022/forty-cdk-core.mjs.map +1 -0
- package/fesm2022/forty-cdk-date-field.mjs +744 -0
- package/fesm2022/forty-cdk-date-field.mjs.map +1 -0
- package/fesm2022/forty-cdk-date-picker.mjs +1011 -0
- package/fesm2022/forty-cdk-date-picker.mjs.map +1 -0
- package/fesm2022/forty-cdk-dialog.mjs +707 -0
- package/fesm2022/forty-cdk-dialog.mjs.map +1 -0
- package/fesm2022/forty-cdk-disclosure.mjs +190 -0
- package/fesm2022/forty-cdk-disclosure.mjs.map +1 -0
- package/fesm2022/forty-cdk-drag-drop.mjs +1180 -0
- package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -0
- package/fesm2022/forty-cdk-drawer.mjs +1641 -0
- package/fesm2022/forty-cdk-drawer.mjs.map +1 -0
- package/fesm2022/forty-cdk-dropdown-menu.mjs +350 -0
- package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-field.mjs +425 -0
- package/fesm2022/forty-cdk-field.mjs.map +1 -0
- package/fesm2022/forty-cdk-fieldset.mjs +164 -0
- package/fesm2022/forty-cdk-fieldset.mjs.map +1 -0
- package/fesm2022/forty-cdk-file-upload.mjs +221 -0
- package/fesm2022/forty-cdk-file-upload.mjs.map +1 -0
- package/fesm2022/forty-cdk-hover-card.mjs +496 -0
- package/fesm2022/forty-cdk-hover-card.mjs.map +1 -0
- package/fesm2022/forty-cdk-input.mjs +274 -0
- package/fesm2022/forty-cdk-input.mjs.map +1 -0
- package/fesm2022/forty-cdk-internationalized-date.mjs +1 -1
- package/fesm2022/forty-cdk-internationalized-date.mjs.map +1 -1
- package/fesm2022/forty-cdk-listbox.mjs +1279 -0
- package/fesm2022/forty-cdk-listbox.mjs.map +1 -0
- package/fesm2022/forty-cdk-menu.mjs +1439 -0
- package/fesm2022/forty-cdk-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-menubar.mjs +787 -0
- package/fesm2022/forty-cdk-menubar.mjs.map +1 -0
- package/fesm2022/forty-cdk-meter.mjs +211 -0
- package/fesm2022/forty-cdk-meter.mjs.map +1 -0
- package/fesm2022/forty-cdk-navigation-menu.mjs +1145 -0
- package/fesm2022/forty-cdk-navigation-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-number-input.mjs +559 -0
- package/fesm2022/forty-cdk-number-input.mjs.map +1 -0
- package/fesm2022/forty-cdk-otp-input.mjs +527 -0
- package/fesm2022/forty-cdk-otp-input.mjs.map +1 -0
- package/fesm2022/forty-cdk-pagination.mjs +323 -0
- package/fesm2022/forty-cdk-pagination.mjs.map +1 -0
- package/fesm2022/forty-cdk-pane-resizer.mjs +297 -0
- package/fesm2022/forty-cdk-pane-resizer.mjs.map +1 -0
- package/fesm2022/forty-cdk-popover.mjs +698 -0
- package/fesm2022/forty-cdk-popover.mjs.map +1 -0
- package/fesm2022/forty-cdk-progress.mjs +226 -0
- package/fesm2022/forty-cdk-progress.mjs.map +1 -0
- package/fesm2022/forty-cdk-radio-group.mjs +378 -0
- package/fesm2022/forty-cdk-radio-group.mjs.map +1 -0
- package/fesm2022/forty-cdk-scroll-area.mjs +640 -0
- package/fesm2022/forty-cdk-scroll-area.mjs.map +1 -0
- package/fesm2022/forty-cdk-search.mjs +205 -0
- package/fesm2022/forty-cdk-search.mjs.map +1 -0
- package/fesm2022/forty-cdk-select.mjs +1661 -0
- package/fesm2022/forty-cdk-select.mjs.map +1 -0
- package/fesm2022/forty-cdk-separator.mjs +82 -0
- package/fesm2022/forty-cdk-separator.mjs.map +1 -0
- package/fesm2022/forty-cdk-signal-forms.mjs +97 -0
- package/fesm2022/forty-cdk-signal-forms.mjs.map +1 -0
- package/fesm2022/forty-cdk-slider.mjs +803 -0
- package/fesm2022/forty-cdk-slider.mjs.map +1 -0
- package/fesm2022/forty-cdk-stepper.mjs +886 -0
- package/fesm2022/forty-cdk-stepper.mjs.map +1 -0
- package/fesm2022/forty-cdk-switch.mjs +137 -0
- package/fesm2022/forty-cdk-switch.mjs.map +1 -0
- package/fesm2022/forty-cdk-table.mjs +1518 -0
- package/fesm2022/forty-cdk-table.mjs.map +1 -0
- package/fesm2022/forty-cdk-tabs.mjs +400 -0
- package/fesm2022/forty-cdk-tabs.mjs.map +1 -0
- package/fesm2022/forty-cdk-time-field.mjs +593 -0
- package/fesm2022/forty-cdk-time-field.mjs.map +1 -0
- package/fesm2022/forty-cdk-time-picker.mjs +1013 -0
- package/fesm2022/forty-cdk-time-picker.mjs.map +1 -0
- package/fesm2022/forty-cdk-toast.mjs +1153 -0
- package/fesm2022/forty-cdk-toast.mjs.map +1 -0
- package/fesm2022/forty-cdk-toggle.mjs +516 -0
- package/fesm2022/forty-cdk-toggle.mjs.map +1 -0
- package/fesm2022/forty-cdk-toolbar.mjs +374 -0
- package/fesm2022/forty-cdk-toolbar.mjs.map +1 -0
- package/fesm2022/forty-cdk-tooltip.mjs +672 -0
- package/fesm2022/forty-cdk-tooltip.mjs.map +1 -0
- package/fesm2022/forty-cdk-tree.mjs +2007 -0
- package/fesm2022/forty-cdk-tree.mjs.map +1 -0
- package/fesm2022/forty-cdk-virtualization.mjs +1 -1
- package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
- package/fesm2022/forty-cdk.mjs +0 -43310
- package/fesm2022/forty-cdk.mjs.map +1 -1
- package/field/README.md +97 -0
- package/fieldset/README.md +86 -0
- package/file-upload/README.md +73 -0
- package/hover-card/README.md +171 -0
- package/input/README.md +156 -0
- package/listbox/README.md +424 -0
- package/menu/README.md +181 -0
- package/menubar/README.md +140 -0
- package/meter/README.md +128 -0
- package/navigation-menu/README.md +253 -0
- package/number-input/README.md +171 -0
- package/otp-input/README.md +198 -0
- package/package.json +213 -1
- package/pagination/README.md +61 -0
- package/pane-resizer/README.md +136 -0
- package/popover/README.md +262 -0
- package/progress/README.md +115 -0
- package/radio-group/README.md +129 -0
- package/scroll-area/README.md +184 -0
- package/search/README.md +42 -0
- package/select/README.md +488 -0
- package/separator/README.md +84 -0
- package/signal-forms/README.md +72 -0
- package/slider/README.md +152 -0
- package/stepper/README.md +292 -0
- package/switch/README.md +116 -0
- package/table/README.md +769 -0
- package/tabs/README.md +130 -0
- package/time-field/README.md +157 -0
- package/time-picker/README.md +172 -0
- package/toast/README.md +398 -0
- package/toggle/README.md +224 -0
- package/toolbar/README.md +109 -0
- package/tooltip/README.md +274 -0
- package/tree/README.md +708 -0
- package/types/forty-cdk-accordion.d.ts +242 -0
- package/types/forty-cdk-aspect-ratio.d.ts +59 -0
- package/types/forty-cdk-avatar.d.ts +133 -0
- package/types/forty-cdk-breadcrumbs.d.ts +92 -0
- package/types/forty-cdk-breakpoints.d.ts +141 -0
- package/types/forty-cdk-button.d.ts +80 -0
- package/types/forty-cdk-calendar.d.ts +914 -0
- package/types/forty-cdk-carousel.d.ts +530 -0
- package/types/forty-cdk-checkbox.d.ts +141 -0
- package/types/forty-cdk-combobox.d.ts +1259 -0
- package/types/forty-cdk-context-menu.d.ts +313 -0
- package/types/forty-cdk-core.d.ts +5774 -0
- package/types/forty-cdk-date-field.d.ts +307 -0
- package/types/forty-cdk-date-picker.d.ts +622 -0
- package/types/forty-cdk-dialog.d.ts +546 -0
- package/types/forty-cdk-disclosure.d.ts +127 -0
- package/types/forty-cdk-drag-drop.d.ts +456 -0
- package/types/forty-cdk-drawer.d.ts +871 -0
- package/types/forty-cdk-dropdown-menu.d.ts +242 -0
- package/types/forty-cdk-field.d.ts +236 -0
- package/types/forty-cdk-fieldset.d.ts +119 -0
- package/types/forty-cdk-file-upload.d.ts +124 -0
- package/types/forty-cdk-hover-card.d.ts +320 -0
- package/types/forty-cdk-input.d.ts +169 -0
- package/types/forty-cdk-internationalized-date.d.ts +1 -1
- package/types/forty-cdk-listbox.d.ts +513 -0
- package/types/forty-cdk-menu.d.ts +629 -0
- package/types/forty-cdk-menubar.d.ts +451 -0
- package/types/forty-cdk-meter.d.ts +122 -0
- package/types/forty-cdk-navigation-menu.d.ts +514 -0
- package/types/forty-cdk-number-input.d.ts +319 -0
- package/types/forty-cdk-otp-input.d.ts +248 -0
- package/types/forty-cdk-pagination.d.ts +214 -0
- package/types/forty-cdk-pane-resizer.d.ts +145 -0
- package/types/forty-cdk-popover.d.ts +509 -0
- package/types/forty-cdk-progress.d.ts +143 -0
- package/types/forty-cdk-radio-group.d.ts +222 -0
- package/types/forty-cdk-scroll-area.d.ts +258 -0
- package/types/forty-cdk-search.d.ts +142 -0
- package/types/forty-cdk-select.d.ts +899 -0
- package/types/forty-cdk-separator.d.ts +59 -0
- package/types/forty-cdk-signal-forms.d.ts +58 -0
- package/types/forty-cdk-slider.d.ts +379 -0
- package/types/forty-cdk-stepper.d.ts +650 -0
- package/types/forty-cdk-switch.d.ts +87 -0
- package/types/forty-cdk-table.d.ts +723 -0
- package/types/forty-cdk-tabs.d.ts +235 -0
- package/types/forty-cdk-time-field.d.ts +307 -0
- package/types/forty-cdk-time-picker.d.ts +578 -0
- package/types/forty-cdk-toast.d.ts +598 -0
- package/types/forty-cdk-toggle.d.ts +310 -0
- package/types/forty-cdk-toolbar.d.ts +217 -0
- package/types/forty-cdk-tooltip.d.ts +436 -0
- package/types/forty-cdk-tree.d.ts +688 -0
- package/types/forty-cdk.d.ts +1 -19743
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Number Input
|
|
2
|
+
|
|
3
|
+
Headless numeric spinbutton implementing the [WAI-ARIA Spinbutton pattern](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/) and Angular's `FormValueControl<number | null>` from `@angular/forms/signals`, so it auto-wires with `[formField]` and auto-associates inside a [`[forField]`](../field/README.md) — label, description, and error wiring — with zero extra markup.
|
|
4
|
+
|
|
5
|
+
It owns parsing, clamping to `[min, max]`, the full Spinbutton keyboard map, and optional `Intl.NumberFormat`-based display formatting. The directive sits on a `<input type="text">` (not `type="number"`, whose native UI is unstylable and locale-quirky); the focusable spinbutton input itself is the `FormValueControl`, mirroring `<button forSwitch>`.
|
|
6
|
+
|
|
7
|
+
## Pieces
|
|
8
|
+
|
|
9
|
+
| Class | Selector | Element | Role |
|
|
10
|
+
| ------------------------- | --------------------------- | ----------- | -------------------------------------------------------------------- |
|
|
11
|
+
| `ForNumberInput` | `[forNumberInput]` | `<input>` | The spinbutton. Owns value, parsing, clamping, keyboard. |
|
|
12
|
+
| `ForNumberInputGroup` | `[forNumberInputGroup]` | any wrapper | Coordination wrapper — only needed when you use the stepper buttons. |
|
|
13
|
+
| `ForNumberInputIncrement` | `[forNumberInputIncrement]` | `<button>` | "Step up" affordance (`tabindex="-1"`). |
|
|
14
|
+
| `ForNumberInputDecrement` | `[forNumberInputDecrement]` | `<button>` | "Step down" affordance (`tabindex="-1"`). |
|
|
15
|
+
|
|
16
|
+
> **Why the group?** A `<input>` is a void element, so the stepper buttons can't be its DOM descendants and therefore can't inject its context directly. `[forNumberInputGroup]` provides that context and forwards it to the `[forNumberInput]` registered beneath it. A standalone spinbutton (keyboard / `[(value)]` only) needs no group.
|
|
17
|
+
|
|
18
|
+
## Inputs / models (`ForNumberInput`)
|
|
19
|
+
|
|
20
|
+
| API | Type | Description |
|
|
21
|
+
| ---------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
22
|
+
| `value` | `model<number \| null>` | Two-way bindable value. `null` is the empty input (reflected as `data-empty`). |
|
|
23
|
+
| `min` | `input<number \| undefined>` | Lower bound. Reflected as `aria-valuemin`. Unset → no lower bound. |
|
|
24
|
+
| `max` | `input<number \| undefined>` | Upper bound. Reflected as `aria-valuemax`. Unset → no upper bound. |
|
|
25
|
+
| `step` | `input<number>` | Increment for ArrowUp / ArrowDown and the buttons. Defaults to `1`. |
|
|
26
|
+
| `stepMultiplier` | `input<number>` | Multiplier over `step` for PageUp / PageDown. Defaults to `10` (configurable via `provideForNumberInputDefaults`). |
|
|
27
|
+
| `formatOptions` | `input<Intl.NumberFormatOptions \| null>` | When set, drives the displayed text and `aria-valuetext`. |
|
|
28
|
+
| `locale` | `input<string \| null>` | BCP 47 locale for parsing and formatting. Defaults to the runtime locale. |
|
|
29
|
+
| `disabled` / `readonly` / `required` / `invalid` / `pending` / `dirty` | `input<boolean>` | Shared form-control flags (see [Field](../field/README.md)). |
|
|
30
|
+
| `name` | `input<string>` | Mounts a hidden `<input>` carrying the **raw** number for native form submission. |
|
|
31
|
+
| `touched` | `model<boolean>` | Set to `true` on blur. |
|
|
32
|
+
|
|
33
|
+
The host carries `data-empty` (while the value is `null`), `data-disabled`, and `data-readonly`, plus `data-touched` / `data-dirty` / `data-pending` / `data-invalid` from the shared form-control reflection.
|
|
34
|
+
|
|
35
|
+
### Stepper buttons
|
|
36
|
+
|
|
37
|
+
Both `[forNumberInputIncrement]` / `[forNumberInputDecrement]` take the uniform `ariaLabel` input for their accessible name and stay `tabindex="-1"` (focus belongs on the spinbutton). They reflect `[disabled]` + `data-disabled` at the bound (`max` for increment, `min` for decrement) or when the control is disabled / read-only.
|
|
38
|
+
|
|
39
|
+
> Set the accessible name with the `ariaLabel` **input** (`ariaLabel="Increase"`), not the native `aria-label` attribute — like every forty-cdk primitive, the directive host-binds `aria-label` from that input and clears it when empty.
|
|
40
|
+
|
|
41
|
+
## Keyboard (Spinbutton APG)
|
|
42
|
+
|
|
43
|
+
| Key | Behavior |
|
|
44
|
+
| ----------------------- | --------------------------------------------------------------- |
|
|
45
|
+
| `ArrowUp` / `ArrowDown` | `value ± step`, clamped. |
|
|
46
|
+
| `PageUp` / `PageDown` | `value ± step × stepMultiplier`, clamped. |
|
|
47
|
+
| `Home` / `End` | Set to `min` / `max` (when defined). |
|
|
48
|
+
| `Enter` | Commit (clamp the typed text). |
|
|
49
|
+
| typing | Numeric characters parsed live; clamped on blur / Enter / step. |
|
|
50
|
+
|
|
51
|
+
Stepping from an empty field lands on the clamped baseline (`min ?? 0`).
|
|
52
|
+
|
|
53
|
+
## Stand-alone usage
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { Component, signal } from '@angular/core';
|
|
57
|
+
import {
|
|
58
|
+
ForNumberInput,
|
|
59
|
+
ForNumberInputDecrement,
|
|
60
|
+
ForNumberInputGroup,
|
|
61
|
+
ForNumberInputIncrement,
|
|
62
|
+
} from 'forty-cdk/number-input';
|
|
63
|
+
|
|
64
|
+
@Component({
|
|
65
|
+
selector: 'demo-quantity',
|
|
66
|
+
imports: [ForNumberInputGroup, ForNumberInput, ForNumberInputIncrement, ForNumberInputDecrement],
|
|
67
|
+
template: `
|
|
68
|
+
<div forNumberInputGroup>
|
|
69
|
+
<button forNumberInputDecrement class="number-input-decrement" ariaLabel="Decrease">−</button>
|
|
70
|
+
<input forNumberInput [(value)]="qty" [min]="0" [max]="10" [step]="1" />
|
|
71
|
+
<button forNumberInputIncrement class="number-input-increment" ariaLabel="Increase">+</button>
|
|
72
|
+
</div>
|
|
73
|
+
<p>{{ qty() }}</p>
|
|
74
|
+
`,
|
|
75
|
+
})
|
|
76
|
+
export class DemoQuantity {
|
|
77
|
+
readonly qty = signal<number | null>(1);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Keyboard-only (no buttons, no group):
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<input forNumberInput [(value)]="qty" [min]="0" [max]="100" />
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Formatting
|
|
88
|
+
|
|
89
|
+
`formatOptions` (+ optional `locale`) drives both the displayed text and `aria-valuetext`; `value()` stays the raw number, and that raw number is what a surrounding `<form>` submits (via a hidden input).
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<input
|
|
93
|
+
forNumberInput
|
|
94
|
+
[(value)]="price"
|
|
95
|
+
locale="en-US"
|
|
96
|
+
[formatOptions]="{ style: 'currency', currency: 'USD' }"
|
|
97
|
+
/>
|
|
98
|
+
<!-- value() === 1234.5 → displayed "$1,234.50", aria-valuenow="1234.5" -->
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Field composition
|
|
102
|
+
|
|
103
|
+
Drop the spinbutton inside a `[forField]` and it auto-associates with the label, description, and error region — no `id` / `aria-*` wiring by hand.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { Component, signal } from '@angular/core';
|
|
107
|
+
import { form, min, required, FormField } from '@angular/forms/signals';
|
|
108
|
+
import { ForField, ForFieldError, ForLabel } from 'forty-cdk/field';
|
|
109
|
+
import { ForNumberInput } from 'forty-cdk/number-input';
|
|
110
|
+
|
|
111
|
+
@Component({
|
|
112
|
+
selector: 'demo-order',
|
|
113
|
+
imports: [ForField, ForLabel, ForFieldError, ForNumberInput, FormField],
|
|
114
|
+
template: `
|
|
115
|
+
<div forField>
|
|
116
|
+
<label forLabel>Quantity</label>
|
|
117
|
+
<input forNumberInput [formField]="order.qty" [min]="1" />
|
|
118
|
+
@if (err.shown()) {
|
|
119
|
+
<p forFieldError #err="forFieldError">{{ err.messages().join(', ') }}</p>
|
|
120
|
+
}
|
|
121
|
+
</div>
|
|
122
|
+
`,
|
|
123
|
+
})
|
|
124
|
+
export class DemoOrder {
|
|
125
|
+
readonly model = signal({ qty: null as number | null });
|
|
126
|
+
readonly order = form(this.model, (o) => {
|
|
127
|
+
required(o.qty, { message: 'Quantity is required' });
|
|
128
|
+
min(o.qty, 1, { message: 'At least one' });
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Styling
|
|
134
|
+
|
|
135
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes below.
|
|
136
|
+
|
|
137
|
+
### Data attributes
|
|
138
|
+
|
|
139
|
+
| Piece | Attribute | Values |
|
|
140
|
+
| --------------------------- | --------------- | ---------------------------------------------------- |
|
|
141
|
+
| `[forNumberInput]` | `data-empty` | present (while `value()` is `null`) / absent |
|
|
142
|
+
| `[forNumberInput]` | `data-disabled` | present / absent |
|
|
143
|
+
| `[forNumberInput]` | `data-readonly` | present / absent |
|
|
144
|
+
| `[forNumberInput]` | `data-touched` | present / absent |
|
|
145
|
+
| `[forNumberInput]` | `data-dirty` | present / absent |
|
|
146
|
+
| `[forNumberInput]` | `data-pending` | present / absent |
|
|
147
|
+
| `[forNumberInput]` | `data-invalid` | present / absent |
|
|
148
|
+
| `[forNumberInputIncrement]` | `data-disabled` | present (at `max`, or disabled / read-only) / absent |
|
|
149
|
+
| `[forNumberInputDecrement]` | `data-disabled` | present (at `min`, or disabled / read-only) / absent |
|
|
150
|
+
|
|
151
|
+
`[forNumberInputGroup]` carries no styling attributes — it is a behavior-only coordination wrapper.
|
|
152
|
+
|
|
153
|
+
```css
|
|
154
|
+
.number-input-increment[data-disabled],
|
|
155
|
+
.number-input-decrement[data-disabled] {
|
|
156
|
+
opacity: 0.4;
|
|
157
|
+
cursor: not-allowed;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Accessibility notes
|
|
162
|
+
|
|
163
|
+
- **`role="spinbutton"` on a text input.** `aria-valuenow` / `aria-valuemin` / `aria-valuemax` reflect the value and bounds; `aria-valuetext` is emitted only when `formatOptions` is set (so the formatted text — "$1,234.50" — is announced instead of the bare number). `inputmode` is `numeric`, or `decimal` when fractional values are possible.
|
|
164
|
+
- **Clamp on commit, validate on input.** Keystrokes update the parsed value live so you can type transient out-of-range text without fighting the caret; clamping to `[min, max]` happens on blur / Enter / step actions.
|
|
165
|
+
- **Hidden input for submission.** Because the displayed text can be formatted, the visible input does **not** carry `name`; setting `name` mounts a hidden `<input>` with the raw number so native `<form>` serialization sees the value, not "$1,234.50". A disabled control is skipped automatically.
|
|
166
|
+
- **Falsy state styling selects on absence.** `aria-disabled` / `aria-readonly` / `aria-required` / `aria-invalid` / `aria-busy` are emitted only when truthy — style the off state with `:not([aria-invalid])`, never `[aria-invalid="false"]`.
|
|
167
|
+
- **`@angular/forms` is an optional peer.** If you're not using Signal Forms, don't install it — the directive runs fine on a plain `[(value)]` binding (the only `@angular/forms/signals` reference is a type import, erased at build).
|
|
168
|
+
|
|
169
|
+
## Wrapping in a design system
|
|
170
|
+
|
|
171
|
+
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_NUMBER_INPUT_HOST_DIRECTIVE_INPUTS` / `FOR_NUMBER_INPUT_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](../../../../../docs/wrapping-form-primitives.md).
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# OTP Input
|
|
2
|
+
|
|
3
|
+
Headless OTP / PIN input on the **single-input** model: one real `<input maxlength=N>` carries the whole code as a `string`, and the `[forOtpInputSlot]` pieces are a pure styling surface painted over it. There is **no** WAI-ARIA APG pattern for OTP — this approach gives the cleanest screen-reader experience (one ordinary text field, not "edit text, 1 of 6" announced N times), native mobile SMS autofill via `autocomplete="one-time-code"`, and native paste / caret / selection.
|
|
4
|
+
|
|
5
|
+
It implements Angular's `FormValueControl<string>` from `@angular/forms/signals`, so it auto-wires with `[formField]` and auto-associates inside a [`[forField]`](../field/README.md) — label, description, and error wiring — with zero extra markup.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
Apply `[forOtpInput]` on a **wrapper** element. It becomes a `role="group"` and the directive injects the single visually-hidden-but-interactive `<input>` inside it. You style that input to **overlay the slots** (typically `position: absolute; inset: 0` with a transparent or `caret-color`-only appearance); pointer events land on it and native caret positioning drives which slot is active. The slots are inert visual boxes.
|
|
10
|
+
|
|
11
|
+
The focusable, submittable control is the injected `<input>`, not the `role="group"` host — so form-control state, the field association, and native `name` submission all live on that input.
|
|
12
|
+
|
|
13
|
+
## Pieces
|
|
14
|
+
|
|
15
|
+
| Class | Selector | Element | Role |
|
|
16
|
+
| ----------------- | ------------------- | ------- | ------------------------------------------------------------------------------------ |
|
|
17
|
+
| `ForOtpInput` | `[forOtpInput]` | wrapper | `role="group"`. Owns the value, injects the real input, parsing / filtering / paste. |
|
|
18
|
+
| `ForOtpInputSlot` | `[forOtpInputSlot]` | any | One styling surface per index. Exposes `char()` / `active()` / `hasFakeCaret()`. |
|
|
19
|
+
|
|
20
|
+
## Inputs / models (`ForOtpInput`)
|
|
21
|
+
|
|
22
|
+
| API | Type | Description |
|
|
23
|
+
| ---------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
24
|
+
| `value` | `model<string>` | Two-way bindable code. Rendered length is clamped to `length`. |
|
|
25
|
+
| `length` | `input.required<number>` | Number of characters / slots. |
|
|
26
|
+
| `type` | `input<'numeric' \| 'alphanumeric' \| 'alphabetic'>` | Allowed character class. Defaults to `'numeric'`. Ignored when `allowedPattern` is set. |
|
|
27
|
+
| `allowedPattern` | `input<RegExp \| null>` | Custom allowed-character RegExp (tested per character); overrides `type`. |
|
|
28
|
+
| `mask` | `input<boolean>` | Obscure the rendered `char()` (PIN entry); `value()` stays raw. |
|
|
29
|
+
| `oneTimeCode` | `input<boolean>` | Toggle `autocomplete="one-time-code"` for SMS autofill. Defaults to `true`. |
|
|
30
|
+
| `pasteTransformer` | `input<((pasted: string) => string) \| null>` | Rewrite pasted text before it fills the slots (e.g. strip separators). |
|
|
31
|
+
| `ariaLabel` | `input<string \| null>` | Accessible name for the group, also reflected onto the real input when no field label applies. Emits `aria-label` only when truthy. |
|
|
32
|
+
| `disabled` / `readonly` / `required` / `invalid` / `pending` / `dirty` | `input<boolean>` | Shared form-control flags (see [Field](../field/README.md)). |
|
|
33
|
+
| `name` | `input<string>` | Reflected as the real input's `name` for native form submission. |
|
|
34
|
+
| `touched` | `model<boolean>` | Set to `true` on blur. |
|
|
35
|
+
|
|
36
|
+
| Output | Type | Fires |
|
|
37
|
+
| --------------- | --------------------------- | ---------------------------------------------------------------------------- |
|
|
38
|
+
| `valueComplete` | `output<string>` | When every slot is filled, by typing or paste. |
|
|
39
|
+
| `valueInvalid` | `output<{ value: string }>` | When an entered / pasted character is rejected by `type` / `allowedPattern`. |
|
|
40
|
+
|
|
41
|
+
`ForOtpInput` also exposes a `slots()` signal (`readonly number[]`) for the `@for`, a `complete()` signal, and a `focus()` method.
|
|
42
|
+
|
|
43
|
+
> **Why `allowedPattern`, not `pattern`?** `FormUiControl.pattern` is reserved by Signal Forms for an array of validation patterns the `[formField]` directive binds in. Reusing the name would break the `FormValueControl` contract and let the field overwrite your character filter, so the custom char-class RegExp is `allowedPattern`.
|
|
44
|
+
|
|
45
|
+
### Slot (`ForOtpInputSlot`)
|
|
46
|
+
|
|
47
|
+
| API | Type | Description |
|
|
48
|
+
| ---------------- | ------------------------ | ---------------------------------------------------------------- |
|
|
49
|
+
| `index` | `input.required<number>` | This slot's 0-based position. |
|
|
50
|
+
| `char()` | `Signal<string \| null>` | The slot's character (masked when `mask`), or `null` when empty. |
|
|
51
|
+
| `active()` | `Signal<boolean>` | Whether this slot is the active caret position. |
|
|
52
|
+
| `hasFakeCaret()` | `Signal<boolean>` | Whether to render a fake caret here (active + empty + focused). |
|
|
53
|
+
|
|
54
|
+
The slot host reflects boolean `data-active` (current caret slot) and `data-empty` (no character) for CSS.
|
|
55
|
+
|
|
56
|
+
## Exported pattern constants
|
|
57
|
+
|
|
58
|
+
`OTP_REGEXP_ONLY_DIGITS`, `OTP_REGEXP_ONLY_CHARS`, `OTP_REGEXP_ONLY_DIGITS_AND_CHARS` — bind one to `[allowedPattern]` for a custom restriction. `allowedCharForType` / `inputModeForType` expose the `type` → RegExp / `inputmode` mapping.
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { Component, signal } from '@angular/core';
|
|
64
|
+
import { ForOtpInput, ForOtpInputSlot } from 'forty-cdk/otp-input';
|
|
65
|
+
|
|
66
|
+
@Component({
|
|
67
|
+
selector: 'demo-otp',
|
|
68
|
+
imports: [ForOtpInput, ForOtpInputSlot],
|
|
69
|
+
template: `
|
|
70
|
+
<div
|
|
71
|
+
forOtpInput
|
|
72
|
+
class="otp-input"
|
|
73
|
+
[(value)]="code"
|
|
74
|
+
[length]="6"
|
|
75
|
+
type="numeric"
|
|
76
|
+
ariaLabel="Verification code"
|
|
77
|
+
#otp="forOtpInput"
|
|
78
|
+
>
|
|
79
|
+
@for (i of otp.slots(); track i) {
|
|
80
|
+
<div forOtpInputSlot [index]="i" #s="forOtpInputSlot" class="slot otp-input-slot">
|
|
81
|
+
{{ s.char() }}
|
|
82
|
+
@if (s.hasFakeCaret()) {
|
|
83
|
+
<span class="caret"></span>
|
|
84
|
+
}
|
|
85
|
+
</div>
|
|
86
|
+
}
|
|
87
|
+
</div>
|
|
88
|
+
<p>{{ code() }}</p>
|
|
89
|
+
`,
|
|
90
|
+
})
|
|
91
|
+
export class DemoOtp {
|
|
92
|
+
readonly code = signal('');
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The styling is yours. The key rule: make the injected `<input>` overlay the slots so it stays the interactive surface, e.g.
|
|
97
|
+
|
|
98
|
+
```css
|
|
99
|
+
.slot {
|
|
100
|
+
position: relative;
|
|
101
|
+
width: 2.5rem;
|
|
102
|
+
height: 3rem; /* ... */
|
|
103
|
+
}
|
|
104
|
+
.otp-input {
|
|
105
|
+
position: relative;
|
|
106
|
+
display: flex;
|
|
107
|
+
gap: 0.5rem;
|
|
108
|
+
}
|
|
109
|
+
.otp-input > input {
|
|
110
|
+
position: absolute;
|
|
111
|
+
inset: 0;
|
|
112
|
+
opacity: 0;
|
|
113
|
+
}
|
|
114
|
+
.caret {
|
|
115
|
+
/* style + animate; gate the blink on prefers-reduced-motion */
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Field composition
|
|
120
|
+
|
|
121
|
+
Drop the OTP inside a `[forField]` and it auto-associates with the label, description, and error region — no `id` / `aria-*` wiring by hand. The label's `for`, `aria-labelledby`, `aria-describedby`, and `aria-errormessage` all land on the real input.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { Component, signal } from '@angular/core';
|
|
125
|
+
import { form, required, FormField } from '@angular/forms/signals';
|
|
126
|
+
import { ForField, ForFieldError, ForLabel } from 'forty-cdk/field';
|
|
127
|
+
import { ForOtpInput, ForOtpInputSlot } from 'forty-cdk/otp-input';
|
|
128
|
+
|
|
129
|
+
@Component({
|
|
130
|
+
selector: 'demo-otp-field',
|
|
131
|
+
imports: [ForField, ForLabel, ForFieldError, ForOtpInput, ForOtpInputSlot, FormField],
|
|
132
|
+
template: `
|
|
133
|
+
<div forField>
|
|
134
|
+
<label forLabel>One-time code</label>
|
|
135
|
+
<div
|
|
136
|
+
forOtpInput
|
|
137
|
+
class="otp-input"
|
|
138
|
+
[formField]="login.otp"
|
|
139
|
+
[length]="6"
|
|
140
|
+
type="numeric"
|
|
141
|
+
#otp="forOtpInput"
|
|
142
|
+
>
|
|
143
|
+
@for (i of otp.slots(); track i) {
|
|
144
|
+
<div forOtpInputSlot class="otp-input-slot" [index]="i" #s="forOtpInputSlot">
|
|
145
|
+
{{ s.char() }}
|
|
146
|
+
</div>
|
|
147
|
+
}
|
|
148
|
+
</div>
|
|
149
|
+
@if (err.shown()) {
|
|
150
|
+
<p forFieldError #err="forFieldError">{{ err.messages().join(', ') }}</p>
|
|
151
|
+
}
|
|
152
|
+
</div>
|
|
153
|
+
`,
|
|
154
|
+
})
|
|
155
|
+
export class DemoOtpField {
|
|
156
|
+
readonly model = signal({ otp: '' });
|
|
157
|
+
readonly login = form(this.model, (l) => {
|
|
158
|
+
required(l.otp, { message: 'Enter the 6-digit code' });
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Styling
|
|
164
|
+
|
|
165
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes below.
|
|
166
|
+
|
|
167
|
+
### Data attributes
|
|
168
|
+
|
|
169
|
+
| Piece | Attribute | Values |
|
|
170
|
+
| ------------------- | --------------- | ---------------- |
|
|
171
|
+
| `[forOtpInput]` | `data-complete` | present / absent |
|
|
172
|
+
| `[forOtpInput]` | `data-disabled` | present / absent |
|
|
173
|
+
| `[forOtpInputSlot]` | `data-active` | present / absent |
|
|
174
|
+
| `[forOtpInputSlot]` | `data-empty` | present / absent |
|
|
175
|
+
|
|
176
|
+
The injected real `<input>` (created inside the `[forOtpInput]` wrapper) additionally carries `data-disabled`, `data-readonly`, `data-touched`, `data-dirty`, `data-pending`, and `data-invalid` (present / absent), mirroring its form-control flags.
|
|
177
|
+
|
|
178
|
+
```css
|
|
179
|
+
.otp-input-slot[data-active] {
|
|
180
|
+
outline: 2px solid var(--ring);
|
|
181
|
+
}
|
|
182
|
+
.otp-input-slot[data-empty] {
|
|
183
|
+
color: transparent;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Accessibility notes
|
|
188
|
+
|
|
189
|
+
- **One real text field, not N boxes.** The `role="group"` wrapper carries the `ariaLabel`; the single `<input>` inside it is the focusable control, and it reflects the same `ariaLabel` as its own `aria-label` whenever no field-provided `aria-labelledby` applies (a `[forField]` label always wins). Screen readers announce the group name on entry and treat the code as one ordinary, named text field.
|
|
190
|
+
- **Mobile autofill & keypad.** `autocomplete="one-time-code"` (toggle with `oneTimeCode`) drives SMS autofill; `inputmode` is `numeric` for `type="numeric"` (plus a legacy `pattern="[0-9]*"` for older iOS), `text` otherwise.
|
|
191
|
+
- **Character filtering happens live.** Rejected characters (per `type` / `allowedPattern`) are dropped before they reach the value and fire `valueInvalid`. Paste runs through `pasteTransformer`, is filtered, and sliced to `length`.
|
|
192
|
+
- **Fake caret is yours to style.** The slot exposes `hasFakeCaret()`; render and animate the blink in CSS, gated on `prefers-reduced-motion`. There is no JS-driven blink.
|
|
193
|
+
- **Falsy state styling selects on absence.** `aria-disabled` / `aria-readonly` / `aria-required` / `aria-invalid` / `aria-busy` are emitted only when truthy — style the off state with `:not([aria-invalid])`, never `[aria-invalid="false"]`.
|
|
194
|
+
- **`@angular/forms` is an optional peer.** The directive runs fine on a plain `[(value)]` binding; the only `@angular/forms/signals` reference is a type import, erased at build.
|
|
195
|
+
|
|
196
|
+
## Wrapping in a design system
|
|
197
|
+
|
|
198
|
+
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_OTP_INPUT_HOST_DIRECTIVE_INPUTS` / `FOR_OTP_INPUT_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](../../../../../docs/wrapping-form-primitives.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forty-cdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Headless / styleless UI primitives for Angular with WAI-ARIA accessibility built in.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -57,10 +57,222 @@
|
|
|
57
57
|
"types": "./types/forty-cdk.d.ts",
|
|
58
58
|
"default": "./fesm2022/forty-cdk.mjs"
|
|
59
59
|
},
|
|
60
|
+
"./accordion": {
|
|
61
|
+
"types": "./types/forty-cdk-accordion.d.ts",
|
|
62
|
+
"default": "./fesm2022/forty-cdk-accordion.mjs"
|
|
63
|
+
},
|
|
64
|
+
"./aspect-ratio": {
|
|
65
|
+
"types": "./types/forty-cdk-aspect-ratio.d.ts",
|
|
66
|
+
"default": "./fesm2022/forty-cdk-aspect-ratio.mjs"
|
|
67
|
+
},
|
|
68
|
+
"./avatar": {
|
|
69
|
+
"types": "./types/forty-cdk-avatar.d.ts",
|
|
70
|
+
"default": "./fesm2022/forty-cdk-avatar.mjs"
|
|
71
|
+
},
|
|
72
|
+
"./breadcrumbs": {
|
|
73
|
+
"types": "./types/forty-cdk-breadcrumbs.d.ts",
|
|
74
|
+
"default": "./fesm2022/forty-cdk-breadcrumbs.mjs"
|
|
75
|
+
},
|
|
76
|
+
"./breakpoints": {
|
|
77
|
+
"types": "./types/forty-cdk-breakpoints.d.ts",
|
|
78
|
+
"default": "./fesm2022/forty-cdk-breakpoints.mjs"
|
|
79
|
+
},
|
|
80
|
+
"./button": {
|
|
81
|
+
"types": "./types/forty-cdk-button.d.ts",
|
|
82
|
+
"default": "./fesm2022/forty-cdk-button.mjs"
|
|
83
|
+
},
|
|
84
|
+
"./calendar": {
|
|
85
|
+
"types": "./types/forty-cdk-calendar.d.ts",
|
|
86
|
+
"default": "./fesm2022/forty-cdk-calendar.mjs"
|
|
87
|
+
},
|
|
88
|
+
"./carousel": {
|
|
89
|
+
"types": "./types/forty-cdk-carousel.d.ts",
|
|
90
|
+
"default": "./fesm2022/forty-cdk-carousel.mjs"
|
|
91
|
+
},
|
|
92
|
+
"./checkbox": {
|
|
93
|
+
"types": "./types/forty-cdk-checkbox.d.ts",
|
|
94
|
+
"default": "./fesm2022/forty-cdk-checkbox.mjs"
|
|
95
|
+
},
|
|
96
|
+
"./combobox": {
|
|
97
|
+
"types": "./types/forty-cdk-combobox.d.ts",
|
|
98
|
+
"default": "./fesm2022/forty-cdk-combobox.mjs"
|
|
99
|
+
},
|
|
100
|
+
"./context-menu": {
|
|
101
|
+
"types": "./types/forty-cdk-context-menu.d.ts",
|
|
102
|
+
"default": "./fesm2022/forty-cdk-context-menu.mjs"
|
|
103
|
+
},
|
|
104
|
+
"./core": {
|
|
105
|
+
"types": "./types/forty-cdk-core.d.ts",
|
|
106
|
+
"default": "./fesm2022/forty-cdk-core.mjs"
|
|
107
|
+
},
|
|
108
|
+
"./date-field": {
|
|
109
|
+
"types": "./types/forty-cdk-date-field.d.ts",
|
|
110
|
+
"default": "./fesm2022/forty-cdk-date-field.mjs"
|
|
111
|
+
},
|
|
112
|
+
"./date-picker": {
|
|
113
|
+
"types": "./types/forty-cdk-date-picker.d.ts",
|
|
114
|
+
"default": "./fesm2022/forty-cdk-date-picker.mjs"
|
|
115
|
+
},
|
|
116
|
+
"./dialog": {
|
|
117
|
+
"types": "./types/forty-cdk-dialog.d.ts",
|
|
118
|
+
"default": "./fesm2022/forty-cdk-dialog.mjs"
|
|
119
|
+
},
|
|
120
|
+
"./disclosure": {
|
|
121
|
+
"types": "./types/forty-cdk-disclosure.d.ts",
|
|
122
|
+
"default": "./fesm2022/forty-cdk-disclosure.mjs"
|
|
123
|
+
},
|
|
124
|
+
"./drag-drop": {
|
|
125
|
+
"types": "./types/forty-cdk-drag-drop.d.ts",
|
|
126
|
+
"default": "./fesm2022/forty-cdk-drag-drop.mjs"
|
|
127
|
+
},
|
|
128
|
+
"./drawer": {
|
|
129
|
+
"types": "./types/forty-cdk-drawer.d.ts",
|
|
130
|
+
"default": "./fesm2022/forty-cdk-drawer.mjs"
|
|
131
|
+
},
|
|
132
|
+
"./dropdown-menu": {
|
|
133
|
+
"types": "./types/forty-cdk-dropdown-menu.d.ts",
|
|
134
|
+
"default": "./fesm2022/forty-cdk-dropdown-menu.mjs"
|
|
135
|
+
},
|
|
136
|
+
"./field": {
|
|
137
|
+
"types": "./types/forty-cdk-field.d.ts",
|
|
138
|
+
"default": "./fesm2022/forty-cdk-field.mjs"
|
|
139
|
+
},
|
|
140
|
+
"./fieldset": {
|
|
141
|
+
"types": "./types/forty-cdk-fieldset.d.ts",
|
|
142
|
+
"default": "./fesm2022/forty-cdk-fieldset.mjs"
|
|
143
|
+
},
|
|
144
|
+
"./file-upload": {
|
|
145
|
+
"types": "./types/forty-cdk-file-upload.d.ts",
|
|
146
|
+
"default": "./fesm2022/forty-cdk-file-upload.mjs"
|
|
147
|
+
},
|
|
148
|
+
"./hover-card": {
|
|
149
|
+
"types": "./types/forty-cdk-hover-card.d.ts",
|
|
150
|
+
"default": "./fesm2022/forty-cdk-hover-card.mjs"
|
|
151
|
+
},
|
|
152
|
+
"./input": {
|
|
153
|
+
"types": "./types/forty-cdk-input.d.ts",
|
|
154
|
+
"default": "./fesm2022/forty-cdk-input.mjs"
|
|
155
|
+
},
|
|
60
156
|
"./internationalized-date": {
|
|
61
157
|
"types": "./types/forty-cdk-internationalized-date.d.ts",
|
|
62
158
|
"default": "./fesm2022/forty-cdk-internationalized-date.mjs"
|
|
63
159
|
},
|
|
160
|
+
"./listbox": {
|
|
161
|
+
"types": "./types/forty-cdk-listbox.d.ts",
|
|
162
|
+
"default": "./fesm2022/forty-cdk-listbox.mjs"
|
|
163
|
+
},
|
|
164
|
+
"./menu": {
|
|
165
|
+
"types": "./types/forty-cdk-menu.d.ts",
|
|
166
|
+
"default": "./fesm2022/forty-cdk-menu.mjs"
|
|
167
|
+
},
|
|
168
|
+
"./menubar": {
|
|
169
|
+
"types": "./types/forty-cdk-menubar.d.ts",
|
|
170
|
+
"default": "./fesm2022/forty-cdk-menubar.mjs"
|
|
171
|
+
},
|
|
172
|
+
"./meter": {
|
|
173
|
+
"types": "./types/forty-cdk-meter.d.ts",
|
|
174
|
+
"default": "./fesm2022/forty-cdk-meter.mjs"
|
|
175
|
+
},
|
|
176
|
+
"./navigation-menu": {
|
|
177
|
+
"types": "./types/forty-cdk-navigation-menu.d.ts",
|
|
178
|
+
"default": "./fesm2022/forty-cdk-navigation-menu.mjs"
|
|
179
|
+
},
|
|
180
|
+
"./number-input": {
|
|
181
|
+
"types": "./types/forty-cdk-number-input.d.ts",
|
|
182
|
+
"default": "./fesm2022/forty-cdk-number-input.mjs"
|
|
183
|
+
},
|
|
184
|
+
"./otp-input": {
|
|
185
|
+
"types": "./types/forty-cdk-otp-input.d.ts",
|
|
186
|
+
"default": "./fesm2022/forty-cdk-otp-input.mjs"
|
|
187
|
+
},
|
|
188
|
+
"./pagination": {
|
|
189
|
+
"types": "./types/forty-cdk-pagination.d.ts",
|
|
190
|
+
"default": "./fesm2022/forty-cdk-pagination.mjs"
|
|
191
|
+
},
|
|
192
|
+
"./pane-resizer": {
|
|
193
|
+
"types": "./types/forty-cdk-pane-resizer.d.ts",
|
|
194
|
+
"default": "./fesm2022/forty-cdk-pane-resizer.mjs"
|
|
195
|
+
},
|
|
196
|
+
"./popover": {
|
|
197
|
+
"types": "./types/forty-cdk-popover.d.ts",
|
|
198
|
+
"default": "./fesm2022/forty-cdk-popover.mjs"
|
|
199
|
+
},
|
|
200
|
+
"./progress": {
|
|
201
|
+
"types": "./types/forty-cdk-progress.d.ts",
|
|
202
|
+
"default": "./fesm2022/forty-cdk-progress.mjs"
|
|
203
|
+
},
|
|
204
|
+
"./radio-group": {
|
|
205
|
+
"types": "./types/forty-cdk-radio-group.d.ts",
|
|
206
|
+
"default": "./fesm2022/forty-cdk-radio-group.mjs"
|
|
207
|
+
},
|
|
208
|
+
"./scroll-area": {
|
|
209
|
+
"types": "./types/forty-cdk-scroll-area.d.ts",
|
|
210
|
+
"default": "./fesm2022/forty-cdk-scroll-area.mjs"
|
|
211
|
+
},
|
|
212
|
+
"./search": {
|
|
213
|
+
"types": "./types/forty-cdk-search.d.ts",
|
|
214
|
+
"default": "./fesm2022/forty-cdk-search.mjs"
|
|
215
|
+
},
|
|
216
|
+
"./select": {
|
|
217
|
+
"types": "./types/forty-cdk-select.d.ts",
|
|
218
|
+
"default": "./fesm2022/forty-cdk-select.mjs"
|
|
219
|
+
},
|
|
220
|
+
"./separator": {
|
|
221
|
+
"types": "./types/forty-cdk-separator.d.ts",
|
|
222
|
+
"default": "./fesm2022/forty-cdk-separator.mjs"
|
|
223
|
+
},
|
|
224
|
+
"./signal-forms": {
|
|
225
|
+
"types": "./types/forty-cdk-signal-forms.d.ts",
|
|
226
|
+
"default": "./fesm2022/forty-cdk-signal-forms.mjs"
|
|
227
|
+
},
|
|
228
|
+
"./slider": {
|
|
229
|
+
"types": "./types/forty-cdk-slider.d.ts",
|
|
230
|
+
"default": "./fesm2022/forty-cdk-slider.mjs"
|
|
231
|
+
},
|
|
232
|
+
"./stepper": {
|
|
233
|
+
"types": "./types/forty-cdk-stepper.d.ts",
|
|
234
|
+
"default": "./fesm2022/forty-cdk-stepper.mjs"
|
|
235
|
+
},
|
|
236
|
+
"./switch": {
|
|
237
|
+
"types": "./types/forty-cdk-switch.d.ts",
|
|
238
|
+
"default": "./fesm2022/forty-cdk-switch.mjs"
|
|
239
|
+
},
|
|
240
|
+
"./table": {
|
|
241
|
+
"types": "./types/forty-cdk-table.d.ts",
|
|
242
|
+
"default": "./fesm2022/forty-cdk-table.mjs"
|
|
243
|
+
},
|
|
244
|
+
"./tabs": {
|
|
245
|
+
"types": "./types/forty-cdk-tabs.d.ts",
|
|
246
|
+
"default": "./fesm2022/forty-cdk-tabs.mjs"
|
|
247
|
+
},
|
|
248
|
+
"./time-field": {
|
|
249
|
+
"types": "./types/forty-cdk-time-field.d.ts",
|
|
250
|
+
"default": "./fesm2022/forty-cdk-time-field.mjs"
|
|
251
|
+
},
|
|
252
|
+
"./time-picker": {
|
|
253
|
+
"types": "./types/forty-cdk-time-picker.d.ts",
|
|
254
|
+
"default": "./fesm2022/forty-cdk-time-picker.mjs"
|
|
255
|
+
},
|
|
256
|
+
"./toast": {
|
|
257
|
+
"types": "./types/forty-cdk-toast.d.ts",
|
|
258
|
+
"default": "./fesm2022/forty-cdk-toast.mjs"
|
|
259
|
+
},
|
|
260
|
+
"./toggle": {
|
|
261
|
+
"types": "./types/forty-cdk-toggle.d.ts",
|
|
262
|
+
"default": "./fesm2022/forty-cdk-toggle.mjs"
|
|
263
|
+
},
|
|
264
|
+
"./toolbar": {
|
|
265
|
+
"types": "./types/forty-cdk-toolbar.d.ts",
|
|
266
|
+
"default": "./fesm2022/forty-cdk-toolbar.mjs"
|
|
267
|
+
},
|
|
268
|
+
"./tooltip": {
|
|
269
|
+
"types": "./types/forty-cdk-tooltip.d.ts",
|
|
270
|
+
"default": "./fesm2022/forty-cdk-tooltip.mjs"
|
|
271
|
+
},
|
|
272
|
+
"./tree": {
|
|
273
|
+
"types": "./types/forty-cdk-tree.d.ts",
|
|
274
|
+
"default": "./fesm2022/forty-cdk-tree.mjs"
|
|
275
|
+
},
|
|
64
276
|
"./virtualization": {
|
|
65
277
|
"types": "./types/forty-cdk-virtualization.d.ts",
|
|
66
278
|
"default": "./fesm2022/forty-cdk-virtualization.mjs"
|