@rozie-ui/data-table-solid 0.7.1 → 0.7.2
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/CHANGELOG.md +357 -0
- package/README.md +11 -11
- package/dist/index.cjs +13 -13
- package/dist/index.d.cts +165 -96
- package/dist/index.d.mts +165 -96
- package/dist/index.mjs +13 -13
- package/dist/source/index.jsx +12 -12
- package/package.json +4 -3
- package/src/DataTable.tsx +134 -62
- package/src/index.ts +1 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# @rozie-ui/data-table-solid
|
|
2
|
+
|
|
3
|
+
## 0.7.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c362398: The npm package now includes `CHANGELOG.md`. It was written for every release but left out of the tarball, because npm no longer adds a changelog by itself, so a behaviour change recorded there (such as the 0.7.0 combobox Ctrl/Cmd/Alt+Enter change) was invisible to anyone reading the installed package.
|
|
8
|
+
- edb2ec4: DataTable: all 17 event handlers, the imperative handle and the scoped-slot parameters now have real types instead of `(...args: any[]) => void`, `(...args: any[]) => any` and `any`.
|
|
9
|
+
- Events: the state events carry the matching TanStack Table type (`sort-change` → `SortingState`, `selection-change` → `RowSelectionState`, `page-change` → `PaginationState`, and likewise `expand-change`, `group-change`, `pin-change`, `reorder-change`, `resize-change`, `visibility-change`). The rest have exported payload types: `DataTableFilterChangePayload`, `DataTableActiveCellChangePayload`, `DataTableCellEditCommitPayload`, `DataTableRowEditCommitPayload`, `DataTableRowActivatePayload`, `DataTableRangeChangePayload`, `DataTableHistoryChangePayload` and `DataTableVisibleRangeChangePayload`.
|
|
10
|
+
- Handle: every verb now has a typed signature (for example `sortColumn(colId: string, desc?: boolean)`, `getActiveCell(): DataTableActiveCell`, `getSelectedRange(): DataTableRange`, `pinColumn(colId, 'left' | 'right' | false)`). `DataTableCellPosition`, `DataTableActiveCell`, `DataTableRange` and `DataTableGroupableColumn` are exported.
|
|
11
|
+
- Slots: the `#cell`, `#editor`, `#colHeader`, `#filter`, `#selectAll`, `#selectCell`, `#groupBar`, `#placeholder` and `#detail` parameters are typed (`columnId: string`, `commit: (value: any) => void`, `column: Column<any, unknown>`, …).
|
|
12
|
+
|
|
13
|
+
Row data has no generic, so row-data positions (`row`, `value`, `oldValue`, `newValue`) stay `any`. A handler written against a different payload shape may now be rejected by the type checker.
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [c362398]
|
|
16
|
+
- @rozie/runtime-solid@0.9.0
|
|
17
|
+
|
|
18
|
+
## 0.7.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- a9d67cb: Accept `@rozie-ui/popover-<framework>` 0.3 as a peer dependency, alongside the 0.2 range (and, for data-table, the 0.1 range). Popover 0.3 adds the `reference` prop; the popover features these components already use are unchanged.
|
|
23
|
+
- a9d67cb: Typed public surface, phase 1: a component can now declare real TypeScript types for its events, slot parameters and imperative handle, and a consumer on any target sees them instead of `any`. See the new guide, "Typed public surface".
|
|
24
|
+
|
|
25
|
+
Four opt-in authoring features (a component that uses none of them compiles exactly as before; all are types-only, with no runtime change on any target):
|
|
26
|
+
- `<types>` block: type-only statements (`import type`, `interface`, `type`, and `export` of those) hoisted into every target and re-exported from the package entry. Anything else is an error (ROZ019, ROZ020). A `<types>` import that clashes with a `<script>` import is ROZ024; an identical duplicate is dropped silently. A `<types>` name that collides with a generated name (`<Name>Props`, `<Name>Handle`, `Rozie<Name>EventMap`, slot context interfaces, …), with a name the compiled module imports (a `<components>` key, its `<Local>Handle`, or a framework / `@rozie/runtime-*` import such as `ReactNode` or `TemplateRef`, reserved on every target), or with a top-level `<script>` declaration is ROZ025.
|
|
27
|
+
- `<emits>` block: `{ name: { payload?: '<type>', docs?: {...} } }`. When present it is the complete list: an undeclared `$emit` is an error (ROZ151), reported at the `$emit` call, and a declared event that is never emitted is a warning (ROZ152), reported at its `<emits>` entry. A `$emit` whose argument count does not match the declared payload is a warning (ROZ157), reported at the call. Invalid entries (including a repeated event name or `payload`/`docs` key), types and docs are ROZ021, ROZ022 and ROZ023. React and Solid get `onX?: (payload: P) => void`, Vue a typed `defineEmits`, Svelte a lowercase `onx` callback, Angular `output<P>()`, and Lit a `CustomEvent<P>` with a generated `Rozie<Name>EventMap` and typed `addEventListener`/`removeEventListener` overloads.
|
|
28
|
+
- `<slot :param-types="{ row: 'Row' }">` types a slot parameter (unknown key ROZ153, malformed value ROZ154).
|
|
29
|
+
- `$expose(verbs, signatures)`: a compile-time-only second argument typing the handle (unknown verb ROZ155, malformed ROZ156). The signature strings are stripped from every emitted module. A verb without a signature keeps its implementation's own types when it has them (a return-type annotation or an annotated `const`, in `<script lang="ts">`) on every target; only a fully untyped verb is `(...args: any[]) => any`.
|
|
30
|
+
|
|
31
|
+
Also in this release:
|
|
32
|
+
- The component manifest (`rozie-manifest.json`) is schema v2 and carries emit payloads, expose signatures, the `<types>` text and slot `:param-types`. The reader still accepts v1, so composing an already-published v1 package keeps working. Composing a package whose leaves ship a v2 manifest (`@rozie-ui/popover`, `@rozie-ui/combobox`, …) from your own `.rozie` requires `@rozie/*` at or above this release; a compiler that is too old now says so in ROZ988 (upgrade the toolchain) instead of advising a reinstall of the primitive.
|
|
33
|
+
- `.d.rozie.ts` sidecars now carry `<types>` and type slots and events exactly as each compiled module does. Apart from `<types>`, these changes apply to every component, not only to ones that use the new features: Solid `<slot>Slot` props and JSX.Element shapes; Svelte Snippet shapes and lowercase handler names; no spurious `render<X>` props on Vue, Angular and Lit (Lit declares its slot receivers on the element class instead); no `on<X>` props on Lit; and on Angular, every component with events loses its spurious `on<Event>` props, and the declared class gets typed `OutputEmitterRef<T>` outputs from the same derivation as the compiled `output()` fields (`T` is the declared payload, otherwise `void`, or `unknown` when an untyped `$emit` passes a payload). The `<Name>Handle` of an `$expose` component now keeps the type of a verb declared as an annotated `const` (`const add: AddFn = …`) instead of `(...args: any[]) => any` (or the implementation's own signature). A Solid scoped default slot now accepts a function child.
|
|
34
|
+
- Text such as `<script`, `<style`, `<title` or `<textarea` inside a `<types>`, `<emits>`, `<props>`, `<data>`, `<listeners>` or `<components>` body (in a comment, a docs string, or a generic like `Array<Style>`) no longer desynchronises the block splitter. Those bodies are now opaque to the HTML tokenizer.
|
|
35
|
+
|
|
36
|
+
Untyped-handler convergence (the one planned typing change for components that do not opt in; the sidecar fixes above reach them too): an untyped event handler is now `(...args: any[]) => void` on every target. The shared `.d.ts` sidecar, Solid and Svelte used to emit `unknown[]`, which rejected handlers written with a concrete parameter type; React already used `any[]`. The generated sources of the Solid and Svelte leaves (and the React `.d.ts`) change accordingly, hence the patch bumps. `@rozie-ui/sortable-list-solid` and `@rozie-ui/switch-solid` also pick up the scoped-default-slot function-child fix.
|
|
37
|
+
|
|
38
|
+
`@rozie-ui/popover-*` and `@rozie-ui/fullcalendar-*` adopt the features and are bumped minor, because typed events can reject a previously accepted wrong-typed handler:
|
|
39
|
+
- popover: the `anchor` slot context is typed (including the new `panelId: string`) and the handle (`show`, `hide`, `toggle`, `reposition`) is typed. Its open state's change event is the `open` model's (Lit: `open-change`, now in `RoziePopoverEventMap` as `CustomEvent<boolean>`).
|
|
40
|
+
- fullcalendar: 11 typed events (for example `eventClick` with `jsEvent: MouseEvent | KeyboardEvent`, and `unselect` with `jsEvent: UIEvent | null`), 10 typed portal slot arguments and 16 typed handle verbs. The `<types>` names are re-exported from every package entry, and the package barrels re-export the handle types and Lit event maps.
|
|
41
|
+
- Both families generate their README event tables from `<emits>` and no longer ship `scripts/event-manifest.mjs`.
|
|
42
|
+
- @rozie/runtime-solid@0.8.0
|
|
43
|
+
|
|
44
|
+
## 0.7.0
|
|
45
|
+
|
|
46
|
+
### Minor Changes
|
|
47
|
+
|
|
48
|
+
- d6e1909: Added `scrollToRow(index, options?)` and `getScrollElement()` to the DataTable imperative handle.
|
|
49
|
+
|
|
50
|
+
Previously, scrolling a `virtual` table to a specific row programmatically meant reaching into the internal `.rdt-scroll` class selector — the only prior way to do it, and one that breaks on any internal refactor. `scrollToRow` closes that gap: it mirrors TanStack virtual-core's own `scrollToIndex` API shape exactly, forwarding `options` (`{ align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' | 'instant' }`) unchanged. `getScrollElement()` returns the same `.rdt-scroll` DOM node the row/column virtualizer(s) observe, for a consumer that wants to read scroll position directly.
|
|
51
|
+
|
|
52
|
+
Both verbs are independent of `focusCell`'s grid-mode focus — `scrollToRow` never moves the roving active cell or fires `activecell-change`, and is callable in either `interactionMode`, table or grid. Both are safe no-ops/`null` when the table is not `virtual`.
|
|
53
|
+
|
|
54
|
+
## 0.6.0
|
|
55
|
+
|
|
56
|
+
### Minor Changes
|
|
57
|
+
|
|
58
|
+
- 4f2148d: Three new capabilities, a cross-target `<select>` correctness fix, an extensive keyboard/a11y
|
|
59
|
+
hardening pass, and the theming + packaging fixes shared with the rest of this release.
|
|
60
|
+
|
|
61
|
+
**`getRowId` — selection and expansion now follow the row, not its position.** `table-core`
|
|
62
|
+
keys `rowSelection`/`expanded` by row position unless given a `getRowId`, so a row inserted
|
|
63
|
+
above a checked one silently moved the selection (and an open detail row) onto a different row.
|
|
64
|
+
New prop `getRowId: (originalRow, index, parentRow?) => string | number`. The active cell and an
|
|
65
|
+
in-progress edit remain positional by design of the grid — a push insert above them still shifts
|
|
66
|
+
the keyboard cursor; that is a separate, deliberately deferred design question.
|
|
67
|
+
|
|
68
|
+
**`row-activate` — open a row by click, or Enter in grid mode.** New event
|
|
69
|
+
`row-activate { row, index, trigger }` (`trigger` is `'click' | 'keyboard'`) for list-style use
|
|
70
|
+
(e.g. opening an email thread). Fires on a plain click outside any control in the clicked cell,
|
|
71
|
+
or on Enter over a non-editable, control-less cell in grid mode; never on group-header or detail
|
|
72
|
+
rows, selection gestures, drag-select, or a `singleClickEdit` click. Table mode is click-only (no
|
|
73
|
+
row focus there). Purely additive.
|
|
74
|
+
|
|
75
|
+
**Virtual lazy loading — sparse data up to `rowCount`, placeholder rows, and a
|
|
76
|
+
`visible-range-change` event.** Under `virtual` + `manual` + `rowCount`, `data` may now be
|
|
77
|
+
sparse: any `undefined`/`null` entry, or anything past `data.length`, is treated as a
|
|
78
|
+
not-yet-loaded row and fed to `table-core` as a cached placeholder. Placeholder rows carry
|
|
79
|
+
`aria-busy`, a new `#placeholder` scoped slot per data cell (`{ index, columnId }`, default a
|
|
80
|
+
skeleton bar), and are excluded from selection, expansion, editing and activation. New event
|
|
81
|
+
`visible-range-change { start, end }` reports the rendered window (overscan included) over the
|
|
82
|
+
full row space, deduped, so a consumer can fetch the rows currently on screen. Placeholder rows
|
|
83
|
+
are keyed `__rdt_ph_<index>` until they fill.
|
|
84
|
+
|
|
85
|
+
**Fixed: a filled placeholder row's cached measured size now migrates to its real id** (and the
|
|
86
|
+
migration is compatible with `@tanstack/virtual-core` `<=3.14`, whose cache-invalidation shape
|
|
87
|
+
differs from `3.15+`). Previously, when a lazy-loaded placeholder row filled with real data and
|
|
88
|
+
changed id, the virtualizer's size cache kept the stale entry — the new id had no cached size,
|
|
89
|
+
got re-estimated, and every re-keyed row's remeasure nudged the scroll anchor (measured: -4px per
|
|
90
|
+
row on React). No API surface change; this is purely an internal scroll-anchoring correctness fix
|
|
91
|
+
for `virtual` + `manual` + `getRowId` tables that lazy-fill placeholder rows.
|
|
92
|
+
|
|
93
|
+
**Cross-target — a bound `<select>`'s value now survives its own options rendering after it**
|
|
94
|
+
(Lit and Angular only; see the `@rozie/core` changeset in this same release for the emitter-level
|
|
95
|
+
fix). Consumer-visible symptom before this fix: a `<select>`-backed editor or filter could commit
|
|
96
|
+
whatever option happened to render first, not the value you set.
|
|
97
|
+
|
|
98
|
+
**An extensive keyboard/a11y hardening pass**, covering (non-exhaustively): pinned columns now
|
|
99
|
+
stick exactly past the pinned columns before them; a header-active-cell move that reaches an
|
|
100
|
+
off-window column keeps the tab stop; the active row stays rendered when the viewport scrolls it
|
|
101
|
+
away; Ctrl+Shift+Arrow extends a range from its focus corner rather than the active cell;
|
|
102
|
+
Shift+Space selects the row and Ctrl+Space the column, Escape drops an in-progress range; the
|
|
103
|
+
`GroupBar` is now fully keyboard-operable; the grid keymap now reaches a custom `#editor`
|
|
104
|
+
drop-in; the clipboard cluster (copy/cut/paste/fill/delete) is closed and each operation
|
|
105
|
+
announces the correct verb to assistive tech instead of always saying "pasted"; the column axis
|
|
106
|
+
and cell-range selection now carry a real accessible surface (`aria-colindex`/`aria-colcount` on
|
|
107
|
+
header and body cells, matching the row-axis equivalent that already existed); filter re-sync and
|
|
108
|
+
date-coercion edge cases are fixed; every built-in drop-in editor (not just `EditorText`) now
|
|
109
|
+
focuses on open and refocuses correctly on a reactive re-open; `width` now actually maps to the
|
|
110
|
+
underlying column `size` (it was previously a fully inert documented prop); a text filter's
|
|
111
|
+
commit timing no longer races the input's own draft write; and column headers announce their
|
|
112
|
+
label text to assistive tech instead of the raw column id.
|
|
113
|
+
|
|
114
|
+
**Theming — design-system bridges now yield to an ancestor's own tokens, and apply correctly on
|
|
115
|
+
Lit.** Same fix as every other themed family in this release: previously a bridge (`bootstrap`,
|
|
116
|
+
`material`, `shadcn`) assigned the tokens it maps directly on the table's own class, which always
|
|
117
|
+
beats an ancestor's value by CSS specificity rules regardless of import order — so with a bridge
|
|
118
|
+
imported, an ancestor override of a public `--rozie-data-table-*` token had no effect, and on Lit
|
|
119
|
+
(whose classes render inside a shadow root) every bridge was completely inert. Bridges now
|
|
120
|
+
redeclare only the wiring they map, with the design system's own variable as the fallback,
|
|
121
|
+
resolved at the table itself — so it follows the nearest theme scope and works identically
|
|
122
|
+
whichever CSS is imported first.
|
|
123
|
+
|
|
124
|
+
**Fixed: the toolbar keeps its shape under a host page's typography CSS.** A host page that
|
|
125
|
+
styles bare `<summary>` elements (VitePress, Tailwind's `prose`, most CMS themes) grew the
|
|
126
|
+
column-visibility `<details>` and stretched the search input to match, because the component set
|
|
127
|
+
padding/border but not margin on its own `<summary>`. `margin: 0` is now set explicitly.
|
|
128
|
+
|
|
129
|
+
**Solid packaging.** `@rozie-ui/data-table-solid` ships the same compiled-JS-by-default,
|
|
130
|
+
JSX-under-the-`solid`-condition packaging shape as every other published Solid leaf this release
|
|
131
|
+
— see the dedicated Solid packaging changeset for the full description. No API change.
|
|
132
|
+
|
|
133
|
+
No breaking type-shape change: the public `.d.ts` surface only grows (`getRowId`, the
|
|
134
|
+
`row-activate` event, the `visible-range-change` event, and the `#placeholder` slot scope).
|
|
135
|
+
|
|
136
|
+
### Patch Changes
|
|
137
|
+
|
|
138
|
+
- 4f2148d: Fixed: the `themes/*.css` design-token bridge files' example `import` line named the wrong package (`@rozie-ui/<family>-react`) on every non-React target — copied byte-for-byte from one canonical source. It now names `@rozie-ui/data-table-solid`, this package's own.
|
|
139
|
+
|
|
140
|
+
**Fixed: lazy placeholder rows are now excluded from every clipboard write and from full-row
|
|
141
|
+
edit**, making the "excluded from selection, expansion, editing and activation" claim above
|
|
142
|
+
actually true. A paste, a cut, the Delete/Backspace range clear, and a fill-drag that span a
|
|
143
|
+
placeholder row (including a Ctrl+A that spans the whole `rowCount` space) no longer fabricate
|
|
144
|
+
a `cell-edit-commit` for it, inflate the N-of-M aria-live announce, or write a partial row into
|
|
145
|
+
the still-unloaded sparse hole; `editRow()` (and Shift+F2) on a placeholder row is now a no-op
|
|
146
|
+
instead of opening a row editor seeded with `undefined`s.
|
|
147
|
+
|
|
148
|
+
**Docs: the `placeholder` slot's per-target prop name is now documented**, alongside
|
|
149
|
+
`detail`/`groupBar`/`filter`, in the Slots section below (`renderPlaceholder` on React,
|
|
150
|
+
`placeholderSlot` on Solid, the `.placeholder` property on Lit, `#placeholder` elsewhere) — it
|
|
151
|
+
was previously listed only in the generic slots table with no naming note.
|
|
152
|
+
|
|
153
|
+
- 4f2148d: **Fixed: published Solid leaves now ship compiled JavaScript for `import`/`require`, with JSX
|
|
154
|
+
kept only under the `solid` export condition.**
|
|
155
|
+
|
|
156
|
+
Every `@rozie-ui/*-solid` leaf with markup previously shipped Solid JSX inside
|
|
157
|
+
`dist/index.{mjs,cjs}` under a plain `import`/`require` (`chartjs-solid` renders no markup of its
|
|
158
|
+
own, but ships the same corrected export shape for consistency with its siblings). That is not
|
|
159
|
+
valid JavaScript on its own — a default `vite-plugin-solid` setup
|
|
160
|
+
fails with "JSX syntax is disabled" (the plugin only transforms `.[mc]?[jt]sx` files), and any
|
|
161
|
+
bundler without a Solid plugin fails outright. The only way to consume these packages was to
|
|
162
|
+
manually point `vite-plugin-solid` at the package's `.mjs` files inside `node_modules` — a
|
|
163
|
+
workaround, not a supported shape.
|
|
164
|
+
|
|
165
|
+
New export shape (the standard one for a published Solid library):
|
|
166
|
+
- `import` / `require` → `dist/<entry>.{mjs,cjs}`, compiled to plain DOM output by
|
|
167
|
+
`babel-preset-solid`. Any bundler consumes this with no Solid plugin at all.
|
|
168
|
+
- `solid` (export condition) → `dist/source/<entry>.jsx`, JSX kept intact. `vite-plugin-solid`
|
|
169
|
+
and SolidStart resolve this condition first and compile it themselves for their own mode (DOM /
|
|
170
|
+
SSR / hydration).
|
|
171
|
+
|
|
172
|
+
**If you were using the `extensions: ['.mjs']` / `node_modules` `include` workaround with
|
|
173
|
+
`vite-plugin-solid` to consume one of these packages, remove it — it is no longer needed** and a
|
|
174
|
+
default `vite-plugin-solid` setup now resolves the `solid` condition correctly on its own. No
|
|
175
|
+
public API change on any of these leaves.
|
|
176
|
+
|
|
177
|
+
- Updated dependencies [4f2148d]
|
|
178
|
+
- @rozie/runtime-solid@0.7.5
|
|
179
|
+
|
|
180
|
+
## 0.5.0
|
|
181
|
+
|
|
182
|
+
### Minor Changes
|
|
183
|
+
|
|
184
|
+
- b084200: Two behavior changes plus the documentation remediation pass.
|
|
185
|
+
|
|
186
|
+
**`pinned` is now a real initial pin seed.** A per-column `pinned` of `left`/`right` — from `<Column pinned>` or from the `columns` config array — was previously inert metadata. It is now applied once as the table's starting `columnPinning` state, so `getIsPinned()` reports it and the column joins the matching sticky rail. That also **reorders** the column, since table-core orders visible cells `[left-pinned, center, right-pinned]`. A consumer who has already expressed a pin owns the slice and the declaration is ignored; an interactive unpin is never re-applied.
|
|
187
|
+
|
|
188
|
+
**The four theme bridges now assign at `:root`.** `bootstrap`, `material`, and `shadcn` previously assigned their tokens only on the table's own classes. On the Lit target both `.rozie-data-table` and `.rozie-data-table-wrap` render inside the component's shadow root, where a document-level class selector can never match — so all four bridges were inert on Lit. Trade-off, stated rather than buried: two tables on one page can no longer take different bridges by ancestor class alone. Per-instance overrides still work on the five light-DOM targets via the class selectors, and on all six by setting the public tokens on any ancestor.
|
|
189
|
+
|
|
190
|
+
Also fixes a column resize that did nothing on React (stale mount-time `columnSizingInfo`), a column-window versioning bug that collapsed the column spacer, and a focus steal in the grid active-cell path. The published token surface is now documented accurately: 18 public `--rozie-data-table-*` tokens wired onto 82 internal `--rdt-*` tokens, with the 58 that have no public counterpart named explicitly rather than implied to be covered.
|
|
191
|
+
|
|
192
|
+
No type-shape change: the `.d.ts` delta is documentation comments only, with nothing removed.
|
|
193
|
+
|
|
194
|
+
### Patch Changes
|
|
195
|
+
|
|
196
|
+
- b084200: Solid: slot scope values are now passed as lazy getters instead of eager reads.
|
|
197
|
+
|
|
198
|
+
A scoped slot invocation used to build its param object as `{ open: open() }`. Because that object is constructed inside the JSX insert that invokes the slot, Solid subscribed the **insert itself** to every signal read while building it — so any change re-ran the insert, re-invoked the consumer's slot function, and replaced the rendered subtree. Emitting `{ get open() { return open(); } }` defers the read into the consumer's own reactive scope, which is Solid's own convention for passing reactive props.
|
|
199
|
+
|
|
200
|
+
Observable fix: opening the data-table column menu no longer tears the just-focused trigger out of the DOM, so the documented "Escape returns focus to the trigger" guarantee now holds on Solid as it already did on the other five targets.
|
|
201
|
+
|
|
202
|
+
Literals and function-valued expressions are deliberately left as plain properties — neither can read a signal, and wrapping a function would hand the consumer a new identity on every property access.
|
|
203
|
+
|
|
204
|
+
Note for consumers: destructuring a slot scope (`({ option, index }) => …`) and spreading it behave exactly as before. The one behavior change is that **assigning** to a scope property now throws `TypeError: Cannot set property x of #<Object> which has only a getter`, where it previously succeeded silently. Writing to a slot scope was never a supported pattern.
|
|
205
|
+
|
|
206
|
+
`@rozie/core` is named here even though no file under `packages/core/` changed: the emitter lives in the private `@rozie/target-solid` package, which is bundled into core's published dist (and into `unplugin`, `babel-plugin`, and `cli`). A changeset derived from changed paths alone would ship a toolchain that still emits the bug.
|
|
207
|
+
- @rozie/runtime-solid@0.7.4
|
|
208
|
+
|
|
209
|
+
## 0.4.0
|
|
210
|
+
|
|
211
|
+
### Minor Changes
|
|
212
|
+
|
|
213
|
+
- 5ad5ef4: Adds a **per-column dynamic-name slot family** on each of data-table's four column-scoped slots — `cell`, `colHeader`, `filter`, and `editor`. Previously the only way to customize one column's rendering was the single catch-all `#cell` slot, branched by hand on the `columnId` scoped param; that branch does not compose, and the same story applied to `#colHeader`, `#filter`, and `#editor`. Now you can fill a specific column directly with an ordinary static named slot, e.g.:
|
|
214
|
+
|
|
215
|
+
```html
|
|
216
|
+
<DataTable :columns="columns">
|
|
217
|
+
<template #cell-price="{ row, value }">
|
|
218
|
+
<span class="price">{{ formatCurrency(value) }}</span>
|
|
219
|
+
</template>
|
|
220
|
+
</DataTable>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
replacing `cell-price` with `colHeader-price`, `filter-price`, or `editor-price` for the other three seams. On React, Solid, Svelte, Lit, and Vue the slot key is template-literal-typed with the same scoped-parameter typing the generic slot already had (`{ row, value }` for `cell`, not an untyped `(...args) => ReactNode`). Angular's `templates()` intake stays `Record<string, TemplateRef<unknown>>`, type-erased per key — see `docs/parity.md` for that divergence.
|
|
224
|
+
|
|
225
|
+
**Precedence is three-tier and structural, not a runtime presence check:** a family fill (`#cell-price`) wins over a generic fill (`#cell`), which wins over the built-in render. A column that only fills `#cell` behaves exactly as before for every other column; a column that fills neither renders the built-in cell.
|
|
226
|
+
|
|
227
|
+
**Both `filter-<id>` and `editor-<id>` are gated the same way their generic siblings already were:** a `filter-<id>` fill only applies to a column with `filterable: true`, and an `editor-<id>` fill only applies to a column with `editor: 'custom'` — filling `#editor-status` on a column that isn't `editor: 'custom'` is a no-op, matching today's `#editor` behavior. `cell-<id>` and `colHeader-<id>` are ungated (every column is eligible), matching their generic siblings.
|
|
228
|
+
|
|
229
|
+
**The built-in editor inputs now carry a `data-builtin-editor` marker attribute.** This is an internal implementation detail of the editor-owns-focus contract (the host needs to tell "this is my own editor" from "this is a consumer's drop-in editor" without a runtime slot-presence test) — it has no effect on a consumer's own markup or fills, and no prop or event surface changed.
|
|
230
|
+
|
|
231
|
+
**Emitted markup is no longer byte-identical to 0.3.2 on any of the six targets**, even for a consumer who never touches a family slot: the filter seam's built-in `<input>` moved from a sibling gated by a presence check into a slot fallback, the editor chain now nests inside a fourth branch, and the built-in editors gained the marker attribute above. Behavior for an existing consumer is unchanged — this is a structural refactor of how the same three tiers (family / generic / built-in) are expressed, verified by the full data-table behavioral suite and a dedicated six-target focus-contract spec, not by comparing generated source. See the "Per-column slot families" section on the data-table columns docs page for the full precedence and gating reference.
|
|
232
|
+
|
|
233
|
+
This release also folds in a separately-landed grouped-header width fix (`.changeset/data-table-grouped-header-width-fix.md`): under `table-layout: fixed`, a multi-level group header's `<th>` now correctly sums its spanned leaf columns' widths instead of reporting table-core's flat single-column default.
|
|
234
|
+
|
|
235
|
+
### Patch Changes
|
|
236
|
+
|
|
237
|
+
- c62c832: Fixes a grouped-header rendering defect: under `table-layout: fixed` (which every windowed/virtualized data-table already opts into), a multi-level group header's `<th>` reported table-core's flat single-column default size (150px) instead of the sum of its spanned leaf columns' sizes, so the browser divided that single declared width across every leaf column the group spans — a 5-column group rendered each leaf at 30px (150 / 5) instead of its real declared width. This was a pre-existing gap (tracked since Phase 87 as "Gap 1" in that phase's deferred-items ledger) that surfaced whenever a grouped-header table's rendered column window happened to include the grouped columns; it is now fixed at the source — the header-width chrome helper reads table-core's own `Header.getSize()` (which already sums descendant leaf-column sizes correctly for a group header, and is behavior-identical to the old code path for an ordinary leaf header) instead of the ungrouped `Column.getSize()` accessor. No prop or markup changes; any consumer using multi-level grouped headers will simply see the grouped columns render at their correct, intended width.
|
|
238
|
+
|
|
239
|
+
Also hardens the fill-drag edge-auto-scroll gesture's cell hit-test (`fillDrag.rzts`, shared by the drag-select gesture too): the single-exact-pixel `elementFromPoint` probe used to resolve which cell sits under a stationary pointer while content auto-scrolls beneath it now falls back to a small nearest-cell horizontal search when the exact point misses, making the gesture robust against a narrow column transiting past the fixed probe point within a single animation frame. This is defense-in-depth alongside the width fix above (which was the actual root cause of the one observed user-facing symptom, a fill-drag range that failed to extend past a grouped-header column region during auto-scroll) — behavior is unchanged on every ordinary (non-edge-case) frame.
|
|
240
|
+
- @rozie/runtime-solid@0.7.3
|
|
241
|
+
|
|
242
|
+
## 0.3.2
|
|
243
|
+
|
|
244
|
+
### Patch Changes
|
|
245
|
+
|
|
246
|
+
- Fix eight defects in grouped columns and grouped rows. All six targets.
|
|
247
|
+
|
|
248
|
+
**Nested group leaf columns now resolve their own column definition.** A leaf declared inside a `columns:` group entry was never registered in the internal by-id lookup, so every definition-derived lookup fell back: the `<th>` rendered the raw column id instead of the declared `header`, the column could never be filterable or editable whatever its config said, and the clipboard/fill accessor fell back to the column id instead of the configured `field` — writing to the wrong key. Nested leaves now behave identically to top-level leaves.
|
|
249
|
+
|
|
250
|
+
**A group-header row no longer receives an unrelated record in scoped slots.** The table engine builds each group-header row from its first leaf's record, which the `#cell`, `#selectCell` and `#editor` slots passed straight through as `row` — so a template reading `{{ row.someField }}` painted the first leaf's value on the group line. These slots now receive a group descriptor on group-header rows:
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
{
|
|
254
|
+
isGroupRow: (true, groupId, groupingColumnId, groupingValue, leafCount);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Ordinary rows are unchanged and still receive their record. If your template reads record fields off `row`, guard with `row.isGroupRow` — the previous value on those rows was another row's data, never this one's.
|
|
259
|
+
|
|
260
|
+
**Group-header rows are no longer editable, and bulk writes skip them.** Enter, F2, Space, a printable key, or a click on an editable non-grouping column would open an editor on a group-header row, and committing wrote to the first leaf's record. Paste, cut, clear and fill-drag wrote through the same path. Group rows are now guarded at every edit and write entry point; Enter on a group row toggles the group, as it already did for the grouping column. Copy is unaffected — it still serializes the displayed aggregate.
|
|
261
|
+
|
|
262
|
+
**The group member count now counts records, not nodes.** Under multi-level grouping the count included intermediate sub-group nodes, so a region with 2 sub-groups and 3 records displayed `(5)`. It now displays `(3)`. Single-level grouping is unchanged.
|
|
263
|
+
|
|
264
|
+
**`groupableColumns` (the `#groupBar` slot prop) now offers the right set.** Group columns are no longer offered — a group entry has no accessor and cannot be a grouping key. Groupable leaves nested under a group header are now offered, in declaration order; they were previously omitted entirely. Opt a leaf out with `groupable: false` as before.
|
|
265
|
+
|
|
266
|
+
## 0.3.1
|
|
267
|
+
|
|
268
|
+
### Patch Changes
|
|
269
|
+
|
|
270
|
+
- Performance: `columnDefs()` is now memoized, removing an accidental O(columns² × rows) recompute from the per-cell metadata path.
|
|
271
|
+
|
|
272
|
+
`columnDefs()` rebuilt the entire column-definition array on every call, and its caller chain (`defFor` → `editMetaOf` / `columnEditable` / `editorTypeOf` / `isEditing`) runs once per rendered cell, per render commit. On a 60-column table that is roughly 72,000 column-definition rebuilds per commit — repeated on every frame during a sustained scroll gesture, because the fill-drag edge auto-scroll bumps the window version each frame.
|
|
273
|
+
|
|
274
|
+
The array is now cached on the reference identity of `:columns` and the internal `<Column>` registry — the same two dependencies the component's existing re-feed watch already treats as reference-only. A cache hit is an O(1) identity check; a miss recomputes exactly as before. Output is byte-identical; this is a pure memoization with no behavior or API change.
|
|
275
|
+
|
|
276
|
+
The cost was identical on all six targets, but it was most visible on Vue, where `:columns` and the column registry are reactive proxies and every property read the builder performs pays proxy-tracking overhead on top of the redundant work. Under CPU contention that combination could starve the fill-drag auto-scroll loop badly enough that a drag toward the bottom edge scrolled the viewport without the selection range keeping pace with the newly revealed rows. That is fixed, and the same fix removes the wasted work for every other target too.
|
|
277
|
+
|
|
278
|
+
## 0.3.0
|
|
279
|
+
|
|
280
|
+
### Minor Changes
|
|
281
|
+
|
|
282
|
+
- 877dbdf: Data-table gains column (horizontal) windowing and content-driven auto-measure — the shared windowing engine's two remaining "what Rozie defers" bullets are closed. Combobox picks up the shared engine's new host-contract stubs as dead code, no behavior change. Command-palette republishes in lockstep, with one genuine bug fix on its Lit leaf. The compiler's inliner gets a small tree-shaking fix that this phase's own pure-helper extraction needed.
|
|
283
|
+
|
|
284
|
+
**`data-table` — column windowing.** `virtual` widens from a Boolean to a value grammar: `false` (default, unchanged) | `true` / `'rows'` (unchanged from before — every existing consumer is untouched) | `'columns'` (new: horizontal windowing) | `'both'` (new: both axes). Under column windowing, pinned columns, the active cell's column, and a single in-progress edit's column always stay rendered regardless of scroll position; every header level (including grouped headers) windows on the same slice as the body with a clamped `colSpan`; the dedicated filter row windows the same way; and `focusCell` / `getActiveCell` / `activecell-change` all resolve against the absolute (unwindowed) column index, so off-window columns stay fully addressable through the handle. Fill-drag gets edge auto-scroll on all four container edges — this also closes a pre-existing gap on the row axis, where a fill drag previously could not reach unrendered rows past the top or bottom edge of a row-windowed table either.
|
|
285
|
+
|
|
286
|
+
Two consumer-visible consequences: `virtual='columns'` (and `'both'`) moves the `<table>` inside an `rdt-scroll` `<div>` wrapper, the same wrapper row windowing already uses; and the windowed path applies `table-layout: fixed`, so columns stop auto-fitting their content — size them via `:columnSizing`, a `<Column size>` attribute, or the resize handle. `virtual={false}` and `virtual` unset remain byte-identical to before this change; `virtual={true}` / `'rows'` remains byte-behavior-identical to today's row-only windowing.
|
|
287
|
+
|
|
288
|
+
The `.d.ts` for `virtual` widens from `boolean` to `boolean | string` on all six leaves — a typed-surface change existing consumers with strict TypeScript will see, even though the runtime default is unchanged.
|
|
289
|
+
|
|
290
|
+
**`data-table` — `autoMeasure`.** A new, independent `autoMeasure: Boolean` prop (default `false`). When on, the windowing engine feeds `estimateSize()` a running mean of measured row heights instead of the fixed `estimateRowHeight` seed, so `getTotalSize()` (and the scrollbar it drives) converges toward the true content total on a large table with variable-height rows, instead of staying pinned at `rowCount x estimateRowHeight` forever. The re-feed is hysteresis-gated and anchor-preserving — the topmost rendered row's position holds steady while the estimate refines, so content does not visibly lurch. `estimateRowHeight` is unchanged and un-deprecated: it remains the required first-paint seed (the very first render has zero measurements regardless of `autoMeasure`), and remains the explicit, permanent override when `autoMeasure` is off.
|
|
291
|
+
|
|
292
|
+
**`combobox` — engine only, no behavior change.** Gains the shared windowing engine's new required host-contract one-liners (`rowsWindowed()`, `autoMeasureOn()`) preserving today's exact semantics: `autoMeasureOn()` returns `false`, so `windowing.rzts`'s content-driven-estimate accumulator stays dead code here, exactly as before. (A gap-closure during review removed five _additional_ column-axis stub declarations — `colVirtualizer`, `colsWindowed()`, `columnCount()`, `columnSize()`, `forcedColumns()` — that an earlier draft of this same patch had also added under a mistaken premise about the compiler's tree-shaking requirements; they were genuinely dead code with zero callers, verified by tracing every function combobox imports from `windowing.rzts` back to its body. Their removal is folded into this same patch bump since neither of them has shipped to npm yet — see `87-16-SUMMARY.md`.) No new props, no behavior change, regenerated dist only. (Listbox's source gets the identical mechanical `rowsWindowed()`/`autoMeasureOn()` addition, but listbox has never been published — per standing policy this repo does not version or changelog packages that are not yet on npm, so listbox is not part of this changeset; its addition ships whenever listbox itself is first published.)
|
|
293
|
+
|
|
294
|
+
**`@rozie/core` (and the rest of the toolchain fixed group) — two compiler-level fixes surfaced by this phase.** `@rozie/target-lit` (inlined into `@rozie/core` / `@rozie/cli` / `@rozie/unplugin` / `@rozie/babel-plugin` at build time) fixes a real bug in Lit's emitted output for any `[Boolean, String]` union prop: Lit's built-in `type: Boolean` attribute converter collapses any non-null static attribute value to `true`, silently discarding a string value. `emitNonModelProp()` now emits a custom `converter.fromAttribute` for this prop shape instead. This is the SAME fix that closes `command-palette-lit`'s `appendTo` bug above — one emitter fix, two visible symptoms. Separately, this phase's own `DataTable.rozie` pure-helper extraction (moving framework-agnostic logic into colocated `.ts` helpers) surfaced a real gap in `inlineScriptPartials()`'s tree-shaking: a script partial that only re-exports a name introduced by its own plain-module import (no local declaration body) was not recognized as a valid tree-shake target, silently dropping the backing import and producing a `TS2304` in the emitted leaves. Both are compiler-level fixes; no `.rozie`-author-visible API change.
|
|
295
|
+
|
|
296
|
+
**`command-palette` — lockstep republish, with one genuine fix.** Five of its six leaves have a byte-identical emitted diff from this phase: command-palette composes the _published_ combobox package for its own target at compile time rather than the combobox source, so the shared engine change does not reach those five leaves' bytes at all — this patch keeps them in the same release wave as their combobox peer, per the release-mechanics decision that every published leaf should ride the same windowing engine generation. The Lit leaf is the one exception with a real emitted change: its `appendTo` property's Lit `@property({ type: Boolean })` converter previously discarded a string value (`appendTo="body"`, the documented example) by coercing it to `true` via Lit's default Boolean-attribute converter — the string was silently dropped. It now uses an explicit converter that preserves `true` / `false` / a string value correctly, matching the `[Boolean, String]` union type the prop has always declared.
|
|
297
|
+
|
|
298
|
+
### Patch Changes
|
|
299
|
+
|
|
300
|
+
- @rozie/runtime-solid@0.7.2
|
|
301
|
+
|
|
302
|
+
## 0.2.6
|
|
303
|
+
|
|
304
|
+
### Patch Changes
|
|
305
|
+
|
|
306
|
+
- 287dbf2: All six `@rozie-ui/data-table-<target>` leaves widen their `@rozie-ui/popover-<target>` peer dependency from `^0.1.0` to `^0.1.0 || ^0.2.0`.
|
|
307
|
+
|
|
308
|
+
**Why both, not just the new one.** Combobox moves its own popover peer to `^0.2.0` in this same wave. A caret range on a 0.x version pins the minor, so leaving data-table's range at `^0.1.0` would give any consumer installing both the combobox family and the data-table family two mutually exclusive ranges for the same `@rozie-ui/popover-<target>` package — an unsatisfiable peer pair. Forcing data-table forward to `^0.2.0` alone would avoid that conflict but strand existing data-table consumers on a popover upgrade they have no reason to take, since data-table does not use any of popover's five new props. Admitting both ranges is the option that resolves the conflict without an unnecessary forced upgrade.
|
|
309
|
+
|
|
310
|
+
**Why it is safe to admit both.** Data-table composes a `<Popover>` at exactly two sites in source (`DataTable.rozie`), and both are byte-identical, binding only four props: `trigger="click"`, `placement="bottom-end"`, `strategy="fixed"`, `:offset="4"`. All four are present, unchanged, in both `0.1.x` and `0.2.0` — data-table binds none of popover's five new props (`bare`, `disablePositioning`, `keepMounted`, `matchWidth`, `disableDismiss`). The one behavioral change in this wave that touches existing consumers — `aria-haspopup`/`aria-expanded` gating on `hasGestureTrigger()` — only affects `trigger="manual"` popovers; data-table's `trigger="click"` stays on the gesture-trigger branch and sees no ARIA change in either version.
|
|
311
|
+
|
|
312
|
+
**Scope of the change.** There is no runtime, API, or DOM change in `@rozie-ui/data-table-<target>` itself. The entire leaf diff is the one peer dependency range line per target, six lines total. This changeset is deliberately separate from the popover-promotion changeset covering combobox and popover: it is its own story about data-table's peer contract, not a restatement of theirs.
|
|
313
|
+
- @rozie/runtime-solid@0.7.1
|
|
314
|
+
|
|
315
|
+
## 0.2.5
|
|
316
|
+
|
|
317
|
+
### Patch Changes
|
|
318
|
+
|
|
319
|
+
- @rozie/runtime-solid@0.7.0
|
|
320
|
+
|
|
321
|
+
## 0.2.4
|
|
322
|
+
|
|
323
|
+
### Patch Changes
|
|
324
|
+
|
|
325
|
+
- @rozie/runtime-solid@0.6.0
|
|
326
|
+
|
|
327
|
+
## 0.2.3
|
|
328
|
+
|
|
329
|
+
### Patch Changes
|
|
330
|
+
|
|
331
|
+
- Regenerated against `@rozie/core@0.3.0`. The `splitProps` skip-list now correctly excludes emit-handler props from the root DOM fallthrough spread — previously a consumer's handler fired twice per emit. No API surface change.
|
|
332
|
+
|
|
333
|
+
## 0.2.2
|
|
334
|
+
|
|
335
|
+
### Patch Changes
|
|
336
|
+
|
|
337
|
+
- @rozie/runtime-solid@0.2.1
|
|
338
|
+
|
|
339
|
+
## 0.2.1
|
|
340
|
+
|
|
341
|
+
### Patch Changes
|
|
342
|
+
|
|
343
|
+
- @rozie/runtime-solid@0.2.0
|
|
344
|
+
|
|
345
|
+
## 0.2.0
|
|
346
|
+
|
|
347
|
+
### Minor Changes
|
|
348
|
+
|
|
349
|
+
- 1a2e30c: data-table composes `@rozie-ui/popover` via the published-package model (Option A) instead of vendoring its source.
|
|
350
|
+
|
|
351
|
+
The header column `⋯` menu previously vendored the popover primitive's source into each data-table leaf. It now resolves the published `@rozie-ui/popover-<target>` package at compile time (via the schema-versioned manifest), and each data-table leaf declares `@rozie-ui/popover-<target>` (`^0.1.0`) as a required runtime **peerDependency**.
|
|
352
|
+
|
|
353
|
+
**Consumer action:** install the matching popover leaf alongside data-table, e.g. `@rozie-ui/popover-react` for `@rozie-ui/data-table-react`. (`@floating-ui/dom` is no longer a direct data-table peer — it graduates to the popover leaf's own peer.)
|
|
354
|
+
|
|
355
|
+
Also fixes `@rozie-ui/data-table-lit` `sideEffects` (was a css-only allowlist that left the `customElements.define(...)` registrations for `rozie-data-table` / `rozie-column` / `rozie-editor-*` / `rozie-filter-*` unprotected against production tree-shaking).
|
|
356
|
+
|
|
357
|
+
**Release ordering:** `@rozie-ui/popover-<target>` must be published to npm before this release, since it is now a required peer of every data-table leaf.
|
package/README.md
CHANGED
|
@@ -498,23 +498,23 @@ import '@rozie-ui/data-table-solid/themes/shadcn.css'; // or material.css, bo
|
|
|
498
498
|
|
|
499
499
|
| Event | Description |
|
|
500
500
|
| --- | --- |
|
|
501
|
-
| `
|
|
501
|
+
| `activecell-change` | Fired (grid interaction mode only) whenever the active cell moves — by keyboard navigation or a `focusCell` call. One-way notification; payload is `{ rowIndex, colIndex }` integers over the visible model. Fires on every move including arrow keypresses. |
|
|
502
|
+
| `cell-edit-commit` | Fired when an editable cell commits a NEW, validated value — once per committed cell, from the single `commitEdit` call site (a rejected/invalid commit fires nothing). Pairs with the two-way `data` write (one fresh-array replace per commit). Payload is `{ rowId, columnId, oldValue, newValue }`. `cancel`/`Escape` and a validation failure emit nothing. |
|
|
502
503
|
| `expand-change` | Fired when the expanded-row set changes (an expander chevron toggle — click / Enter / Space — or a `toggleRowExpanded`/`expandAll`/`collapseAll` call). Fires exactly once per change (the echo-guarded write funnel dedups the React multi-render re-entry) and REGARDLESS of whether the two-way `expanded` model is bound. Payload is the fresh `ExpandedState` — a `{ [rowId]: true }` object, or the `true` literal after `expandAll` (passed through verbatim — never `Object.keys` it without a `=== true` guard). Named `expand-change` (not `expanded-change`): the model:true `expanded` prop owns the `onExpandedChange` callback on the React/Solid Props interface, so the event stems off a distinct name to avoid a duplicate-identifier collision (the house convention every slice follows). |
|
|
503
|
-
| `group-change` | Fired when the grouping state changes (a consumer-built `#groupBar` apply/clear, mutating the `grouping` model, or an `applyGrouping`/`clearGrouping` call). Fires exactly once per change (the echo-guarded write funnel dedups the React multi-render re-entry) and REGARDLESS of whether the two-way `grouping` model is bound. Payload is the fresh `GroupingState` — an ORDERED `string[]` of column ids (e.g. `["region","category"]` for nested groups), or `[]` when cleared. Named `group-change` (not `grouping-change`): the model:true `grouping` prop owns the `onGroupingChange` callback on the React/Solid Props interface, so the event stems off a distinct name to avoid a duplicate-identifier collision (the house convention every slice follows — sorting→sort-change, expanded→expand-change). |
|
|
504
504
|
| `filter-change` | Fired when a filter changes. Payload is `{ globalFilter }` for the global search box or `{ columnFilters }` (the fresh `ColumnFiltersState` `[{ id, value }]`) for a per-column filter — both surface through this one event. |
|
|
505
|
+
| `group-change` | Fired when the grouping state changes (a consumer-built `#groupBar` apply/clear, mutating the `grouping` model, or an `applyGrouping`/`clearGrouping` call). Fires exactly once per change (the echo-guarded write funnel dedups the React multi-render re-entry) and REGARDLESS of whether the two-way `grouping` model is bound. Payload is the fresh `GroupingState` — an ORDERED `string[]` of column ids (e.g. `["region","category"]` for nested groups), or `[]` when cleared. Named `group-change` (not `grouping-change`): the model:true `grouping` prop owns the `onGroupingChange` callback on the React/Solid Props interface, so the event stems off a distinct name to avoid a duplicate-identifier collision (the house convention every slice follows — sorting→sort-change, expanded→expand-change). |
|
|
506
|
+
| `history-change` | Fired when undo/redo AVAILABILITY changes (one unified grid-wide undo/redo stack, not scoped per-cell or per-row) — EDGE-triggered (only when `canUndo`/`canRedo` actually flip, not on every recorded edit) so a toolbar can enable/disable its buttons without polling. Only meaningful when `undoable` is `true`. Payload is `{ canUndo, canRedo }` booleans. No `history` model prop exists, so there is no model-prop==emit-name duplicate-identifier collision. |
|
|
505
507
|
| `page-change` | Fired when pagination changes (prev/next, a page-size change, or a `setPage`/`setRowsPerPage` call). Payload is the fresh `{ pageIndex, pageSize }` object. |
|
|
506
|
-
| `selection-change` | Fired when the row selection changes (a row/select-all checkbox toggle or a `toggleAllRows`/`clearSelection` call). Payload is the fresh `RowSelectionState` `{ [rowId]: true }` object. |
|
|
507
|
-
| `visibility-change` | Fired when a column is shown/hidden (the column-toggle menu or a `toggleColumnVisibility` call). Payload is the fresh `VisibilityState` `{ [colId]: boolean }` object. |
|
|
508
|
-
| `resize-change` | Fired live during a column resize drag (`columnResizeMode: "onChange"`). Payload is the fresh `ColumnSizingState` `{ [colId]: number }` object. |
|
|
509
|
-
| `reorder-change` | Fired when the column order changes. Column reorder is programmatic only — an `applyColumnOrder` call or a two-way `columnOrder` write; the component ships NO drag or menu affordance for it. Payload is the fresh `ColumnOrderState` `string[]`. |
|
|
510
508
|
| `pin-change` | Fired when a column is pinned/unpinned (the per-header pin buttons or a `pinColumn` call). Payload is the fresh `ColumnPinningState` `{ left: string[], right: string[] }` object. |
|
|
511
|
-
| `history-change` | Fired when undo/redo AVAILABILITY changes (one unified grid-wide undo/redo stack, not scoped per-cell or per-row) — EDGE-triggered (only when `canUndo`/`canRedo` actually flip, not on every recorded edit) so a toolbar can enable/disable its buttons without polling. Only meaningful when `undoable` is `true`. Payload is `{ canUndo, canRedo }` booleans. No `history` model prop exists, so there is no model-prop==emit-name duplicate-identifier collision. |
|
|
512
|
-
| `visible-range-change` | Fired when the RENDERED row window changes under row windowing (`virtual`) — the window the table actually renders, overscan included — and once after mount. Payload `{ start, end }` over the full row space (`end` exclusive; with lazy rows that space is `rowCount` long). Deduped: a scroll that does not move the window emits nothing. Pair with `manual` + `rowCount` and sparse `data` to fetch the rows the viewport needs. |
|
|
513
|
-
| `activecell-change` | Fired (grid interaction mode only) whenever the active cell moves — by keyboard navigation or a `focusCell` call. One-way notification; payload is `{ rowIndex, colIndex }` integers over the visible model. Fires on every move including arrow keypresses. |
|
|
514
|
-
| `row-activate` | Fired when the user opens a row (list-style "open this item" — oinbox's email thread). A plain click on a body data row, outside any control in the clicked cell (the selection checkbox, the expander, links, inputs, drop-in widgets and an open editor do NOT activate), in both interaction modes; not a shift/ctrl/meta click (selection gestures), the end of a drag-select, or a `singleClickEdit` click on an editable grid cell (that opens the editor). In grid mode also Enter on a non-editable cell that has no controls of its own (Enter on an editable cell still begins the edit; Enter on a cell with controls still enters them). Group-header and detail rows never activate. Payload is `{ row, index, trigger }` — `row` the original data object, `index` its position in the rendered model (page-relative; the full model when virtual), `trigger` `'click'` or `'keyboard'`. |
|
|
515
509
|
| `range-change` | Fired whenever the rectangular cell-range selection changes — extended by `Shift+Arrow` / `Shift+Click` from the single `extendRange`/`setRangeFocus` call sites (React multi-emit dedup). One-way notification (the range is NOT a `model:true` slice — the model:true count stays at 12, leaving the Angular multi-model-CVA condition untouched); it is a SEPARATE layer from the row-selection slice and the two never corrupt each other. Payload is `getSelectedRange()` → `{ anchor, focus }` where each corner is a `{ rowIndex, colIndex }` index pair over the visible model (integers only — no row data, no DOM node), or `{ anchor: null, focus: null }` when no range is set. |
|
|
516
|
-
| `
|
|
510
|
+
| `reorder-change` | Fired when the column order changes. Column reorder is programmatic only — an `applyColumnOrder` call or a two-way `columnOrder` write; the component ships NO drag or menu affordance for it. Payload is the fresh `ColumnOrderState` `string[]`. |
|
|
511
|
+
| `resize-change` | Fired live during a column resize drag (`columnResizeMode: "onChange"`). Payload is the fresh `ColumnSizingState` `{ [colId]: number }` object. |
|
|
512
|
+
| `row-activate` | Fired when the user opens a row (list-style "open this item" — oinbox's email thread). A plain click on a body data row, outside any control in the clicked cell (the selection checkbox, the expander, links, inputs, drop-in widgets and an open editor do NOT activate), in both interaction modes; not a shift/ctrl/meta click (selection gestures), the end of a drag-select, or a `singleClickEdit` click on an editable grid cell (that opens the editor). In grid mode also Enter on a non-editable cell that has no controls of its own (Enter on an editable cell still begins the edit; Enter on a cell with controls still enters them). Group-header and detail rows never activate. Payload is `{ row, index, trigger }` — `row` the original data object, `index` its position in the rendered model (page-relative; the full model when virtual), `trigger` `'click'` or `'keyboard'`. |
|
|
517
513
|
| `row-edit-commit` | Fired when a FULL-ROW edit commits — once per row save, from the single `commitRow` call site (React multi-emit dedup). A row enters full-row edit via `Shift+F2` or the `editRow` verb (every editable cell edits at once); one save validates every edited cell (a single failure blocks the whole row and emits nothing) then writes the two-way `data` model ONCE (a single fresh-array row-object replace with all changes applied) and fires this event ONCE. `Escape` reverts the whole row as a unit and emits nothing. Payload is `{ rowId, changes }` where `changes` is `[{ columnId, oldValue, newValue }]` for ONLY the columns whose value actually changed. |
|
|
514
|
+
| `selection-change` | Fired when the row selection changes (a row/select-all checkbox toggle or a `toggleAllRows`/`clearSelection` call). Payload is the fresh `RowSelectionState` `{ [rowId]: true }` object. |
|
|
515
|
+
| `sort-change` | Fired when the sort state changes (header click / shift-click multi-sort / a `sortColumn`/`clearSorting` call). Payload is the fresh `SortingState` array `[{ id, desc }]`. |
|
|
516
|
+
| `visibility-change` | Fired when a column is shown/hidden (the column-toggle menu or a `toggleColumnVisibility` call). Payload is the fresh `VisibilityState` `{ [colId]: boolean }` object. |
|
|
517
|
+
| `visible-range-change` | Fired when the RENDERED row window changes under row windowing (`virtual`) — the window the table actually renders, overscan included — and once after mount. Payload `{ start, end }` over the full row space (`end` exclusive; with lazy rows that space is `rowCount` long). Deduped: a scroll that does not move the window emits nothing. Pair with `manual` + `rowCount` and sparse `data` to fetch the rows the viewport needs. |
|
|
518
518
|
|
|
519
519
|
## Imperative handle
|
|
520
520
|
|
package/dist/index.cjs
CHANGED
|
@@ -266,7 +266,7 @@ const indexOfRowIn = (rows, rowOriginal, rowId) => {
|
|
|
266
266
|
//#endregion
|
|
267
267
|
//#region src/DataTable.tsx
|
|
268
268
|
var _tmpl$$11 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rozie-data-table-wrap data-rozie-s-d5dcab4c=""><div class=rdt-column-defs aria-hidden=true data-rozie-s-d5dcab4c=""></div><div class=rdt-toolbar data-rozie-s-d5dcab4c=""><input type=text role=searchbox aria-label="Search table"class=rdt-global-filter data-rozie-s-d5dcab4c="">`), _tmpl$2$4 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-sr-live role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$3$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class="rdt-sr-live rdt-sr-paste"data-testid=paste-announce role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$4$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class="rdt-sr-live rdt-sr-range"data-testid=range-announce role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$5$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class="rdt-sr-live rdt-sr-sortfilter"data-testid=sortfilter-announce role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$6 = /* @__PURE__ */ (0, solid_js_web.template)(`<details class=rdt-colvis data-rozie-s-d5dcab4c=""><summary class=rdt-colvis-summary data-rozie-s-d5dcab4c="">Columns</summary><div class=rdt-colvis-menu role=group aria-label="Toggle columns"data-rozie-s-d5dcab4c="">`), _tmpl$7 = /* @__PURE__ */ (0, solid_js_web.template)(`<label class=rdt-colvis-item data-rozie-s-d5dcab4c=""><input type=checkbox class=rdt-colvis-checkbox data-rozie-s-d5dcab4c=""><span class=rdt-colvis-label data-rozie-s-d5dcab4c="">`), _tmpl$8 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-group-bar-host data-rozie-s-d5dcab4c="">`), _tmpl$9 = /* @__PURE__ */ (0, solid_js_web.template)(`<span class=rdt-group-token data-group-token=""data-rozie-s-d5dcab4c="">`), _tmpl$0 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-scroll data-rozie-s-d5dcab4c=""><table data-rozie-s-d5dcab4c=""><thead class=rdt-thead role=rowgroup data-rozie-s-d5dcab4c=""></thead><tbody class=rdt-tbody role=rowgroup data-rozie-s-d5dcab4c=""><tr class=rdt-spacer aria-hidden=true data-rozie-s-d5dcab4c=""><td data-rozie-s-d5dcab4c=""></td></tr><tr class=rdt-spacer aria-hidden=true data-rozie-s-d5dcab4c=""><td data-rozie-s-d5dcab4c="">`), _tmpl$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<table data-rozie-s-d5dcab4c=""><thead class=rdt-thead role=rowgroup data-rozie-s-d5dcab4c=""></thead><tbody class=rdt-tbody role=rowgroup data-rozie-s-d5dcab4c="">`), _tmpl$10 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr class=rdt-tr role=row data-rozie-s-d5dcab4c="">`), _tmpl$11 = /* @__PURE__ */ (0, solid_js_web.template)(`<th role=columnheader data-grid-cell=""data-row=__header data-rozie-s-d5dcab4c="">`), _tmpl$12 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c="">`), _tmpl$13 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-col-menu role=menu data-rozie-s-d5dcab4c=""><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Pin left</button><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Pin right</button><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Unpin</button><hr class=rdt-col-menu-sep data-rozie-s-d5dcab4c=""><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Hide column`), _tmpl$14 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><button type=button class=rdt-resize-handle data-rozie-s-d5dcab4c=""><span class=rdt-resize-grip aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$15 = /* @__PURE__ */ (0, solid_js_web.template)(`<button type=button class=rdt-sort-btn data-rozie-s-d5dcab4c=""><span class=rdt-header-label data-rozie-s-d5dcab4c=""></span><span class=rdt-sort-ind aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$16 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><span class=rdt-header-label data-rozie-s-d5dcab4c="">`), _tmpl$17 = /* @__PURE__ */ (0, solid_js_web.template)(`<button type=button class=rdt-col-menu-trigger data-rozie-s-d5dcab4c="">⋯`), _tmpl$18 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=checkbox aria-label="Select all rows"class=rdt-select-all data-rozie-s-d5dcab4c="">`), _tmpl$19 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr class=rdt-filter-row data-rozie-s-d5dcab4c="">`), _tmpl$20 = /* @__PURE__ */ (0, solid_js_web.template)(`<th role=presentation data-rozie-s-d5dcab4c="">`), _tmpl$21 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=text class=rdt-col-filter data-rozie-s-d5dcab4c="">`), _tmpl$22 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr role=row data-rozie-s-d5dcab4c="">`), _tmpl$23 = /* @__PURE__ */ (0, solid_js_web.template)(`<td data-grid-cell=""data-rozie-s-d5dcab4c="">`), _tmpl$24 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><button type=button data-expander=""class="rdt-expander rdt-group-toggle"data-rozie-s-d5dcab4c=""></button><span class=rdt-group-value data-rozie-s-d5dcab4c=""></span><span class=rdt-group-count data-rozie-s-d5dcab4c="">`), _tmpl$25 = /* @__PURE__ */ (0, solid_js_web.template)(`<span class=rdt-cell-value data-rozie-s-d5dcab4c="">`), _tmpl$26 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=number data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$27 = /* @__PURE__ */ (0, solid_js_web.template)(`<select data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$28 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=checkbox data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$29 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=text data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$30 = /* @__PURE__ */ (0, solid_js_web.template)(`<option data-rozie-s-d5dcab4c="">`), _tmpl$31 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=checkbox aria-label="Select row"class=rdt-select-row data-rozie-s-d5dcab4c="">`), _tmpl$32 = /* @__PURE__ */ (0, solid_js_web.template)(`<button type=button data-expander=""class=rdt-expander data-rozie-s-d5dcab4c="">`), _tmpl$33 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-fill-handle=""data-testid=fill-handle aria-hidden=true class=rdt-fill-handle data-rozie-s-d5dcab4c="">`), _tmpl$34 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr class=rdt-detail-row role=row data-rozie-s-d5dcab4c=""><td class=rdt-detail-cell data-rozie-s-d5dcab4c="">`), _tmpl$35 = /* @__PURE__ */ (0, solid_js_web.template)(`<th class=rdt-col-spacer aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$36 = /* @__PURE__ */ (0, solid_js_web.template)(`<td class=rdt-col-spacer aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$37 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><input class=rdt-select-placeholder type=checkbox tabindex=-1 aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$38 = /* @__PURE__ */ (0, solid_js_web.template)(`<span class=rdt-skeleton aria-hidden=true data-rozie-s-d5dcab4c="">​`), _tmpl$39 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-pagination role=group aria-label=Pagination data-rozie-s-d5dcab4c=""><button type=button class="rdt-page-btn rdt-page-prev"data-rozie-s-d5dcab4c="">Prev</button><span class=rdt-page-status aria-live=polite data-rozie-s-d5dcab4c=""></span><button type=button class="rdt-page-btn rdt-page-next"data-rozie-s-d5dcab4c="">Next</button><select aria-label="Rows per page"class=rdt-page-size data-rozie-s-d5dcab4c=""><option value=10 data-rozie-s-d5dcab4c="">10</option><option value=25 data-rozie-s-d5dcab4c="">25</option><option value=50 data-rozie-s-d5dcab4c="">50</option><option value=100 data-rozie-s-d5dcab4c="">100`);
|
|
269
|
-
(0, _rozie_runtime_solid.__rozieInjectStyle)("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
|
|
269
|
+
/** A cell position as integers over the visible (display-order) model. */ /** The active (roving-focus) cell. A header cell reports `rowIndex: null` and `isHeader: true`. */ /** The rectangular cell-range selection. Both corners are `null` when there is no range. */ /** One data column offered to the `#groupBar` slot. */ /** One changed cell inside a row edit commit. */ /** The `activecell-change` payload. `isHeader` is set when the move landed on or left a header cell. */ /** The `cell-edit-commit` payload: one committed cell. */ /** The `row-edit-commit` payload: the row and every cell the save changed. */ /** The `filter-change` payload: `globalFilter` for the search box, `columnFilters` for a per-column filter. Exactly one key is set. */ /** The `history-change` payload: undo/redo availability. */ /** The `range-change` payload: the new range corners (both `null` when the range cleared). */ /** The `row-activate` payload. `row` is the original data object and `index` its position in the rendered model. */ /** The `visible-range-change` payload: the rendered row window, `end` exclusive. */ (0, _rozie_runtime_solid.__rozieInjectStyle)("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
|
|
270
270
|
--rdt-color: var(--rozie-data-table-fg, var(--rdt-ds-fg));
|
|
271
271
|
--rdt-select-accent: var(--rozie-data-table-select-accent, var(--rozie-data-table-accent, var(--rdt-ds-select-accent)));
|
|
272
272
|
--rdt-border: 1px solid var(--rozie-data-table-border-color, var(--rdt-ds-border-color));
|
|
@@ -719,23 +719,23 @@ function DataTable(_props) {
|
|
|
719
719
|
"maxHeight",
|
|
720
720
|
"children",
|
|
721
721
|
"ref",
|
|
722
|
-
"
|
|
722
|
+
"onActivecellChange",
|
|
723
|
+
"onCellEditCommit",
|
|
723
724
|
"onExpandChange",
|
|
724
|
-
"onGroupChange",
|
|
725
725
|
"onFilterChange",
|
|
726
|
+
"onGroupChange",
|
|
727
|
+
"onHistoryChange",
|
|
726
728
|
"onPageChange",
|
|
727
|
-
"onSelectionChange",
|
|
728
|
-
"onVisibilityChange",
|
|
729
|
-
"onResizeChange",
|
|
730
|
-
"onReorderChange",
|
|
731
729
|
"onPinChange",
|
|
732
|
-
"onHistoryChange",
|
|
733
|
-
"onVisibleRangeChange",
|
|
734
|
-
"onActivecellChange",
|
|
735
|
-
"onRowActivate",
|
|
736
730
|
"onRangeChange",
|
|
737
|
-
"
|
|
738
|
-
"
|
|
731
|
+
"onReorderChange",
|
|
732
|
+
"onResizeChange",
|
|
733
|
+
"onRowActivate",
|
|
734
|
+
"onRowEditCommit",
|
|
735
|
+
"onSelectionChange",
|
|
736
|
+
"onSortChange",
|
|
737
|
+
"onVisibilityChange",
|
|
738
|
+
"onVisibleRangeChange"
|
|
739
739
|
]);
|
|
740
740
|
const resolved = () => local.children;
|
|
741
741
|
(0, solid_js.onMount)(() => {
|