@lavalogic/scoria 0.40.13 → 0.40.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -58
- package/dist/Components/AccordionGroup.svelte +35 -46
- package/dist/Components/AccordionGroupButton.svelte +68 -76
- package/dist/Components/Action.svelte +103 -135
- package/dist/Components/AlertModal.svelte +171 -190
- package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +614 -697
- package/dist/Components/Base/BaseModal.svelte +90 -116
- package/dist/Components/Base/ContextWrapper.svelte +67 -72
- package/dist/Components/Base/Pagination.svelte +173 -196
- package/dist/Components/Base/Snippets.svelte +34 -36
- package/dist/Components/BigRadioSet.svelte +36 -38
- package/dist/Components/Bubble.svelte +78 -101
- package/dist/Components/Button.svelte +175 -208
- package/dist/Components/Checkbox.svelte +75 -86
- package/dist/Components/CollapsibleCard.svelte +72 -87
- package/dist/Components/CollapsibleMenuGroup.svelte +53 -57
- package/dist/Components/ConditionBuilder/ConditionBuilder.svelte +39 -64
- package/dist/Components/Contexts/ContextMenu.svelte +141 -156
- package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
- package/dist/Components/Contexts/ContextMenuOption.svelte +53 -60
- package/dist/Components/Contexts/Toast.svelte +81 -86
- package/dist/Components/Contexts/ToastContainer.svelte +58 -62
- package/dist/Components/Contexts/Tooltip.svelte +36 -37
- package/dist/Components/DataMatrixIcon.svelte +95 -108
- package/dist/Components/DateInput.svelte +118 -146
- package/dist/Components/DatePicker.svelte +255 -294
- package/dist/Components/DesktopModal.svelte +70 -90
- package/dist/Components/Dial.svelte +167 -197
- package/dist/Components/DimensionInput.svelte +124 -169
- package/dist/Components/DragMenu/DragMenuHolder.svelte +98 -114
- package/dist/Components/DragMenu/DraggableCard.svelte +64 -76
- package/dist/Components/FileCard.svelte +21 -24
- package/dist/Components/FileUpload.svelte +190 -225
- package/dist/Components/GridInput.svelte +159 -196
- package/dist/Components/GridInputSet.svelte +24 -29
- package/dist/Components/HorizontalTabGroup.svelte +73 -89
- package/dist/Components/HorizontalTabGroupButton.svelte +40 -44
- package/dist/Components/Icon.svelte +99 -128
- package/dist/Components/Icons.js +357 -357
- package/dist/Components/InfoAlert.svelte +35 -38
- package/dist/Components/LoadingAnimation.svelte +691 -755
- package/dist/Components/LoadingModal.svelte +36 -44
- package/dist/Components/LoadingOverlay.svelte +22 -26
- package/dist/Components/Modal.svelte +204 -254
- package/dist/Components/MultiSelect.svelte +186 -216
- package/dist/Components/Nav/Nav.svelte +94 -110
- package/dist/Components/Nav/NavServiceMenuList.svelte +57 -61
- package/dist/Components/Nav/NavTab.svelte +58 -62
- package/dist/Components/Nav/ServiceMenuItem.svelte +103 -111
- package/dist/Components/Nav/ServicesNav.svelte +72 -79
- package/dist/Components/NumberInput.svelte +121 -155
- package/dist/Components/OptionCards.svelte +62 -73
- package/dist/Components/PageHeading.svelte +23 -25
- package/dist/Components/PasswordInput.svelte +69 -88
- package/dist/Components/PopoverButton.svelte +151 -0
- package/dist/Components/PopoverButton.svelte.d.ts +9 -0
- package/dist/Components/PopoverButtonProps.d.ts +21 -0
- package/dist/Components/PopoverButtonProps.js +1 -0
- package/dist/Components/Portal.svelte +29 -35
- package/dist/Components/ProgressBubble.svelte +91 -106
- package/dist/Components/QuerySelect.svelte +260 -346
- package/dist/Components/SidebarPanel.svelte +34 -36
- package/dist/Components/SingleSelect.svelte +196 -244
- package/dist/Components/StepButton.svelte +65 -70
- package/dist/Components/StepForm.svelte +115 -135
- package/dist/Components/Switch.svelte +57 -69
- package/dist/Components/Table/ARCHITECTURE.md +298 -298
- package/dist/Components/Table/Body/QuickSearchCell.svelte +578 -655
- package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +42 -51
- package/dist/Components/Table/Body/Rows/ColumnList.svelte +42 -58
- package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +403 -442
- package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +51 -78
- package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +165 -184
- package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +110 -123
- package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +134 -160
- package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +190 -231
- package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +82 -104
- package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +52 -87
- package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +122 -150
- package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +132 -159
- package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +190 -236
- package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +173 -211
- package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +204 -244
- package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +140 -177
- package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +188 -217
- package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +173 -193
- package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +166 -187
- package/dist/Components/Table/Body/Rows/TableRow.svelte +245 -288
- package/dist/Components/Table/Body/TableBody.svelte +141 -154
- package/dist/Components/Table/Headers/HighlightAllHeader.svelte +35 -41
- package/dist/Components/Table/Headers/SelectAllHeader.svelte +24 -30
- package/dist/Components/Table/Headers/TableHead.svelte +348 -402
- package/dist/Components/Table/Misc/ColumnPanel.svelte +37 -39
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +35 -39
- package/dist/Components/Table/Misc/FilterInput.svelte +556 -619
- package/dist/Components/Table/Misc/FilterPanel.svelte +170 -183
- package/dist/Components/Table/Misc/FilterPanelModal.svelte +25 -31
- package/dist/Components/Table/Misc/ShareViewModal.svelte +252 -281
- package/dist/Components/Table/Misc/SidePanel.svelte +32 -35
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +574 -629
- package/dist/Components/Table/Misc/TableFooter.svelte +326 -332
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +134 -140
- package/dist/Components/Table/Misc/TableSidebar.svelte +183 -198
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +83 -103
- package/dist/Components/Table/Misc/ToolboxPanel.svelte +83 -100
- package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +88 -107
- package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +163 -190
- package/dist/Components/Table/NestedTable.svelte +102 -128
- package/dist/Components/Table/Table.svelte +531 -663
- package/dist/Components/Test/TestContextConsumer.svelte +11 -13
- package/dist/Components/TextArea.svelte +95 -130
- package/dist/Components/TextInput.svelte +125 -176
- package/dist/Components/ThreeStateRadio.svelte +111 -130
- package/dist/Components/Touch/BoolCard.svelte +33 -45
- package/dist/Components/Touch/DateModal.svelte +164 -204
- package/dist/Components/Touch/EditCard.svelte +48 -59
- package/dist/Components/Touch/InfoCard.svelte +28 -31
- package/dist/Components/Touch/InfoTextCard.svelte +26 -28
- package/dist/Components/Touch/ModalExplanation.svelte +15 -17
- package/dist/Components/Touch/NumberKeyboard.svelte +181 -218
- package/dist/Components/Touch/NumberModal.svelte +59 -79
- package/dist/Components/Touch/PlusMinusCard.svelte +43 -46
- package/dist/Components/Touch/SelectModal.svelte +111 -126
- package/dist/Components/Touch/SummaryCard.svelte +80 -93
- package/dist/Components/Touch/TextAreaModal.svelte +72 -94
- package/dist/Components/Touch/TextModal.svelte +77 -105
- package/dist/Components/Touch/TouchCard.svelte +31 -33
- package/dist/Components/Touch/TouchModal.svelte +214 -270
- package/dist/Components/Touch/UtilityButton.svelte +88 -109
- package/dist/Components/VerticalTabGroup.svelte +60 -78
- package/dist/Components/VerticalTabGroupButton.svelte +54 -58
- package/dist/Helpers/Datamatrix.d.ts +19 -19
- package/dist/Helpers/Datamatrix.js +291 -291
- package/dist/Types/Examples/ExampleModal.svelte +31 -35
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/scss/_basics.scss +12 -12
- package/dist/scss/_colours.scss +134 -134
- package/dist/scss/_mixins.scss +3392 -3392
- package/dist/scss/_motion.scss +57 -57
- package/dist/scss/_sizing.scss +85 -85
- package/dist/scss/_transitions.scss +8 -8
- package/package.json +1 -1
|
@@ -1,298 +1,298 @@
|
|
|
1
|
-
# `<Table>` architecture
|
|
2
|
-
|
|
3
|
-
Orientation for a new developer opening `src/lib/Components/Table/`. Read this once before changing anything substantive in this subtree. Read it again before reviewing a PR.
|
|
4
|
-
|
|
5
|
-
For the cross-cutting story of how the current shape came to be, see
|
|
6
|
-
`agent-review/dev-changelog.md` at repo root. For the consumer-facing
|
|
7
|
-
public API, see the Storybook stories under `Table/Table API` and
|
|
8
|
-
`src/stories/Table/*`.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## What ships out of the front door
|
|
13
|
-
|
|
14
|
-
Everything in the public surface is re-exported from
|
|
15
|
-
`src/lib/index.ts`. The Table-side of that file is small on purpose:
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
import {
|
|
19
|
-
createTable,
|
|
20
|
-
localRows,
|
|
21
|
-
remoteRows,
|
|
22
|
-
customRows,
|
|
23
|
-
Table,
|
|
24
|
-
type CreateTableOptions,
|
|
25
|
-
type DisplayModalProps,
|
|
26
|
-
// …per-kind option types: TextColumnOptions, NumberColumnOptions, …
|
|
27
|
-
} from '@lavalogic/scoria';
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Three entry points cover every legitimate use:
|
|
31
|
-
|
|
32
|
-
1. `createTable<TRow, IdType>({...})` builds a structured `Table`
|
|
33
|
-
instance. The returned value carries the typed sub-APIs (`selection`,
|
|
34
|
-
`filtering`, `sorting`, `clipboard`, `columns`, `pagination`,
|
|
35
|
-
`preferences`, `focus`, `modal`).
|
|
36
|
-
2. `<Table {table} />` mounts the instance.
|
|
37
|
-
3. The column builder closure passed under `columns:` is given a
|
|
38
|
-
`ColumnFactory<TRow>` parameter; consumers reach for the matching
|
|
39
|
-
`col.text(...)`, `col.number(...)`, `col.select(...)` and so on.
|
|
40
|
-
|
|
41
|
-
The Def classes (`TextInputDef`, `DisplayDef`, …) are NOT exported. They
|
|
42
|
-
are constructed inside `ColumnFactory.svelte.ts` and never appear on a
|
|
43
|
-
consumer's import surface. If you need to alter Def behaviour, do it
|
|
44
|
-
through the factory.
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Folder tour
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
Table/
|
|
52
|
-
├── Table.svelte — top-level component (mounts the grid + chrome)
|
|
53
|
-
├── createTable.svelte.ts — the consumer-facing entry; builds the TableContext + public Table instance
|
|
54
|
-
├── ColumnFactory.svelte.ts — closure-based column builder; wraps each Def
|
|
55
|
-
├── ColumnKindRegistry.ts — kind→category map used by setupDefaultColumnDefs
|
|
56
|
-
├── ColumnKindRegistry.test.ts — registry contract tests
|
|
57
|
-
├── SubApis.svelte.ts — facade constructors for each typed sub-API on the public Table instance
|
|
58
|
-
├── NestedTable.svelte — internal Expand-column body
|
|
59
|
-
├── TableHelpers.svelte.ts — co-located helpers (column-id mint, etc.)
|
|
60
|
-
├── clipboardEscape.ts — escapeForSpreadsheet / encapsulate
|
|
61
|
-
│
|
|
62
|
-
├── Body/ — body-grid layer
|
|
63
|
-
│ ├── TableBody.svelte
|
|
64
|
-
│ ├── QuickSearchCell.svelte — filter row inputs
|
|
65
|
-
│ └── Rows/Columns/ — per-kind cell components
|
|
66
|
-
│
|
|
67
|
-
├── Headers/ — header-row layer
|
|
68
|
-
│ └── TableHead.svelte — column headers, sort buttons, resize handles
|
|
69
|
-
│
|
|
70
|
-
├── Misc/ — toolbars, side-panels, footer, filter panels
|
|
71
|
-
│ ├── TableFooter.svelte
|
|
72
|
-
│ ├── TableSidebar.svelte
|
|
73
|
-
│ ├── TableHorizontalBar.svelte
|
|
74
|
-
│ ├── FilterPanel.svelte
|
|
75
|
-
│ ├── FilterInput.svelte — advanced-filter panel inputs
|
|
76
|
-
│ ├── ColumnPanel.svelte — column visibility & order panel
|
|
77
|
-
│ └── ToolboxPanel.svelte — extra tool buttons
|
|
78
|
-
│
|
|
79
|
-
└── Types/ — all type declarations + state classes
|
|
80
|
-
├── Public/ — every consumer-facing type
|
|
81
|
-
├── Context/ — TableContext (god) + the Phase 6 sub-contexts
|
|
82
|
-
├── Columns/ — Def classes (internal) + Column shape types
|
|
83
|
-
├── DataRepository/ — TableDataRepository abstract + BuiltInRemoteRepository
|
|
84
|
-
├── Filtering/ — FilterFn, ColumnFiltersState, FilterMode enums
|
|
85
|
-
├── Pagination/ — PaginationState, PaginationType enum
|
|
86
|
-
├── Focus/ — focus-coordinate helpers
|
|
87
|
-
├── Coordinates/ — CellCoordinates, ColumnIndices brands
|
|
88
|
-
├── Layout/ — layout-related helpers
|
|
89
|
-
└── Toolbar/ — ToolbarPosition enum
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## The state graph
|
|
95
|
-
|
|
96
|
-
`TableContext` is the root state object. It owns the data repo and seven
|
|
97
|
-
sub-contexts:
|
|
98
|
-
|
|
99
|
-
| Sub-context | Owns |
|
|
100
|
-
| ----------------- | ------------------------------------------------------------------------- |
|
|
101
|
-
| `_sorting` | Sort comparators + the `sortedData` derived chain |
|
|
102
|
-
| `_filtering` | Filter-fn relays + the `filteredData` derived chain + quick-filter toggle |
|
|
103
|
-
| `_columnLayout` | Column widths / pinning / visibility / id-index maps |
|
|
104
|
-
| `_selection` | Selected & highlighted maps, key cache, page-wide select helpers |
|
|
105
|
-
| `_preferences` | Table settings + layout / filter / view localStorage round-trip |
|
|
106
|
-
| `_focus` | Focus-coordinate state + multi-cell selection |
|
|
107
|
-
| `_virtualisation` | Row virtualisation window |
|
|
108
|
-
| `_queryValues` | Typeahead-echo cache for QuerySelect filter inputs |
|
|
109
|
-
|
|
110
|
-
Each sub-context is a class under `Types/Context/<Name>State.svelte.ts`
|
|
111
|
-
that takes a `deps` object of thunk-returning fields the parent reads
|
|
112
|
-
on demand. The thunks keep reactivity flowing without the sub-context
|
|
113
|
-
holding a parent reference — re-binding `TableContext._sorting` (or
|
|
114
|
-
swapping its parent) is impossible by construction.
|
|
115
|
-
|
|
116
|
-
The pattern when adding a new sub-context:
|
|
117
|
-
|
|
118
|
-
1. Drop a `Types/Context/<Name>State.svelte.ts` file using
|
|
119
|
-
`FilteringState` as the structural template (`<Name>StateDeps`
|
|
120
|
-
interface, class with `$state` / `$derived` slots, `deps` thunks).
|
|
121
|
-
2. Add a `_name: <Name>State` field on `TableContext` constructed with
|
|
122
|
-
the deps thunks closed over `this`.
|
|
123
|
-
3. Add public passthrough getters/setters on `TableContext` for any
|
|
124
|
-
slot consumers reached for through the legacy field name.
|
|
125
|
-
4. Write a `<Name>State.svelte.test.ts` test next to the new class.
|
|
126
|
-
Cover construction, each writer, and each derived read.
|
|
127
|
-
5. If the sub-context surfaces a typed sub-API on the public `Table`
|
|
128
|
-
instance, wire a builder in `SubApis.svelte.ts` returning a frozen
|
|
129
|
-
object literal.
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## The data repo
|
|
134
|
-
|
|
135
|
-
`TableContext.dataRepo` is the storage layer. Three concrete shapes:
|
|
136
|
-
|
|
137
|
-
- `LocalDataRepository` — handed a plain array; sorts/filters/paginates
|
|
138
|
-
in process.
|
|
139
|
-
- `BuiltInRemoteRepository` — fetches pages from a REST endpoint with
|
|
140
|
-
scoria's built-in query-string format.
|
|
141
|
-
- `CustomDataRepository` — built by `customRows({ fetch, … })` for
|
|
142
|
-
consumer-shaped query strings. flowms wraps this in
|
|
143
|
-
`createRemoteRowSource.ts` to map flowms's filter format.
|
|
144
|
-
|
|
145
|
-
The repo abstract base (`TableDataRepository.svelte.ts`) owns:
|
|
146
|
-
|
|
147
|
-
- `paginationState` (page index + size, persisted)
|
|
148
|
-
- the per-column `_filterModes` SvelteMap
|
|
149
|
-
- the `forceRefresh` callback hook (use `registerRefreshMethod` to
|
|
150
|
-
assign without firing; the setter form fires immediately and is
|
|
151
|
-
`@deprecated`)
|
|
152
|
-
|
|
153
|
-
If you add a new repo subclass, also extend the runtime discriminator
|
|
154
|
-
on `IDataRepository.paginationType` so existing callers can branch.
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Adding a new column kind
|
|
159
|
-
|
|
160
|
-
This is intentionally not a one-file change; the surface area below is
|
|
161
|
-
the irreducible minimum. Pick the four (sometimes five) sites carefully:
|
|
162
|
-
|
|
163
|
-
1. **Def class** — `Types/Columns/Definitions/{Accessors,Display,…}/<Kind>Def.svelte.ts`.
|
|
164
|
-
Inherits from the matching category base (`AccessorDef` / `DisplayDef` / etc.).
|
|
165
|
-
2. **Cell renderer** — `Body/Rows/Columns/<Kind>Cell.svelte`. Picked
|
|
166
|
-
by the dispatch chain in `TableColumn.svelte` (currently an
|
|
167
|
-
`instanceof` if/else; intentionally not registry-driven — see
|
|
168
|
-
follow-up F3 in `PROJECT_CONTEXT.md`).
|
|
169
|
-
3. **Public option type** — add to `Types/Public/ColumnOptions.ts`.
|
|
170
|
-
Discriminated by the kind literal.
|
|
171
|
-
4. **Factory method** — add a method on `ColumnFactory<TRow>` in
|
|
172
|
-
`ColumnFactory.svelte.ts`. The factory's `makeSpec(kind, def, …)`
|
|
173
|
-
tags the def with `def.kind = kind` automatically.
|
|
174
|
-
5. **Registry entry** — add to `COLUMN_KIND_REGISTRY` in
|
|
175
|
-
`ColumnKindRegistry.ts`. Mark `category` and (if applicable) a
|
|
176
|
-
`defaultFilter` key. The companion test file enforces "every kind
|
|
177
|
-
has an entry".
|
|
178
|
-
|
|
179
|
-
A `setupDefaultColumnDefs` change is no longer needed; it now reads
|
|
180
|
-
from the registry.
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## Load-bearing invariants
|
|
185
|
-
|
|
186
|
-
These each cost real time to discover the first time. Tagged for future
|
|
187
|
-
greppability.
|
|
188
|
-
|
|
189
|
-
### `def.kind` is the canonical sort key
|
|
190
|
-
|
|
191
|
-
Every `ColumnDef` produced by the factory carries `def.kind`. Filter
|
|
192
|
-
wiring (`setupDefaultColumnDefs`), debug logs, and the public spec all
|
|
193
|
-
derive from it. A hand-constructed `ColumnDef` (test stub, legacy code)
|
|
194
|
-
without `kind` is tolerated but skips registry-driven defaults — the
|
|
195
|
-
consumer must assign `filterFn` themselves.
|
|
196
|
-
|
|
197
|
-
### Filter-input `__queryValues` is gone; use `tableContext.queryValues`
|
|
198
|
-
|
|
199
|
-
The legacy `dataRepo.__queryValues: Map<string, unknown>` shared cache
|
|
200
|
-
has been replaced by the typed `QueryValuesState` sub-context. New
|
|
201
|
-
filter widgets should call `tableContext.queryValues.get(def)` /
|
|
202
|
-
`set(def, value)`. The sub-context keys by `ColumnDef` so the
|
|
203
|
-
historical `def.id` vs `label` keying bug class is structurally
|
|
204
|
-
prevented.
|
|
205
|
-
|
|
206
|
-
### `reactiveDependencies` for async accessors
|
|
207
|
-
|
|
208
|
-
`col.display({ value: async (row) => row.foo.value })` will only
|
|
209
|
-
re-render when row identity changes — not when `row.foo.value` mutates,
|
|
210
|
-
because the reactive read happens after the `await` boundary. Pass a
|
|
211
|
-
`reactiveDependencies: (row) => [row.foo.value]` thunk on the column
|
|
212
|
-
options so the cell's `$derived` registers the dep synchronously.
|
|
213
|
-
|
|
214
|
-
### Dropdowns do NOT move in the DOM
|
|
215
|
-
|
|
216
|
-
`Helpers/dropdownPortal.ts` flips a Svelecte dropdown to
|
|
217
|
-
`position: fixed` and lifts its stacking-context ancestor; it does NOT
|
|
218
|
-
re-parent the dropdown to `document.body`. Svelte 5's root-level event
|
|
219
|
-
delegation walks the live `parentNode` chain at dispatch time — moving
|
|
220
|
-
the element out of the mount target silently breaks mouse-click option
|
|
221
|
-
selection while keyboard Enter keeps working. See the header comment in
|
|
222
|
-
`dropdownPortal.ts` for the full reasoning.
|
|
223
|
-
|
|
224
|
-
### Pinned cells skip horizontal scrollIntoView
|
|
225
|
-
|
|
226
|
-
In `Table.svelte`'s focus-restore effects, the scroll-into-view call
|
|
227
|
-
omits `inline: 'nearest'` for pinned cells. Sticky positioning makes
|
|
228
|
-
them visually always-on-screen, but their layout position is at the
|
|
229
|
-
real (often off-screen) column track; an unconditional inline scroll
|
|
230
|
-
would surface the underlying position and the table would "jump" when
|
|
231
|
-
focus lands on a pinned Actions button.
|
|
232
|
-
|
|
233
|
-
### Clipboard copy must pass through `escapeForSpreadsheet`
|
|
234
|
-
|
|
235
|
-
Every path that writes to `navigator.clipboard.writeText` is required
|
|
236
|
-
to neutralise formula-injection prefixes via
|
|
237
|
-
`escapeForSpreadsheet` (or `encapsulate`, which calls it). The single-
|
|
238
|
-
cell `clipboard.copyCell` route and the bulk
|
|
239
|
-
`copyDataToClipboard` / `copyHighlightedRowsToClipboard` paths both
|
|
240
|
-
already use it; new copy paths must too.
|
|
241
|
-
|
|
242
|
-
### `createTable` is async-effective; consume via reactive readers
|
|
243
|
-
|
|
244
|
-
`createTable({...})` returns the structured `Table` instance synchronously, but the underlying `TableContext` finishes initialising asynchronously: `setupDefaultColumnDefs` runs unawaited in the constructor, and `_selection`'s pending-changes buffer flushes on `tick()`. Two practical consequences:
|
|
245
|
-
|
|
246
|
-
- `table.columns.specs` and `table._context.columnDefs` are empty for the first microtask after `createTable` returns. Reactive readers (a `$derived` or `$effect`) re-evaluate when the columns land, so consumer code reads through these without thinking about it.
|
|
247
|
-
- `table.selection.set(rowId, row)` writes into the pending-changes buffer and flushes on `tick()`. `table.selection.size` returns the post-flush value the next time a reactive consumer reads it; a synchronous read on the same call frame returns the pre-flush value.
|
|
248
|
-
|
|
249
|
-
Direct synchronous read-back of state is therefore only safe inside an `$effect` or after `await tick()`. Unit tests at the public API surface need either a reactive harness or explicit `await tick()` between writes and assertions; that's why scoria's table tests use the `.svelte.test.ts` (browser-project) shape rather than plain server-mode unit tests.
|
|
250
|
-
|
|
251
|
-
### Custom-row sources must defensively resolve their accessor thunks
|
|
252
|
-
|
|
253
|
-
A `customRows({ uri, defaultFilters, remoteFilters })` source can have
|
|
254
|
-
its accessor thunks called after the surrounding Svelte component has
|
|
255
|
-
torn down (a debounced fetch landing across a route change). Wrap the
|
|
256
|
-
thunk reads in try/catch and validate the returned shape — see
|
|
257
|
-
`flowms-svelte-web/src/lib/components/base/Table/createRemoteRowSource.ts`
|
|
258
|
-
for the canonical pattern.
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
## Testing model
|
|
263
|
-
|
|
264
|
-
| File pattern | Project | What it covers |
|
|
265
|
-
| --------------------------- | -------- | ------------------------------------------------------------------------------------- |
|
|
266
|
-
| `*.test.ts` (no `.svelte.`) | `server` | Pure-node unit tests (helpers, type contracts). Runs via `pnpm test`. |
|
|
267
|
-
| `*.svelte.test.ts` | `client` | Tests using `$state` / `$effect` from Svelte 5. Browser mode via Vitest + Playwright. |
|
|
268
|
-
|
|
269
|
-
The browser-mode runner has a Windows-specific chromium launch issue;
|
|
270
|
-
set `SCORIA_CHROMIUM_EXECUTABLE` to the headless-shell binary to work
|
|
271
|
-
around it (follow-up F1 in `PROJECT_CONTEXT.md`). The server project
|
|
272
|
-
covers the kind-registry contract, clipboard escape behaviour, and the
|
|
273
|
-
co-located decoupling tests.
|
|
274
|
-
|
|
275
|
-
Add new tests next to the code they cover, not in a global `__tests__`
|
|
276
|
-
folder.
|
|
277
|
-
|
|
278
|
-
---
|
|
279
|
-
|
|
280
|
-
## Storybook
|
|
281
|
-
|
|
282
|
-
Stories live under `src/stories/Table/`. Mount via the shared host
|
|
283
|
-
`_helpers/TableHost.svelte` which accepts a `CreateTableOptions` payload
|
|
284
|
-
and runs `createTable` inside instance init (module-scope `createTable`
|
|
285
|
-
would trip `effect_orphan`). The `Table/Table API` MDX page is the
|
|
286
|
-
companion reference; keep it in sync with significant public-API
|
|
287
|
-
changes.
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
## Cross-references
|
|
292
|
-
|
|
293
|
-
- `PROJECT_CONTEXT.md` (repo root) — project state, known issues and
|
|
294
|
-
follow-ups (Part A), plus the consumer migration guide (Part B).
|
|
295
|
-
- `agent-review/dev-changelog.md` — long-form record of the
|
|
296
|
-
decomposition phases.
|
|
297
|
-
- `src/lib/Components/Table/Types/Public/index.ts` — barrel for every
|
|
298
|
-
public type re-exported from `src/lib/index.ts`.
|
|
1
|
+
# `<Table>` architecture
|
|
2
|
+
|
|
3
|
+
Orientation for a new developer opening `src/lib/Components/Table/`. Read this once before changing anything substantive in this subtree. Read it again before reviewing a PR.
|
|
4
|
+
|
|
5
|
+
For the cross-cutting story of how the current shape came to be, see
|
|
6
|
+
`agent-review/dev-changelog.md` at repo root. For the consumer-facing
|
|
7
|
+
public API, see the Storybook stories under `Table/Table API` and
|
|
8
|
+
`src/stories/Table/*`.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## What ships out of the front door
|
|
13
|
+
|
|
14
|
+
Everything in the public surface is re-exported from
|
|
15
|
+
`src/lib/index.ts`. The Table-side of that file is small on purpose:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import {
|
|
19
|
+
createTable,
|
|
20
|
+
localRows,
|
|
21
|
+
remoteRows,
|
|
22
|
+
customRows,
|
|
23
|
+
Table,
|
|
24
|
+
type CreateTableOptions,
|
|
25
|
+
type DisplayModalProps,
|
|
26
|
+
// …per-kind option types: TextColumnOptions, NumberColumnOptions, …
|
|
27
|
+
} from '@lavalogic/scoria';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Three entry points cover every legitimate use:
|
|
31
|
+
|
|
32
|
+
1. `createTable<TRow, IdType>({...})` builds a structured `Table`
|
|
33
|
+
instance. The returned value carries the typed sub-APIs (`selection`,
|
|
34
|
+
`filtering`, `sorting`, `clipboard`, `columns`, `pagination`,
|
|
35
|
+
`preferences`, `focus`, `modal`).
|
|
36
|
+
2. `<Table {table} />` mounts the instance.
|
|
37
|
+
3. The column builder closure passed under `columns:` is given a
|
|
38
|
+
`ColumnFactory<TRow>` parameter; consumers reach for the matching
|
|
39
|
+
`col.text(...)`, `col.number(...)`, `col.select(...)` and so on.
|
|
40
|
+
|
|
41
|
+
The Def classes (`TextInputDef`, `DisplayDef`, …) are NOT exported. They
|
|
42
|
+
are constructed inside `ColumnFactory.svelte.ts` and never appear on a
|
|
43
|
+
consumer's import surface. If you need to alter Def behaviour, do it
|
|
44
|
+
through the factory.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Folder tour
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Table/
|
|
52
|
+
├── Table.svelte — top-level component (mounts the grid + chrome)
|
|
53
|
+
├── createTable.svelte.ts — the consumer-facing entry; builds the TableContext + public Table instance
|
|
54
|
+
├── ColumnFactory.svelte.ts — closure-based column builder; wraps each Def
|
|
55
|
+
├── ColumnKindRegistry.ts — kind→category map used by setupDefaultColumnDefs
|
|
56
|
+
├── ColumnKindRegistry.test.ts — registry contract tests
|
|
57
|
+
├── SubApis.svelte.ts — facade constructors for each typed sub-API on the public Table instance
|
|
58
|
+
├── NestedTable.svelte — internal Expand-column body
|
|
59
|
+
├── TableHelpers.svelte.ts — co-located helpers (column-id mint, etc.)
|
|
60
|
+
├── clipboardEscape.ts — escapeForSpreadsheet / encapsulate
|
|
61
|
+
│
|
|
62
|
+
├── Body/ — body-grid layer
|
|
63
|
+
│ ├── TableBody.svelte
|
|
64
|
+
│ ├── QuickSearchCell.svelte — filter row inputs
|
|
65
|
+
│ └── Rows/Columns/ — per-kind cell components
|
|
66
|
+
│
|
|
67
|
+
├── Headers/ — header-row layer
|
|
68
|
+
│ └── TableHead.svelte — column headers, sort buttons, resize handles
|
|
69
|
+
│
|
|
70
|
+
├── Misc/ — toolbars, side-panels, footer, filter panels
|
|
71
|
+
│ ├── TableFooter.svelte
|
|
72
|
+
│ ├── TableSidebar.svelte
|
|
73
|
+
│ ├── TableHorizontalBar.svelte
|
|
74
|
+
│ ├── FilterPanel.svelte
|
|
75
|
+
│ ├── FilterInput.svelte — advanced-filter panel inputs
|
|
76
|
+
│ ├── ColumnPanel.svelte — column visibility & order panel
|
|
77
|
+
│ └── ToolboxPanel.svelte — extra tool buttons
|
|
78
|
+
│
|
|
79
|
+
└── Types/ — all type declarations + state classes
|
|
80
|
+
├── Public/ — every consumer-facing type
|
|
81
|
+
├── Context/ — TableContext (god) + the Phase 6 sub-contexts
|
|
82
|
+
├── Columns/ — Def classes (internal) + Column shape types
|
|
83
|
+
├── DataRepository/ — TableDataRepository abstract + BuiltInRemoteRepository
|
|
84
|
+
├── Filtering/ — FilterFn, ColumnFiltersState, FilterMode enums
|
|
85
|
+
├── Pagination/ — PaginationState, PaginationType enum
|
|
86
|
+
├── Focus/ — focus-coordinate helpers
|
|
87
|
+
├── Coordinates/ — CellCoordinates, ColumnIndices brands
|
|
88
|
+
├── Layout/ — layout-related helpers
|
|
89
|
+
└── Toolbar/ — ToolbarPosition enum
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## The state graph
|
|
95
|
+
|
|
96
|
+
`TableContext` is the root state object. It owns the data repo and seven
|
|
97
|
+
sub-contexts:
|
|
98
|
+
|
|
99
|
+
| Sub-context | Owns |
|
|
100
|
+
| ----------------- | ------------------------------------------------------------------------- |
|
|
101
|
+
| `_sorting` | Sort comparators + the `sortedData` derived chain |
|
|
102
|
+
| `_filtering` | Filter-fn relays + the `filteredData` derived chain + quick-filter toggle |
|
|
103
|
+
| `_columnLayout` | Column widths / pinning / visibility / id-index maps |
|
|
104
|
+
| `_selection` | Selected & highlighted maps, key cache, page-wide select helpers |
|
|
105
|
+
| `_preferences` | Table settings + layout / filter / view localStorage round-trip |
|
|
106
|
+
| `_focus` | Focus-coordinate state + multi-cell selection |
|
|
107
|
+
| `_virtualisation` | Row virtualisation window |
|
|
108
|
+
| `_queryValues` | Typeahead-echo cache for QuerySelect filter inputs |
|
|
109
|
+
|
|
110
|
+
Each sub-context is a class under `Types/Context/<Name>State.svelte.ts`
|
|
111
|
+
that takes a `deps` object of thunk-returning fields the parent reads
|
|
112
|
+
on demand. The thunks keep reactivity flowing without the sub-context
|
|
113
|
+
holding a parent reference — re-binding `TableContext._sorting` (or
|
|
114
|
+
swapping its parent) is impossible by construction.
|
|
115
|
+
|
|
116
|
+
The pattern when adding a new sub-context:
|
|
117
|
+
|
|
118
|
+
1. Drop a `Types/Context/<Name>State.svelte.ts` file using
|
|
119
|
+
`FilteringState` as the structural template (`<Name>StateDeps`
|
|
120
|
+
interface, class with `$state` / `$derived` slots, `deps` thunks).
|
|
121
|
+
2. Add a `_name: <Name>State` field on `TableContext` constructed with
|
|
122
|
+
the deps thunks closed over `this`.
|
|
123
|
+
3. Add public passthrough getters/setters on `TableContext` for any
|
|
124
|
+
slot consumers reached for through the legacy field name.
|
|
125
|
+
4. Write a `<Name>State.svelte.test.ts` test next to the new class.
|
|
126
|
+
Cover construction, each writer, and each derived read.
|
|
127
|
+
5. If the sub-context surfaces a typed sub-API on the public `Table`
|
|
128
|
+
instance, wire a builder in `SubApis.svelte.ts` returning a frozen
|
|
129
|
+
object literal.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## The data repo
|
|
134
|
+
|
|
135
|
+
`TableContext.dataRepo` is the storage layer. Three concrete shapes:
|
|
136
|
+
|
|
137
|
+
- `LocalDataRepository` — handed a plain array; sorts/filters/paginates
|
|
138
|
+
in process.
|
|
139
|
+
- `BuiltInRemoteRepository` — fetches pages from a REST endpoint with
|
|
140
|
+
scoria's built-in query-string format.
|
|
141
|
+
- `CustomDataRepository` — built by `customRows({ fetch, … })` for
|
|
142
|
+
consumer-shaped query strings. flowms wraps this in
|
|
143
|
+
`createRemoteRowSource.ts` to map flowms's filter format.
|
|
144
|
+
|
|
145
|
+
The repo abstract base (`TableDataRepository.svelte.ts`) owns:
|
|
146
|
+
|
|
147
|
+
- `paginationState` (page index + size, persisted)
|
|
148
|
+
- the per-column `_filterModes` SvelteMap
|
|
149
|
+
- the `forceRefresh` callback hook (use `registerRefreshMethod` to
|
|
150
|
+
assign without firing; the setter form fires immediately and is
|
|
151
|
+
`@deprecated`)
|
|
152
|
+
|
|
153
|
+
If you add a new repo subclass, also extend the runtime discriminator
|
|
154
|
+
on `IDataRepository.paginationType` so existing callers can branch.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Adding a new column kind
|
|
159
|
+
|
|
160
|
+
This is intentionally not a one-file change; the surface area below is
|
|
161
|
+
the irreducible minimum. Pick the four (sometimes five) sites carefully:
|
|
162
|
+
|
|
163
|
+
1. **Def class** — `Types/Columns/Definitions/{Accessors,Display,…}/<Kind>Def.svelte.ts`.
|
|
164
|
+
Inherits from the matching category base (`AccessorDef` / `DisplayDef` / etc.).
|
|
165
|
+
2. **Cell renderer** — `Body/Rows/Columns/<Kind>Cell.svelte`. Picked
|
|
166
|
+
by the dispatch chain in `TableColumn.svelte` (currently an
|
|
167
|
+
`instanceof` if/else; intentionally not registry-driven — see
|
|
168
|
+
follow-up F3 in `PROJECT_CONTEXT.md`).
|
|
169
|
+
3. **Public option type** — add to `Types/Public/ColumnOptions.ts`.
|
|
170
|
+
Discriminated by the kind literal.
|
|
171
|
+
4. **Factory method** — add a method on `ColumnFactory<TRow>` in
|
|
172
|
+
`ColumnFactory.svelte.ts`. The factory's `makeSpec(kind, def, …)`
|
|
173
|
+
tags the def with `def.kind = kind` automatically.
|
|
174
|
+
5. **Registry entry** — add to `COLUMN_KIND_REGISTRY` in
|
|
175
|
+
`ColumnKindRegistry.ts`. Mark `category` and (if applicable) a
|
|
176
|
+
`defaultFilter` key. The companion test file enforces "every kind
|
|
177
|
+
has an entry".
|
|
178
|
+
|
|
179
|
+
A `setupDefaultColumnDefs` change is no longer needed; it now reads
|
|
180
|
+
from the registry.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Load-bearing invariants
|
|
185
|
+
|
|
186
|
+
These each cost real time to discover the first time. Tagged for future
|
|
187
|
+
greppability.
|
|
188
|
+
|
|
189
|
+
### `def.kind` is the canonical sort key
|
|
190
|
+
|
|
191
|
+
Every `ColumnDef` produced by the factory carries `def.kind`. Filter
|
|
192
|
+
wiring (`setupDefaultColumnDefs`), debug logs, and the public spec all
|
|
193
|
+
derive from it. A hand-constructed `ColumnDef` (test stub, legacy code)
|
|
194
|
+
without `kind` is tolerated but skips registry-driven defaults — the
|
|
195
|
+
consumer must assign `filterFn` themselves.
|
|
196
|
+
|
|
197
|
+
### Filter-input `__queryValues` is gone; use `tableContext.queryValues`
|
|
198
|
+
|
|
199
|
+
The legacy `dataRepo.__queryValues: Map<string, unknown>` shared cache
|
|
200
|
+
has been replaced by the typed `QueryValuesState` sub-context. New
|
|
201
|
+
filter widgets should call `tableContext.queryValues.get(def)` /
|
|
202
|
+
`set(def, value)`. The sub-context keys by `ColumnDef` so the
|
|
203
|
+
historical `def.id` vs `label` keying bug class is structurally
|
|
204
|
+
prevented.
|
|
205
|
+
|
|
206
|
+
### `reactiveDependencies` for async accessors
|
|
207
|
+
|
|
208
|
+
`col.display({ value: async (row) => row.foo.value })` will only
|
|
209
|
+
re-render when row identity changes — not when `row.foo.value` mutates,
|
|
210
|
+
because the reactive read happens after the `await` boundary. Pass a
|
|
211
|
+
`reactiveDependencies: (row) => [row.foo.value]` thunk on the column
|
|
212
|
+
options so the cell's `$derived` registers the dep synchronously.
|
|
213
|
+
|
|
214
|
+
### Dropdowns do NOT move in the DOM
|
|
215
|
+
|
|
216
|
+
`Helpers/dropdownPortal.ts` flips a Svelecte dropdown to
|
|
217
|
+
`position: fixed` and lifts its stacking-context ancestor; it does NOT
|
|
218
|
+
re-parent the dropdown to `document.body`. Svelte 5's root-level event
|
|
219
|
+
delegation walks the live `parentNode` chain at dispatch time — moving
|
|
220
|
+
the element out of the mount target silently breaks mouse-click option
|
|
221
|
+
selection while keyboard Enter keeps working. See the header comment in
|
|
222
|
+
`dropdownPortal.ts` for the full reasoning.
|
|
223
|
+
|
|
224
|
+
### Pinned cells skip horizontal scrollIntoView
|
|
225
|
+
|
|
226
|
+
In `Table.svelte`'s focus-restore effects, the scroll-into-view call
|
|
227
|
+
omits `inline: 'nearest'` for pinned cells. Sticky positioning makes
|
|
228
|
+
them visually always-on-screen, but their layout position is at the
|
|
229
|
+
real (often off-screen) column track; an unconditional inline scroll
|
|
230
|
+
would surface the underlying position and the table would "jump" when
|
|
231
|
+
focus lands on a pinned Actions button.
|
|
232
|
+
|
|
233
|
+
### Clipboard copy must pass through `escapeForSpreadsheet`
|
|
234
|
+
|
|
235
|
+
Every path that writes to `navigator.clipboard.writeText` is required
|
|
236
|
+
to neutralise formula-injection prefixes via
|
|
237
|
+
`escapeForSpreadsheet` (or `encapsulate`, which calls it). The single-
|
|
238
|
+
cell `clipboard.copyCell` route and the bulk
|
|
239
|
+
`copyDataToClipboard` / `copyHighlightedRowsToClipboard` paths both
|
|
240
|
+
already use it; new copy paths must too.
|
|
241
|
+
|
|
242
|
+
### `createTable` is async-effective; consume via reactive readers
|
|
243
|
+
|
|
244
|
+
`createTable({...})` returns the structured `Table` instance synchronously, but the underlying `TableContext` finishes initialising asynchronously: `setupDefaultColumnDefs` runs unawaited in the constructor, and `_selection`'s pending-changes buffer flushes on `tick()`. Two practical consequences:
|
|
245
|
+
|
|
246
|
+
- `table.columns.specs` and `table._context.columnDefs` are empty for the first microtask after `createTable` returns. Reactive readers (a `$derived` or `$effect`) re-evaluate when the columns land, so consumer code reads through these without thinking about it.
|
|
247
|
+
- `table.selection.set(rowId, row)` writes into the pending-changes buffer and flushes on `tick()`. `table.selection.size` returns the post-flush value the next time a reactive consumer reads it; a synchronous read on the same call frame returns the pre-flush value.
|
|
248
|
+
|
|
249
|
+
Direct synchronous read-back of state is therefore only safe inside an `$effect` or after `await tick()`. Unit tests at the public API surface need either a reactive harness or explicit `await tick()` between writes and assertions; that's why scoria's table tests use the `.svelte.test.ts` (browser-project) shape rather than plain server-mode unit tests.
|
|
250
|
+
|
|
251
|
+
### Custom-row sources must defensively resolve their accessor thunks
|
|
252
|
+
|
|
253
|
+
A `customRows({ uri, defaultFilters, remoteFilters })` source can have
|
|
254
|
+
its accessor thunks called after the surrounding Svelte component has
|
|
255
|
+
torn down (a debounced fetch landing across a route change). Wrap the
|
|
256
|
+
thunk reads in try/catch and validate the returned shape — see
|
|
257
|
+
`flowms-svelte-web/src/lib/components/base/Table/createRemoteRowSource.ts`
|
|
258
|
+
for the canonical pattern.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Testing model
|
|
263
|
+
|
|
264
|
+
| File pattern | Project | What it covers |
|
|
265
|
+
| --------------------------- | -------- | ------------------------------------------------------------------------------------- |
|
|
266
|
+
| `*.test.ts` (no `.svelte.`) | `server` | Pure-node unit tests (helpers, type contracts). Runs via `pnpm test`. |
|
|
267
|
+
| `*.svelte.test.ts` | `client` | Tests using `$state` / `$effect` from Svelte 5. Browser mode via Vitest + Playwright. |
|
|
268
|
+
|
|
269
|
+
The browser-mode runner has a Windows-specific chromium launch issue;
|
|
270
|
+
set `SCORIA_CHROMIUM_EXECUTABLE` to the headless-shell binary to work
|
|
271
|
+
around it (follow-up F1 in `PROJECT_CONTEXT.md`). The server project
|
|
272
|
+
covers the kind-registry contract, clipboard escape behaviour, and the
|
|
273
|
+
co-located decoupling tests.
|
|
274
|
+
|
|
275
|
+
Add new tests next to the code they cover, not in a global `__tests__`
|
|
276
|
+
folder.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Storybook
|
|
281
|
+
|
|
282
|
+
Stories live under `src/stories/Table/`. Mount via the shared host
|
|
283
|
+
`_helpers/TableHost.svelte` which accepts a `CreateTableOptions` payload
|
|
284
|
+
and runs `createTable` inside instance init (module-scope `createTable`
|
|
285
|
+
would trip `effect_orphan`). The `Table/Table API` MDX page is the
|
|
286
|
+
companion reference; keep it in sync with significant public-API
|
|
287
|
+
changes.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Cross-references
|
|
292
|
+
|
|
293
|
+
- `PROJECT_CONTEXT.md` (repo root) — project state, known issues and
|
|
294
|
+
follow-ups (Part A), plus the consumer migration guide (Part B).
|
|
295
|
+
- `agent-review/dev-changelog.md` — long-form record of the
|
|
296
|
+
decomposition phases.
|
|
297
|
+
- `src/lib/Components/Table/Types/Public/index.ts` — barrel for every
|
|
298
|
+
public type re-exported from `src/lib/index.ts`.
|