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.
Files changed (147) hide show
  1. package/apps/lib/components/DataViews/{badgeAdapter.ts → badge.ts} +2 -2
  2. package/apps/lib/components/DataViews/cell.tsx +324 -0
  3. package/apps/lib/components/DataViews/context.ts +144 -0
  4. package/apps/lib/components/DataViews/data-views.tsx +383 -0
  5. package/apps/lib/components/DataViews/filters/children.tsx +98 -0
  6. package/apps/lib/components/DataViews/filters/custom.tsx +34 -0
  7. package/apps/lib/components/DataViews/filters/filters.tsx +163 -0
  8. package/apps/lib/components/DataViews/filters/index.ts +4 -0
  9. package/apps/lib/components/DataViews/filters/labelled.tsx +20 -0
  10. package/apps/lib/components/DataViews/filters/presets.tsx +65 -0
  11. package/apps/lib/components/DataViews/filters/summary.tsx +65 -0
  12. package/apps/lib/components/DataViews/filters/sync.tsx +35 -0
  13. package/apps/lib/components/DataViews/filters/values.ts +173 -0
  14. package/apps/lib/components/DataViews/header.tsx +217 -0
  15. package/apps/lib/components/DataViews/hooks/index.ts +5 -0
  16. package/apps/lib/components/DataViews/hooks/useActiveRow.ts +22 -0
  17. package/apps/lib/components/DataViews/hooks/useControllable.ts +52 -0
  18. package/apps/lib/components/DataViews/index.ts +74 -26
  19. package/apps/lib/components/DataViews/panel/columns.tsx +153 -0
  20. package/apps/lib/components/DataViews/panel/controls.tsx +106 -0
  21. package/apps/lib/components/DataViews/panel/index.ts +3 -0
  22. package/apps/lib/components/DataViews/panel/panel.tsx +164 -0
  23. package/apps/lib/components/DataViews/panel/saved-views.tsx +67 -0
  24. package/apps/lib/components/DataViews/panel/section.tsx +79 -0
  25. package/apps/lib/components/DataViews/panel/sort.tsx +42 -0
  26. package/apps/lib/components/DataViews/panel/tab.tsx +31 -0
  27. package/apps/lib/components/DataViews/slots.ts +63 -0
  28. package/apps/lib/components/DataViews/states.tsx +38 -0
  29. package/apps/lib/components/DataViews/types.ts +485 -178
  30. package/apps/lib/components/DataViews/views/board-view.tsx +379 -0
  31. package/apps/lib/components/DataViews/views/card-rows.tsx +36 -0
  32. package/apps/lib/components/DataViews/views/inbox-view.tsx +257 -0
  33. package/apps/lib/components/DataViews/views/pane-views.tsx +192 -0
  34. package/apps/lib/components/DataViews/views/table-view.tsx +426 -0
  35. package/apps/lib/components/DataViews/views/tree-view.tsx +365 -0
  36. package/apps/lib/components/FormBuilder/context.ts +20 -6
  37. package/apps/lib/components/FormBuilder/field-kind.ts +28 -0
  38. package/apps/lib/components/FormBuilder/fields/DateField.tsx +3 -3
  39. package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +7 -6
  40. package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +30 -4
  41. package/apps/lib/components/FormBuilder/fields/SelectField.tsx +7 -7
  42. package/apps/lib/components/FormBuilder/fields/TableField.tsx +80 -52
  43. package/apps/lib/components/FormBuilder/fields/TextField.tsx +9 -9
  44. package/apps/lib/components/FormBuilder/form-builder.tsx +66 -6
  45. package/apps/lib/components/FormBuilder/index.ts +3 -1
  46. package/apps/lib/components/FormBuilder/types.ts +40 -0
  47. package/apps/lib/components/Input.tsx +3 -0
  48. package/apps/lib/components/SearchableTable.tsx +5 -4
  49. package/apps/lib/components/SectionBlock.tsx +58 -11
  50. package/apps/lib/components/Select.tsx +3 -1
  51. package/apps/lib/components/TabSwitch.tsx +16 -4
  52. package/apps/lib/components/Table.tsx +265 -67
  53. package/apps/lib/components/TreeFolder/TreeFolder.tsx +6 -3
  54. package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +16 -14
  55. package/apps/lib/components/TreeFolder/index.ts +1 -1
  56. package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +70 -207
  57. package/apps/lib/hooks/useDragDrop.tsx +365 -0
  58. package/apps/lib/hooks/useInfiniteScroll.ts +108 -0
  59. package/apps/lib/registry.json +159 -4
  60. package/apps/lib/tsconfig.tsbuildinfo +1 -1
  61. package/apps/lib/utils/dataViews/path.ts +67 -0
  62. package/apps/lib/utils/dataViews/query.ts +73 -0
  63. package/apps/lib/utils/dataViews/types.ts +187 -0
  64. package/docs/components/breadcrumb.md +1 -1
  65. package/docs/components/button-group.md +1 -1
  66. package/docs/components/button.md +1 -1
  67. package/docs/components/card.md +1 -1
  68. package/docs/components/checkbox.md +1 -1
  69. package/docs/components/data-views/backend-response.md +324 -0
  70. package/docs/components/data-views/examples/a11y-rtl.md +250 -0
  71. package/docs/components/data-views/examples/api-orders-route.md +130 -0
  72. package/docs/components/data-views/examples/fields.md +362 -0
  73. package/docs/components/data-views/examples/filters.md +308 -0
  74. package/docs/components/data-views/examples/inbox-routing.md +218 -0
  75. package/docs/components/data-views/examples/index.md +29 -0
  76. package/docs/components/data-views/examples/overview.md +244 -0
  77. package/docs/components/data-views/examples/panel.md +212 -0
  78. package/docs/components/data-views/examples/scale.md +231 -0
  79. package/docs/components/data-views/examples/server-side.md +210 -0
  80. package/docs/components/data-views/examples/state.md +250 -0
  81. package/docs/components/data-views/examples/tree-custom.md +388 -0
  82. package/docs/components/data-views/examples/view-registry.md +313 -0
  83. package/docs/components/data-views/examples/views.md +534 -0
  84. package/docs/components/data-views/guide.md +405 -0
  85. package/docs/components/data-views/index.md +1504 -0
  86. package/docs/components/data-views/migration.md +79 -0
  87. package/docs/components/date-picker.md +0 -1
  88. package/docs/components/form-builder.md +19 -8
  89. package/docs/components/form-renderer.md +2 -1
  90. package/docs/components/form.md +1 -1
  91. package/docs/components/input-field.md +1 -1
  92. package/docs/components/input-otp.md +1 -1
  93. package/docs/components/input.md +1 -1
  94. package/docs/components/labeled-check-box.md +1 -1
  95. package/docs/components/labeled-radio.md +1 -1
  96. package/docs/components/radio-card.md +1 -1
  97. package/docs/components/radio.md +1 -1
  98. package/docs/components/search-field.md +1 -1
  99. package/docs/components/section-block.md +79 -3
  100. package/docs/components/select.md +1 -1
  101. package/docs/components/simple-select.md +1 -1
  102. package/docs/components/switch.md +1 -1
  103. package/docs/components/tab-switch.md +1 -1
  104. package/docs/components/table.md +45 -8
  105. package/docs/components/text-editor.md +1 -1
  106. package/docs/components/textarea.md +1 -1
  107. package/docs/components/toggle-button.md +1 -1
  108. package/docs/components/toggle.md +1 -1
  109. package/docs/components/tree-folder.md +110 -0
  110. package/docs/how-to/forms-with-form-builder.md +6 -4
  111. package/docs/reference/components.md +16 -6
  112. package/docs/tutorials/component-composition.md +11 -13
  113. package/package.json +3 -2
  114. package/apps/lib/components/DataViews/DataViewRadio.tsx +0 -49
  115. package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +0 -393
  116. package/apps/lib/components/DataViews/DataViewsHeader.tsx +0 -207
  117. package/apps/lib/components/DataViews/DataViewsLayout.tsx +0 -332
  118. package/apps/lib/components/DataViews/FilterPanel.tsx +0 -493
  119. package/apps/lib/components/DataViews/HeaderSearch.tsx +0 -93
  120. package/apps/lib/components/DataViews/InboxView.tsx +0 -463
  121. package/apps/lib/components/DataViews/InboxViewCard.tsx +0 -127
  122. package/apps/lib/components/DataViews/KanbanView.tsx +0 -336
  123. package/apps/lib/components/DataViews/PanelControls.tsx +0 -39
  124. package/apps/lib/components/DataViews/SettingsPanel.tsx +0 -279
  125. package/apps/lib/components/DataViews/TableView.tsx +0 -212
  126. package/apps/lib/components/DataViews/TreeView.tsx +0 -364
  127. package/apps/lib/components/DataViews/fieldRenderers.tsx +0 -299
  128. package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +0 -87
  129. package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +0 -120
  130. package/apps/lib/components/DataViews/filters/PresetChips.tsx +0 -45
  131. package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +0 -165
  132. package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +0 -50
  133. package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +0 -74
  134. package/apps/lib/hooks/useDataViewsState.ts +0 -175
  135. package/apps/lib/utils/dataViews/columnUtils.ts +0 -132
  136. package/apps/lib/utils/dataViews/fieldUtils.ts +0 -197
  137. package/apps/lib/utils/dataViews/nestedDataUtils.tsx +0 -371
  138. package/apps/lib/utils/dataViews/pathUtils.ts +0 -139
  139. package/apps/lib/utils/dataViews/rangeUtils.ts +0 -234
  140. package/apps/lib/utils/dataViews/treeUtils.ts +0 -396
  141. package/docs/components/data-views-config-panel.md +0 -208
  142. package/docs/components/data-views-layout.md +0 -291
  143. package/docs/components/inbox-view.md +0 -170
  144. package/docs/components/kanban-view.md +0 -135
  145. package/docs/components/table-view.md +0 -141
  146. package/docs/components/tree-view.md +0 -147
  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` / `.SearchableSelect` (`options`, async props) | `SearchableSelect` | `string` |
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`, `formatView`) | your control | anything |
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 **inside a
110
- `SectionBlock`**, so place it as a **top-level child** of the form (not inside a `FormBuilder.Section`).
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>`. The section header carries the actions: a **Add New** button (also repeated as the
113
- bottom footer) and a **Delete Row** button that's disabled until rows are checkbox-selected. Rows support
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`. `FormBuilder.Submit` is a loading-aware submit button. It
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` does **not** forward `summary` use `FormDrawer` directly when you need one.
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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Form
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, validation, react-hook-form, accessible, compound]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: InputField
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, input, field, popover, tooltip, compound, accessible]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: InputOTP
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, otp, input, verification, authentication, accessible]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Input
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, input, text, field, accessible, compound]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: LabeledCheckBox
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, checkbox, label, selection, accessible, compound]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: LabeledRadio
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, radio, label, selection, accessible, compound]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: RadioCard
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, radio, card, selection, compound, accessible]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Radio
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, radio, selection, radix-ui, accessible, group, controlled]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: SearchField
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, search, input, field, system-style, glassmorphism]
@@ -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.0
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
- - **Default width**: The component ships with `w-[1100px]`. Override via `containerClassName="w-full"` (or any specific width) for narrower containers.
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 | Default width is `w-[1100px]`. Override with `containerClassName="w-full"` or a smaller fixed width. |
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). |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Select
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, select, dropdown, accessible, radix-ui]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: SimpleSelect
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, select, dropdown, custom, system-style, accessible]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Switch
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, switch, toggle, radix-ui, accessible, controlled]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: TabSwitch
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/navigation
6
6
  tags: [tab-switch, segmented-control, view-switcher, toggle, list-cards, pills]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Table
3
- version: 2.4.0
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` | - | Additional CSS classes |
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-w-[200px] overflow-hidden` plus a fade-out gradient mask. Three common breakages:
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
- childrenClassName="flex flex-col items-center justify-center gap-3 py-12 w-full min-w-0 text-content-presentation-global-secondary"
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 on `childrenClassName`:
853
+ Key overrides:
820
854
 
821
- - `flex flex-col` overrides the default `flex-row`
822
- - `items-center justify-center` overrides `justify-start`
823
- - `w-full min-w-0` overrides the hardcoded `min-w-[200px]`
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
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: TextEditor
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/editors
6
6
  tags: [editor, rich-text, block-editor, editorjs, markdown, rtl, accessible]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Textarea
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, textarea, multiline, input, field, accessible, auto-resize]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ToggleButton
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/buttons
6
6
  tags: [toggle, button, pressed, radix-ui, accessible, variants]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Toggle
3
- version: 2.4.0
3
+ version: 2.4.5
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, toggle, button, radix-ui, accessible, variants]