forty-cdk 0.24.1 → 0.25.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 +7 -0
- package/aspect-ratio/README.md +6 -0
- package/avatar/README.md +6 -0
- package/breadcrumbs/README.md +7 -0
- package/breakpoints/README.md +6 -0
- package/button/README.md +8 -1
- package/calendar/README.md +10 -1
- package/carousel/README.md +7 -0
- package/checkbox/README.md +7 -0
- package/combobox/README.md +8 -1
- package/context-menu/README.md +7 -0
- package/date-field/README.md +9 -2
- package/date-picker/README.md +7 -0
- package/dialog/README.md +7 -0
- package/disclosure/README.md +7 -0
- package/drag-drop/README.md +6 -0
- package/drawer/README.md +7 -0
- package/dropdown-menu/README.md +7 -0
- package/fesm2022/forty-cdk-table-virtualization.mjs +20 -3
- package/fesm2022/forty-cdk-table-virtualization.mjs.map +1 -1
- package/fesm2022/forty-cdk-table.mjs +74 -11
- package/fesm2022/forty-cdk-table.mjs.map +1 -1
- package/field/README.md +7 -1
- package/fieldset/README.md +7 -1
- package/file-upload/README.md +7 -1
- package/hover-card/README.md +6 -0
- package/input/README.md +7 -1
- package/internationalized-date/README.md +7 -1
- package/listbox/README.md +7 -0
- package/menu/README.md +7 -0
- package/menubar/README.md +7 -0
- package/meter/README.md +7 -0
- package/navigation-menu/README.md +7 -0
- package/number-input/README.md +7 -0
- package/otp-input/README.md +6 -0
- package/package.json +1 -1
- package/pagination/README.md +7 -0
- package/pane-resizer/README.md +7 -0
- package/popover/README.md +7 -0
- package/progress/README.md +7 -0
- package/radio-group/README.md +7 -0
- package/scroll-area/README.md +6 -0
- package/search/README.md +6 -0
- package/select/README.md +7 -0
- package/separator/README.md +6 -0
- package/shared/README.md +6 -0
- package/slider/README.md +7 -0
- package/stepper/README.md +7 -0
- package/switch/README.md +7 -0
- package/table/README.md +89 -16
- package/table-virtualization/README.md +38 -10
- package/tabs/README.md +7 -0
- package/time-field/README.md +9 -2
- package/time-picker/README.md +7 -0
- package/toast/README.md +7 -0
- package/toggle/README.md +7 -0
- package/toolbar/README.md +7 -0
- package/tooltip/README.md +7 -0
- package/tree/README.md +8 -1
- package/types/forty-cdk-table-virtualization.d.ts +18 -3
- package/types/forty-cdk-table.d.ts +78 -25
- package/virtual-reorder/README.md +7 -0
- package/virtualization/README.md +6 -0
- package/visually-hidden/README.md +6 -0
package/accordion/README.md
CHANGED
package/aspect-ratio/README.md
CHANGED
package/avatar/README.md
CHANGED
package/breadcrumbs/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Breadcrumbs
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [composable-ui]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Breadcrumbs
|
|
2
9
|
|
|
3
10
|
A labelled navigation landmark for a breadcrumb trail: links with aria-current='page' on the current page and decorative separators hidden from assistive technology.
|
package/breakpoints/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Breakpoints
|
|
3
|
+
group: utilities
|
|
4
|
+
archetype: [headless-utility]
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# Breakpoints
|
|
2
8
|
|
|
3
9
|
A signal-first, zoneless, SSR-safe viewport breakpoint observer (injectBreakpoints). Configure the breakpoint map once via provideForBreakpointsDefaults — or use the Tailwind scale by default — then read up / down / between / only / active or any arbitrary media query, each as a live Signal<boolean>.
|
package/button/README.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Button
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [composable-ui]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/button/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# ForButton
|
|
2
9
|
|
|
3
|
-
Turns any element — a native
|
|
10
|
+
Turns any element — a native `<button>` or a custom host like `<div>` / `<span>` — into an accessible button with keyboard activation. Disabled stays focusable (aria-disabled, never the native attribute) and pressed / hovered / focus-visible are reflected as data-\* hooks.
|
|
4
11
|
|
|
5
12
|
A single `[forButton]` directive does all of this. On a native `<button>` host the platform owns Enter/Space activation and `type` handling; on any non-button host the directive adds `role="button"`, `tabindex="0"`, and keyboard activation so the contract matches.
|
|
6
13
|
|
package/calendar/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Calendar
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [composable-ui, form-control]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/grid/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Calendar
|
|
2
9
|
|
|
3
10
|
A single-date calendar grid implementing the APG Grid pattern over a pluggable date adapter: roving-tabindex day navigation, month / year paging, and min / max / per-date availability.
|
|
@@ -26,6 +33,8 @@ bootstrapApplication(App, {
|
|
|
26
33
|
|
|
27
34
|
`@internationalized/date` is a widely-used immutable date primitive; it works in every browser today with no polyfill, and its reference-equality-on-mutation makes it signal-friendly.
|
|
28
35
|
|
|
36
|
+
→ **[Date adapters](../../../docs/date-adapters.md)** — picking one, the optional peer dependency, and writing your own.
|
|
37
|
+
|
|
29
38
|
**Calendar system (Gregorian).** The adapter seam abstracts the date _library_ and locale-aware _formatting_, not the calendar _system_'s month structure. Both `@internationalized/date` adapters build Gregorian dates, so the grid stays Gregorian regardless of the runtime locale, and the grid, the month picker and the date field all assume a Gregorian-structured year — exactly twelve months, `month` **1-12**, the year ending at month 12. Adapters over calendars with a different month structure (e.g. a 13-month year) are not supported. The optional `compareDate` hook overrides day-only _ordering_ only — it does not make the grid non-Gregorian.
|
|
30
39
|
|
|
31
40
|
## Anatomy
|
|
@@ -401,7 +410,7 @@ Auto-disabled when the entire previous / next page would be outside `[min, max]`
|
|
|
401
410
|
| `[forCalendarYearCell]` | `data-highlighted` | present \| absent |
|
|
402
411
|
| `[forCalendarYearCell]` | `data-disabled` | present \| absent |
|
|
403
412
|
|
|
404
|
-
##
|
|
413
|
+
## Scoped defaults
|
|
405
414
|
|
|
406
415
|
```ts
|
|
407
416
|
import { provideForCalendarDefaults } from 'forty-cdk/calendar';
|
package/carousel/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Carousel
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [composable-ui]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/carousel/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# ForCarousel
|
|
2
9
|
|
|
3
10
|
A slideshow of content panels with previous / next controls, an indicator group, optional looping and multi-slide views, and an accessible autoplay mode with a pause control.
|
package/checkbox/README.md
CHANGED
package/combobox/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Combobox
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [overlay, form-control]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Combobox
|
|
2
9
|
|
|
3
10
|
An editable input paired with a filterable listbox popup, supporting single or multi selection with chips.
|
|
@@ -259,7 +266,7 @@ An action:
|
|
|
259
266
|
|
|
260
267
|
Use `[forComboboxAction]` for a pinned side-effect. For an entry that _does_
|
|
261
268
|
select (an "Add new" row that adds an item and commits it to `value`), use a
|
|
262
|
-
plain `[forComboboxOption]` — see
|
|
269
|
+
plain `[forComboboxOption]` — see the static options under [Examples](#examples).
|
|
263
270
|
|
|
264
271
|
### Focus & keyboard (model A)
|
|
265
272
|
|
package/context-menu/README.md
CHANGED
package/date-field/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Date Field
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [form-control]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# DateField
|
|
2
9
|
|
|
3
10
|
A segmented date (and optional time) input over a pluggable date adapter — each part a spinbutton with keyboard stepping, locale-driven segment order and min / max clamping.
|
|
@@ -171,7 +178,7 @@ Set `granularity` to `'hour'`, `'minute'`, or `'second'` (`granularity > 'day'`)
|
|
|
171
178
|
|
|
172
179
|
On the AM/PM segment, `a` / `p` set the period and ArrowUp / ArrowDown toggle it; the period is derived from the entered hour, so clearing it is a no-op (clear or step the hour instead). The value stays `null` until every visible segment — date **and** time — is filled.
|
|
173
180
|
|
|
174
|
-
##
|
|
181
|
+
## Scoped defaults
|
|
175
182
|
|
|
176
183
|
```ts
|
|
177
184
|
import { provideForDateFieldDefaults } from 'forty-cdk/date-field';
|
|
@@ -256,7 +263,7 @@ The two endpoints are typed independently, so order is not guaranteed by constru
|
|
|
256
263
|
|
|
257
264
|
Each endpoint is its own tab stop, so `Tab` moves start group → end group → next control; arrows move between segments **within** an endpoint. Every other key behaves as in the [Keyboard](#keyboard) table below. Roving tabindex is per endpoint, and `aria-invalid="true"` is reflected on the root when the form marks it invalid **or** when two complete endpoints are out of order; everything else matches the [Accessibility](#accessibility) notes below.
|
|
258
265
|
|
|
259
|
-
### Range
|
|
266
|
+
### Range scoped defaults
|
|
260
267
|
|
|
261
268
|
`provideForDateRangeFieldDefaults` mirrors `provideForDateFieldDefaults` and adds `startLabel` / `endLabel` for the two endpoint group `aria-label`s (`'Start date'` / `'End date'` by default). Both wrapper patterns work via `FOR_DATE_RANGE_FIELD_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_RANGE_FIELD_HOST_DIRECTIVE_OUTPUTS` — see [Wrapping form primitives](../../../docs/wrapping-form-primitives.md).
|
|
262
269
|
|
package/date-picker/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Date Picker
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [overlay, form-control]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# DatePicker
|
|
2
9
|
|
|
3
10
|
A trigger that opens a floating calendar to pick a date, composing ForCalendar inside a dismissible popover with min / max bounds and per-date availability.
|
package/dialog/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Dialog
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [overlay]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Dialog
|
|
2
9
|
|
|
3
10
|
A modal window overlaid on the page, with a focus trap, scroll lock and Escape / dismiss handling. Also openable imperatively through ForDialogManager.
|
package/disclosure/README.md
CHANGED
package/drag-drop/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Drag & Drop
|
|
3
|
+
group: utilities
|
|
4
|
+
archetype: [headless-utility]
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# Drag & Drop
|
|
2
8
|
|
|
3
9
|
Headless, accessible drag-and-drop for sortable lists and cross-list transfers, driven by both keyboard and pointer. Ships drag handles, custom preview / placeholder templates, live-sort, FLIP reorder animations, auto-scroll, and boundary / axis-lock constraints.
|
package/drawer/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Drawer
|
|
3
|
+
group: primitives
|
|
4
|
+
archetype: [overlay]
|
|
5
|
+
apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Drawer
|
|
2
9
|
|
|
3
10
|
A side or bottom sheet built on the modal dialog pattern, adding pointer-driven swipe-to-dismiss and snap points.
|
package/dropdown-menu/README.md
CHANGED
|
@@ -37,6 +37,7 @@ import { injectVirtualizer } from 'forty-cdk/virtualization';
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
class TableVirtualizedNavigator {
|
|
@@ -177,6 +178,7 @@ function injectTableRegistration() {
|
|
|
177
178
|
|
|
178
179
|
|
|
179
180
|
|
|
181
|
+
|
|
180
182
|
class ForTableVirtualized {
|
|
181
183
|
#ctx = injectTableContext();
|
|
182
184
|
#registration = injectTableRegistration();
|
|
@@ -193,9 +195,24 @@ class ForTableVirtualized {
|
|
|
193
195
|
|
|
194
196
|
scrollElement = input(null, /* @ts-ignore */
|
|
195
197
|
...(ngDevMode ? [{ debugName: "scrollElement" }] : /* istanbul ignore next */ []));
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
virtualRowCount = input(undefined, /* @ts-ignore */
|
|
212
|
+
...(ngDevMode ? [{ debugName: "virtualRowCount" }] : /* istanbul ignore next */ []));
|
|
196
213
|
#scrollElement = computed(() => this.scrollElement() ?? this.#rootEl, /* @ts-ignore */
|
|
197
214
|
...(ngDevMode ? [{ debugName: "#scrollElement" }] : /* istanbul ignore next */ []));
|
|
198
|
-
#rowCount = computed(() => this.#ctx.rowCount() ?? 0, /* @ts-ignore */
|
|
215
|
+
#rowCount = computed(() => this.virtualRowCount() ?? this.#ctx.rowCount() ?? 0, /* @ts-ignore */
|
|
199
216
|
...(ngDevMode ? [{ debugName: "#rowCount" }] : /* istanbul ignore next */ []));
|
|
200
217
|
#virtualizer = injectVirtualizer({
|
|
201
218
|
count: this.#rowCount,
|
|
@@ -279,7 +296,7 @@ class ForTableVirtualized {
|
|
|
279
296
|
this.#virtualizer.measureElement(element);
|
|
280
297
|
}
|
|
281
298
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTableVirtualized, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
282
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForTableVirtualized, isStandalone: true, selector: "[forTableVirtualized]", inputs: { estimateRowSize: { classPropertyName: "estimateRowSize", publicName: "estimateRowSize", isSignal: true, isRequired: false, transformFunction: null }, scrollElement: { classPropertyName: "scrollElement", publicName: "scrollElement", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["forTableVirtualized"], ngImport: i0 });
|
|
299
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForTableVirtualized, isStandalone: true, selector: "[forTableVirtualized]", inputs: { estimateRowSize: { classPropertyName: "estimateRowSize", publicName: "estimateRowSize", isSignal: true, isRequired: false, transformFunction: null }, scrollElement: { classPropertyName: "scrollElement", publicName: "scrollElement", isSignal: true, isRequired: false, transformFunction: null }, virtualRowCount: { classPropertyName: "virtualRowCount", publicName: "virtualRowCount", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["forTableVirtualized"], ngImport: i0 });
|
|
283
300
|
}
|
|
284
301
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTableVirtualized, decorators: [{
|
|
285
302
|
type: Directive,
|
|
@@ -287,7 +304,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
287
304
|
selector: '[forTableVirtualized]',
|
|
288
305
|
exportAs: 'forTableVirtualized',
|
|
289
306
|
}]
|
|
290
|
-
}], ctorParameters: () => [], propDecorators: { estimateRowSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "estimateRowSize", required: false }] }], scrollElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollElement", required: false }] }] } });
|
|
307
|
+
}], ctorParameters: () => [], propDecorators: { estimateRowSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "estimateRowSize", required: false }] }], scrollElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollElement", required: false }] }], virtualRowCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualRowCount", required: false }] }] } });
|
|
291
308
|
|
|
292
309
|
|
|
293
310
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forty-cdk-table-virtualization.mjs","sources":["../../../projects/forty-cdk/table-virtualization/src/table-virtualized-navigator.ts","../../../projects/forty-cdk/table-virtualization/src/table-virtualized.ts","../../../projects/forty-cdk/table-virtualization/src/public-api.ts","../../../projects/forty-cdk/table-virtualization/src/forty-cdk-table-virtualization.ts"],"sourcesContent":["import { signal, type Signal } from '@angular/core';\n\nimport { type ForTableRowHandle } from 'forty-cdk/core';\n\n/**\n * An absolute `(rowIndex, 0-based column)` target awaiting the row to mount,\n * plus the travel `direction` used to step over full-span variant rows (which\n * register no cells and so cannot receive roving focus).\n */\ninterface PendingTarget {\n readonly row: number;\n readonly col: number;\n readonly direction: 1 | -1;\n}\n\ntype ProbeResult = 'focused' | 'variant' | 'disabled' | 'unmounted';\n\n/**\n * Dependencies for `TableVirtualizedNavigator`. Wires the bridge to the table's\n * live row registry and the companion's scroll method.\n */\nexport interface TableVirtualizedNavigatorDeps {\n /** Live registered data rows, so the bridge can resolve a pending target once it mounts. */\n readonly rows: Signal<readonly ForTableRowHandle[]>;\n /** Scroll the virtualizer so the row at the absolute index mounts. */\n readonly scrollToRow: (index: number) => void;\n /** The scroll container's bounding rect, or `null` before it is available. */\n readonly scrollViewportRect: () => DOMRect | null;\n /** The true total data-row count, used to clamp when stepping over variant rows. */\n readonly rowCount: () => number;\n /** The count of currently loaded data rows (the body dataset length), or `undefined` when unknown (raw-primitive rendering). Cross-window targets are clamped to this so an out-of-prefix row never stashes a pending focus move that can only resolve when a far page later loads. */\n readonly loadedRowCount?: () => number | undefined;\n}\n\n/**\n * Cross-window keyboard-navigation bridge for a virtualized `[forTable]` grid,\n * owned by `[forTableVirtualized]`. The grid keeps roving-tabindex and renders\n * only a window of rows, so a navigation target can land on a row that is not\n * currently mounted. This bridge resolves that:\n *\n * - **Move** — `navigateTo(row, col, direction)` focuses the cell at the\n * absolute `(row, col)` when its row is already rendered; otherwise it stashes\n * the target and calls `scrollToRow(row)` to mount it.\n * - **Resolve** — once the freshly-mounted row registers, the companion's bridge\n * effect calls `tryResolvePending`, which moves roving focus onto the target\n * cell (its `(focus)` handler promotes it to the active roving cell) and clears\n * the pending target.\n *\n * Full-span **variant rows** (group headers / separators / summary rows) mount\n * as a single presentational cell and register no cell handles, so they cannot\n * hold roving focus; likewise a mounted row whose target-column cell is\n * `disabled` (e.g. skeleton / placeholder rows) cannot receive focus. When a\n * target lands on either, the bridge steps `row` by `direction` (clamped to the\n * loaded prefix) to the adjacent enabled data cell — scrolling it in when it is\n * outside the window — and clears the target if the dataset bound is reached\n * with no landable data row in that direction, so a stale target can never\n * later steal focus.\n *\n * Off-prefix targets are clamped to the last loaded row: when `loadedRowCount`\n * is smaller than the total `rowCount` (a server-paged grid whose far pages are\n * not yet loaded), a target beyond the loaded prefix restarts at the last loaded\n * row searching upward, so a Ctrl+End / Page / Arrow move can never stash a\n * pending focus that only resolves — and steals focus — when a far page later\n * mounts.\n *\n * Mirrors the 1D `ListboxVirtualizedNavigator` precedent, adapted to the table's\n * roving + focused-row-retention model. Internal — not re-exported from\n * `table/index.ts` or `public-api.ts`.\n */\nexport class TableVirtualizedNavigator {\n readonly #deps: TableVirtualizedNavigatorDeps;\n\n readonly #pending = signal<PendingTarget | null>(null);\n\n constructor(deps: TableVirtualizedNavigatorDeps) {\n this.#deps = deps;\n }\n\n /**\n * Move roving focus to the data cell at the absolute `(row, col)`, travelling\n * in `direction` (`+1` down / `-1` up) so full-span variant rows are stepped\n * over. When the target row is already rendered as a data row, focuses\n * immediately. Otherwise stashes the target and scrolls it into the window;\n * the bridge effect resolves it once the row mounts.\n */\n navigateTo(row: number, col: number, direction: 1 | -1): void {\n this.#resolve(row, col, direction);\n }\n\n /** Scroll the virtualizer so the row at the absolute `index` is in the window. */\n scrollToRow(index: number): void {\n this.#deps.scrollToRow(index);\n }\n\n /** The scroll container's bounding rect, or `null` before it is available. */\n scrollViewportRect(): DOMRect | null {\n return this.#deps.scrollViewportRect();\n }\n\n /**\n * Resolve a pending cross-window navigation: once the row carrying the pending\n * absolute index mounts, focus its cell and clear the pending target. Returns\n * `true` when a pending request was resolved, `false` otherwise. Called from\n * the companion's bridge effect whenever the rendered rows change.\n */\n tryResolvePending(): boolean {\n const pending = this.#pending();\n if (pending === null) {\n return false;\n }\n return this.#resolve(pending.row, pending.col, pending.direction);\n }\n\n /**\n * Drop any stashed cross-window target. `ForTable` calls this on the next\n * keyboard interaction that reaches the grid, so a pending move set by an\n * earlier Ctrl+End / Page / Arrow is superseded rather than teleporting focus\n * when a far page later mounts.\n */\n clearPending(): void {\n this.#pending.set(null);\n }\n\n #resolve(row: number, col: number, direction: 1 | -1): boolean {\n const count = this.#deps.rowCount();\n const bound = Math.min(this.#deps.loadedRowCount?.() ?? count, count);\n let target = row;\n let dir = direction;\n if (bound > 0 && target >= bound) {\n target = bound - 1;\n dir = -1;\n }\n while (target >= 0 && target < bound) {\n const result = this.#probeCell(target, col);\n if (result === 'focused') {\n this.#pending.set(null);\n return true;\n }\n if (result === 'unmounted') {\n const current = this.#pending();\n const unchanged =\n current !== null &&\n current.row === target &&\n current.col === col &&\n current.direction === dir;\n if (!unchanged) {\n this.#pending.set({ row: target, col, direction: dir });\n this.#deps.scrollToRow(target);\n }\n return false;\n }\n target += dir;\n }\n this.#pending.set(null);\n return false;\n }\n\n #probeCell(row: number, col: number): ProbeResult {\n const handle = this.#deps.rows().find((r) => r.virtualIndex() === row);\n if (!handle) {\n return 'unmounted';\n }\n const cells = handle.cells();\n const cell = cells[col] ?? cells[cells.length - 1];\n if (!cell) {\n return 'variant';\n }\n if (cell.disabled()) {\n return 'disabled';\n }\n cell.host.focus();\n return 'focused';\n }\n}\n","import {\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n numberAttribute,\n} from '@angular/core';\n\nimport {\n orphanContextError,\n TABLE_REGISTRATION_CONTEXT,\n type TableRegistrationContext,\n} from 'forty-cdk/core';\nimport { FOR_TABLE_CONTEXT, type ForTableContext } from 'forty-cdk/table';\nimport { injectVirtualizer, type VirtualItem } from 'forty-cdk/virtualization';\n\nimport { TableVirtualizedNavigator } from './table-virtualized-navigator';\n\nfunction injectTableContext(): ForTableContext {\n const ctx = inject(FOR_TABLE_CONTEXT, { optional: true });\n if (!ctx) {\n throw orphanContextError({\n code: 'FORCDK-TABLE-VIRTUALIZATION-001',\n piece: 'ForTableVirtualized',\n root: '[forTable]',\n token: 'FOR_TABLE_CONTEXT',\n });\n }\n return ctx;\n}\n\nfunction injectTableRegistration(): TableRegistrationContext {\n const registration = inject(TABLE_REGISTRATION_CONTEXT, { optional: true });\n if (!registration) {\n throw orphanContextError({\n code: 'FORCDK-TABLE-VIRTUALIZATION-002',\n piece: 'ForTableVirtualized',\n root: '[forTable]',\n token: 'TABLE_REGISTRATION_CONTEXT',\n });\n }\n return registration;\n}\n\n/**\n * Opt-in row-virtualization companion for `[forTable]` in `<div role>` grid mode. Place it on the\n * same element as `[forTable]`; it builds the windowing core from the table's `[rowCount]` and\n * exposes the visible window for the consumer to render with their own `@for` + position transform.\n *\n * Tree-shakeable: `ForTable` never imports the virtualization core — only consumers that import\n * `ForTableVirtualized` bundle `@tanstack/virtual-core`.\n *\n * The focused row is kept mounted even when scrolled out of the window so the roving-focused\n * `gridcell` is never unmounted. SSR-safe: off-browser the window is empty and\n * `totalSize` is the estimate-based total.\n *\n * Also drives cross-window keyboard navigation: when an Arrow / Page / Ctrl+Home / Ctrl+End grid\n * action resolves a row outside the rendered window, it scrolls that row into view and moves roving\n * focus onto the target cell once it mounts (preserving the current column). `ForTable` stays\n * unaware of virtualization — it delegates the row-crossing move through the table context.\n */\n@Directive({\n selector: '[forTableVirtualized]',\n exportAs: 'forTableVirtualized',\n})\nexport class ForTableVirtualized {\n readonly #ctx = injectTableContext();\n readonly #registration = injectTableRegistration();\n readonly #rootEl = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n /** Estimated row size in px along the scroll axis (the fixed-size fast path). Read for the size estimate. */\n readonly estimateRowSize = input(44, { transform: numberAttribute });\n\n /**\n * Scroll container. Defaults to the table root element (the scroll container in `<div>` grid\n * mode). Bind it explicitly when the scroll container is an **ancestor** of the table — e.g. an\n * app-shell viewport that scrolls projected content — since the table cannot inject an ancestor\n * it does not own. A design-system wrapper can re-expose or rename this input through\n * `hostDirectives` input aliasing (`inputs: ['scrollElement: scrollContainer']`) with no bridging\n * effect required.\n */\n readonly scrollElement = input<HTMLElement | null>(null);\n\n readonly #scrollElement = computed(() => this.scrollElement() ?? this.#rootEl);\n readonly #rowCount = computed(() => this.#ctx.rowCount() ?? 0);\n\n readonly #virtualizer = injectVirtualizer({\n count: this.#rowCount,\n estimateSize: () => this.estimateRowSize(),\n scrollElement: this.#scrollElement,\n });\n\n readonly #navigator = new TableVirtualizedNavigator({\n rows: this.#registration.rows,\n scrollToRow: (index) => this.scrollToRow(index),\n scrollViewportRect: () => this.#scrollElement().getBoundingClientRect(),\n rowCount: this.#rowCount,\n loadedRowCount: () => this.#ctx.loadedRowCount(),\n });\n\n constructor() {\n this.#registration.registerVirtualNavigation(this.#navigator);\n this.#registration.registerVirtualWindow({\n rows: this.virtualRows,\n totalSize: this.totalSize,\n measureRow: (element) => this.measureRow(element),\n });\n inject(DestroyRef).onDestroy(() => {\n this.#registration.registerVirtualNavigation(null);\n this.#registration.registerVirtualWindow(null);\n });\n effect(() => {\n this.#registration.rows();\n this.#navigator.tryResolvePending();\n });\n }\n\n /**\n * The rows in the visible window plus overscan, augmented to always include the focused row and\n * the row being reordered even when they are scrolled out of view (so the roving-focused cell\n * stays mounted, and a pointer reorder drag never unmounts the lifted row). Render these with\n * `@for (vrow of v.virtualRows(); track vrow.index)` and position each row absolutely with\n * `transform: translateY(vrow.start + 'px')`. Bind each row's `[virtualIndex]=\"vrow.index\"`.\n */\n readonly virtualRows = computed<readonly VirtualItem[]>(() => {\n const items = this.#virtualizer.virtualItems();\n const retain = new Set<number>();\n const focused = this.#ctx.focusedRowIndex();\n if (focused !== null) {\n retain.add(focused);\n }\n const reordering = this.#registration.reorderingRowIndex();\n if (reordering !== null) {\n retain.add(reordering);\n }\n for (const it of items) {\n retain.delete(it.index);\n }\n if (retain.size === 0) {\n return items;\n }\n const size = this.estimateRowSize();\n const retained: VirtualItem[] = [...retain].map(\n (index) =>\n this.#virtualizer.measurementFor(index) ?? { index, key: index, start: index * size, size },\n );\n return [...items, ...retained].sort((a, b) => a.index - b.index);\n });\n\n /** Total scroll size of all rows in px. Bind to the body container's height to size the scroll range. */\n readonly totalSize = this.#virtualizer.totalSize;\n\n /**\n * The rendered window as the inclusive-exclusive `[firstIndex, lastIndex + 1)` index range,\n * sourced from the underlying virtualizer (the true window) — not from {@link virtualRows},\n * which is augmented with the focused / reordering rows. So a row retained out of the window\n * never widens this range. Plugs straight into `injectInfiniteScroll({ range, count, onLoadMore })`.\n */\n readonly range = this.#virtualizer.range;\n\n /**\n * Scroll the container so the row at `index` is in view. Cross-window keyboard\n * navigation calls this internally; consumers may also call it to scroll\n * programmatically.\n */\n scrollToRow(index: number, options?: { align?: 'start' | 'center' | 'end' | 'auto' }): void {\n this.#virtualizer.scrollToIndex(index, options);\n }\n\n /**\n * Record the measured size of a rendered row element (dynamic / measured row heights).\n * Passing `null` sweeps evicted rows recycled out of the window from the measurement cache.\n */\n measureRow(element: HTMLElement | null): void {\n this.#virtualizer.measureElement(element);\n }\n}\n","/*\n * Public API surface of forty-cdk/table-virtualization.\n *\n * The `[forTableVirtualized]` adapter ships from its own secondary entry point\n * because it composes two primitives: it reads the table's context and\n * registration surface from `forty-cdk/table` and builds its window with\n * `forty-cdk/virtualization`. Keeping it here is what lets `forty-cdk/virtualization`\n * stay free of any other primitive's module graph, so a consumer virtualizing a\n * plain list never resolves the table entry point.\n */\n\nexport { ForTableVirtualized } from './table-virtualized';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"forty-cdk-table-virtualization.mjs","sources":["../../../projects/forty-cdk/table-virtualization/src/table-virtualized-navigator.ts","../../../projects/forty-cdk/table-virtualization/src/table-virtualized.ts","../../../projects/forty-cdk/table-virtualization/src/public-api.ts","../../../projects/forty-cdk/table-virtualization/src/forty-cdk-table-virtualization.ts"],"sourcesContent":["import { signal, type Signal } from '@angular/core';\n\nimport { type ForTableRowHandle } from 'forty-cdk/core';\n\n/**\n * An absolute `(rowIndex, 0-based column)` target awaiting the row to mount,\n * plus the travel `direction` used to step over full-span variant rows (which\n * register no cells and so cannot receive roving focus).\n */\ninterface PendingTarget {\n readonly row: number;\n readonly col: number;\n readonly direction: 1 | -1;\n}\n\ntype ProbeResult = 'focused' | 'variant' | 'disabled' | 'unmounted';\n\n/**\n * Dependencies for `TableVirtualizedNavigator`. Wires the bridge to the table's\n * live row registry and the companion's scroll method.\n */\nexport interface TableVirtualizedNavigatorDeps {\n /** Live registered data rows, so the bridge can resolve a pending target once it mounts. */\n readonly rows: Signal<readonly ForTableRowHandle[]>;\n /** Scroll the virtualizer so the row at the absolute index mounts. */\n readonly scrollToRow: (index: number) => void;\n /** The scroll container's bounding rect, or `null` before it is available. */\n readonly scrollViewportRect: () => DOMRect | null;\n /** The count of rows the virtualizer can place (`[virtualRowCount]`, else the table's `[rowCount]`), used to clamp when stepping over variant rows. */\n readonly rowCount: () => number;\n /** The count of currently loaded data rows (the body dataset length), or `undefined` when unknown (raw-primitive rendering). Cross-window targets are clamped to this so an out-of-prefix row never stashes a pending focus move that can only resolve when a far page later loads. */\n readonly loadedRowCount?: () => number | undefined;\n}\n\n/**\n * Cross-window keyboard-navigation bridge for a virtualized `[forTable]` grid,\n * owned by `[forTableVirtualized]`. The grid keeps roving-tabindex and renders\n * only a window of rows, so a navigation target can land on a row that is not\n * currently mounted. This bridge resolves that:\n *\n * - **Move** — `navigateTo(row, col, direction)` focuses the cell at the\n * absolute `(row, col)` when its row is already rendered; otherwise it stashes\n * the target and calls `scrollToRow(row)` to mount it.\n * - **Resolve** — once the freshly-mounted row registers, the companion's bridge\n * effect calls `tryResolvePending`, which moves roving focus onto the target\n * cell (its `(focus)` handler promotes it to the active roving cell) and clears\n * the pending target.\n *\n * Full-span **variant rows** (group headers / separators / summary rows) mount\n * as a single presentational cell and register no cell handles, so they cannot\n * hold roving focus; likewise a mounted row whose target-column cell is\n * `disabled` (e.g. skeleton / placeholder rows) cannot receive focus. When a\n * target lands on either, the bridge steps `row` by `direction` (clamped to the\n * loaded prefix) to the adjacent enabled data cell — scrolling it in when it is\n * outside the window — and clears the target if the dataset bound is reached\n * with no landable data row in that direction, so a stale target can never\n * later steal focus.\n *\n * Off-prefix targets are clamped to the last loaded row: when `loadedRowCount`\n * is smaller than the placeable `rowCount` (a server-paged grid whose far pages\n * are not yet loaded), a target beyond the loaded prefix restarts at the last\n * loaded row searching upward, so a Ctrl+End / Page / Arrow move can never stash\n * a pending focus that only resolves — and steals focus — when a far page later\n * mounts. A raw-primitive grid registers no body dataset, so there the same bound\n * arrives through `[virtualRowCount]` instead.\n *\n * Mirrors the 1D `ListboxVirtualizedNavigator` precedent, adapted to the table's\n * roving + focused-row-retention model. Internal — not re-exported from\n * `table/index.ts` or `public-api.ts`.\n */\nexport class TableVirtualizedNavigator {\n readonly #deps: TableVirtualizedNavigatorDeps;\n\n readonly #pending = signal<PendingTarget | null>(null);\n\n constructor(deps: TableVirtualizedNavigatorDeps) {\n this.#deps = deps;\n }\n\n /**\n * Move roving focus to the data cell at the absolute `(row, col)`, travelling\n * in `direction` (`+1` down / `-1` up) so full-span variant rows are stepped\n * over. When the target row is already rendered as a data row, focuses\n * immediately. Otherwise stashes the target and scrolls it into the window;\n * the bridge effect resolves it once the row mounts.\n */\n navigateTo(row: number, col: number, direction: 1 | -1): void {\n this.#resolve(row, col, direction);\n }\n\n /** Scroll the virtualizer so the row at the absolute `index` is in the window. */\n scrollToRow(index: number): void {\n this.#deps.scrollToRow(index);\n }\n\n /** The scroll container's bounding rect, or `null` before it is available. */\n scrollViewportRect(): DOMRect | null {\n return this.#deps.scrollViewportRect();\n }\n\n /**\n * Resolve a pending cross-window navigation: once the row carrying the pending\n * absolute index mounts, focus its cell and clear the pending target. Returns\n * `true` when a pending request was resolved, `false` otherwise. Called from\n * the companion's bridge effect whenever the rendered rows change.\n */\n tryResolvePending(): boolean {\n const pending = this.#pending();\n if (pending === null) {\n return false;\n }\n return this.#resolve(pending.row, pending.col, pending.direction);\n }\n\n /**\n * Drop any stashed cross-window target. `ForTable` calls this on the next\n * keyboard interaction that reaches the grid, so a pending move set by an\n * earlier Ctrl+End / Page / Arrow is superseded rather than teleporting focus\n * when a far page later mounts.\n */\n clearPending(): void {\n this.#pending.set(null);\n }\n\n #resolve(row: number, col: number, direction: 1 | -1): boolean {\n const count = this.#deps.rowCount();\n const bound = Math.min(this.#deps.loadedRowCount?.() ?? count, count);\n let target = row;\n let dir = direction;\n if (bound > 0 && target >= bound) {\n target = bound - 1;\n dir = -1;\n }\n while (target >= 0 && target < bound) {\n const result = this.#probeCell(target, col);\n if (result === 'focused') {\n this.#pending.set(null);\n return true;\n }\n if (result === 'unmounted') {\n const current = this.#pending();\n const unchanged =\n current !== null &&\n current.row === target &&\n current.col === col &&\n current.direction === dir;\n if (!unchanged) {\n this.#pending.set({ row: target, col, direction: dir });\n this.#deps.scrollToRow(target);\n }\n return false;\n }\n target += dir;\n }\n this.#pending.set(null);\n return false;\n }\n\n #probeCell(row: number, col: number): ProbeResult {\n const handle = this.#deps.rows().find((r) => r.virtualIndex() === row);\n if (!handle) {\n return 'unmounted';\n }\n const cells = handle.cells();\n const cell = cells[col] ?? cells[cells.length - 1];\n if (!cell) {\n return 'variant';\n }\n if (cell.disabled()) {\n return 'disabled';\n }\n cell.host.focus();\n return 'focused';\n }\n}\n","import {\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n numberAttribute,\n} from '@angular/core';\n\nimport {\n orphanContextError,\n TABLE_REGISTRATION_CONTEXT,\n type TableRegistrationContext,\n} from 'forty-cdk/core';\nimport { FOR_TABLE_CONTEXT, type ForTableContext } from 'forty-cdk/table';\nimport { injectVirtualizer, type VirtualItem } from 'forty-cdk/virtualization';\n\nimport { TableVirtualizedNavigator } from './table-virtualized-navigator';\n\nfunction injectTableContext(): ForTableContext {\n const ctx = inject(FOR_TABLE_CONTEXT, { optional: true });\n if (!ctx) {\n throw orphanContextError({\n code: 'FORCDK-TABLE-VIRTUALIZATION-001',\n piece: 'ForTableVirtualized',\n root: '[forTable]',\n token: 'FOR_TABLE_CONTEXT',\n });\n }\n return ctx;\n}\n\nfunction injectTableRegistration(): TableRegistrationContext {\n const registration = inject(TABLE_REGISTRATION_CONTEXT, { optional: true });\n if (!registration) {\n throw orphanContextError({\n code: 'FORCDK-TABLE-VIRTUALIZATION-002',\n piece: 'ForTableVirtualized',\n root: '[forTable]',\n token: 'TABLE_REGISTRATION_CONTEXT',\n });\n }\n return registration;\n}\n\n/**\n * Opt-in row-virtualization companion for `[forTable]` in `<div role>` grid mode. Place it on the\n * same element as `[forTable]`; it builds the windowing core from `[virtualRowCount]` — which\n * defaults to the table's `[rowCount]` — and exposes the visible window for the consumer to render\n * with their own `@for` + position transform.\n *\n * Tree-shakeable: `ForTable` never imports the virtualization core — only consumers that import\n * `ForTableVirtualized` bundle `@tanstack/virtual-core`.\n *\n * The focused row is kept mounted even when scrolled out of the window so the roving-focused\n * `gridcell` is never unmounted. SSR-safe: off-browser the window is empty and\n * `totalSize` is the estimate-based total.\n *\n * Also drives cross-window keyboard navigation: when an Arrow / Page / Ctrl+Home / Ctrl+End grid\n * action resolves a row outside the rendered window, it scrolls that row into view and moves roving\n * focus onto the target cell once it mounts (preserving the current column). `ForTable` stays\n * unaware of virtualization — it delegates the row-crossing move through the table context.\n */\n@Directive({\n selector: '[forTableVirtualized]',\n exportAs: 'forTableVirtualized',\n})\nexport class ForTableVirtualized {\n readonly #ctx = injectTableContext();\n readonly #registration = injectTableRegistration();\n readonly #rootEl = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n /** Estimated row size in px along the scroll axis (the fixed-size fast path). Read for the size estimate. */\n readonly estimateRowSize = input(44, { transform: numberAttribute });\n\n /**\n * Scroll container. Defaults to the table root element (the scroll container in `<div>` grid\n * mode). Bind it explicitly when the scroll container is an **ancestor** of the table — e.g. an\n * app-shell viewport that scrolls projected content — since the table cannot inject an ancestor\n * it does not own. A design-system wrapper can re-expose or rename this input through\n * `hostDirectives` input aliasing (`inputs: ['scrollElement: scrollContainer']`) with no bridging\n * effect required.\n */\n readonly scrollElement = input<HTMLElement | null>(null);\n\n /**\n * Count of rows the virtualizer can place: it sizes the scroll range and bounds\n * cross-window keyboard navigation. Defaults to the table's `[rowCount]`, which is also\n * the placeable range for an **index-addressable** dataset — any absolute index is\n * fetchable, so the window can travel the whole server-known total.\n *\n * Bind it for an **append-style** infinite list, whose loaded prefix is the only range\n * that can be rendered: leave `[rowCount]` at the server-known total `aria-rowcount`\n * reports and set this to the loaded count, so the scroll range covers exactly the rows\n * the virtualizer can place instead of stretching over pages only an append can reach.\n * It is the one channel the raw-primitive shape has for that count, since\n * `<for-table-body>` is what otherwise derives it from its dataset.\n */\n readonly virtualRowCount = input<number | undefined>(undefined);\n\n readonly #scrollElement = computed(() => this.scrollElement() ?? this.#rootEl);\n readonly #rowCount = computed(() => this.virtualRowCount() ?? this.#ctx.rowCount() ?? 0);\n\n readonly #virtualizer = injectVirtualizer({\n count: this.#rowCount,\n estimateSize: () => this.estimateRowSize(),\n scrollElement: this.#scrollElement,\n });\n\n readonly #navigator = new TableVirtualizedNavigator({\n rows: this.#registration.rows,\n scrollToRow: (index) => this.scrollToRow(index),\n scrollViewportRect: () => this.#scrollElement().getBoundingClientRect(),\n rowCount: this.#rowCount,\n loadedRowCount: () => this.#ctx.loadedRowCount(),\n });\n\n constructor() {\n this.#registration.registerVirtualNavigation(this.#navigator);\n this.#registration.registerVirtualWindow({\n rows: this.virtualRows,\n totalSize: this.totalSize,\n measureRow: (element) => this.measureRow(element),\n });\n inject(DestroyRef).onDestroy(() => {\n this.#registration.registerVirtualNavigation(null);\n this.#registration.registerVirtualWindow(null);\n });\n effect(() => {\n this.#registration.rows();\n this.#navigator.tryResolvePending();\n });\n }\n\n /**\n * The rows in the visible window plus overscan, augmented to always include the focused row and\n * the row being reordered even when they are scrolled out of view (so the roving-focused cell\n * stays mounted, and a pointer reorder drag never unmounts the lifted row). Render these with\n * `@for (vrow of v.virtualRows(); track vrow.index)` and position each row absolutely with\n * `transform: translateY(vrow.start + 'px')`. Bind each row's `[virtualIndex]=\"vrow.index\"`.\n */\n readonly virtualRows = computed<readonly VirtualItem[]>(() => {\n const items = this.#virtualizer.virtualItems();\n const retain = new Set<number>();\n const focused = this.#ctx.focusedRowIndex();\n if (focused !== null) {\n retain.add(focused);\n }\n const reordering = this.#registration.reorderingRowIndex();\n if (reordering !== null) {\n retain.add(reordering);\n }\n for (const it of items) {\n retain.delete(it.index);\n }\n if (retain.size === 0) {\n return items;\n }\n const size = this.estimateRowSize();\n const retained: VirtualItem[] = [...retain].map(\n (index) =>\n this.#virtualizer.measurementFor(index) ?? { index, key: index, start: index * size, size },\n );\n return [...items, ...retained].sort((a, b) => a.index - b.index);\n });\n\n /** Total scroll size of all rows in px. Bind to the body container's height to size the scroll range. */\n readonly totalSize = this.#virtualizer.totalSize;\n\n /**\n * The rendered window as the inclusive-exclusive `[firstIndex, lastIndex + 1)` index range,\n * sourced from the underlying virtualizer (the true window) — not from {@link virtualRows},\n * which is augmented with the focused / reordering rows. So a row retained out of the window\n * never widens this range. Plugs straight into `injectInfiniteScroll({ range, count, onLoadMore })`.\n */\n readonly range = this.#virtualizer.range;\n\n /**\n * Scroll the container so the row at `index` is in view. Cross-window keyboard\n * navigation calls this internally; consumers may also call it to scroll\n * programmatically.\n */\n scrollToRow(index: number, options?: { align?: 'start' | 'center' | 'end' | 'auto' }): void {\n this.#virtualizer.scrollToIndex(index, options);\n }\n\n /**\n * Record the measured size of a rendered row element (dynamic / measured row heights).\n * Passing `null` sweeps evicted rows recycled out of the window from the measurement cache.\n */\n measureRow(element: HTMLElement | null): void {\n this.#virtualizer.measureElement(element);\n }\n}\n","/*\n * Public API surface of forty-cdk/table-virtualization.\n *\n * The `[forTableVirtualized]` adapter ships from its own secondary entry point\n * because it composes two primitives: it reads the table's context and\n * registration surface from `forty-cdk/table` and builds its window with\n * `forty-cdk/virtualization`. Keeping it here is what lets `forty-cdk/virtualization`\n * stay free of any other primitive's module graph, so a consumer virtualizing a\n * plain list never resolves the table entry point.\n */\n\nexport { ForTableVirtualized } from './table-virtualized';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -474,12 +474,15 @@ class TableRowSelection {
|
|
|
474
474
|
|
|
475
475
|
|
|
476
476
|
|
|
477
|
+
|
|
478
|
+
|
|
477
479
|
select(value, modifiers) {
|
|
478
480
|
const mode = this.#selectionMode();
|
|
479
|
-
|
|
481
|
+
const behavior = this.#selectionBehavior();
|
|
482
|
+
if (mode === 'none' || behavior === 'none') {
|
|
480
483
|
return;
|
|
481
484
|
}
|
|
482
|
-
if (
|
|
485
|
+
if (behavior === 'toggle') {
|
|
483
486
|
this.#model.toggle(value);
|
|
484
487
|
this.#anchor.set(value);
|
|
485
488
|
return;
|
|
@@ -642,6 +645,7 @@ class ForTable {
|
|
|
642
645
|
|
|
643
646
|
|
|
644
647
|
|
|
648
|
+
|
|
645
649
|
_rowCountInput = input(undefined, { ...(ngDevMode ? { debugName: "_rowCountInput" } : /* istanbul ignore next */ {}), alias: 'rowCount' });
|
|
646
650
|
#registry = inject(TableRegistry);
|
|
647
651
|
|
|
@@ -650,6 +654,7 @@ class ForTable {
|
|
|
650
654
|
|
|
651
655
|
|
|
652
656
|
|
|
657
|
+
|
|
653
658
|
rowCount = computed(() => this._rowCountInput() ?? this.#registry.bodyRowCount()?.(), /* @ts-ignore */
|
|
654
659
|
...(ngDevMode ? [{ debugName: "rowCount" }] : /* istanbul ignore next */ []));
|
|
655
660
|
|
|
@@ -690,6 +695,10 @@ class ForTable {
|
|
|
690
695
|
|
|
691
696
|
|
|
692
697
|
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
693
702
|
selectionBehavior = input('toggle', /* @ts-ignore */
|
|
694
703
|
...(ngDevMode ? [{ debugName: "selectionBehavior" }] : /* istanbul ignore next */ []));
|
|
695
704
|
|
|
@@ -771,6 +780,7 @@ class ForTable {
|
|
|
771
780
|
return dataCols > 0 ? dataCols : this.#headerCellHosts().length;
|
|
772
781
|
}, /* @ts-ignore */
|
|
773
782
|
...(ngDevMode ? [{ debugName: "#cols" }] : /* istanbul ignore next */ []));
|
|
783
|
+
columnCount = this.#cols;
|
|
774
784
|
|
|
775
785
|
|
|
776
786
|
|
|
@@ -3316,6 +3326,13 @@ class ForTableBody {
|
|
|
3316
3326
|
|
|
3317
3327
|
|
|
3318
3328
|
|
|
3329
|
+
|
|
3330
|
+
|
|
3331
|
+
|
|
3332
|
+
|
|
3333
|
+
|
|
3334
|
+
|
|
3335
|
+
|
|
3319
3336
|
|
|
3320
3337
|
|
|
3321
3338
|
|
|
@@ -3334,7 +3351,6 @@ class ForTableBody {
|
|
|
3334
3351
|
|
|
3335
3352
|
|
|
3336
3353
|
|
|
3337
|
-
|
|
3338
3354
|
rowContextMenu = output();
|
|
3339
3355
|
|
|
3340
3356
|
|
|
@@ -3528,11 +3544,15 @@ class ForTableBody {
|
|
|
3528
3544
|
return descriptor && descriptor.column === column ? descriptor.direction : 'none';
|
|
3529
3545
|
}
|
|
3530
3546
|
|
|
3531
|
-
|
|
3532
|
-
|
|
3547
|
+
|
|
3548
|
+
|
|
3549
|
+
|
|
3550
|
+
|
|
3551
|
+
rowsKeyboardInteractive = computed(() => this.interactiveRows() && this.#ctx.mode() === 'table', /* @ts-ignore */
|
|
3552
|
+
...(ngDevMode ? [{ debugName: "rowsKeyboardInteractive" }] : /* istanbul ignore next */ []));
|
|
3533
3553
|
|
|
3534
3554
|
rowTabIndex(row) {
|
|
3535
|
-
return this.
|
|
3555
|
+
return this.rowsKeyboardInteractive() && !row.variant ? 0 : null;
|
|
3536
3556
|
}
|
|
3537
3557
|
|
|
3538
3558
|
rowClassFor(row) {
|
|
@@ -3570,21 +3590,23 @@ class ForTableBody {
|
|
|
3570
3590
|
this.onColumnWidthChange(descriptor.column, descriptor.width);
|
|
3571
3591
|
};
|
|
3572
3592
|
onRowClick(row, event) {
|
|
3573
|
-
this
|
|
3593
|
+
if (this.interactiveRows()) {
|
|
3594
|
+
this.#activateRow(row, event);
|
|
3595
|
+
}
|
|
3574
3596
|
}
|
|
3575
3597
|
onRowEnter(row, event) {
|
|
3576
|
-
if (this.#activateRow(row, event)) {
|
|
3598
|
+
if (this.rowsKeyboardInteractive() && this.#activateRow(row, event)) {
|
|
3577
3599
|
event.preventDefault();
|
|
3578
3600
|
}
|
|
3579
3601
|
}
|
|
3580
3602
|
onRowContextMenu(row, event) {
|
|
3581
|
-
if (!this.
|
|
3603
|
+
if (!this.interactiveRows() || row.variant) {
|
|
3582
3604
|
return;
|
|
3583
3605
|
}
|
|
3584
3606
|
this.rowContextMenu.emit({ row: row.datum, index: row.index, event });
|
|
3585
3607
|
}
|
|
3586
3608
|
#activateRow(row, event) {
|
|
3587
|
-
if (
|
|
3609
|
+
if (row.variant || eventFromInteractiveDescendant(event)) {
|
|
3588
3610
|
return false;
|
|
3589
3611
|
}
|
|
3590
3612
|
this.rowActivate.emit({ row: row.datum, index: row.index, event });
|
|
@@ -4044,6 +4066,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
4044
4066
|
|
|
4045
4067
|
|
|
4046
4068
|
|
|
4069
|
+
class ForTableVariantCell {
|
|
4070
|
+
#ctx = injectTableContext('ForTableVariantCell');
|
|
4071
|
+
role = computed(() => (this.#ctx.mode() === 'table' ? 'cell' : 'gridcell'), /* @ts-ignore */
|
|
4072
|
+
...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
|
|
4073
|
+
colSpan = computed(() => {
|
|
4074
|
+
const cols = this.#ctx.columnCount();
|
|
4075
|
+
return cols > 0 ? cols : null;
|
|
4076
|
+
}, /* @ts-ignore */
|
|
4077
|
+
...(ngDevMode ? [{ debugName: "colSpan" }] : /* istanbul ignore next */ []));
|
|
4078
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTableVariantCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4079
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForTableVariantCell, isStandalone: true, selector: "[forTableVariantCell]", host: { attributes: { "data-row-variant": "" }, properties: { "attr.role": "role()", "attr.aria-colindex": "1", "attr.aria-colspan": "colSpan()" } }, exportAs: ["forTableVariantCell"], ngImport: i0 });
|
|
4080
|
+
}
|
|
4081
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTableVariantCell, decorators: [{
|
|
4082
|
+
type: Directive,
|
|
4083
|
+
args: [{
|
|
4084
|
+
selector: '[forTableVariantCell]',
|
|
4085
|
+
exportAs: 'forTableVariantCell',
|
|
4086
|
+
host: {
|
|
4087
|
+
'data-row-variant': '',
|
|
4088
|
+
'[attr.role]': 'role()',
|
|
4089
|
+
'[attr.aria-colindex]': '1',
|
|
4090
|
+
'[attr.aria-colspan]': 'colSpan()',
|
|
4091
|
+
},
|
|
4092
|
+
}]
|
|
4093
|
+
}] });
|
|
4094
|
+
|
|
4095
|
+
|
|
4096
|
+
|
|
4097
|
+
|
|
4098
|
+
|
|
4099
|
+
|
|
4100
|
+
|
|
4101
|
+
|
|
4102
|
+
|
|
4103
|
+
|
|
4104
|
+
|
|
4105
|
+
|
|
4106
|
+
|
|
4107
|
+
|
|
4108
|
+
|
|
4109
|
+
|
|
4047
4110
|
class ForTableRowSelector {
|
|
4048
4111
|
ctx = injectTableContext('ForTableRowSelector');
|
|
4049
4112
|
row = injectTableRowContext('ForTableRowSelector');
|
|
@@ -4673,5 +4736,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
4673
4736
|
|
|
4674
4737
|
|
|
4675
4738
|
|
|
4676
|
-
export { FOR_TABLE_CONTEXT, FOR_TABLE_DEF_REGISTRY, ForTable, ForTableBody, ForTableCell, ForTableCellDef, ForTableColumnDef, ForTableColumnDragPlaceholder, ForTableColumnLabel, ForTableColumnReorder, ForTableColumnResizer, ForTableHeaderCell, ForTableHeaderCellDef, ForTableHeaderRow, ForTablePlaceholderCellDef, ForTablePlaceholderCellDefault, ForTableRow, ForTableRowCellDef, ForTableRowDef, ForTableRowReorder, ForTableRowSelector, ForTableSelectAll, ForTableSortHeader, provideForTable, provideForTableDefRegistry };
|
|
4739
|
+
export { FOR_TABLE_CONTEXT, FOR_TABLE_DEF_REGISTRY, ForTable, ForTableBody, ForTableCell, ForTableCellDef, ForTableColumnDef, ForTableColumnDragPlaceholder, ForTableColumnLabel, ForTableColumnReorder, ForTableColumnResizer, ForTableHeaderCell, ForTableHeaderCellDef, ForTableHeaderRow, ForTablePlaceholderCellDef, ForTablePlaceholderCellDefault, ForTableRow, ForTableRowCellDef, ForTableRowDef, ForTableRowReorder, ForTableRowSelector, ForTableSelectAll, ForTableSortHeader, ForTableVariantCell, provideForTable, provideForTableDefRegistry };
|
|
4677
4740
|
//# sourceMappingURL=forty-cdk-table.mjs.map
|