torch-glare 2.5.6 → 2.6.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/README.md +4 -3
- package/dist/bin/index.js +9 -24
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts +2 -2
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +4 -70
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/hook.d.ts +5 -4
- package/dist/src/commands/hook.d.ts.map +1 -1
- package/dist/src/commands/hook.js +7 -75
- package/dist/src/commands/hook.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/layout.d.ts +5 -4
- package/dist/src/commands/layout.d.ts.map +1 -1
- package/dist/src/commands/layout.js +7 -75
- package/dist/src/commands/layout.js.map +1 -1
- package/dist/src/commands/provider.d.ts +5 -4
- package/dist/src/commands/provider.d.ts.map +1 -1
- package/dist/src/commands/provider.js +7 -75
- package/dist/src/commands/provider.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +78 -43
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/utils.d.ts +5 -4
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +7 -80
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/addFromRegistry.d.ts +16 -0
- package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
- package/dist/src/shared/addFromRegistry.js +88 -0
- package/dist/src/shared/addFromRegistry.js.map +1 -0
- package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
- package/dist/src/shared/getInstallCommand.js +5 -0
- package/dist/src/shared/getInstallCommand.js.map +1 -1
- package/dist/src/shared/installDependencies.d.ts +0 -10
- package/dist/src/shared/installDependencies.d.ts.map +1 -1
- package/dist/src/shared/installDependencies.js +0 -17
- package/dist/src/shared/installDependencies.js.map +1 -1
- package/dist/src/shared/installFromPlan.d.ts +7 -5
- package/dist/src/shared/installFromPlan.d.ts.map +1 -1
- package/dist/src/shared/installFromPlan.js +103 -36
- package/dist/src/shared/installFromPlan.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +12 -3
- package/dist/src/shared/loadRegistry.d.ts.map +1 -1
- package/dist/src/shared/loadRegistry.js +19 -20
- package/dist/src/shared/loadRegistry.js.map +1 -1
- package/dist/src/shared/registryClient.d.ts +19 -0
- package/dist/src/shared/registryClient.d.ts.map +1 -0
- package/dist/src/shared/registryClient.js +128 -0
- package/dist/src/shared/registryClient.js.map +1 -0
- package/dist/src/shared/resolveEntry.d.ts +10 -7
- package/dist/src/shared/resolveEntry.d.ts.map +1 -1
- package/dist/src/shared/resolveEntry.js +18 -13
- package/dist/src/shared/resolveEntry.js.map +1 -1
- package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
- package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
- package/dist/src/shared/suggestOtherCommand.js +29 -23
- package/dist/src/shared/suggestOtherCommand.js.map +1 -1
- package/dist/src/types/main.d.ts +31 -2
- package/dist/src/types/main.d.ts.map +1 -1
- package/package.json +6 -11
- package/apps/lib/components/ActionButton.tsx +0 -93
- package/apps/lib/components/ActionsGroup.tsx +0 -27
- package/apps/lib/components/AlertDialog.tsx +0 -204
- package/apps/lib/components/Avatar.tsx +0 -46
- package/apps/lib/components/Badge.tsx +0 -250
- package/apps/lib/components/BadgeField.tsx +0 -403
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -325
- package/apps/lib/components/ButtonGroup.tsx +0 -190
- package/apps/lib/components/Calendar.tsx +0 -115
- package/apps/lib/components/Card.tsx +0 -95
- package/apps/lib/components/Checkbox.tsx +0 -42
- package/apps/lib/components/ColorPicker.tsx +0 -441
- package/apps/lib/components/ConclusionHeader.tsx +0 -148
- package/apps/lib/components/ContextMenu.tsx +0 -571
- package/apps/lib/components/CountBadge.tsx +0 -52
- package/apps/lib/components/DataTable.tsx +0 -213
- package/apps/lib/components/DataViews/badge.ts +0 -49
- package/apps/lib/components/DataViews/cell.tsx +0 -324
- package/apps/lib/components/DataViews/context.ts +0 -144
- package/apps/lib/components/DataViews/data-views.tsx +0 -395
- package/apps/lib/components/DataViews/filters/children.tsx +0 -98
- package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
- package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
- package/apps/lib/components/DataViews/filters/index.ts +0 -4
- package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
- package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
- package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
- package/apps/lib/components/DataViews/filters/values.ts +0 -173
- package/apps/lib/components/DataViews/header.tsx +0 -220
- package/apps/lib/components/DataViews/hooks/index.ts +0 -5
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
- package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
- package/apps/lib/components/DataViews/index.ts +0 -88
- package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
- package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
- package/apps/lib/components/DataViews/panel/index.ts +0 -3
- package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
- package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
- package/apps/lib/components/DataViews/panel/section.tsx +0 -81
- package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
- package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
- package/apps/lib/components/DataViews/slots.ts +0 -72
- package/apps/lib/components/DataViews/states.tsx +0 -73
- package/apps/lib/components/DataViews/types.ts +0 -510
- package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
- package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
- package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
- package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
- package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
- package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
- package/apps/lib/components/DatePicker.tsx +0 -232
- package/apps/lib/components/Dialog.tsx +0 -116
- package/apps/lib/components/Divider.tsx +0 -28
- package/apps/lib/components/Drawer.tsx +0 -451
- package/apps/lib/components/DropdownMenu.tsx +0 -554
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -85
- package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -168
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -114
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
- package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
- package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
- package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
- package/apps/lib/components/FormBuilder/index.ts +0 -31
- package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
- package/apps/lib/components/FormBuilder/submit.tsx +0 -67
- package/apps/lib/components/FormBuilder/types.ts +0 -316
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -250
- package/apps/lib/components/FormRenderer/detail.tsx +0 -256
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -358
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -17
- package/apps/lib/components/FormRenderer/notch-action.tsx +0 -64
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -393
- package/apps/lib/components/FormRenderer/types.ts +0 -115
- package/apps/lib/components/FormSummary.tsx +0 -282
- package/apps/lib/components/HeaderBar.tsx +0 -117
- package/apps/lib/components/ImageAttachment.tsx +0 -209
- package/apps/lib/components/InnerLabelField.tsx +0 -154
- package/apps/lib/components/Input.tsx +0 -224
- package/apps/lib/components/InputField.tsx +0 -147
- package/apps/lib/components/InputOTP.tsx +0 -84
- package/apps/lib/components/Label.tsx +0 -129
- package/apps/lib/components/LabelField.tsx +0 -76
- package/apps/lib/components/LabeledCheckBox.tsx +0 -51
- package/apps/lib/components/LabeledRadio.tsx +0 -51
- package/apps/lib/components/LinkButton.tsx +0 -94
- package/apps/lib/components/LoginButton.tsx +0 -51
- package/apps/lib/components/PasswordLevel.tsx +0 -58
- package/apps/lib/components/Popover.tsx +0 -312
- package/apps/lib/components/ProfileMenu.tsx +0 -85
- package/apps/lib/components/Radio.tsx +0 -59
- package/apps/lib/components/RadioCard.tsx +0 -50
- package/apps/lib/components/ScrollArea.tsx +0 -54
- package/apps/lib/components/SearchField.tsx +0 -62
- package/apps/lib/components/SearchableSelect.tsx +0 -318
- package/apps/lib/components/SearchableTable.tsx +0 -344
- package/apps/lib/components/SearchableTree.tsx +0 -485
- package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
- package/apps/lib/components/SectionBlock.tsx +0 -168
- package/apps/lib/components/Select.tsx +0 -347
- package/apps/lib/components/SimpleSelect.tsx +0 -225
- package/apps/lib/components/Skeleton.tsx +0 -12
- package/apps/lib/components/SlideDatePicker.tsx +0 -255
- package/apps/lib/components/SpinLoading.tsx +0 -174
- package/apps/lib/components/Stepper.tsx +0 -480
- package/apps/lib/components/Switch.tsx +0 -82
- package/apps/lib/components/TabFormItem.tsx +0 -153
- package/apps/lib/components/TabSwitch.tsx +0 -172
- package/apps/lib/components/Table.tsx +0 -597
- package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
- package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
- package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
- package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
- package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
- package/apps/lib/components/TextEditor/index.ts +0 -7
- package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
- package/apps/lib/components/Textarea.tsx +0 -117
- package/apps/lib/components/Timeline.tsx +0 -263
- package/apps/lib/components/Toast.tsx +0 -87
- package/apps/lib/components/Toggle.tsx +0 -125
- package/apps/lib/components/ToggleButton.tsx +0 -140
- package/apps/lib/components/Tooltip.tsx +0 -116
- package/apps/lib/components/TransparentLabel.tsx +0 -71
- package/apps/lib/components/TreeDropDown.tsx +0 -115
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
- package/apps/lib/components/TreeFolder/icons.tsx +0 -60
- package/apps/lib/components/TreeFolder/index.ts +0 -24
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
- package/apps/lib/components/TreeFolder/types.ts +0 -77
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
- package/apps/lib/hooks/useActiveTreeItem.ts +0 -61
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useHtmlDir.ts +0 -31
- package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
- package/apps/lib/hooks/useIsMobile.ts +0 -21
- package/apps/lib/hooks/useResize.ts +0 -67
- package/apps/lib/hooks/useTagSelection.ts +0 -300
- package/apps/lib/layouts/CNLayout.tsx +0 -372
- package/apps/lib/layouts/DataViewCard.tsx +0 -62
- package/apps/lib/layouts/FieldSection.tsx +0 -91
- package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
- package/apps/lib/providers/ThemeProvider.tsx +0 -84
- package/apps/lib/registry.json +0 -1217
- package/apps/lib/tsconfig.json +0 -9
- package/apps/lib/tsconfig.tsbuildinfo +0 -1
- package/apps/lib/utils/cn.ts +0 -6
- package/apps/lib/utils/color.ts +0 -175
- package/apps/lib/utils/dataViews/path.ts +0 -67
- package/apps/lib/utils/dataViews/query.ts +0 -73
- package/apps/lib/utils/dataViews/types.ts +0 -187
- package/apps/lib/utils/dateFormat.ts +0 -108
- package/apps/lib/utils/resize.ts +0 -31
- package/apps/lib/utils/scroller.ts +0 -26
- package/apps/lib/utils/types.ts +0 -16
- package/docs/BLOCKS.md +0 -129
- package/docs/CHANGELOG-1.1.16.md +0 -108
- package/docs/Cover.png +0 -0
- package/docs/README.md +0 -215
- package/docs/components/action-button.md +0 -638
- package/docs/components/actions-group.md +0 -708
- package/docs/components/alert-dialog.md +0 -920
- package/docs/components/avatar.md +0 -709
- package/docs/components/badge-field.md +0 -738
- package/docs/components/badge.md +0 -301
- package/docs/components/breadcrumb.md +0 -930
- package/docs/components/button-group.md +0 -650
- package/docs/components/button.md +0 -639
- package/docs/components/calendar.md +0 -555
- package/docs/components/card.md +0 -622
- package/docs/components/chart-block-tool.md +0 -129
- package/docs/components/checkbox.md +0 -699
- package/docs/components/cn-layout.md +0 -854
- package/docs/components/color-picker.md +0 -101
- package/docs/components/conclusion-header.md +0 -80
- package/docs/components/context-menu.md +0 -483
- package/docs/components/count-badge.md +0 -560
- package/docs/components/data-table.md +0 -854
- package/docs/components/data-views/backend-response.md +0 -324
- package/docs/components/data-views/examples/a11y-rtl.md +0 -250
- package/docs/components/data-views/examples/api-orders-route.md +0 -130
- package/docs/components/data-views/examples/fields.md +0 -362
- package/docs/components/data-views/examples/filters.md +0 -307
- package/docs/components/data-views/examples/inbox-routing.md +0 -218
- package/docs/components/data-views/examples/index.md +0 -29
- package/docs/components/data-views/examples/overview.md +0 -244
- package/docs/components/data-views/examples/panel.md +0 -212
- package/docs/components/data-views/examples/scale.md +0 -231
- package/docs/components/data-views/examples/server-side.md +0 -210
- package/docs/components/data-views/examples/state.md +0 -250
- package/docs/components/data-views/examples/tree-custom.md +0 -388
- package/docs/components/data-views/examples/view-registry.md +0 -313
- package/docs/components/data-views/examples/views.md +0 -534
- package/docs/components/data-views/guide.md +0 -405
- package/docs/components/data-views/index.md +0 -1521
- package/docs/components/data-views/migration.md +0 -81
- package/docs/components/date-picker.md +0 -857
- package/docs/components/dialog.md +0 -929
- package/docs/components/divider.md +0 -766
- package/docs/components/drawer.md +0 -654
- package/docs/components/dropdown-menu.md +0 -668
- package/docs/components/field-hint.md +0 -898
- package/docs/components/field-section.md +0 -781
- package/docs/components/form-builder.md +0 -284
- package/docs/components/form-renderer.md +0 -396
- package/docs/components/form-summary.md +0 -138
- package/docs/components/form.md +0 -785
- package/docs/components/header-bar.md +0 -188
- package/docs/components/image-attachment.md +0 -906
- package/docs/components/inner-label-field.md +0 -819
- package/docs/components/input-field.md +0 -623
- package/docs/components/input-otp.md +0 -756
- package/docs/components/input.md +0 -634
- package/docs/components/label-field.md +0 -770
- package/docs/components/label.md +0 -761
- package/docs/components/labeled-check-box.md +0 -642
- package/docs/components/labeled-radio.md +0 -796
- package/docs/components/link-button.md +0 -685
- package/docs/components/login-button.md +0 -872
- package/docs/components/password-level.md +0 -803
- package/docs/components/popover.md +0 -649
- package/docs/components/profile-menu.md +0 -656
- package/docs/components/radio-card.md +0 -801
- package/docs/components/radio.md +0 -735
- package/docs/components/scroll-area.md +0 -691
- package/docs/components/search-field.md +0 -702
- package/docs/components/searchable-select.md +0 -368
- package/docs/components/searchable-table.md +0 -438
- package/docs/components/searchable-tree-dialog.md +0 -190
- package/docs/components/searchable-tree.md +0 -200
- package/docs/components/section-block.md +0 -483
- package/docs/components/select.md +0 -709
- package/docs/components/simple-select.md +0 -741
- package/docs/components/skeleton.md +0 -706
- package/docs/components/slide-date-picker.md +0 -837
- package/docs/components/spin-loading.md +0 -696
- package/docs/components/stepper.md +0 -316
- package/docs/components/switch.md +0 -770
- package/docs/components/tab-form-item.md +0 -773
- package/docs/components/tab-switch.md +0 -170
- package/docs/components/table-dnd-wrapper.md +0 -107
- package/docs/components/table.md +0 -1088
- package/docs/components/text-editor.md +0 -735
- package/docs/components/textarea.md +0 -681
- package/docs/components/timeline.md +0 -254
- package/docs/components/toast.md +0 -773
- package/docs/components/toggle-button.md +0 -643
- package/docs/components/toggle.md +0 -882
- package/docs/components/tooltip.md +0 -513
- package/docs/components/transparent-label.md +0 -721
- package/docs/components/tree-drop-down.md +0 -740
- package/docs/components/tree-folder.md +0 -110
- package/docs/components/tree-sub-layout.md +0 -707
- package/docs/explanation/architecture.md +0 -54
- package/docs/explanation/design-system.md +0 -52
- package/docs/how-to/form-and-list-recipes.md +0 -386
- package/docs/how-to/forms-with-form-builder.md +0 -472
- package/docs/how-to/guides.md +0 -1027
- package/docs/migration/changelog.md +0 -60
- package/docs/migration/form-builder-2.5.2.md +0 -113
- package/docs/reference/cli.md +0 -112
- package/docs/reference/components.md +0 -572
- package/docs/reference/hooks.md +0 -1523
- package/docs/reference/providers.md +0 -866
- package/docs/reference/tailwind-plugins.md +0 -942
- package/docs/reference/theme.md +0 -85
- package/docs/reference/types.md +0 -1016
- package/docs/reference/utilities.md +0 -726
- package/docs/tutorials/building-first-form.md +0 -846
- package/docs/tutorials/component-composition.md +0 -882
- package/docs/tutorials/getting-started.md +0 -302
- package/docs/tutorials/theming-basics.md +0 -785
package/docs/components/table.md
DELETED
|
@@ -1,1088 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Table
|
|
3
|
-
version: 2.4.5
|
|
4
|
-
status: stable
|
|
5
|
-
category: components/data-display
|
|
6
|
-
tags: [table, data, grid, sortable, resizable, accessible, compound]
|
|
7
|
-
last-reviewed: 2024-11-05
|
|
8
|
-
bundle-size: 4.2kb
|
|
9
|
-
dependencies:
|
|
10
|
-
- "class-variance-authority": "^0.7.0"
|
|
11
|
-
- "@/components/Button": "internal"
|
|
12
|
-
- "@/components/Checkbox": "internal"
|
|
13
|
-
- "@/hooks/useResize": "internal"
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
# Table
|
|
17
|
-
|
|
18
|
-
> A comprehensive data table component with resizable columns, sortable headers, row states, and compound architecture. Built for complex data presentation with accessibility and performance in mind.
|
|
19
|
-
|
|
20
|
-
## Installation
|
|
21
|
-
|
|
22
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
23
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npx torch-glare@latest init
|
|
27
|
-
npx torch-glare@latest add Table
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
`add` also copies any components, hooks, and utilities that `Table` depends on.
|
|
31
|
-
|
|
32
|
-
## Import
|
|
33
|
-
|
|
34
|
-
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
35
|
-
|
|
36
|
-
```tsx
|
|
37
|
-
import { Table } from "@/components/Table";
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Quick Examples
|
|
41
|
-
|
|
42
|
-
### Basic Table
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/Table'
|
|
46
|
-
|
|
47
|
-
function BasicTable() {
|
|
48
|
-
return (
|
|
49
|
-
<Table>
|
|
50
|
-
<TableHeader>
|
|
51
|
-
<TableRow>
|
|
52
|
-
<TableHead>Name</TableHead>
|
|
53
|
-
<TableHead>Email</TableHead>
|
|
54
|
-
<TableHead>Status</TableHead>
|
|
55
|
-
</TableRow>
|
|
56
|
-
</TableHeader>
|
|
57
|
-
<TableBody>
|
|
58
|
-
<TableRow>
|
|
59
|
-
<TableCell>John Doe</TableCell>
|
|
60
|
-
<TableCell>john@example.com</TableCell>
|
|
61
|
-
<TableCell>Active</TableCell>
|
|
62
|
-
</TableRow>
|
|
63
|
-
<TableRow>
|
|
64
|
-
<TableCell>Jane Smith</TableCell>
|
|
65
|
-
<TableCell>jane@example.com</TableCell>
|
|
66
|
-
<TableCell>Pending</TableCell>
|
|
67
|
-
</TableRow>
|
|
68
|
-
</TableBody>
|
|
69
|
-
</Table>
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Sortable Table
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
function SortableTable() {
|
|
78
|
-
const [sortField, setSortField] = useState<string | null>(null)
|
|
79
|
-
const [sortType, setSortType] = useState<'asc' | 'desc' | undefined>()
|
|
80
|
-
const [data, setData] = useState(initialData)
|
|
81
|
-
|
|
82
|
-
const handleSort = (field: string) => {
|
|
83
|
-
const newSortType = sortType === 'asc' ? 'desc' : 'asc'
|
|
84
|
-
setSortType(newSortType)
|
|
85
|
-
setSortField(field)
|
|
86
|
-
|
|
87
|
-
// Sort data
|
|
88
|
-
const sorted = [...data].sort((a, b) => {
|
|
89
|
-
if (newSortType === 'asc') {
|
|
90
|
-
return a[field] > b[field] ? 1 : -1
|
|
91
|
-
}
|
|
92
|
-
return a[field] < b[field] ? 1 : -1
|
|
93
|
-
})
|
|
94
|
-
setData(sorted)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return (
|
|
98
|
-
<Table>
|
|
99
|
-
<TableHeader>
|
|
100
|
-
<TableRow>
|
|
101
|
-
<TableHead
|
|
102
|
-
sortType={sortField === 'name' ? sortType : undefined}
|
|
103
|
-
onSort={() => handleSort('name')}
|
|
104
|
-
>
|
|
105
|
-
Name
|
|
106
|
-
</TableHead>
|
|
107
|
-
<TableHead
|
|
108
|
-
sortType={sortField === 'date' ? sortType : undefined}
|
|
109
|
-
onSort={() => handleSort('date')}
|
|
110
|
-
>
|
|
111
|
-
Date
|
|
112
|
-
</TableHead>
|
|
113
|
-
<TableHead
|
|
114
|
-
sortType={sortField === 'amount' ? sortType : undefined}
|
|
115
|
-
onSort={() => handleSort('amount')}
|
|
116
|
-
>
|
|
117
|
-
Amount
|
|
118
|
-
</TableHead>
|
|
119
|
-
</TableRow>
|
|
120
|
-
</TableHeader>
|
|
121
|
-
<TableBody>
|
|
122
|
-
{data.map((item) => (
|
|
123
|
-
<TableRow key={item.id}>
|
|
124
|
-
<TableCell>{item.name}</TableCell>
|
|
125
|
-
<TableCell>{item.date}</TableCell>
|
|
126
|
-
<TableCell>${item.amount}</TableCell>
|
|
127
|
-
</TableRow>
|
|
128
|
-
))}
|
|
129
|
-
</TableBody>
|
|
130
|
-
</Table>
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Table with Row States
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
function TableWithStates() {
|
|
139
|
-
const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set())
|
|
140
|
-
|
|
141
|
-
return (
|
|
142
|
-
<Table>
|
|
143
|
-
<TableHeader>
|
|
144
|
-
<TableRow>
|
|
145
|
-
<TableHead>Item</TableHead>
|
|
146
|
-
<TableHead>Status</TableHead>
|
|
147
|
-
<TableHead>Action</TableHead>
|
|
148
|
-
</TableRow>
|
|
149
|
-
</TableHeader>
|
|
150
|
-
<TableBody>
|
|
151
|
-
<TableRow state="add">
|
|
152
|
-
<TableCell>New Item</TableCell>
|
|
153
|
-
<TableCell>Added</TableCell>
|
|
154
|
-
<TableCell>Review</TableCell>
|
|
155
|
-
</TableRow>
|
|
156
|
-
<TableRow state="update">
|
|
157
|
-
<TableCell>Updated Item</TableCell>
|
|
158
|
-
<TableCell>Modified</TableCell>
|
|
159
|
-
<TableCell>Confirm</TableCell>
|
|
160
|
-
</TableRow>
|
|
161
|
-
<TableRow state="delete">
|
|
162
|
-
<TableCell>Deleted Item</TableCell>
|
|
163
|
-
<TableCell>Removed</TableCell>
|
|
164
|
-
<TableCell>Undo</TableCell>
|
|
165
|
-
</TableRow>
|
|
166
|
-
<TableRow state="selected">
|
|
167
|
-
<TableCell>Selected Item</TableCell>
|
|
168
|
-
<TableCell>Active</TableCell>
|
|
169
|
-
<TableCell>Edit</TableCell>
|
|
170
|
-
</TableRow>
|
|
171
|
-
</TableBody>
|
|
172
|
-
</Table>
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Table with Checkbox Selection
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
function SelectableTable() {
|
|
181
|
-
const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set())
|
|
182
|
-
const [data] = useState(items)
|
|
183
|
-
|
|
184
|
-
const toggleRow = (id: string) => {
|
|
185
|
-
const newSet = new Set(selectedRows)
|
|
186
|
-
if (newSet.has(id)) {
|
|
187
|
-
newSet.delete(id)
|
|
188
|
-
} else {
|
|
189
|
-
newSet.add(id)
|
|
190
|
-
}
|
|
191
|
-
setSelectedRows(newSet)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const toggleAll = () => {
|
|
195
|
-
if (selectedRows.size === data.length) {
|
|
196
|
-
setSelectedRows(new Set())
|
|
197
|
-
} else {
|
|
198
|
-
setSelectedRows(new Set(data.map(d => d.id)))
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return (
|
|
203
|
-
<Table>
|
|
204
|
-
<TableHeader>
|
|
205
|
-
<TableRow>
|
|
206
|
-
<TableHead size="S">
|
|
207
|
-
<TableCheckbox
|
|
208
|
-
id="select-all"
|
|
209
|
-
checked={
|
|
210
|
-
selectedRows.size === data.length
|
|
211
|
-
? true
|
|
212
|
-
: selectedRows.size > 0
|
|
213
|
-
? 'indeterminate'
|
|
214
|
-
: false
|
|
215
|
-
}
|
|
216
|
-
onCheckedChange={toggleAll}
|
|
217
|
-
/>
|
|
218
|
-
</TableHead>
|
|
219
|
-
<TableHead>Name</TableHead>
|
|
220
|
-
<TableHead>Email</TableHead>
|
|
221
|
-
</TableRow>
|
|
222
|
-
</TableHeader>
|
|
223
|
-
<TableBody>
|
|
224
|
-
{data.map((item) => (
|
|
225
|
-
<TableRow
|
|
226
|
-
key={item.id}
|
|
227
|
-
state={selectedRows.has(item.id) ? 'selected' : undefined}
|
|
228
|
-
>
|
|
229
|
-
<TableCell>
|
|
230
|
-
<TableCheckbox
|
|
231
|
-
id={`select-${item.id}`}
|
|
232
|
-
checked={selectedRows.has(item.id)}
|
|
233
|
-
onCheckedChange={() => toggleRow(item.id)}
|
|
234
|
-
/>
|
|
235
|
-
</TableCell>
|
|
236
|
-
<TableCell>{item.name}</TableCell>
|
|
237
|
-
<TableCell>{item.email}</TableCell>
|
|
238
|
-
</TableRow>
|
|
239
|
-
))}
|
|
240
|
-
</TableBody>
|
|
241
|
-
</Table>
|
|
242
|
-
)
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Table with Themed Styles
|
|
247
|
-
|
|
248
|
-
```typescript
|
|
249
|
-
function ThemedTable() {
|
|
250
|
-
return (
|
|
251
|
-
<>
|
|
252
|
-
<Table theme="light">
|
|
253
|
-
<TableCaption>Light Theme Table</TableCaption>
|
|
254
|
-
<TableHeader>
|
|
255
|
-
<TableRow>
|
|
256
|
-
<TableHead>Column 1</TableHead>
|
|
257
|
-
<TableHead>Column 2</TableHead>
|
|
258
|
-
</TableRow>
|
|
259
|
-
</TableHeader>
|
|
260
|
-
<TableBody>
|
|
261
|
-
<TableRow>
|
|
262
|
-
<TableCell>Data 1</TableCell>
|
|
263
|
-
<TableCell>Data 2</TableCell>
|
|
264
|
-
</TableRow>
|
|
265
|
-
</TableBody>
|
|
266
|
-
</Table>
|
|
267
|
-
|
|
268
|
-
<Table theme="dark">
|
|
269
|
-
<TableCaption>Dark Theme Table</TableCaption>
|
|
270
|
-
<TableHeader>
|
|
271
|
-
<TableRow>
|
|
272
|
-
<TableHead>Column 1</TableHead>
|
|
273
|
-
<TableHead>Column 2</TableHead>
|
|
274
|
-
</TableRow>
|
|
275
|
-
</TableHeader>
|
|
276
|
-
<TableBody>
|
|
277
|
-
<TableRow>
|
|
278
|
-
<TableCell>Data 1</TableCell>
|
|
279
|
-
<TableCell>Data 2</TableCell>
|
|
280
|
-
</TableRow>
|
|
281
|
-
</TableBody>
|
|
282
|
-
</Table>
|
|
283
|
-
</>
|
|
284
|
-
)
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### Table with Footer Actions
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
function TableWithFooter() {
|
|
292
|
-
const [showMore, setShowMore] = useState(false)
|
|
293
|
-
|
|
294
|
-
return (
|
|
295
|
-
<Table>
|
|
296
|
-
<TableHeader>
|
|
297
|
-
<TableRow>
|
|
298
|
-
<TableHead>Product</TableHead>
|
|
299
|
-
<TableHead>Price</TableHead>
|
|
300
|
-
<TableHead>Stock</TableHead>
|
|
301
|
-
</TableRow>
|
|
302
|
-
</TableHeader>
|
|
303
|
-
<TableBody>
|
|
304
|
-
{products.slice(0, showMore ? undefined : 5).map((product) => (
|
|
305
|
-
<TableRow key={product.id}>
|
|
306
|
-
<TableCell>{product.name}</TableCell>
|
|
307
|
-
<TableCell>${product.price}</TableCell>
|
|
308
|
-
<TableCell>{product.stock}</TableCell>
|
|
309
|
-
</TableRow>
|
|
310
|
-
))}
|
|
311
|
-
</TableBody>
|
|
312
|
-
<TableFooter>
|
|
313
|
-
<TableFooterButton onClick={() => setShowMore(!showMore)}>
|
|
314
|
-
<i className="ri-add-line" />
|
|
315
|
-
{showMore ? 'Show Less' : 'Show More Items'}
|
|
316
|
-
</TableFooterButton>
|
|
317
|
-
</TableFooter>
|
|
318
|
-
</Table>
|
|
319
|
-
)
|
|
320
|
-
}
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Resizable Columns
|
|
324
|
-
|
|
325
|
-
```typescript
|
|
326
|
-
function ResizableTable() {
|
|
327
|
-
// Column resizing is automatic with the useResize hook
|
|
328
|
-
return (
|
|
329
|
-
<Table>
|
|
330
|
-
<TableHeader>
|
|
331
|
-
<TableRow>
|
|
332
|
-
<TableHead>Resizable Column 1</TableHead>
|
|
333
|
-
<TableHead>Resizable Column 2</TableHead>
|
|
334
|
-
<TableHead isDummy>Fixed Width</TableHead>
|
|
335
|
-
</TableRow>
|
|
336
|
-
</TableHeader>
|
|
337
|
-
<TableBody>
|
|
338
|
-
<TableRow>
|
|
339
|
-
<TableCell>Drag the resize handle</TableCell>
|
|
340
|
-
<TableCell>On column borders</TableCell>
|
|
341
|
-
<TableCell isDummy>Cannot resize</TableCell>
|
|
342
|
-
</TableRow>
|
|
343
|
-
</TableBody>
|
|
344
|
-
</Table>
|
|
345
|
-
)
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
## API Reference
|
|
350
|
-
|
|
351
|
-
### Table Props
|
|
352
|
-
|
|
353
|
-
| Prop | Type | Default | Description |
|
|
354
|
-
|------|------|---------|-------------|
|
|
355
|
-
| `theme` | `'dark' \| 'light' \| 'default'` | `'default'` | Theme variant |
|
|
356
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
357
|
-
| `children` | `React.ReactNode` | - | Table content |
|
|
358
|
-
|
|
359
|
-
### TableHeader Props
|
|
360
|
-
|
|
361
|
-
| Prop | Type | Default | Description |
|
|
362
|
-
|------|------|---------|-------------|
|
|
363
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
364
|
-
| `children` | `React.ReactNode` | - | Header rows |
|
|
365
|
-
|
|
366
|
-
#### Sticky header
|
|
367
|
-
|
|
368
|
-
`TableHeader` carries `position: sticky; top: 0`, so a table inside a vertically scrolling container
|
|
369
|
-
can keep its header in view while the rows move under it. Sticky keeps the element in normal flow,
|
|
370
|
-
so it changes nothing in a table that does not scroll.
|
|
371
|
-
|
|
372
|
-
It needs two things from you.
|
|
373
|
-
|
|
374
|
-
**Pass `overflow-visible`.** Sticky resolves against the **nearest scrollport**, and `Table` defaults
|
|
375
|
-
to `overflow-hidden` — which makes the table itself a scrollport, so the header pins to a box that
|
|
376
|
-
never scrolls and appears not to stick. Turning that clipping off binds it to your scroller instead.
|
|
377
|
-
|
|
378
|
-
Only do this when your scroller is `min-w-0` (or otherwise width-constrained). That default clipping
|
|
379
|
-
is also what stops a `w-auto` table wider than its container from pushing the whole page wide, so
|
|
380
|
-
opting out without a constrained scroller trades a sticky header for a horizontal scrollbar.
|
|
381
|
-
|
|
382
|
-
**Give the header an opaque background** — see below.
|
|
383
|
-
|
|
384
|
-
```tsx
|
|
385
|
-
{/* `min-w-0` so a wide table scrolls in here rather than widening the layout */}
|
|
386
|
-
<div className="min-w-0 max-h-[400px] overflow-auto">
|
|
387
|
-
<Table className="w-full overflow-visible">
|
|
388
|
-
<TableHeader className="bg-background-presentation-form-base">
|
|
389
|
-
...
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
The default header background is translucent, which was fine when nothing ever passed beneath it.
|
|
393
|
-
Once rows scroll under a stuck header they read through it, so give
|
|
394
|
-
the header the opaque colour of whatever surface it sits on — `Table` cannot pick one for you,
|
|
395
|
-
since forcing a surface would recolour every table not on it. `DataViews`' table view is the worked
|
|
396
|
-
example: it paints the surface token as the background colour and re-applies the header tint as a
|
|
397
|
-
`background-image`, which stacks above it, landing on the exact colour the header always had.
|
|
398
|
-
|
|
399
|
-
### TableBody Props
|
|
400
|
-
|
|
401
|
-
| Prop | Type | Default | Description |
|
|
402
|
-
|------|------|---------|-------------|
|
|
403
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
404
|
-
| `children` | `React.ReactNode` | - | Body rows |
|
|
405
|
-
|
|
406
|
-
### TableRow Props
|
|
407
|
-
|
|
408
|
-
| Prop | Type | Default | Description |
|
|
409
|
-
|------|------|---------|-------------|
|
|
410
|
-
| `state` | `'delete' \| 'update' \| 'add' \| 'selected' \| 'open'` | - | Row state styling |
|
|
411
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
412
|
-
| `children` | `React.ReactNode` | - | Row cells |
|
|
413
|
-
|
|
414
|
-
### TableHead Props
|
|
415
|
-
|
|
416
|
-
| Prop | Type | Default | Description |
|
|
417
|
-
|------|------|---------|-------------|
|
|
418
|
-
| `size` | `'S' \| 'M'` | `'M'` | Header cell size |
|
|
419
|
-
| `disabled` | `boolean` | `false` | Disables interactions |
|
|
420
|
-
| `sortType` | `'asc' \| 'desc' \| undefined` | - | Sort indicator |
|
|
421
|
-
| `onSort` | `() => void` | - | Sort handler |
|
|
422
|
-
| `sortLabel` | `string` | - | Column name for the sort button's accessible label |
|
|
423
|
-
| `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. |
|
|
424
|
-
| `isDummy` | `boolean` | `false` | Non-interactive header |
|
|
425
|
-
| `className` / `style` | `string` / `CSSProperties` | - | Applied to the `<th>` — this is how you size a column (`style={{ width: 200 }}`) |
|
|
426
|
-
| `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. |
|
|
427
|
-
|
|
428
|
-
**Every** prop you pass — `className`, `style`, `aria-*`, `role`, `tabIndex` and event
|
|
429
|
-
handlers alike — lands on the `<th>`. They deliberately share one element: libraries like
|
|
430
|
-
dnd-kit hand back accessibility attributes and event listeners as a matched pair, and
|
|
431
|
-
splitting them across two nodes leaves the focusable element without its handlers. Reach the
|
|
432
|
-
inner layout box with `contentClassName`.
|
|
433
|
-
|
|
434
|
-
### TableCell Props
|
|
435
|
-
|
|
436
|
-
| Prop | Type | Default | Description |
|
|
437
|
-
|------|------|---------|-------------|
|
|
438
|
-
| `isDummy` | `boolean` | `false` | Non-interactive cell |
|
|
439
|
-
| `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. |
|
|
440
|
-
| `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. |
|
|
441
|
-
| `childrenClassName` | `string` | - | Classes for content wrapper |
|
|
442
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
443
|
-
| `children` | `React.ReactNode` | - | Cell content |
|
|
444
|
-
|
|
445
|
-
### TableScroller Props
|
|
446
|
-
|
|
447
|
-
Horizontal scroll container for a table, with the thin design-system scrollbar (4px track
|
|
448
|
-
that thickens and turns blue on hover). Accepts any `div` props. Keep header actions and
|
|
449
|
-
`TableEndAction` **outside** it so they don't scroll away on a wide table.
|
|
450
|
-
|
|
451
|
-
### TableEndAction Props
|
|
452
|
-
|
|
453
|
-
The full-width action bar that sits **below** a table — e.g. `+ Add New`. A `<button>`, not
|
|
454
|
-
a `<tr>`, so it is a sibling of `TableScroller` and stays put while the columns scroll. Accepts
|
|
455
|
-
any `button` props. Use `TableFooterButton` instead when the action should scroll with the grid.
|
|
456
|
-
|
|
457
|
-
### TableCheckbox Props
|
|
458
|
-
|
|
459
|
-
| Prop | Type | Default | Description |
|
|
460
|
-
|------|------|---------|-------------|
|
|
461
|
-
| `id` | `string` | - | Required checkbox ID |
|
|
462
|
-
| `checked` | `boolean \| 'indeterminate'` | - | Checked state; pass `'indeterminate'` for the mixed state |
|
|
463
|
-
| `onCheckedChange` | `(checked: boolean \| 'indeterminate') => void` | - | Change handler (Radix Checkbox) |
|
|
464
|
-
|
|
465
|
-
### TableFooterButton Props
|
|
466
|
-
|
|
467
|
-
| Prop | Type | Default | Description |
|
|
468
|
-
|------|------|---------|-------------|
|
|
469
|
-
| `onClick` | `() => void` | - | Click handler |
|
|
470
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
471
|
-
| `children` | `React.ReactNode` | - | Button content |
|
|
472
|
-
|
|
473
|
-
### TypeScript
|
|
474
|
-
|
|
475
|
-
```typescript
|
|
476
|
-
// Table types
|
|
477
|
-
interface TableProps extends HTMLAttributes<HTMLTableElement> {
|
|
478
|
-
theme?: 'dark' | 'light' | 'default'
|
|
479
|
-
className?: string
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// TableRow types
|
|
483
|
-
interface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {
|
|
484
|
-
state?: 'delete' | 'update' | 'add' | 'selected' | 'open'
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// TableHead types
|
|
488
|
-
interface TableHeadProps extends ThHTMLAttributes<HTMLTableCellElement> {
|
|
489
|
-
size?: 'S' | 'M'
|
|
490
|
-
disabled?: boolean
|
|
491
|
-
sortType?: 'asc' | 'desc' | undefined
|
|
492
|
-
onSort?: () => void
|
|
493
|
-
sortLabel?: string
|
|
494
|
-
onResize?: (width: number) => void
|
|
495
|
-
contentClassName?: string
|
|
496
|
-
isDummy?: boolean
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// TableCell types
|
|
500
|
-
interface TableCellProps extends TdHTMLAttributes<HTMLTableCellElement> {
|
|
501
|
-
isDummy?: boolean
|
|
502
|
-
minWidth?: number
|
|
503
|
-
fade?: boolean
|
|
504
|
-
childrenClassName?: string
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// TableScroller / TableEndAction types
|
|
508
|
-
type TableScrollerProps = HTMLAttributes<HTMLDivElement>
|
|
509
|
-
type TableEndActionProps = ButtonHTMLAttributes<HTMLButtonElement>
|
|
510
|
-
|
|
511
|
-
// TableCheckbox types
|
|
512
|
-
interface TableCheckboxProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
513
|
-
id: string
|
|
514
|
-
checked?: boolean | 'indeterminate'
|
|
515
|
-
onCheckedChange?: (checked: boolean | 'indeterminate') => void
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Export structure
|
|
519
|
-
export {
|
|
520
|
-
Table,
|
|
521
|
-
TableHeader,
|
|
522
|
-
TableBody,
|
|
523
|
-
TableFooter,
|
|
524
|
-
TableHead,
|
|
525
|
-
TableRow,
|
|
526
|
-
TableCell,
|
|
527
|
-
TableCaption,
|
|
528
|
-
TableCheckbox,
|
|
529
|
-
SubTableButton,
|
|
530
|
-
TableFooterButton
|
|
531
|
-
}
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
## Common Patterns
|
|
535
|
-
|
|
536
|
-
### Data Table with Pagination
|
|
537
|
-
|
|
538
|
-
```typescript
|
|
539
|
-
function PaginatedTable() {
|
|
540
|
-
const [page, setPage] = useState(1)
|
|
541
|
-
const [rowsPerPage, setRowsPerPage] = useState(10)
|
|
542
|
-
const totalPages = Math.ceil(data.length / rowsPerPage)
|
|
543
|
-
|
|
544
|
-
const paginatedData = data.slice(
|
|
545
|
-
(page - 1) * rowsPerPage,
|
|
546
|
-
page * rowsPerPage
|
|
547
|
-
)
|
|
548
|
-
|
|
549
|
-
return (
|
|
550
|
-
<>
|
|
551
|
-
<Table>
|
|
552
|
-
<TableHeader>
|
|
553
|
-
<TableRow>
|
|
554
|
-
<TableHead>ID</TableHead>
|
|
555
|
-
<TableHead>Name</TableHead>
|
|
556
|
-
<TableHead>Date</TableHead>
|
|
557
|
-
</TableRow>
|
|
558
|
-
</TableHeader>
|
|
559
|
-
<TableBody>
|
|
560
|
-
{paginatedData.map((item) => (
|
|
561
|
-
<TableRow key={item.id}>
|
|
562
|
-
<TableCell>{item.id}</TableCell>
|
|
563
|
-
<TableCell>{item.name}</TableCell>
|
|
564
|
-
<TableCell>{item.date}</TableCell>
|
|
565
|
-
</TableRow>
|
|
566
|
-
))}
|
|
567
|
-
</TableBody>
|
|
568
|
-
</Table>
|
|
569
|
-
<div className="flex justify-between items-center mt-4">
|
|
570
|
-
<select
|
|
571
|
-
value={rowsPerPage}
|
|
572
|
-
onChange={(e) => setRowsPerPage(Number(e.target.value))}
|
|
573
|
-
>
|
|
574
|
-
<option value={10}>10 rows</option>
|
|
575
|
-
<option value={25}>25 rows</option>
|
|
576
|
-
<option value={50}>50 rows</option>
|
|
577
|
-
</select>
|
|
578
|
-
<div className="flex gap-2">
|
|
579
|
-
<button
|
|
580
|
-
disabled={page === 1}
|
|
581
|
-
onClick={() => setPage(page - 1)}
|
|
582
|
-
>
|
|
583
|
-
Previous
|
|
584
|
-
</button>
|
|
585
|
-
<span>Page {page} of {totalPages}</span>
|
|
586
|
-
<button
|
|
587
|
-
disabled={page === totalPages}
|
|
588
|
-
onClick={() => setPage(page + 1)}
|
|
589
|
-
>
|
|
590
|
-
Next
|
|
591
|
-
</button>
|
|
592
|
-
</div>
|
|
593
|
-
</div>
|
|
594
|
-
</>
|
|
595
|
-
)
|
|
596
|
-
}
|
|
597
|
-
```
|
|
598
|
-
|
|
599
|
-
### Expandable Rows
|
|
600
|
-
|
|
601
|
-
```typescript
|
|
602
|
-
function ExpandableTable() {
|
|
603
|
-
const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set())
|
|
604
|
-
|
|
605
|
-
const toggleRow = (id: string) => {
|
|
606
|
-
const newSet = new Set(expandedRows)
|
|
607
|
-
if (newSet.has(id)) {
|
|
608
|
-
newSet.delete(id)
|
|
609
|
-
} else {
|
|
610
|
-
newSet.add(id)
|
|
611
|
-
}
|
|
612
|
-
setExpandedRows(newSet)
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
return (
|
|
616
|
-
<Table>
|
|
617
|
-
<TableHeader>
|
|
618
|
-
<TableRow>
|
|
619
|
-
<TableHead size="S"></TableHead>
|
|
620
|
-
<TableHead>Order ID</TableHead>
|
|
621
|
-
<TableHead>Customer</TableHead>
|
|
622
|
-
<TableHead>Total</TableHead>
|
|
623
|
-
</TableRow>
|
|
624
|
-
</TableHeader>
|
|
625
|
-
<TableBody>
|
|
626
|
-
{orders.map((order) => (
|
|
627
|
-
<React.Fragment key={order.id}>
|
|
628
|
-
<TableRow state={expandedRows.has(order.id) ? 'open' : undefined}>
|
|
629
|
-
<TableCell>
|
|
630
|
-
<SubTableButton
|
|
631
|
-
isActive={expandedRows.has(order.id)}
|
|
632
|
-
onClick={() => toggleRow(order.id)}
|
|
633
|
-
/>
|
|
634
|
-
</TableCell>
|
|
635
|
-
<TableCell>{order.id}</TableCell>
|
|
636
|
-
<TableCell>{order.customer}</TableCell>
|
|
637
|
-
<TableCell>${order.total}</TableCell>
|
|
638
|
-
</TableRow>
|
|
639
|
-
{expandedRows.has(order.id) && (
|
|
640
|
-
<TableRow>
|
|
641
|
-
<TableCell colSpan={4}>
|
|
642
|
-
<div className="p-4">
|
|
643
|
-
<h4>Order Details</h4>
|
|
644
|
-
{order.items.map((item) => (
|
|
645
|
-
<div key={item.id}>
|
|
646
|
-
{item.name} - ${item.price} x {item.quantity}
|
|
647
|
-
</div>
|
|
648
|
-
))}
|
|
649
|
-
</div>
|
|
650
|
-
</TableCell>
|
|
651
|
-
</TableRow>
|
|
652
|
-
)}
|
|
653
|
-
</React.Fragment>
|
|
654
|
-
))}
|
|
655
|
-
</TableBody>
|
|
656
|
-
</Table>
|
|
657
|
-
)
|
|
658
|
-
}
|
|
659
|
-
```
|
|
660
|
-
|
|
661
|
-
### Editable Table
|
|
662
|
-
|
|
663
|
-
```typescript
|
|
664
|
-
function EditableTable() {
|
|
665
|
-
const [data, setData] = useState(initialData)
|
|
666
|
-
const [editingId, setEditingId] = useState<string | null>(null)
|
|
667
|
-
|
|
668
|
-
const handleEdit = (id: string, field: string, value: string) => {
|
|
669
|
-
setData(data.map(item =>
|
|
670
|
-
item.id === id ? { ...item, [field]: value } : item
|
|
671
|
-
))
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
return (
|
|
675
|
-
<Table>
|
|
676
|
-
<TableHeader>
|
|
677
|
-
<TableRow>
|
|
678
|
-
<TableHead>Name</TableHead>
|
|
679
|
-
<TableHead>Email</TableHead>
|
|
680
|
-
<TableHead>Actions</TableHead>
|
|
681
|
-
</TableRow>
|
|
682
|
-
</TableHeader>
|
|
683
|
-
<TableBody>
|
|
684
|
-
{data.map((item) => (
|
|
685
|
-
<TableRow key={item.id}>
|
|
686
|
-
<TableCell>
|
|
687
|
-
{editingId === item.id ? (
|
|
688
|
-
<Input
|
|
689
|
-
value={item.name}
|
|
690
|
-
onChange={(e) => handleEdit(item.id, 'name', e.target.value)}
|
|
691
|
-
onBlur={() => setEditingId(null)}
|
|
692
|
-
/>
|
|
693
|
-
) : (
|
|
694
|
-
item.name
|
|
695
|
-
)}
|
|
696
|
-
</TableCell>
|
|
697
|
-
<TableCell>
|
|
698
|
-
{editingId === item.id ? (
|
|
699
|
-
<Input
|
|
700
|
-
value={item.email}
|
|
701
|
-
onChange={(e) => handleEdit(item.id, 'email', e.target.value)}
|
|
702
|
-
onBlur={() => setEditingId(null)}
|
|
703
|
-
/>
|
|
704
|
-
) : (
|
|
705
|
-
item.email
|
|
706
|
-
)}
|
|
707
|
-
</TableCell>
|
|
708
|
-
<TableCell>
|
|
709
|
-
<button onClick={() => setEditingId(item.id)}>
|
|
710
|
-
Edit
|
|
711
|
-
</button>
|
|
712
|
-
</TableCell>
|
|
713
|
-
</TableRow>
|
|
714
|
-
))}
|
|
715
|
-
</TableBody>
|
|
716
|
-
</Table>
|
|
717
|
-
)
|
|
718
|
-
}
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
## Testing
|
|
722
|
-
|
|
723
|
-
### Unit Test Example
|
|
724
|
-
|
|
725
|
-
```typescript
|
|
726
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
727
|
-
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/Table'
|
|
728
|
-
|
|
729
|
-
describe('Table', () => {
|
|
730
|
-
it('renders table with data', () => {
|
|
731
|
-
render(
|
|
732
|
-
<Table>
|
|
733
|
-
<TableHeader>
|
|
734
|
-
<TableRow>
|
|
735
|
-
<TableHead>Header 1</TableHead>
|
|
736
|
-
</TableRow>
|
|
737
|
-
</TableHeader>
|
|
738
|
-
<TableBody>
|
|
739
|
-
<TableRow>
|
|
740
|
-
<TableCell>Cell 1</TableCell>
|
|
741
|
-
</TableRow>
|
|
742
|
-
</TableBody>
|
|
743
|
-
</Table>
|
|
744
|
-
)
|
|
745
|
-
|
|
746
|
-
expect(screen.getByText('Header 1')).toBeInTheDocument()
|
|
747
|
-
expect(screen.getByText('Cell 1')).toBeInTheDocument()
|
|
748
|
-
})
|
|
749
|
-
|
|
750
|
-
it('handles sorting', () => {
|
|
751
|
-
const handleSort = jest.fn()
|
|
752
|
-
render(
|
|
753
|
-
<Table>
|
|
754
|
-
<TableHeader>
|
|
755
|
-
<TableRow>
|
|
756
|
-
<TableHead onSort={handleSort} sortType="asc">
|
|
757
|
-
Sortable
|
|
758
|
-
</TableHead>
|
|
759
|
-
</TableRow>
|
|
760
|
-
</TableHeader>
|
|
761
|
-
</Table>
|
|
762
|
-
)
|
|
763
|
-
|
|
764
|
-
const sortButton = screen.getByRole('button')
|
|
765
|
-
fireEvent.pointerDown(sortButton)
|
|
766
|
-
expect(handleSort).toHaveBeenCalled()
|
|
767
|
-
})
|
|
768
|
-
|
|
769
|
-
it('applies row states correctly', () => {
|
|
770
|
-
const { container } = render(
|
|
771
|
-
<Table>
|
|
772
|
-
<TableBody>
|
|
773
|
-
<TableRow state="selected">
|
|
774
|
-
<TableCell>Selected</TableCell>
|
|
775
|
-
</TableRow>
|
|
776
|
-
</TableBody>
|
|
777
|
-
</Table>
|
|
778
|
-
)
|
|
779
|
-
|
|
780
|
-
const row = container.querySelector('tr')
|
|
781
|
-
expect(row).toHaveClass('bg-background-presentation-table-row-selected')
|
|
782
|
-
})
|
|
783
|
-
})
|
|
784
|
-
```
|
|
785
|
-
|
|
786
|
-
### Accessibility Test
|
|
787
|
-
|
|
788
|
-
```typescript
|
|
789
|
-
import { axe } from '@axe-core/react'
|
|
790
|
-
|
|
791
|
-
test('Table meets WCAG standards', async () => {
|
|
792
|
-
const { container } = render(
|
|
793
|
-
<Table>
|
|
794
|
-
<TableCaption>User Data</TableCaption>
|
|
795
|
-
<TableHeader>
|
|
796
|
-
<TableRow>
|
|
797
|
-
<TableHead scope="col">Name</TableHead>
|
|
798
|
-
<TableHead scope="col">Email</TableHead>
|
|
799
|
-
</TableRow>
|
|
800
|
-
</TableHeader>
|
|
801
|
-
<TableBody>
|
|
802
|
-
<TableRow>
|
|
803
|
-
<TableCell>John Doe</TableCell>
|
|
804
|
-
<TableCell>john@example.com</TableCell>
|
|
805
|
-
</TableRow>
|
|
806
|
-
</TableBody>
|
|
807
|
-
</Table>
|
|
808
|
-
)
|
|
809
|
-
|
|
810
|
-
const results = await axe(container)
|
|
811
|
-
expect(results).toHaveNoViolations()
|
|
812
|
-
})
|
|
813
|
-
```
|
|
814
|
-
|
|
815
|
-
## Known Limitations & Frontend Patterns
|
|
816
|
-
|
|
817
|
-
### `Table` defaults to `w-auto` — always pass `className="w-full"` for data tables
|
|
818
|
-
|
|
819
|
-
The shipped `Table` base classes include `w-auto`, so the table sizes to its content. Inside a `Card`, `Dialog`, or any flex/grid container with short rows, the table collapses to a narrow column on the left with empty space on the right. This is rarely what you want for a data list.
|
|
820
|
-
|
|
821
|
-
**Always pass `className="w-full"`** for list/data tables:
|
|
822
|
-
|
|
823
|
-
```tsx
|
|
824
|
-
<Card className="p-0 overflow-hidden">
|
|
825
|
-
<CardContent className="p-0 overflow-x-auto">
|
|
826
|
-
<Table className="w-full">
|
|
827
|
-
<TableHeader>
|
|
828
|
-
<TableRow>
|
|
829
|
-
<TableHead>Number</TableHead>
|
|
830
|
-
<TableHead>Status</TableHead>
|
|
831
|
-
<TableHead className="text-right">Total Debit</TableHead>
|
|
832
|
-
</TableRow>
|
|
833
|
-
</TableHeader>
|
|
834
|
-
<TableBody>...</TableBody>
|
|
835
|
-
</Table>
|
|
836
|
-
</CardContent>
|
|
837
|
-
</Card>
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
**Wrap with `overflow-x-auto`** on the parent so wide tables (10+ columns) scroll horizontally inside the card instead of overflowing it.
|
|
841
|
-
|
|
842
|
-
### Numeric columns: `text-right` on both head and cell
|
|
843
|
-
|
|
844
|
-
Right-align debit, credit, amount, count columns on **both** `TableHead` and the corresponding `TableCell`:
|
|
845
|
-
|
|
846
|
-
```tsx
|
|
847
|
-
<TableHead className="text-right">Total Debit</TableHead>
|
|
848
|
-
<TableCell className="text-right font-mono">{voucher.totalDebit}</TableCell>
|
|
849
|
-
```
|
|
850
|
-
|
|
851
|
-
Use `font-mono` on the cell so digits line up across rows.
|
|
852
|
-
|
|
853
|
-
### `whitespace-nowrap` on date and numeric cells
|
|
854
|
-
|
|
855
|
-
Dates and amounts wrap awkwardly when the column is narrow. Add `whitespace-nowrap` on those cells (not on heads):
|
|
856
|
-
|
|
857
|
-
```tsx
|
|
858
|
-
<TableCell className="whitespace-nowrap">{formatDate(voucher.date)}</TableCell>
|
|
859
|
-
```
|
|
860
|
-
|
|
861
|
-
### `TableCell` force-wraps children — use `childrenClassName` to override
|
|
862
|
-
|
|
863
|
-
`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:
|
|
864
|
-
|
|
865
|
-
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.
|
|
866
|
-
2. **Multi-line content is clipped** by `overflow-hidden` + the gradient mask.
|
|
867
|
-
3. **`flex-col` doesn't work** because the wrapper is `flex` (row) by default.
|
|
868
|
-
|
|
869
|
-
**Workaround — use the `childrenClassName` prop**, which merges into the inner wrapper, and skip your own outer `<div>`:
|
|
870
|
-
|
|
871
|
-
```tsx
|
|
872
|
-
<TableRow>
|
|
873
|
-
<TableCell
|
|
874
|
-
colSpan={7}
|
|
875
|
-
minWidth={0}
|
|
876
|
-
fade={false}
|
|
877
|
-
childrenClassName="flex flex-col items-center justify-center gap-3 py-12 w-full text-content-presentation-global-secondary"
|
|
878
|
-
>
|
|
879
|
-
<i className="ri-inbox-line text-4xl opacity-60" />
|
|
880
|
-
<p className="typography-body-medium-regular">No data</p>
|
|
881
|
-
<p className="typography-body-small-regular opacity-80">Try adjusting filters</p>
|
|
882
|
-
</TableCell>
|
|
883
|
-
</TableRow>
|
|
884
|
-
```
|
|
885
|
-
|
|
886
|
-
Key overrides:
|
|
887
|
-
|
|
888
|
-
- `flex flex-col` on `childrenClassName` overrides the default `flex-row`
|
|
889
|
-
- `items-center justify-center` on `childrenClassName` overrides `justify-start`
|
|
890
|
-
- **`minWidth={0}`** clears the 200px floor. It is an inline style, so a class such as
|
|
891
|
-
`min-w-0` on `childrenClassName` cannot beat it — use the prop.
|
|
892
|
-
- **`fade={false}`** drops both the gradient mask and the `overflow-hidden` that clips
|
|
893
|
-
multi-line content.
|
|
894
|
-
|
|
895
|
-
## Accessibility
|
|
896
|
-
|
|
897
|
-
### Keyboard Support
|
|
898
|
-
|
|
899
|
-
- **Tab**: Navigate through interactive elements
|
|
900
|
-
- **Space/Enter**: Activate buttons and checkboxes
|
|
901
|
-
- **Arrow Keys**: Navigate cells (with additional implementation)
|
|
902
|
-
- **Home/End**: Jump to first/last cell in row
|
|
903
|
-
|
|
904
|
-
### ARIA Attributes
|
|
905
|
-
|
|
906
|
-
```typescript
|
|
907
|
-
// Sortable headers
|
|
908
|
-
<TableHead
|
|
909
|
-
role="columnheader"
|
|
910
|
-
aria-sort={sortType === 'asc' ? 'ascending' : 'descending'}
|
|
911
|
-
>
|
|
912
|
-
|
|
913
|
-
// Row selection
|
|
914
|
-
<TableRow
|
|
915
|
-
role="row"
|
|
916
|
-
aria-selected={isSelected}
|
|
917
|
-
>
|
|
918
|
-
|
|
919
|
-
// Table caption for screen readers
|
|
920
|
-
<TableCaption>
|
|
921
|
-
Showing {start} to {end} of {total} results
|
|
922
|
-
</TableCaption>
|
|
923
|
-
```
|
|
924
|
-
|
|
925
|
-
### Screen Reader Support
|
|
926
|
-
|
|
927
|
-
- Announces table structure and dimensions
|
|
928
|
-
- Reads column headers with cells
|
|
929
|
-
- Announces sort state changes
|
|
930
|
-
- Communicates row selection state
|
|
931
|
-
|
|
932
|
-
## Styling
|
|
933
|
-
|
|
934
|
-
### Custom Styles with className
|
|
935
|
-
|
|
936
|
-
```typescript
|
|
937
|
-
<Table className="border rounded-lg">
|
|
938
|
-
<TableHeader className="bg-gray-100">
|
|
939
|
-
<TableRow className="border-b-2">
|
|
940
|
-
<TableHead className="font-bold">Custom Styled</TableHead>
|
|
941
|
-
</TableRow>
|
|
942
|
-
</TableHeader>
|
|
943
|
-
</Table>
|
|
944
|
-
```
|
|
945
|
-
|
|
946
|
-
### CSS Variables
|
|
947
|
-
|
|
948
|
-
```css
|
|
949
|
-
/* Custom theme variables */
|
|
950
|
-
[data-theme="custom"] {
|
|
951
|
-
--table-border: #your-border;
|
|
952
|
-
--table-header-bg: #your-header-bg;
|
|
953
|
-
--table-row-hover: #your-hover;
|
|
954
|
-
--table-row-selected: #your-selected;
|
|
955
|
-
--table-sort-active: #your-sort-color;
|
|
956
|
-
}
|
|
957
|
-
```
|
|
958
|
-
|
|
959
|
-
### Row State Classes
|
|
960
|
-
|
|
961
|
-
```css
|
|
962
|
-
/* Row states */
|
|
963
|
-
.state-delete { background: var(--color-negative); }
|
|
964
|
-
.state-update { background: var(--color-information); }
|
|
965
|
-
.state-add { background: var(--color-success); }
|
|
966
|
-
.state-selected { background: var(--color-selected); }
|
|
967
|
-
.state-open { background: var(--color-hover); }
|
|
968
|
-
```
|
|
969
|
-
|
|
970
|
-
## Performance
|
|
971
|
-
|
|
972
|
-
| Metric | Value |
|
|
973
|
-
|--------|-------|
|
|
974
|
-
| Bundle size (gzip) | 4.2kb |
|
|
975
|
-
| First render (100 rows) | <20ms |
|
|
976
|
-
| Re-render (100 rows) | <10ms |
|
|
977
|
-
| Column resize | <5ms |
|
|
978
|
-
| Tree-shakeable | ✅ |
|
|
979
|
-
|
|
980
|
-
### Optimization Tips
|
|
981
|
-
|
|
982
|
-
1. Use `React.memo()` for row components with large datasets
|
|
983
|
-
2. Implement virtual scrolling for tables with >100 rows
|
|
984
|
-
3. Debounce sort and filter operations
|
|
985
|
-
4. Use `useCallback` for event handlers
|
|
986
|
-
5. Consider pagination for large datasets
|
|
987
|
-
|
|
988
|
-
## Migration
|
|
989
|
-
|
|
990
|
-
### From v1.0.x
|
|
991
|
-
|
|
992
|
-
```diff
|
|
993
|
-
// Import path changed
|
|
994
|
-
- import Table from 'torch-glare/Table'
|
|
995
|
-
+ import { Table, TableHeader, TableBody } from '@/components/Table'
|
|
996
|
-
|
|
997
|
-
// Component structure
|
|
998
|
-
- <Table headers={headers} data={data} />
|
|
999
|
-
+ <Table>
|
|
1000
|
-
+ <TableHeader>
|
|
1001
|
-
+ <TableRow>
|
|
1002
|
-
+ {headers.map(h => <TableHead key={h}>{h}</TableHead>)}
|
|
1003
|
-
+ </TableRow>
|
|
1004
|
-
+ </TableHeader>
|
|
1005
|
-
+ <TableBody>
|
|
1006
|
-
+ {data.map(row => (
|
|
1007
|
-
+ <TableRow key={row.id}>
|
|
1008
|
-
+ {row.cells.map(cell => <TableCell key={cell}>{cell}</TableCell>)}
|
|
1009
|
-
+ </TableRow>
|
|
1010
|
-
+ ))}
|
|
1011
|
-
+ </TableBody>
|
|
1012
|
-
+ </Table>
|
|
1013
|
-
```
|
|
1014
|
-
|
|
1015
|
-
## Troubleshooting
|
|
1016
|
-
|
|
1017
|
-
### Common Issues
|
|
1018
|
-
|
|
1019
|
-
#### Columns not resizing
|
|
1020
|
-
|
|
1021
|
-
**Solution:** Ensure resize handles are not disabled
|
|
1022
|
-
|
|
1023
|
-
```typescript
|
|
1024
|
-
// ❌ Wrong - disables resize
|
|
1025
|
-
<TableHead isDummy>Column</TableHead>
|
|
1026
|
-
|
|
1027
|
-
// ✅ Correct - allows resize
|
|
1028
|
-
<TableHead>Column</TableHead>
|
|
1029
|
-
```
|
|
1030
|
-
|
|
1031
|
-
#### Sort not working
|
|
1032
|
-
|
|
1033
|
-
**Solution:** Implement sort handler properly
|
|
1034
|
-
|
|
1035
|
-
```typescript
|
|
1036
|
-
// ❌ Wrong - no state update
|
|
1037
|
-
<TableHead onSort={() => console.log('sort')}>
|
|
1038
|
-
|
|
1039
|
-
// ✅ Correct - updates data
|
|
1040
|
-
<TableHead
|
|
1041
|
-
onSort={() => handleSort('field')}
|
|
1042
|
-
sortType={sortType}
|
|
1043
|
-
>
|
|
1044
|
-
```
|
|
1045
|
-
|
|
1046
|
-
#### Row selection not visible
|
|
1047
|
-
|
|
1048
|
-
**Solution:** Apply state prop to TableRow
|
|
1049
|
-
|
|
1050
|
-
```typescript
|
|
1051
|
-
// ❌ Wrong - no visual feedback
|
|
1052
|
-
<TableRow>
|
|
1053
|
-
|
|
1054
|
-
// ✅ Correct - shows selection
|
|
1055
|
-
<TableRow state={isSelected ? 'selected' : undefined}>
|
|
1056
|
-
```
|
|
1057
|
-
|
|
1058
|
-
## Related Components
|
|
1059
|
-
|
|
1060
|
-
- [DataTable](/docs/components/data-table.md) - Advanced table with built-in features
|
|
1061
|
-
- [Card](/docs/components/card.md) - Alternative data display format
|
|
1062
|
-
- [ScrollArea](/docs/components/scroll-area.md) - For scrollable tables
|
|
1063
|
-
- [Checkbox](/docs/components/checkbox.md) - For row selection
|
|
1064
|
-
- [Button](/docs/components/button.md) - For table actions
|
|
1065
|
-
|
|
1066
|
-
## Browser Support
|
|
1067
|
-
|
|
1068
|
-
- Chrome 90+ ✅
|
|
1069
|
-
- Firefox 88+ ✅
|
|
1070
|
-
- Safari 14+ ✅
|
|
1071
|
-
- Edge 90+ ✅
|
|
1072
|
-
- Mobile browsers ✅
|
|
1073
|
-
|
|
1074
|
-
## Changelog
|
|
1075
|
-
|
|
1076
|
-
### v1.1.15
|
|
1077
|
-
- Added column resizing functionality
|
|
1078
|
-
- Improved sorting indicators
|
|
1079
|
-
- Enhanced row state styling
|
|
1080
|
-
- Better TypeScript types
|
|
1081
|
-
|
|
1082
|
-
### v1.1.14
|
|
1083
|
-
- Table component refactor
|
|
1084
|
-
- Added compound architecture
|
|
1085
|
-
- Performance optimizations
|
|
1086
|
-
|
|
1087
|
-
### v1.1.0
|
|
1088
|
-
- Initial stable release
|