torch-glare 2.4.4 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/lib/components/DataViews/{badgeAdapter.ts → badge.ts} +2 -2
- package/apps/lib/components/DataViews/cell.tsx +324 -0
- package/apps/lib/components/DataViews/context.ts +144 -0
- package/apps/lib/components/DataViews/data-views.tsx +383 -0
- package/apps/lib/components/DataViews/filters/children.tsx +98 -0
- package/apps/lib/components/DataViews/filters/custom.tsx +34 -0
- package/apps/lib/components/DataViews/filters/filters.tsx +163 -0
- package/apps/lib/components/DataViews/filters/index.ts +4 -0
- package/apps/lib/components/DataViews/filters/labelled.tsx +20 -0
- package/apps/lib/components/DataViews/filters/presets.tsx +65 -0
- package/apps/lib/components/DataViews/filters/summary.tsx +65 -0
- package/apps/lib/components/DataViews/filters/sync.tsx +35 -0
- package/apps/lib/components/DataViews/filters/values.ts +173 -0
- package/apps/lib/components/DataViews/header.tsx +217 -0
- package/apps/lib/components/DataViews/hooks/index.ts +5 -0
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +22 -0
- package/apps/lib/components/DataViews/hooks/useControllable.ts +52 -0
- package/apps/lib/components/DataViews/index.ts +74 -26
- package/apps/lib/components/DataViews/panel/columns.tsx +153 -0
- package/apps/lib/components/DataViews/panel/controls.tsx +106 -0
- package/apps/lib/components/DataViews/panel/index.ts +3 -0
- package/apps/lib/components/DataViews/panel/panel.tsx +164 -0
- package/apps/lib/components/DataViews/panel/saved-views.tsx +67 -0
- package/apps/lib/components/DataViews/panel/section.tsx +79 -0
- package/apps/lib/components/DataViews/panel/sort.tsx +42 -0
- package/apps/lib/components/DataViews/panel/tab.tsx +31 -0
- package/apps/lib/components/DataViews/slots.ts +63 -0
- package/apps/lib/components/DataViews/states.tsx +38 -0
- package/apps/lib/components/DataViews/types.ts +485 -178
- package/apps/lib/components/DataViews/views/board-view.tsx +379 -0
- package/apps/lib/components/DataViews/views/card-rows.tsx +36 -0
- package/apps/lib/components/DataViews/views/inbox-view.tsx +257 -0
- package/apps/lib/components/DataViews/views/pane-views.tsx +192 -0
- package/apps/lib/components/DataViews/views/table-view.tsx +426 -0
- package/apps/lib/components/DataViews/views/tree-view.tsx +365 -0
- package/apps/lib/components/FormBuilder/context.ts +20 -6
- package/apps/lib/components/FormBuilder/field-kind.ts +28 -0
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +3 -3
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +7 -6
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +30 -4
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +7 -7
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +80 -52
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +9 -9
- package/apps/lib/components/FormBuilder/form-builder.tsx +66 -6
- package/apps/lib/components/FormBuilder/index.ts +3 -1
- package/apps/lib/components/FormBuilder/types.ts +40 -0
- package/apps/lib/components/Input.tsx +3 -0
- package/apps/lib/components/SearchableTable.tsx +5 -4
- package/apps/lib/components/SectionBlock.tsx +58 -11
- package/apps/lib/components/Select.tsx +3 -1
- package/apps/lib/components/TabSwitch.tsx +16 -4
- package/apps/lib/components/Table.tsx +265 -67
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +6 -3
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +16 -14
- package/apps/lib/components/TreeFolder/index.ts +1 -1
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +70 -207
- package/apps/lib/hooks/useDragDrop.tsx +365 -0
- package/apps/lib/hooks/useInfiniteScroll.ts +108 -0
- package/apps/lib/registry.json +159 -4
- package/apps/lib/tsconfig.tsbuildinfo +1 -1
- package/apps/lib/utils/dataViews/path.ts +67 -0
- package/apps/lib/utils/dataViews/query.ts +73 -0
- package/apps/lib/utils/dataViews/types.ts +187 -0
- package/docs/components/breadcrumb.md +1 -1
- package/docs/components/button-group.md +1 -1
- package/docs/components/button.md +1 -1
- package/docs/components/card.md +1 -1
- package/docs/components/checkbox.md +1 -1
- package/docs/components/data-views/backend-response.md +324 -0
- package/docs/components/data-views/examples/a11y-rtl.md +250 -0
- package/docs/components/data-views/examples/api-orders-route.md +130 -0
- package/docs/components/data-views/examples/fields.md +362 -0
- package/docs/components/data-views/examples/filters.md +308 -0
- package/docs/components/data-views/examples/inbox-routing.md +218 -0
- package/docs/components/data-views/examples/index.md +29 -0
- package/docs/components/data-views/examples/overview.md +244 -0
- package/docs/components/data-views/examples/panel.md +212 -0
- package/docs/components/data-views/examples/scale.md +231 -0
- package/docs/components/data-views/examples/server-side.md +210 -0
- package/docs/components/data-views/examples/state.md +250 -0
- package/docs/components/data-views/examples/tree-custom.md +388 -0
- package/docs/components/data-views/examples/view-registry.md +313 -0
- package/docs/components/data-views/examples/views.md +534 -0
- package/docs/components/data-views/guide.md +405 -0
- package/docs/components/data-views/index.md +1504 -0
- package/docs/components/data-views/migration.md +79 -0
- package/docs/components/date-picker.md +0 -1
- package/docs/components/form-builder.md +19 -8
- package/docs/components/form-renderer.md +2 -1
- package/docs/components/form.md +1 -1
- package/docs/components/input-field.md +1 -1
- package/docs/components/input-otp.md +1 -1
- package/docs/components/input.md +1 -1
- package/docs/components/labeled-check-box.md +1 -1
- package/docs/components/labeled-radio.md +1 -1
- package/docs/components/radio-card.md +1 -1
- package/docs/components/radio.md +1 -1
- package/docs/components/search-field.md +1 -1
- package/docs/components/section-block.md +79 -3
- package/docs/components/select.md +1 -1
- package/docs/components/simple-select.md +1 -1
- package/docs/components/switch.md +1 -1
- package/docs/components/tab-switch.md +1 -1
- package/docs/components/table.md +45 -8
- package/docs/components/text-editor.md +1 -1
- package/docs/components/textarea.md +1 -1
- package/docs/components/toggle-button.md +1 -1
- package/docs/components/toggle.md +1 -1
- package/docs/components/tree-folder.md +110 -0
- package/docs/how-to/forms-with-form-builder.md +6 -4
- package/docs/reference/components.md +16 -6
- package/docs/tutorials/component-composition.md +11 -13
- package/package.json +3 -2
- package/apps/lib/components/DataViews/DataViewRadio.tsx +0 -49
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +0 -393
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +0 -207
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +0 -332
- package/apps/lib/components/DataViews/FilterPanel.tsx +0 -493
- package/apps/lib/components/DataViews/HeaderSearch.tsx +0 -93
- package/apps/lib/components/DataViews/InboxView.tsx +0 -463
- package/apps/lib/components/DataViews/InboxViewCard.tsx +0 -127
- package/apps/lib/components/DataViews/KanbanView.tsx +0 -336
- package/apps/lib/components/DataViews/PanelControls.tsx +0 -39
- package/apps/lib/components/DataViews/SettingsPanel.tsx +0 -279
- package/apps/lib/components/DataViews/TableView.tsx +0 -212
- package/apps/lib/components/DataViews/TreeView.tsx +0 -364
- package/apps/lib/components/DataViews/fieldRenderers.tsx +0 -299
- package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +0 -87
- package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +0 -120
- package/apps/lib/components/DataViews/filters/PresetChips.tsx +0 -45
- package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +0 -165
- package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +0 -50
- package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +0 -74
- package/apps/lib/hooks/useDataViewsState.ts +0 -175
- package/apps/lib/utils/dataViews/columnUtils.ts +0 -132
- package/apps/lib/utils/dataViews/fieldUtils.ts +0 -197
- package/apps/lib/utils/dataViews/nestedDataUtils.tsx +0 -371
- package/apps/lib/utils/dataViews/pathUtils.ts +0 -139
- package/apps/lib/utils/dataViews/rangeUtils.ts +0 -234
- package/apps/lib/utils/dataViews/treeUtils.ts +0 -396
- package/docs/components/data-views-config-panel.md +0 -208
- package/docs/components/data-views-layout.md +0 -291
- package/docs/components/inbox-view.md +0 -170
- package/docs/components/kanban-view.md +0 -135
- package/docs/components/table-view.md +0 -141
- package/docs/components/tree-view.md +0 -147
- package/docs/how-to/data-views-from-backend-response.md +0 -194
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Migrating to the DataViews component
|
|
3
|
+
description: The DataViewsLayout family was replaced by one compound DataViews component. What each old part maps to, and what was removed.
|
|
4
|
+
group: migration
|
|
5
|
+
keywords: [migration, data-views, dataviews-layout, kanban-view, table-view, inbox-view, tree-view, config-panel, upgrade, breaking]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Migrating to the DataViews component
|
|
9
|
+
|
|
10
|
+
The `DataViewsLayout` family — a layout component plus one standalone component per view, wired
|
|
11
|
+
together with `useDataViewsState` — was replaced by a single compound component, `DataViews`.
|
|
12
|
+
|
|
13
|
+
If you never used those, there is nothing to do here: they were **folder components that the
|
|
14
|
+
registry never listed**, so `npx torch-glare add KanbanView` was never able to install one. The
|
|
15
|
+
docs described them, the CLI could not deliver them. That mismatch is what this release fixes.
|
|
16
|
+
|
|
17
|
+
## What maps to what
|
|
18
|
+
|
|
19
|
+
| Old | New |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `DataViewsLayout` | `DataViews` |
|
|
22
|
+
| `TableView` | `DataViews.Table` |
|
|
23
|
+
| `KanbanView` | `DataViews.Board` |
|
|
24
|
+
| `InboxView` | `DataViews.Inbox` |
|
|
25
|
+
| `TreeView` | `DataViews.Tree` |
|
|
26
|
+
| `DataViewsConfigPanel` | `DataViews.Panel`, with `Panel.Tab` · `Panel.SavedViews` · `Panel.Columns` · `Panel.Sort` |
|
|
27
|
+
| `useDataViewsState` | the `query` prop + `onQueryChange` |
|
|
28
|
+
|
|
29
|
+
The shape of the change is that a view is no longer *configured*, it is *rendered*. There is no map
|
|
30
|
+
of which views to enable: render `<DataViews.Board/>` and a Board tab appears; wrap it in a
|
|
31
|
+
condition and it disappears, switching away from it if it was the open one.
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// before — composable mode, wired by hand
|
|
35
|
+
const state = useDataViewsState();
|
|
36
|
+
<DataViewsLayout state={state} views={{ table: true, kanban: true }}>
|
|
37
|
+
<TableView state={state} />
|
|
38
|
+
<KanbanView state={state} groups={groups} />
|
|
39
|
+
</DataViewsLayout>
|
|
40
|
+
|
|
41
|
+
// after
|
|
42
|
+
<DataViews rows={rows} total={total} fields={fields} onQueryChange={setQuery}>
|
|
43
|
+
<DataViews.Header title="Orders">
|
|
44
|
+
<DataViews.ViewSwitch />
|
|
45
|
+
</DataViews.Header>
|
|
46
|
+
<DataViews.Table />
|
|
47
|
+
<DataViews.Board groups={groups} />
|
|
48
|
+
</DataViews>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Also removed
|
|
52
|
+
|
|
53
|
+
Three parts of `DataViews` itself went in the same release.
|
|
54
|
+
|
|
55
|
+
**`DataViews.Pagination`** — rows now load as you scroll. Pass `onLoadMore` and append each page to
|
|
56
|
+
`rows`; whether there is more is derived from `rows.length < total`, so there is no `hasMore` prop.
|
|
57
|
+
See the *Large datasets* section of the [DataViews doc](./index.md).
|
|
58
|
+
|
|
59
|
+
**`DataViews.Empty`** — when there is nothing to show, the view shows nothing: the table keeps its
|
|
60
|
+
header band and has no rows, the board keeps its columns and has no cards. A centred message in
|
|
61
|
+
place of the view threw away the chrome, and it could not tell "no results" apart from "not fetched
|
|
62
|
+
yet" — so the first load of every page announced that nothing matched before anything had been
|
|
63
|
+
asked for.
|
|
64
|
+
|
|
65
|
+
**`DataViews.Loading`** — each view now paints its own skeleton, in its own shape, driven by the
|
|
66
|
+
`loading` prop. A custom view registered with `markView` gets the same thing: read `loading` from
|
|
67
|
+
`useDataViewsData()` and lay out the exported `SkeletonBar` / `skeletonKeys`.
|
|
68
|
+
|
|
69
|
+
## Upgrading a copied component
|
|
70
|
+
|
|
71
|
+
`DataViews` is copy-in like everything else, so upgrading means re-running `add` and re-applying any
|
|
72
|
+
local edits:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx torch-glare@latest add DataViews
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
That copies the folder plus its dependencies — `Table`, `FormBuilder`, `TreeFolder`, the
|
|
79
|
+
`useDragDrop` and `useInfiniteScroll` hooks, and the `dataViews` utilities.
|
|
@@ -855,4 +855,3 @@ function DatePickerWithStore() {
|
|
|
855
855
|
- [SlideDatePicker](./slide-date-picker.md) - Mobile-optimized slide picker
|
|
856
856
|
- [InputField](./input-field.md) - Input field used as default trigger
|
|
857
857
|
- [Popover](./popover.md) - Dropdown container
|
|
858
|
-
- [TimePicker](./time-picker.md) - Standalone time picker
|
|
@@ -81,7 +81,8 @@ Each is a JSX child taking at least `name`, plus `label`, `placeholder`,
|
|
|
81
81
|
| `FormBuilder.Slider` (`min,max,step,range`) | `@radix-ui/react-slider` | `number` / `[number,number]` |
|
|
82
82
|
| `FormBuilder.Color` (`presets`, `alpha`) | `ColorPicker` (full palette: SV area, hue, opacity, eyedropper, HEX/RGB/HSL, presets) | hex `string` (`#rrggbb`, or `#rrggbbaa` when opacity < 100%) |
|
|
83
83
|
| `FormBuilder.Phone` (`defaultCountry`) | `SearchableSelect` + `InputField` | `string` |
|
|
84
|
-
| `FormBuilder.Select`
|
|
84
|
+
| `FormBuilder.Select` (`options`) | `Select` | `string` |
|
|
85
|
+
| `FormBuilder.SearchableSelect` (`options`, async: `onSearchChange`/`onLoadMore`/`hasMore`) | `SearchableSelect` | `string` |
|
|
85
86
|
| `FormBuilder.MultiSelect` / `.Tags` (`options`) | `BadgeField` | `string[]` |
|
|
86
87
|
| `FormBuilder.RadioList` (`options`, each with optional `description`) | boxed radio list | `string` |
|
|
87
88
|
| `FormBuilder.CheckboxGroup` (`options`, each with optional `description`) | boxed checkbox list | `string[]` |
|
|
@@ -99,24 +100,33 @@ Each is a JSX child taking at least `name`, plus `label`, `placeholder`,
|
|
|
99
100
|
| `FormBuilder.Signature` (`penColor`) | canvas pad | PNG data-URL `string` |
|
|
100
101
|
| `FormBuilder.FieldArray` (`children` render fn, `defaultItem`) | RHF `useFieldArray` | `object[]` |
|
|
101
102
|
| `FormBuilder.Table` (`columns`, `selectable`, `reorderable`, `defaultItem`) | editable grid in a `SectionBlock` | `object[]` |
|
|
102
|
-
| `FormBuilder.Custom` (`render
|
|
103
|
+
| `FormBuilder.Custom` (`render`) | your control | anything |
|
|
103
104
|
|
|
104
105
|
`FormBuilder.Password` accepts `strengthMeter` (shows a `PasswordLevel` meter). `FormBuilder.FieldArray`
|
|
105
106
|
renders a repeating list — its `children` is a render fn `(rowName, index, remove) => …` and sub-fields
|
|
106
107
|
are named `${rowName}.field`.
|
|
107
108
|
|
|
108
109
|
`FormBuilder.Table` is the **table-shaped** counterpart of `FieldArray` (value `object[]`): an editable
|
|
109
|
-
grid where each row is a record and each column cell is any `FormBuilder.*` field. It renders
|
|
110
|
-
`SectionBlock
|
|
110
|
+
grid where each row is a record and each column cell is any `FormBuilder.*` field. It renders its own
|
|
111
|
+
`SectionBlock` (`variant="Table"` — the full-bleed table shell), so place it as a **top-level child** of
|
|
112
|
+
the form, **not** inside a `FormBuilder.Section` — nesting produces a card inside a card. When you need a
|
|
113
|
+
table that isn't a form field, compose the shell yourself with `SectionBlock variant="Table"` (see
|
|
114
|
+
[SectionBlock → Table Variant](./section-block.md#table-variant)).
|
|
115
|
+
|
|
111
116
|
Each column pairs a `header` with a `cell(rowName, index)` renderer — name the cell's field
|
|
112
|
-
`${rowName}.<key>`.
|
|
113
|
-
|
|
117
|
+
`${rowName}.<key>`. Set `width` to size a column; it is applied to both the header and the body cells.
|
|
118
|
+
The section header carries the actions: an **Add New** button and a **Delete Row** button that's disabled
|
|
119
|
+
until rows are checkbox-selected. A second **+ Add New** sits below the grid. Both live *outside* the
|
|
120
|
+
horizontal scroll container, so they stay put when a wide table is scrolled sideways. Rows support
|
|
114
121
|
**checkbox selection** (+ select-all), **drag-drop reordering**, and — per column, via `sortKey` — a
|
|
115
122
|
sort toggle in the header. Cells render
|
|
116
123
|
"bare" (control only) with validation errors shown as a tooltip on the control, so a row stays one line
|
|
117
124
|
tall, and each field passes `onTable` so it's borderless and blends into the grid. Practical cell fields
|
|
118
125
|
are the compact ones — `Text`, `Number`, `Currency`, `Select`, `SearchableSelect`, `Date`, `Phone`,
|
|
119
126
|
`Checkbox`, `SwitchBox`; wide fields (`RichText`, `Signature`, `File`) work but aren't suited to a cell.
|
|
127
|
+
`FormBuilder.Phone` collapses to a **plain number input** in a cell — two controls in one cell is not a
|
|
128
|
+
table column, so add a separate column (e.g. a `FormBuilder.Select` of dial codes) if you need the
|
|
129
|
+
country code.
|
|
120
130
|
|
|
121
131
|
```tsx
|
|
122
132
|
<FormBuilder.Table
|
|
@@ -158,8 +168,9 @@ clickable. Multi-select is also available as `.MultiSelect` / `.Tags` (a tag-chi
|
|
|
158
168
|
renders like any other field — the `label` sits in the normal label column — and the box holds
|
|
159
169
|
an optional inline `subLabel`, a vertical divider, and the switch.
|
|
160
170
|
|
|
161
|
-
`FormBuilder.Section` (props `title`, `color`, `icon`) groups fields in a Glare
|
|
162
|
-
`SectionBlock`. `
|
|
171
|
+
`FormBuilder.Section` (props `title`, `color`, `icon`, `action`, `variant`) groups fields in a Glare
|
|
172
|
+
`SectionBlock`. `action` puts buttons on the title row; `variant="Table"` switches to the
|
|
173
|
+
full-bleed table shell (what `FormBuilder.Table` uses internally). `FormBuilder.Submit` is a loading-aware submit button. It
|
|
163
174
|
**auto-associates with the enclosing form** (via context), so it submits even when placed in a
|
|
164
175
|
header / action bar that renders _outside_ the `<form>` — no manual `form={id}` wiring.
|
|
165
176
|
|
|
@@ -286,4 +286,5 @@ const form = useForm({ resolver, defaultValues })
|
|
|
286
286
|
|
|
287
287
|
> `childrenOutside` is the deprecated former name for `summary`. It still works.
|
|
288
288
|
|
|
289
|
-
`FormRenderer`
|
|
289
|
+
`FormRenderer` forwards `summary` straight into the drawer tray, so you rarely need
|
|
290
|
+
`FormDrawer` directly — reach for it only when you want the drawer without a form.
|
package/docs/components/form.md
CHANGED
package/docs/components/input.md
CHANGED
package/docs/components/radio.md
CHANGED
|
@@ -6,7 +6,7 @@ category: layout
|
|
|
6
6
|
group: Layout & Containers
|
|
7
7
|
tags: [layout, card, section, container, form, group]
|
|
8
8
|
status: stable
|
|
9
|
-
version: 2.4.
|
|
9
|
+
version: 2.4.5
|
|
10
10
|
dependencies:
|
|
11
11
|
- "class-variance-authority": "^0.7.0"
|
|
12
12
|
---
|
|
@@ -59,6 +59,9 @@ export function Example() {
|
|
|
59
59
|
|------|------|---------|-------------|
|
|
60
60
|
| `color` | `SectionColor` | `"Blue"` | Color of the title badge. One of `Blue`, `Yellow`, `Green`, `Red`, `Orange`, `Purple`, `Pink`, `Gray`. |
|
|
61
61
|
| `title` | `ReactNode` | — | Title rendered inside the colored badge. Optional — when omitted, the header is hidden entirely. Accepts any ReactNode (string, JSX with icons, links, etc.). |
|
|
62
|
+
| `icon` | `ReactNode` | — | Rendered inside the badge, to the left of `title`. |
|
|
63
|
+
| `action` | `ReactNode` | — | Right-aligned content on the title row — typically action buttons. |
|
|
64
|
+
| `variant` | `SectionVariant` | `"Default"` | `"Default"` is the padded form card. `"Table"` is the full-bleed table shell: no body padding, a rule under the header, no bottom padding, and the card clipped to its radius. See [Table Variant](#table-variant). |
|
|
62
65
|
| `containerClassName` | `string` | — | Class name applied to the outer container (alongside `className`). |
|
|
63
66
|
| `headerClassName` | `string` | — | Class name applied to the header wrapper around the title badge. |
|
|
64
67
|
| `bodyClassName` | `string` | — | Class name applied to the body wrapper holding `children`. |
|
|
@@ -79,10 +82,15 @@ export type SectionColor =
|
|
|
79
82
|
| "Pink"
|
|
80
83
|
| "Gray";
|
|
81
84
|
|
|
85
|
+
export type SectionVariant = "Default" | "Table";
|
|
86
|
+
|
|
82
87
|
export interface SectionBlockProps
|
|
83
88
|
extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
84
89
|
color?: SectionColor;
|
|
90
|
+
variant?: SectionVariant;
|
|
85
91
|
title?: ReactNode;
|
|
92
|
+
icon?: ReactNode;
|
|
93
|
+
action?: ReactNode;
|
|
86
94
|
containerClassName?: string;
|
|
87
95
|
headerClassName?: string;
|
|
88
96
|
bodyClassName?: string;
|
|
@@ -362,6 +370,74 @@ function RowDivider() {
|
|
|
362
370
|
}
|
|
363
371
|
```
|
|
364
372
|
|
|
373
|
+
### Table Variant
|
|
374
|
+
|
|
375
|
+
`variant="Table"` swaps the padded form body for the full-bleed table shell: the body loses
|
|
376
|
+
its `px-[42px]` gutter, gains a rule under the header, and the card is clipped to its 16px
|
|
377
|
+
radius with no bottom padding — so an end-action row meets the card edge.
|
|
378
|
+
|
|
379
|
+
The layout has three stacked parts, and the order matters. Only the **scroller** scrolls
|
|
380
|
+
horizontally; the header actions above it and the end-action below it stay put, which is
|
|
381
|
+
what keeps `Add New` reachable on a wide table.
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
import { SectionBlock } from "@/components/SectionBlock";
|
|
385
|
+
import { Button } from "@/components/Button";
|
|
386
|
+
import {
|
|
387
|
+
Table,
|
|
388
|
+
TableBody,
|
|
389
|
+
TableCell,
|
|
390
|
+
TableEndAction,
|
|
391
|
+
TableHead,
|
|
392
|
+
TableHeader,
|
|
393
|
+
TableRow,
|
|
394
|
+
TableScroller,
|
|
395
|
+
} from "@/components/Table";
|
|
396
|
+
|
|
397
|
+
<SectionBlock
|
|
398
|
+
variant="Table"
|
|
399
|
+
color="Purple"
|
|
400
|
+
title="Items Table"
|
|
401
|
+
icon={<i className="ri-box-3-line text-[18px]" />}
|
|
402
|
+
action={
|
|
403
|
+
<>
|
|
404
|
+
<Button type="button" size="M" variant="BorderStyle" disabled>
|
|
405
|
+
Delete Row
|
|
406
|
+
</Button>
|
|
407
|
+
<Button type="button" size="M" variant="BluColStyle">
|
|
408
|
+
Add New
|
|
409
|
+
</Button>
|
|
410
|
+
</>
|
|
411
|
+
}
|
|
412
|
+
>
|
|
413
|
+
<TableScroller>
|
|
414
|
+
<Table className="min-w-full">
|
|
415
|
+
<TableHeader>
|
|
416
|
+
<TableRow>
|
|
417
|
+
<TableHead style={{ width: 200 }}>Items</TableHead>
|
|
418
|
+
<TableHead style={{ width: 200 }}>Label</TableHead>
|
|
419
|
+
</TableRow>
|
|
420
|
+
</TableHeader>
|
|
421
|
+
<TableBody>
|
|
422
|
+
<TableRow>
|
|
423
|
+
<TableCell minWidth={0}>Product name</TableCell>
|
|
424
|
+
<TableCell minWidth={0}>Label</TableCell>
|
|
425
|
+
</TableRow>
|
|
426
|
+
</TableBody>
|
|
427
|
+
</Table>
|
|
428
|
+
</TableScroller>
|
|
429
|
+
|
|
430
|
+
<TableEndAction>
|
|
431
|
+
<i className="ri-add-line" />
|
|
432
|
+
Add New
|
|
433
|
+
</TableEndAction>
|
|
434
|
+
</SectionBlock>
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
For a table that edits form values, don't hand-compose this — use
|
|
438
|
+
[`FormBuilder.Table`](./form-builder.md#formbuildertable), which renders exactly this shell
|
|
439
|
+
and wires rows to `react-hook-form`.
|
|
440
|
+
|
|
365
441
|
### Custom Layout (override defaults)
|
|
366
442
|
|
|
367
443
|
Use `containerClassName`, `headerClassName`, and `bodyClassName` to override the built-in spacing and width without losing the title/body structure.
|
|
@@ -384,7 +460,7 @@ Use `containerClassName`, `headerClassName`, and `bodyClassName` to override the
|
|
|
384
460
|
- **Color coding**: Use distinct colors to help users scan a page of multiple sections (e.g., Blue for primary forms, Yellow for warnings, Red for destructive zones).
|
|
385
461
|
- **No-title sections**: Drop the `title` prop entirely when the section's purpose is obvious from context — keeps the body padding without the visual weight of a header.
|
|
386
462
|
- **Composing with form fields**: `SectionBlock` does not impose any inner layout — pair it with helpers like the `FieldRow` pattern above, or with `InputField`, `Form`, or `FieldSection` for more structured forms.
|
|
387
|
-
- **
|
|
463
|
+
- **Width**: The component is `w-full` — it fills its parent. Constrain it from the outside, or with `containerClassName="max-w-[1100px]"`.
|
|
388
464
|
|
|
389
465
|
## Accessibility
|
|
390
466
|
|
|
@@ -395,7 +471,7 @@ Use `containerClassName`, `headerClassName`, and `bodyClassName` to override the
|
|
|
395
471
|
|
|
396
472
|
| Issue | Fix |
|
|
397
473
|
|-------|-----|
|
|
398
|
-
| Card overflows on small screens |
|
|
474
|
+
| Card overflows on small screens | The card is `w-full`; the overflow is coming from its content. Give the content `min-w-0`, or cap the card with `containerClassName="max-w-[…]"`. |
|
|
399
475
|
| Title not showing | The `title` prop is optional — omitting it hides the entire header. Pass any non-null `ReactNode` to render it. |
|
|
400
476
|
| Badge color looks wrong | `color` only accepts the predefined `SectionColor` values. For custom badge colors, override via `headerClassName` and a custom child node. |
|
|
401
477
|
| Need a different background | The body uses `bg-background-presentation-form-base`. Override via `containerClassName` (your class wins via `cn()` merging). |
|
package/docs/components/table.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Table
|
|
3
|
-
version: 2.4.
|
|
3
|
+
version: 2.4.5
|
|
4
4
|
status: stable
|
|
5
5
|
category: components/data-display
|
|
6
6
|
tags: [table, data, grid, sortable, resizable, accessible, compound]
|
|
@@ -386,18 +386,41 @@ function ResizableTable() {
|
|
|
386
386
|
| `disabled` | `boolean` | `false` | Disables interactions |
|
|
387
387
|
| `sortType` | `'asc' \| 'desc' \| undefined` | - | Sort indicator |
|
|
388
388
|
| `onSort` | `() => void` | - | Sort handler |
|
|
389
|
+
| `sortLabel` | `string` | - | Column name for the sort button's accessible label |
|
|
390
|
+
| `onResize` | `(width: number) => void` | - | Fires while the column is drag-resized. Passing it makes the width **controlled** — you own the value and feed it back via `style.width`. Required whenever the table needs a definite width (`table-layout: fixed`), since only the owner of every column width can total them. Omit for uncontrolled resizing. |
|
|
389
391
|
| `isDummy` | `boolean` | `false` | Non-interactive header |
|
|
390
|
-
| `className` | `string` | - |
|
|
392
|
+
| `className` / `style` | `string` / `CSSProperties` | - | Applied to the `<th>` — this is how you size a column (`style={{ width: 200 }}`) |
|
|
393
|
+
| `contentClassName` | `string` | - | Classes for the inner layout box (the flex row holding the label and sort toggle). Use it for typography or colour; `className` styles the `<th>` itself. |
|
|
394
|
+
|
|
395
|
+
**Every** prop you pass — `className`, `style`, `aria-*`, `role`, `tabIndex` and event
|
|
396
|
+
handlers alike — lands on the `<th>`. They deliberately share one element: libraries like
|
|
397
|
+
dnd-kit hand back accessibility attributes and event listeners as a matched pair, and
|
|
398
|
+
splitting them across two nodes leaves the focusable element without its handlers. Reach the
|
|
399
|
+
inner layout box with `contentClassName`.
|
|
391
400
|
|
|
392
401
|
### TableCell Props
|
|
393
402
|
|
|
394
403
|
| Prop | Type | Default | Description |
|
|
395
404
|
|------|------|---------|-------------|
|
|
396
405
|
| `isDummy` | `boolean` | `false` | Non-interactive cell |
|
|
406
|
+
| `minWidth` | `number` | `200` | Minimum width of the content box, in px. Pass `0` when the column width is driven by the caller — otherwise this floor silently overrides any narrower column. |
|
|
407
|
+
| `fade` | `boolean` | `true` | Whether the cell **crops** its content and fades the last 25% of it, signalling text clipped by the column width. Set `false` for cells holding a **control**: the fade washes out whatever sits at the right edge (a Select's chevron, a date button), and the crop — the content box hugs the control exactly — would clip every side of the control's hover/focus drop shadow. `isDummy` cells never fade. |
|
|
397
408
|
| `childrenClassName` | `string` | - | Classes for content wrapper |
|
|
398
409
|
| `className` | `string` | - | Additional CSS classes |
|
|
399
410
|
| `children` | `React.ReactNode` | - | Cell content |
|
|
400
411
|
|
|
412
|
+
### TableScroller Props
|
|
413
|
+
|
|
414
|
+
Horizontal scroll container for a table, with the thin design-system scrollbar (4px track
|
|
415
|
+
that thickens and turns blue on hover). Accepts any `div` props. Keep header actions and
|
|
416
|
+
`TableEndAction` **outside** it so they don't scroll away on a wide table.
|
|
417
|
+
|
|
418
|
+
### TableEndAction Props
|
|
419
|
+
|
|
420
|
+
The full-width action bar that sits **below** a table — e.g. `+ Add New`. A `<button>`, not
|
|
421
|
+
a `<tr>`, so it is a sibling of `TableScroller` and stays put while the columns scroll. Accepts
|
|
422
|
+
any `button` props. Use `TableFooterButton` instead when the action should scroll with the grid.
|
|
423
|
+
|
|
401
424
|
### TableCheckbox Props
|
|
402
425
|
|
|
403
426
|
| Prop | Type | Default | Description |
|
|
@@ -434,15 +457,24 @@ interface TableHeadProps extends ThHTMLAttributes<HTMLTableCellElement> {
|
|
|
434
457
|
disabled?: boolean
|
|
435
458
|
sortType?: 'asc' | 'desc' | undefined
|
|
436
459
|
onSort?: () => void
|
|
460
|
+
sortLabel?: string
|
|
461
|
+
onResize?: (width: number) => void
|
|
462
|
+
contentClassName?: string
|
|
437
463
|
isDummy?: boolean
|
|
438
464
|
}
|
|
439
465
|
|
|
440
466
|
// TableCell types
|
|
441
467
|
interface TableCellProps extends TdHTMLAttributes<HTMLTableCellElement> {
|
|
442
468
|
isDummy?: boolean
|
|
469
|
+
minWidth?: number
|
|
470
|
+
fade?: boolean
|
|
443
471
|
childrenClassName?: string
|
|
444
472
|
}
|
|
445
473
|
|
|
474
|
+
// TableScroller / TableEndAction types
|
|
475
|
+
type TableScrollerProps = HTMLAttributes<HTMLDivElement>
|
|
476
|
+
type TableEndActionProps = ButtonHTMLAttributes<HTMLButtonElement>
|
|
477
|
+
|
|
446
478
|
// TableCheckbox types
|
|
447
479
|
interface TableCheckboxProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
448
480
|
id: string
|
|
@@ -795,7 +827,7 @@ Dates and amounts wrap awkwardly when the column is narrow. Add `whitespace-nowr
|
|
|
795
827
|
|
|
796
828
|
### `TableCell` force-wraps children — use `childrenClassName` to override
|
|
797
829
|
|
|
798
|
-
`TableCell` unconditionally wraps children in an inner `<div>` with `flex justify-start items-center gap-1 min-
|
|
830
|
+
`TableCell` unconditionally wraps children in an inner `<div>` with `flex justify-start items-center gap-1`, a `min-width` of 200px, `overflow-hidden`, and a fade-out gradient mask. Three common breakages:
|
|
799
831
|
|
|
800
832
|
1. **Empty-state rows don't center.** A `flex flex-col items-center` empty state ends up flush left because the outer wrapper's `justify-start` already decided alignment.
|
|
801
833
|
2. **Multi-line content is clipped** by `overflow-hidden` + the gradient mask.
|
|
@@ -807,7 +839,9 @@ Dates and amounts wrap awkwardly when the column is narrow. Add `whitespace-nowr
|
|
|
807
839
|
<TableRow>
|
|
808
840
|
<TableCell
|
|
809
841
|
colSpan={7}
|
|
810
|
-
|
|
842
|
+
minWidth={0}
|
|
843
|
+
fade={false}
|
|
844
|
+
childrenClassName="flex flex-col items-center justify-center gap-3 py-12 w-full text-content-presentation-global-secondary"
|
|
811
845
|
>
|
|
812
846
|
<i className="ri-inbox-line text-4xl opacity-60" />
|
|
813
847
|
<p className="typography-body-medium-regular">No data</p>
|
|
@@ -816,11 +850,14 @@ Dates and amounts wrap awkwardly when the column is narrow. Add `whitespace-nowr
|
|
|
816
850
|
</TableRow>
|
|
817
851
|
```
|
|
818
852
|
|
|
819
|
-
Key overrides
|
|
853
|
+
Key overrides:
|
|
820
854
|
|
|
821
|
-
- `flex flex-col` overrides the default `flex-row`
|
|
822
|
-
- `items-center justify-center` overrides `justify-start`
|
|
823
|
-
-
|
|
855
|
+
- `flex flex-col` on `childrenClassName` overrides the default `flex-row`
|
|
856
|
+
- `items-center justify-center` on `childrenClassName` overrides `justify-start`
|
|
857
|
+
- **`minWidth={0}`** clears the 200px floor. It is an inline style, so a class such as
|
|
858
|
+
`min-w-0` on `childrenClassName` cannot beat it — use the prop.
|
|
859
|
+
- **`fade={false}`** drops both the gradient mask and the `overflow-hidden` that clips
|
|
860
|
+
multi-line content.
|
|
824
861
|
|
|
825
862
|
## Accessibility
|
|
826
863
|
|