@stealthscale/component-tables 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,488 @@
1
+ import { CONTROL_INSET_END, CONTROL_INSET_START, defineSlotRecipe, dense } from "@stealthscale/theme/authoring";
2
+ //#region src/data-table/properties.ts
3
+ /**
4
+ * Names the custom properties the collections table's rows and cells state, which the data table's
5
+ * recipes read and set.
6
+ */
7
+ /**
8
+ * Custom property of a row's fill, which the collections table's rows state and paint.
9
+ */
10
+ const ROW_FILL = "--table-row-fill";
11
+ /**
12
+ * Custom property of the ink the collections table's rows rule their cells in.
13
+ */
14
+ const RULE_INK = "--table-rule";
15
+ /**
16
+ * Custom property of the width of the rule under the collections table's rows.
17
+ */
18
+ const RULE_WIDTH = "--table-rule-width";
19
+ /**
20
+ * Custom property of a cell's inline inset at the table's size, which the collections table's
21
+ * cells state and an editor's control starts its text at.
22
+ */
23
+ const CELL_INSET = "--table-cell-inset";
24
+ //#endregion
25
+ //#region src/data-table/gridded.ts
26
+ /**
27
+ * Styles a grid's cells and the editor over a cell: the selected fill, the line along the
28
+ * selection's outer edges, the focus ring, the unsaved mark, the editor's control and the reason a
29
+ * value was refused.
30
+ *
31
+ * @remarks
32
+ * In a grid a selected cell fills with the palette's subtle role over its row, a line in the
33
+ * palette's solid runs along the selection's outer edges, and the cell with the tab stop rings
34
+ * its edge inside while it has keyboard focus. An open editor covers its cell. The cell's content
35
+ * remains under it, hidden, so the cell keeps its size. The editor's control fills the cell with
36
+ * square corners and starts its text at the cell's inline inset less its edge, where the cell's
37
+ * text starts, and ends it there in a column of figures. The reason a value was refused is placed
38
+ * under the cell in the error inks, over the rows below, or above the cell in a body's last row,
39
+ * so the scroller never clips it. It is as wide as its words up to `sizes.xs`, from the cell's
40
+ * end in a column of figures. A cell with an unsaved change marks its inline start with a bar in
41
+ * the warning palette's solid, `CanvasText` under forced colours.
42
+ */
43
+ /**
44
+ * Styles a cell of a grid: the selected fill, the line along the selection's outer edges, the
45
+ * unsaved mark, and the focus ring inside the cell with the tab stop.
46
+ *
47
+ * @remarks
48
+ * A selected cell paints the fill it states over its row, as a pinned cell paints its row's fill
49
+ * over the panel. The line is a box over the cell, as wide as the indicator on each side
50
+ * `data-edges` lists, in the palette's solid, which is at least 3:1 against the panel. Each side
51
+ * reads its own custom property, so no rule depends on the order of another. Under forced colours
52
+ * a selected cell fills with `Highlight` over `Canvas`, and its text, its rule, its line and its
53
+ * focus ring take `HighlightText`. A cell whose editor is open shows no line and takes no forced
54
+ * fill. Its editor covers the cell with a field in the forced colours of every field.
55
+ */
56
+ const GRIDDED = {
57
+ "&:is([data-edges], [data-editing], [data-unsaved]):not([data-pinned])": { position: "relative" },
58
+ "&[aria-selected=true]": {
59
+ backgroundImage: `linear-gradient(var(${ROW_FILL}), var(${ROW_FILL}))`,
60
+ [ROW_FILL]: "colors.colorPalette.subtle"
61
+ },
62
+ "&[aria-selected=true]:not([data-editing])": { _highContrast: {
63
+ "& *": { color: "HighlightText" },
64
+ backgroundColor: "Canvas",
65
+ color: "HighlightText",
66
+ focusRingColor: "HighlightText",
67
+ forcedColorAdjust: "none",
68
+ [ROW_FILL]: "Highlight",
69
+ [RULE_INK]: "HighlightText"
70
+ } },
71
+ "&[data-edges]": { _after: {
72
+ _highContrast: { borderColor: "HighlightText" },
73
+ borderBlockEndWidth: "var(--edge-block-end, 0)",
74
+ borderBlockStartWidth: "var(--edge-block-start, 0)",
75
+ borderColor: "colorPalette.solid",
76
+ borderInlineEndWidth: "var(--edge-inline-end, 0)",
77
+ borderInlineStartWidth: "var(--edge-inline-start, 0)",
78
+ borderStyle: "solid",
79
+ content: "\"\"",
80
+ inset: "0",
81
+ pointerEvents: "none",
82
+ position: "absolute"
83
+ } },
84
+ "&[data-edges~=block-end]": { "--edge-block-end": "borderWidths.indicator" },
85
+ "&[data-edges~=block-start]": { "--edge-block-start": "borderWidths.indicator" },
86
+ "&[data-edges~=inline-end]": { "--edge-inline-end": "borderWidths.indicator" },
87
+ "&[data-edges~=inline-start]": { "--edge-inline-start": "borderWidths.indicator" },
88
+ "&[data-editing]": { _after: { display: "none" } },
89
+ "&[data-unsaved]": { _before: {
90
+ _highContrast: {
91
+ background: "CanvasText",
92
+ forcedColorAdjust: "none"
93
+ },
94
+ background: "warning.solid",
95
+ content: "\"\"",
96
+ inlineSize: "{borderWidths.indicator}",
97
+ insetBlock: "0",
98
+ insetInlineStart: "0",
99
+ pointerEvents: "none",
100
+ position: "absolute"
101
+ } },
102
+ "&[tabindex]": {
103
+ _focusVisible: { outlineOffset: "calc({borderWidths.ring} * -1)" },
104
+ focusRingColor: "colorPalette.focusRing",
105
+ focusVisibleRing: "inside"
106
+ }
107
+ };
108
+ /**
109
+ * Styles the editor over a cell: a flex box over the cell's padding box, whose control fills it
110
+ * with square corners and starts its text where the cell's text starts.
111
+ */
112
+ const EDITOR = {
113
+ "[data-numeric] > &": { "& input": { textAlign: "end" } },
114
+ "& > :first-child": {
115
+ borderRadius: "none",
116
+ [CONTROL_INSET_END]: `calc(var(${CELL_INSET}) - {borderWidths.control})`,
117
+ [CONTROL_INSET_START]: `calc(var(${CELL_INSET}) - {borderWidths.control})`,
118
+ flex: "1",
119
+ maxBlockSize: "full",
120
+ minBlockSize: "full",
121
+ minInlineSize: "0"
122
+ },
123
+ display: "flex",
124
+ inset: "0",
125
+ position: "absolute"
126
+ };
127
+ /**
128
+ * Styles the reason a value was refused: a box in the error inks under the cell, above it in a
129
+ * body's last row, as wide as its words up to `sizes.xs`.
130
+ */
131
+ const EDITOR_ERROR = {
132
+ "[data-numeric] > * > &": {
133
+ insetInlineEnd: "0",
134
+ insetInlineStart: "auto"
135
+ },
136
+ background: "bg.panel",
137
+ borderColor: "border.error",
138
+ borderRadius: "l2",
139
+ borderStyle: "solid",
140
+ borderWidth: "hairline",
141
+ color: "fg.error",
142
+ inlineSize: "max-content",
143
+ insetBlockStart: "100%",
144
+ insetInlineStart: "0",
145
+ marginBlockStart: dense("{spacing.gap.xs}"),
146
+ maxInlineSize: "xs",
147
+ paddingBlock: dense("{spacing.gap.xs}"),
148
+ paddingInline: dense("{spacing.inset.xs}"),
149
+ position: "absolute",
150
+ textStyle: "body.sm",
151
+ "tr:last-child > * > * > &": {
152
+ insetBlockEnd: "100%",
153
+ insetBlockStart: "auto",
154
+ marginBlockEnd: dense("{spacing.gap.xs}"),
155
+ marginBlockStart: "0"
156
+ },
157
+ zIndex: "3"
158
+ };
159
+ //#endregion
160
+ //#region src/data-table/recipe.ts
161
+ /**
162
+ * Recipe for the parts a data table adds around the collections table: the column that stacks the
163
+ * table and its controls, the row of a header's name and its column actions, the indicators in a
164
+ * header and a row, the resize separator, the cells of a pinned column, the widths of a sized
165
+ * table, and words that render only for assistive technology.
166
+ *
167
+ * @remarks
168
+ * The table's own look (its surface, rules, stripes and sizes) is the collections table's recipe,
169
+ * which `DataTable.Table` passes its axes to. The sort indicator is the caller's glyph, pointing
170
+ * up. It turns half a circle for a descending sort. On a sortable column that is not sorted it is
171
+ * transparent until the pointer is over the sort button or the button has keyboard focus. The
172
+ * expand indicator is the caller's glyph, pointing to the inline end, and turns a quarter while
173
+ * the row's detail is open. A pinned column's cells stick at `--pin-offset` from their region's
174
+ * edge on the panel under their row's fill, and the column at a region's edge rules its side next
175
+ * to the scrolling columns. A sized table is as wide as `--table-size`, each column as wide as
176
+ * its `--column-size`, and its scroller as wide as the table and never wider than its room. A
177
+ * header with column actions lays its name and the actions out in an inline row, which the header
178
+ * aligns as it aligns its name, so the actions follow the name, or precede it in a column of
179
+ * figures, where the header renders them first. The actions take a negative block margin of half
180
+ * the difference between an `xs` button and a line, so a header with actions is as tall as one
181
+ * without. A range filter lays its two fields out side by side, and a value filter writes each
182
+ * value's count in the muted ink with tabular figures. The column manager stacks its list over
183
+ * its reset button, which keeps its own width. The page size select follows its label in a row,
184
+ * the label in the muted ink at the small body size. A body row that ends a region of rows
185
+ * another region follows, such as the last row pinned to the top, rules its end at the indicator
186
+ * width. A cell whose rows span ends on the body's last row takes no rule before a footer, as the
187
+ * last row's cells do. The search field is at most `sizes.xs` wide. A resize separator is centred
188
+ * on its column's end, and the last column's is inside the table's end, so the table overflows
189
+ * nothing. Its line is transparent at rest and takes the palette's solid under the pointer, with
190
+ * keyboard focus and while it resizes, `Highlight` under forced colours. In a windowed table a
191
+ * group of pinned rows sticks on the panel over the rows that scroll: the top group under the
192
+ * header at `--table-head-size`, the bottom group at the viewport's end. A spacer row is as tall
193
+ * as `--spacer-size`, and its cell has no padding. A row with a tab stop, in a table with levels,
194
+ * rings its edge inside while it has keyboard focus. A cell that leads with a row's toggle lays
195
+ * the toggle and its content out in a row, indented `spacing.6` for each of `--row-depth` levels.
196
+ * A button in a body cell, a row's toggle, a detail button or a pin toggle, is in a box as wide
197
+ * as an `xs` button with the same negative block margin, so a row with a button is as tall as one
198
+ * without. A checkbox of the select column is in a box one line tall that centres it, so a row or
199
+ * a header with a checkbox is as tall as one without. A `Code` chip in a cell aligns to the
200
+ * bottom of the cell's text, so a small chip keeps its row's height. A grid's cells, the editor
201
+ * over a cell and the reason a value was refused take `GRIDDED`, `EDITOR` and `EDITOR_ERROR`, and
202
+ * an open editor's cell content is hidden under it.
203
+ */
204
+ /**
205
+ * Styles an indicator that turns: a box around the caller's glyph that turns at the press pace,
206
+ * at once under reduced motion.
207
+ */
208
+ const TURNING = {
209
+ _motionReduce: { transitionDuration: "0s" },
210
+ alignItems: "center",
211
+ display: "inline-flex",
212
+ flexShrink: "0",
213
+ transitionDuration: "press",
214
+ transitionProperty: "opacity, rotate",
215
+ transitionTimingFunction: "press"
216
+ };
217
+ /**
218
+ * Styles the cells of a pinned column: sticky at the offset, the panel under the row's fill, and
219
+ * a rule in the row's ink at the side of the region's edge.
220
+ *
221
+ * @remarks
222
+ * The row's fill is its stripe, its hover fill or its selected fill, so a pinned cell matches
223
+ * its row and hides the figures scrolled under it. Under forced colours a selected row's fill is
224
+ * `Highlight` and its ink `HighlightText`. A pinned cell paints `Canvas` under it, the row's own
225
+ * composite, because Chromium's `Highlight` is 80% opaque.
226
+ */
227
+ const PINNED = {
228
+ "&[data-pinned]": {
229
+ backgroundColor: "bg.panel",
230
+ backgroundImage: `linear-gradient(var(${ROW_FILL}), var(${ROW_FILL}))`,
231
+ position: "sticky",
232
+ "tr[aria-selected=true] > &": { _highContrast: { backgroundColor: "Canvas" } },
233
+ zIndex: "1"
234
+ },
235
+ "&[data-pinned=end]": { insetInlineEnd: "var(--pin-offset)" },
236
+ "&[data-pinned=end][data-pinned-edge]": {
237
+ borderInlineStartColor: `var(${RULE_INK}, {colors.border})`,
238
+ borderInlineStartWidth: "indicator"
239
+ },
240
+ "&[data-pinned=start]": { insetInlineStart: "var(--pin-offset)" },
241
+ "&[data-pinned=start][data-pinned-edge]": {
242
+ borderInlineEndColor: `var(${RULE_INK}, {colors.border})`,
243
+ borderInlineEndWidth: "indicator"
244
+ }
245
+ };
246
+ /**
247
+ * Styles the cells of a column that fits its content: as narrow as the content while the table
248
+ * lays out its columns by their content, where a column declaration sizes a sized table's.
249
+ */
250
+ const FIT = { "&[data-fit]": { inlineSize: "0" } };
251
+ /**
252
+ * Styles a cell whose rows span ends on the body's last row: before a footer it takes no rule, as
253
+ * the collections table's last row does, because the footer rules its own start.
254
+ */
255
+ const SPAN_END = { "&[data-span-end]": { "tbody:has(+ tfoot) > tr > &": { [RULE_WIDTH]: "0" } } };
256
+ /**
257
+ * Aligns typography's `Code` chip in a cell to the bottom of the cell's text.
258
+ *
259
+ * @remarks
260
+ * A chip at `sm` then keeps its row at 41px, and its text's middle is within a third of a pixel
261
+ * of the next cell's text in Firefox and Chromium. A chip at `md` is as tall as the line and
262
+ * makes a 42px row.
263
+ */
264
+ const CHIP = { "& .code": { verticalAlign: "text-bottom" } };
265
+ /**
266
+ * Height of the smallest button, which an action or a toggle in a line of text is.
267
+ */
268
+ const BUTTON = dense("{sizes.control.xs}");
269
+ /**
270
+ * Styles the box around a button in a line of text with a negative block margin of half the
271
+ * difference between the button and the line, so the line keeps its height.
272
+ */
273
+ const ONE_LINE = { marginBlock: `calc((1lh - ${BUTTON}) / 2)` };
274
+ /**
275
+ * Defines the data table recipe.
276
+ */
277
+ const recipe = defineSlotRecipe({
278
+ base: {
279
+ actions: {
280
+ ...ONE_LINE,
281
+ alignItems: "center",
282
+ display: "flex",
283
+ flexShrink: "0"
284
+ },
285
+ branch: {
286
+ alignItems: "center",
287
+ display: "flex",
288
+ gap: dense("{spacing.gap.xs}"),
289
+ paddingInlineStart: `calc(var(--row-depth, 0) * ${dense("{spacing.6}")})`
290
+ },
291
+ cell: {
292
+ ...PINNED,
293
+ ...FIT,
294
+ ...SPAN_END,
295
+ ...CHIP,
296
+ ...GRIDDED
297
+ },
298
+ column: { inlineSize: "var(--column-size)" },
299
+ columnHeader: {
300
+ ...PINNED,
301
+ ...FIT,
302
+ "&[data-resizable]:not([data-pinned])": { position: "relative" }
303
+ },
304
+ count: {
305
+ color: "fg.muted",
306
+ fontVariantNumeric: "tabular-nums"
307
+ },
308
+ covered: { visibility: "hidden" },
309
+ editor: EDITOR,
310
+ editorError: EDITOR_ERROR,
311
+ expandIndicator: {
312
+ ...TURNING,
313
+ _open: { rotate: "90deg" },
314
+ _rtl: {
315
+ _open: { rotate: "90deg" },
316
+ rotate: "180deg"
317
+ }
318
+ },
319
+ frame: { "&[data-sized]": {
320
+ inlineSize: "fit-content",
321
+ maxInlineSize: "full"
322
+ } },
323
+ heading: {
324
+ alignItems: "center",
325
+ display: "inline-flex",
326
+ gap: dense("{spacing.gap.xs}"),
327
+ verticalAlign: "middle"
328
+ },
329
+ manager: {
330
+ display: "flex",
331
+ flexDirection: "column",
332
+ gap: dense("{spacing.gap.sm}")
333
+ },
334
+ pageSize: {
335
+ alignItems: "center",
336
+ display: "inline-flex",
337
+ gap: dense("{spacing.gap.sm}")
338
+ },
339
+ pageSizeLabel: {
340
+ color: "fg.muted",
341
+ textStyle: "body.sm",
342
+ whiteSpace: "nowrap"
343
+ },
344
+ panel: { inlineSize: "60" },
345
+ range: {
346
+ display: "grid",
347
+ gap: dense("{spacing.gap.sm}"),
348
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))"
349
+ },
350
+ region: {
351
+ "&[data-pinned=bottom]": { insetBlockEnd: "0" },
352
+ "&[data-pinned=top]": { insetBlockStart: "var(--table-head-size)" },
353
+ backgroundColor: "bg.panel",
354
+ position: "sticky",
355
+ zIndex: "2"
356
+ },
357
+ reset: { alignSelf: "flex-end" },
358
+ resizer: {
359
+ _after: {
360
+ background: "transparent",
361
+ content: "\"\"",
362
+ forcedColorAdjust: "none",
363
+ inlineSize: "{borderWidths.indicator}",
364
+ insetBlock: "0",
365
+ insetInlineStart: "50%",
366
+ marginInlineStart: "calc({borderWidths.indicator} / -2)",
367
+ position: "absolute"
368
+ },
369
+ "&:is(:hover, :focus-visible, [data-resizing])": { _after: {
370
+ _highContrast: { background: "Highlight" },
371
+ background: "colorPalette.solid"
372
+ } },
373
+ background: "transparent",
374
+ blockSize: "full",
375
+ borderStyle: "none",
376
+ cursor: "resizeColumn",
377
+ focusVisibleRing: "inside",
378
+ inlineSize: "3",
379
+ insetBlock: "0",
380
+ insetInlineEnd: "calc({sizes.3} / -2)",
381
+ margin: "0",
382
+ position: "absolute",
383
+ "th:last-child > &": {
384
+ _after: {
385
+ insetInlineStart: "calc(100% - {borderWidths.indicator})",
386
+ marginInlineStart: "0"
387
+ },
388
+ insetInlineEnd: "0"
389
+ },
390
+ touchAction: "none",
391
+ userSelect: "none",
392
+ zIndex: "1"
393
+ },
394
+ root: {
395
+ display: "flex",
396
+ flexDirection: "column",
397
+ gap: dense("{spacing.gap.md}"),
398
+ minInlineSize: "0"
399
+ },
400
+ row: {
401
+ "&[data-region-end]": { [RULE_WIDTH]: "borderWidths.indicator" },
402
+ "&[tabindex]": {
403
+ _focusVisible: { outlineOffset: "calc({borderWidths.ring} * -1)" },
404
+ focusRingColor: "colorPalette.focusRing",
405
+ focusVisibleRing: "inside"
406
+ }
407
+ },
408
+ rowHeader: {
409
+ ...PINNED,
410
+ ...FIT,
411
+ ...SPAN_END,
412
+ ...CHIP,
413
+ ...GRIDDED
414
+ },
415
+ search: { maxInlineSize: "xs" },
416
+ selectBox: {
417
+ alignItems: "center",
418
+ blockSize: "1lh",
419
+ display: "flex"
420
+ },
421
+ sortIndicator: {
422
+ ...TURNING,
423
+ "&[data-direction=descending]": { rotate: "180deg" },
424
+ "&[data-direction=none]": {
425
+ "*:is(:hover, :focus-visible) > &": { opacity: "muted" },
426
+ opacity: "0"
427
+ }
428
+ },
429
+ spacer: {
430
+ "& > td": { padding: "0" },
431
+ blockSize: "var(--spacer-size)"
432
+ },
433
+ table: { "&[data-sized]": { inlineSize: "var(--table-size)" } },
434
+ toggle: {
435
+ ...ONE_LINE,
436
+ display: "flex",
437
+ flexShrink: "0",
438
+ inlineSize: BUTTON,
439
+ justifyContent: "center"
440
+ },
441
+ value: { alignSelf: "stretch" },
442
+ valueLabel: {
443
+ display: "flex",
444
+ flex: "1",
445
+ gap: dense("{spacing.gap.md}"),
446
+ justifyContent: "space-between"
447
+ },
448
+ visuallyHidden: { srOnly: true }
449
+ },
450
+ className: "data-table",
451
+ jsx: [/^DataTable\.\w+$/u],
452
+ slots: [
453
+ "root",
454
+ "frame",
455
+ "table",
456
+ "column",
457
+ "columnHeader",
458
+ "heading",
459
+ "actions",
460
+ "region",
461
+ "row",
462
+ "spacer",
463
+ "rowHeader",
464
+ "cell",
465
+ "covered",
466
+ "editor",
467
+ "editorError",
468
+ "branch",
469
+ "toggle",
470
+ "selectBox",
471
+ "search",
472
+ "panel",
473
+ "range",
474
+ "value",
475
+ "valueLabel",
476
+ "count",
477
+ "manager",
478
+ "reset",
479
+ "pageSize",
480
+ "pageSizeLabel",
481
+ "sortIndicator",
482
+ "expandIndicator",
483
+ "resizer",
484
+ "visuallyHidden"
485
+ ]
486
+ });
487
+ //#endregion
488
+ export { recipe as t };
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
@@ -0,0 +1,11 @@
1
+ //#region src/theme.d.ts
2
+ /**
3
+ * Registers every recipe in the package in the preset an application's style compiler installs.
4
+ *
5
+ * @remarks
6
+ * The list is written by hand. `theme.spec.ts` fails when a recipe file is missing from it, so no
7
+ * generator writes it.
8
+ */
9
+ declare const _default: import("@stealthscale/theme/authoring").Preset;
10
+ //#endregion
11
+ export { _default as default };
package/dist/theme.js ADDED
@@ -0,0 +1,16 @@
1
+ import { t as recipe } from "./recipe-DKCE3olL.js";
2
+ import { definePreset } from "@stealthscale/theme/authoring";
3
+ //#region src/theme.ts
4
+ /**
5
+ * Registers every recipe in the package in the preset an application's style compiler installs.
6
+ *
7
+ * @remarks
8
+ * The list is written by hand. `theme.spec.ts` fails when a recipe file is missing from it, so no
9
+ * generator writes it.
10
+ */
11
+ var theme_default = definePreset({
12
+ name: "@stealthscale/component-tables",
13
+ theme: { extend: { slotRecipes: { dataTable: recipe } } }
14
+ });
15
+ //#endregion
16
+ export { theme_default as default };
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@stealthscale/component-tables",
3
+ "version": "0.1.0",
4
+ "description": "Renders records in data tables over TanStack Table: sorting, filtering, selection, pages, column sizes and pins, rows with levels, windowed rows, pivots and editable grids.",
5
+ "keywords": [
6
+ "components",
7
+ "data-table",
8
+ "grid",
9
+ "react",
10
+ "table"
11
+ ],
12
+ "homepage": "https://github.com/stealth-scale/scale/tree/main/components/tables#readme",
13
+ "bugs": "https://github.com/stealth-scale/scale/issues",
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/stealth-scale/scale.git",
18
+ "directory": "components/tables"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "LICENSE",
23
+ "README.md"
24
+ ],
25
+ "type": "module",
26
+ "sideEffects": false,
27
+ "imports": {
28
+ "#*": "./src/*"
29
+ },
30
+ "exports": {
31
+ ".": "./dist/index.js",
32
+ "./theme": "./dist/theme.js",
33
+ "./package.json": "./package.json"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "dependencies": {
39
+ "@stealthscale/component-actions": "^0.1.0",
40
+ "@stealthscale/component-collections": "^0.0.1",
41
+ "@stealthscale/component-data": "^0.1.0",
42
+ "@stealthscale/component-disclosure": "^0.1.0",
43
+ "@stealthscale/component-feedback": "^0.1.0",
44
+ "@stealthscale/component-forms": "^0.1.0",
45
+ "@stealthscale/component-navigation": "^0.1.0",
46
+ "@tanstack/react-table": "^9.2",
47
+ "@tanstack/react-virtual": "^3.14"
48
+ },
49
+ "devDependencies": {
50
+ "@arethetypeswrong/core": "^0.18",
51
+ "@stealthscale/component-a11y": "^0.1.0",
52
+ "@stealthscale/component-primitives": "^0.1.0",
53
+ "@stealthscale/hooks": "^0.1.0",
54
+ "@stealthscale/provider-locale": "^0.1.0",
55
+ "@stealthscale/theme": "^0.3.0",
56
+ "@stealthscale/vite-config": "^0.6.0",
57
+ "@stealthscale/vite-config-i18n": "^0.1.0",
58
+ "@stealthscale/vite-config-react": "^0.8.0",
59
+ "@stealthscale/vite-config-specimen": "^0.1.0",
60
+ "@stealthscale/vite-config-theme": "^0.1.0",
61
+ "@stealthscale/vite-config-typescript": "^0.3.0",
62
+ "@testing-library/react": "^16.3",
63
+ "@types/react": "^19.3",
64
+ "@types/react-dom": "^19.3",
65
+ "happy-dom": "^20.14",
66
+ "lucide-react": "^1.48",
67
+ "oxc-transform-react": "^0.151",
68
+ "publint": "^0.3",
69
+ "react": "^19.3",
70
+ "react-dom": "^19.3",
71
+ "typescript": "^7.0",
72
+ "vitest": "5.0.1"
73
+ },
74
+ "peerDependencies": {
75
+ "@stealthscale/component-a11y": "^0.1.0",
76
+ "@stealthscale/component-primitives": "^0.1.0",
77
+ "@stealthscale/hooks": "^0.1.0",
78
+ "@stealthscale/provider-locale": "^0.1.0",
79
+ "@stealthscale/theme": "^0.3.0",
80
+ "react": "^19.3",
81
+ "react-dom": "^19.3"
82
+ },
83
+ "engines": {
84
+ "node": ">=26.0.0"
85
+ },
86
+ "scripts": {
87
+ "build": "vp pack",
88
+ "check": "vp check",
89
+ "test": "vp test"
90
+ }
91
+ }