forty-cdk 0.17.0 → 0.18.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/combobox/README.md +1 -0
- package/context-menu/README.md +18 -0
- package/date-picker/README.md +5 -2
- package/dropdown-menu/README.md +16 -0
- package/fesm2022/forty-cdk-combobox.mjs +2 -1
- package/fesm2022/forty-cdk-combobox.mjs.map +1 -1
- package/fesm2022/forty-cdk-context-menu.mjs +102 -42
- package/fesm2022/forty-cdk-context-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-core.mjs +292 -14
- package/fesm2022/forty-cdk-core.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-picker.mjs +37 -7
- package/fesm2022/forty-cdk-date-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-dropdown-menu.mjs +90 -21
- package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-listbox.mjs +2 -1
- package/fesm2022/forty-cdk-listbox.mjs.map +1 -1
- package/fesm2022/forty-cdk-menu.mjs +310 -31
- package/fesm2022/forty-cdk-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-menubar.mjs +62 -12
- package/fesm2022/forty-cdk-menubar.mjs.map +1 -1
- package/fesm2022/forty-cdk-otp-input.mjs +6 -4
- package/fesm2022/forty-cdk-otp-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-select.mjs +7 -3
- package/fesm2022/forty-cdk-select.mjs.map +1 -1
- package/fesm2022/forty-cdk-table.mjs +460 -57
- package/fesm2022/forty-cdk-table.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-picker.mjs +20 -3
- package/fesm2022/forty-cdk-time-picker.mjs.map +1 -1
- package/listbox/README.md +1 -0
- package/menu/README.md +94 -3
- package/menubar/README.md +17 -17
- package/otp-input/README.md +1 -0
- package/package.json +1 -1
- package/select/README.md +2 -0
- package/table/README.md +11 -0
- package/time-picker/README.md +21 -0
- package/types/forty-cdk-context-menu.d.ts +70 -14
- package/types/forty-cdk-core.d.ts +183 -14
- package/types/forty-cdk-date-picker.d.ts +23 -5
- package/types/forty-cdk-dropdown-menu.d.ts +59 -9
- package/types/forty-cdk-menu.d.ts +260 -17
- package/types/forty-cdk-menubar.d.ts +56 -12
- package/types/forty-cdk-otp-input.d.ts +4 -3
- package/types/forty-cdk-select.d.ts +3 -1
- package/types/forty-cdk-shared.d.ts +1 -1
- package/types/forty-cdk-table.d.ts +196 -26
- package/types/forty-cdk-time-picker.d.ts +11 -1
package/combobox/README.md
CHANGED
|
@@ -118,6 +118,7 @@ Input tables are not yet tabulated for this primitive. See the feature sections
|
|
|
118
118
|
| ------------------------ | ------------------ | ------------------------------------------------------------------- |
|
|
119
119
|
| `[forCombobox]` | `data-state` | `open` \| `closed` |
|
|
120
120
|
| `[forCombobox]` | `data-disabled` | present / absent |
|
|
121
|
+
| `[forCombobox]` | `data-readonly` | present / absent |
|
|
121
122
|
| `[forComboboxInput]` | `data-state` | `open` \| `closed` |
|
|
122
123
|
| `[forComboboxInput]` | `data-disabled` | present / absent |
|
|
123
124
|
| `[forComboboxContent]` | `data-state` | `open` \| `closed` |
|
package/context-menu/README.md
CHANGED
|
@@ -95,6 +95,24 @@ Angular resolves `ng-template` DI at the template's **declaration** site, not wh
|
|
|
95
95
|
</ng-template>
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
+
### Sharing one menu with a second opener
|
|
99
|
+
|
|
100
|
+
`[forContextMenu]` is a **single-opener preset**: one root, one right-click region. When the same actions must also be reachable another way — the canonical case being a table row with a right-click region _and_ a kebab button — bind the trigger to a `[forMenu]` root instead, which drives one `[forMenuContent]` block from any number of openers. See [Shared openers](../menu/README.md#shared-openers-formenu).
|
|
101
|
+
|
|
102
|
+
The same explicit-reference input carries it, and here the binding is **required** rather than optional: the trigger resolves `FOR_CONTEXT_MENU_CONTEXT`, which `[forMenu]` deliberately does not provide (`forty-cdk/menu` must not depend on `forty-cdk/context-menu`).
|
|
103
|
+
|
|
104
|
+
```html
|
|
105
|
+
<tr forMenu #row="forMenu" [(open)]="open" ariaLabel="Row actions">
|
|
106
|
+
<td [forContextMenuTrigger]="row">…cells…</td>
|
|
107
|
+
<td>
|
|
108
|
+
<button [forDropdownMenuTrigger]="row" [menuPositioning]="{ sideOffset: 4 }">⋮</button>
|
|
109
|
+
</td>
|
|
110
|
+
<!-- one content block, no duplication -->
|
|
111
|
+
</tr>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Both triggers carry `[menuPositioning]`, a partial `{ side, align, sideOffset, alignOffset }` override applied only to the opens that trigger drives, with each omitted key falling back to the root's input. It exists because a shared root cannot pick offsets that suit heterogeneous openers: the region above keeps the root's `sideOffset` of `0` — flush at the cursor, which is what a pointer-anchored menu wants — while the sibling button opener asks for the 4px of clearance a menu button wants. Under a `[forContextMenu]` root it resolves the same way, where it is simply a per-trigger spelling of the root's inputs. See [Per-opener positioning](../menu/README.md#per-opener-positioning).
|
|
115
|
+
|
|
98
116
|
## API
|
|
99
117
|
|
|
100
118
|
### `ForContextMenu`
|
package/date-picker/README.md
CHANGED
|
@@ -171,8 +171,10 @@ Plus the shared `FormUiControl` inputs from the base (`disabled`, `readonly`, `r
|
|
|
171
171
|
| ------------------------ | ------------------ | ------------------ |
|
|
172
172
|
| `[forDatePicker]` | `data-state` | `open` \| `closed` |
|
|
173
173
|
| `[forDatePicker]` | `data-disabled` | present \| absent |
|
|
174
|
+
| `[forDatePicker]` | `data-readonly` | present \| absent |
|
|
174
175
|
| `[forDatePickerTrigger]` | `data-state` | `open` \| `closed` |
|
|
175
176
|
| `[forDatePickerTrigger]` | `data-disabled` | present \| absent |
|
|
177
|
+
| `[forDatePickerTrigger]` | `data-readonly` | present \| absent |
|
|
176
178
|
| `[forDatePickerContent]` | `data-state` | `open` \| `closed` |
|
|
177
179
|
| `[forDatePickerValue]` | `data-placeholder` | present \| absent |
|
|
178
180
|
|
|
@@ -333,9 +335,10 @@ Inside the surface, the projected `ForCalendar` owns the full grid keyboard map
|
|
|
333
335
|
|
|
334
336
|
Implements the [WAI-ARIA Date Picker Dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/).
|
|
335
337
|
|
|
336
|
-
- **`
|
|
338
|
+
- **`role="combobox"`** on the trigger with **`aria-haspopup="dialog"`**, `aria-expanded` reflecting `open()`, and `aria-controls` pointing at the surface while open — the same shape `[forSelectTrigger]` / `[forTimePickerTrigger]` ship, with the `dialog` popup token ARIA 1.2 allows for a combobox surface. The role is also what makes the form-control ARIA below legal: `role="button"` supports neither `aria-readonly` nor `aria-required`.
|
|
337
339
|
- **`role="dialog"`** on the surface, named by `[ariaLabel]` (or `aria-labelledby` the trigger when no label is set). `aria-modal="true"` only in modal mode (truthy-only).
|
|
338
|
-
- **Form-control ARIA** (`aria-readonly` / `aria-required` / `aria-invalid` / `aria-busy`) is reflected on the focusable trigger so assistive tech announces validity on the element that takes focus. The disabled state is the exception: it reflects through the native `disabled` attribute alone (plus `data-disabled`), never `aria-disabled` — one channel per #561 D2.
|
|
340
|
+
- **Form-control ARIA** (`aria-readonly` / `aria-required` / `aria-invalid` / `aria-busy`) is reflected on the focusable trigger so assistive tech announces validity on the element that takes focus, alongside the `data-readonly` styling hook. The disabled state is the exception: it reflects through the native `disabled` attribute alone (plus `data-disabled`), never `aria-disabled` — one channel per #561 D2.
|
|
341
|
+
- **Inside a `[forField]` the labelled element is the trigger**, not the `[forDatePicker]` / `[forDateRangePicker]` wrapper: the field's `controlId` and its `aria-labelledby` / `aria-describedby` / `aria-errormessage` land on `[forDatePickerTrigger]`, so `[forLabel]`'s `for` points at the element that takes focus, clicking a non-`<label>` `[forLabel]` opens the surface, and Signal Forms' focus-on-error reaches the trigger. `role="combobox"` takes its name from the author, so this is the channel that names the control — the root's `[ariaLabel]` names the `role="dialog"` surface instead.
|
|
339
342
|
- **Focus management**: focus enters the surface on open (the calendar's roving cell in non-modal mode) and returns to the trigger on close, both vetoable via `(autoFocusOnOpen)` / `(autoFocusOnClose)`.
|
|
340
343
|
- **Dismissal**: Escape (`(escapeKeyDown)`) and outside-pointer (`(pointerDownOutside)` / `(interactOutside)`) close the surface, each vetoable.
|
|
341
344
|
|
package/dropdown-menu/README.md
CHANGED
|
@@ -113,6 +113,22 @@ Angular resolves `ng-template` DI at the template's **declaration** site, not wh
|
|
|
113
113
|
</ng-template>
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
### Sharing one menu with a second opener
|
|
117
|
+
|
|
118
|
+
`[forDropdownMenu]` is a **single-opener preset**: one root, one button trigger. When the same actions must also be reachable another way — the canonical case being a table row with a kebab button _and_ a right-click region over the whole row — bind the trigger to a `[forMenu]` root instead, which drives one `[forMenuContent]` block from any number of openers. See [Shared openers](../menu/README.md#shared-openers-formenu).
|
|
119
|
+
|
|
120
|
+
```html
|
|
121
|
+
<tr forMenu #row="forMenu" [(open)]="open" ariaLabel="Row actions">
|
|
122
|
+
<td [forContextMenuTrigger]="row">…cells…</td>
|
|
123
|
+
<td>
|
|
124
|
+
<button [forDropdownMenuTrigger]="row" [menuPositioning]="{ sideOffset: 4 }">⋮</button>
|
|
125
|
+
</td>
|
|
126
|
+
<!-- one content block, no duplication -->
|
|
127
|
+
</tr>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`[menuPositioning]` is the trigger's own placement override — a partial `{ side, align, sideOffset, alignOffset }`, each key falling back to the root's input when omitted. It exists because a shared root cannot pick offsets that suit heterogeneous openers: the `sideOffset: 4` above keeps the button-opened menu clear of the button while a sibling right-click region still opens flush at the cursor. Under a `[forDropdownMenu]` root it resolves the same way, where it is simply a per-trigger spelling of the root's inputs. See [Per-opener positioning](../menu/README.md#per-opener-positioning).
|
|
131
|
+
|
|
116
132
|
## API
|
|
117
133
|
|
|
118
134
|
### `ForDropdownMenu`
|
|
@@ -1169,7 +1169,7 @@ class ForCombobox extends FormUiControlBase {
|
|
|
1169
1169
|
this.markTouched();
|
|
1170
1170
|
}
|
|
1171
1171
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForCombobox, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1172
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForCombobox, isStandalone: true, selector: "[forCombobox]", inputs: { query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, itemToStringLabel: { classPropertyName: "itemToStringLabel", publicName: "itemToStringLabel", isSignal: true, isRequired: false, transformFunction: null }, itemToFormValue: { classPropertyName: "itemToFormValue", publicName: "itemToFormValue", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, autocompleteMode: { classPropertyName: "autocompleteMode", publicName: "autocompleteMode", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "openOnFocus", isSignal: true, isRequired: false, transformFunction: null }, openOnQuery: { classPropertyName: "openOnQuery", publicName: "openOnQuery", isSignal: true, isRequired: false, transformFunction: null }, commitOnSelect: { classPropertyName: "commitOnSelect", publicName: "commitOnSelect", isSignal: true, isRequired: false, transformFunction: null }, clearOnQueryChange: { classPropertyName: "clearOnQueryChange", publicName: "clearOnQueryChange", isSignal: true, isRequired: false, transformFunction: null }, autoHighlight: { classPropertyName: "autoHighlight", publicName: "autoHighlight", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, _alignInput: { classPropertyName: "_alignInput", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, avoidCollisions: { classPropertyName: "avoidCollisions", publicName: "avoidCollisions", isSignal: true, isRequired: false, transformFunction: null }, collisionPadding: { classPropertyName: "collisionPadding", publicName: "collisionPadding", isSignal: true, isRequired: false, transformFunction: null }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, hideWhenDetached: { classPropertyName: "hideWhenDetached", publicName: "hideWhenDetached", isSignal: true, isRequired: false, transformFunction: null }, clipUntilPositioned: { classPropertyName: "clipUntilPositioned", publicName: "clipUntilPositioned", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null }, returnFocus: { classPropertyName: "returnFocus", publicName: "returnFocus", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, visibleRange: { classPropertyName: "visibleRange", publicName: "visibleRange", isSignal: true, isRequired: false, transformFunction: null }, dataVersion: { classPropertyName: "dataVersion", publicName: "dataVersion", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { query: "queryChange", value: "valueChange", open: "openChange", scrollToIndex: "scrollToIndex", escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", autoFocusOnOpen: "autoFocusOnOpen", autoFocusOnClose: "autoFocusOnClose" }, host: { listeners: { "focusout": "onFocusOut($event)" }, properties: { "attr.data-state": "open() ? \"open\" : \"closed\"", "attr.data-disabled": "effectiveDisabled() ? \"\" : null", "attr.dir": "dir()" } }, providers: provideForCombobox(ForCombobox), exportAs: ["forCombobox"], usesInheritance: true, ngImport: i0 });
|
|
1172
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForCombobox, isStandalone: true, selector: "[forCombobox]", inputs: { query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, itemToStringLabel: { classPropertyName: "itemToStringLabel", publicName: "itemToStringLabel", isSignal: true, isRequired: false, transformFunction: null }, itemToFormValue: { classPropertyName: "itemToFormValue", publicName: "itemToFormValue", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, autocompleteMode: { classPropertyName: "autocompleteMode", publicName: "autocompleteMode", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "openOnFocus", isSignal: true, isRequired: false, transformFunction: null }, openOnQuery: { classPropertyName: "openOnQuery", publicName: "openOnQuery", isSignal: true, isRequired: false, transformFunction: null }, commitOnSelect: { classPropertyName: "commitOnSelect", publicName: "commitOnSelect", isSignal: true, isRequired: false, transformFunction: null }, clearOnQueryChange: { classPropertyName: "clearOnQueryChange", publicName: "clearOnQueryChange", isSignal: true, isRequired: false, transformFunction: null }, autoHighlight: { classPropertyName: "autoHighlight", publicName: "autoHighlight", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, _alignInput: { classPropertyName: "_alignInput", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, avoidCollisions: { classPropertyName: "avoidCollisions", publicName: "avoidCollisions", isSignal: true, isRequired: false, transformFunction: null }, collisionPadding: { classPropertyName: "collisionPadding", publicName: "collisionPadding", isSignal: true, isRequired: false, transformFunction: null }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, hideWhenDetached: { classPropertyName: "hideWhenDetached", publicName: "hideWhenDetached", isSignal: true, isRequired: false, transformFunction: null }, clipUntilPositioned: { classPropertyName: "clipUntilPositioned", publicName: "clipUntilPositioned", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null }, returnFocus: { classPropertyName: "returnFocus", publicName: "returnFocus", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, visibleRange: { classPropertyName: "visibleRange", publicName: "visibleRange", isSignal: true, isRequired: false, transformFunction: null }, dataVersion: { classPropertyName: "dataVersion", publicName: "dataVersion", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { query: "queryChange", value: "valueChange", open: "openChange", scrollToIndex: "scrollToIndex", escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", autoFocusOnOpen: "autoFocusOnOpen", autoFocusOnClose: "autoFocusOnClose" }, host: { listeners: { "focusout": "onFocusOut($event)" }, properties: { "attr.data-state": "open() ? \"open\" : \"closed\"", "attr.data-disabled": "effectiveDisabled() ? \"\" : null", "attr.data-readonly": "readonly() ? \"\" : null", "attr.dir": "dir()" } }, providers: provideForCombobox(ForCombobox), exportAs: ["forCombobox"], usesInheritance: true, ngImport: i0 });
|
|
1173
1173
|
}
|
|
1174
1174
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForCombobox, decorators: [{
|
|
1175
1175
|
type: Directive,
|
|
@@ -1179,6 +1179,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
1179
1179
|
host: {
|
|
1180
1180
|
'[attr.data-state]': 'open() ? "open" : "closed"',
|
|
1181
1181
|
'[attr.data-disabled]': 'effectiveDisabled() ? "" : null',
|
|
1182
|
+
'[attr.data-readonly]': 'readonly() ? "" : null',
|
|
1182
1183
|
'[attr.dir]': 'dir()',
|
|
1183
1184
|
'(focusout)': 'onFocusOut($event)',
|
|
1184
1185
|
},
|