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.
Files changed (362) hide show
  1. package/README.md +4 -3
  2. package/dist/bin/index.js +9 -24
  3. package/dist/bin/index.js.map +1 -1
  4. package/dist/src/commands/add.d.ts +2 -2
  5. package/dist/src/commands/add.d.ts.map +1 -1
  6. package/dist/src/commands/add.js +4 -70
  7. package/dist/src/commands/add.js.map +1 -1
  8. package/dist/src/commands/hook.d.ts +5 -4
  9. package/dist/src/commands/hook.d.ts.map +1 -1
  10. package/dist/src/commands/hook.js +7 -75
  11. package/dist/src/commands/hook.js.map +1 -1
  12. package/dist/src/commands/init.js +1 -1
  13. package/dist/src/commands/init.js.map +1 -1
  14. package/dist/src/commands/layout.d.ts +5 -4
  15. package/dist/src/commands/layout.d.ts.map +1 -1
  16. package/dist/src/commands/layout.js +7 -75
  17. package/dist/src/commands/layout.js.map +1 -1
  18. package/dist/src/commands/provider.d.ts +5 -4
  19. package/dist/src/commands/provider.d.ts.map +1 -1
  20. package/dist/src/commands/provider.js +7 -75
  21. package/dist/src/commands/provider.js.map +1 -1
  22. package/dist/src/commands/update.d.ts.map +1 -1
  23. package/dist/src/commands/update.js +78 -43
  24. package/dist/src/commands/update.js.map +1 -1
  25. package/dist/src/commands/utils.d.ts +5 -4
  26. package/dist/src/commands/utils.d.ts.map +1 -1
  27. package/dist/src/commands/utils.js +7 -80
  28. package/dist/src/commands/utils.js.map +1 -1
  29. package/dist/src/shared/addFromRegistry.d.ts +16 -0
  30. package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
  31. package/dist/src/shared/addFromRegistry.js +88 -0
  32. package/dist/src/shared/addFromRegistry.js.map +1 -0
  33. package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
  34. package/dist/src/shared/getInstallCommand.js +5 -0
  35. package/dist/src/shared/getInstallCommand.js.map +1 -1
  36. package/dist/src/shared/installDependencies.d.ts +0 -10
  37. package/dist/src/shared/installDependencies.d.ts.map +1 -1
  38. package/dist/src/shared/installDependencies.js +0 -17
  39. package/dist/src/shared/installDependencies.js.map +1 -1
  40. package/dist/src/shared/installFromPlan.d.ts +7 -5
  41. package/dist/src/shared/installFromPlan.d.ts.map +1 -1
  42. package/dist/src/shared/installFromPlan.js +103 -36
  43. package/dist/src/shared/installFromPlan.js.map +1 -1
  44. package/dist/src/shared/loadRegistry.d.ts +12 -3
  45. package/dist/src/shared/loadRegistry.d.ts.map +1 -1
  46. package/dist/src/shared/loadRegistry.js +19 -20
  47. package/dist/src/shared/loadRegistry.js.map +1 -1
  48. package/dist/src/shared/registryClient.d.ts +19 -0
  49. package/dist/src/shared/registryClient.d.ts.map +1 -0
  50. package/dist/src/shared/registryClient.js +128 -0
  51. package/dist/src/shared/registryClient.js.map +1 -0
  52. package/dist/src/shared/resolveEntry.d.ts +10 -7
  53. package/dist/src/shared/resolveEntry.d.ts.map +1 -1
  54. package/dist/src/shared/resolveEntry.js +18 -13
  55. package/dist/src/shared/resolveEntry.js.map +1 -1
  56. package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
  57. package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
  58. package/dist/src/shared/suggestOtherCommand.js +29 -23
  59. package/dist/src/shared/suggestOtherCommand.js.map +1 -1
  60. package/dist/src/types/main.d.ts +31 -2
  61. package/dist/src/types/main.d.ts.map +1 -1
  62. package/package.json +6 -11
  63. package/apps/lib/components/ActionButton.tsx +0 -93
  64. package/apps/lib/components/ActionsGroup.tsx +0 -27
  65. package/apps/lib/components/AlertDialog.tsx +0 -204
  66. package/apps/lib/components/Avatar.tsx +0 -46
  67. package/apps/lib/components/Badge.tsx +0 -250
  68. package/apps/lib/components/BadgeField.tsx +0 -403
  69. package/apps/lib/components/Breadcrumb.tsx +0 -280
  70. package/apps/lib/components/Button.tsx +0 -325
  71. package/apps/lib/components/ButtonGroup.tsx +0 -190
  72. package/apps/lib/components/Calendar.tsx +0 -115
  73. package/apps/lib/components/Card.tsx +0 -95
  74. package/apps/lib/components/Checkbox.tsx +0 -42
  75. package/apps/lib/components/ColorPicker.tsx +0 -441
  76. package/apps/lib/components/ConclusionHeader.tsx +0 -148
  77. package/apps/lib/components/ContextMenu.tsx +0 -571
  78. package/apps/lib/components/CountBadge.tsx +0 -52
  79. package/apps/lib/components/DataTable.tsx +0 -213
  80. package/apps/lib/components/DataViews/badge.ts +0 -49
  81. package/apps/lib/components/DataViews/cell.tsx +0 -324
  82. package/apps/lib/components/DataViews/context.ts +0 -144
  83. package/apps/lib/components/DataViews/data-views.tsx +0 -395
  84. package/apps/lib/components/DataViews/filters/children.tsx +0 -98
  85. package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
  86. package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
  87. package/apps/lib/components/DataViews/filters/index.ts +0 -4
  88. package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
  89. package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
  90. package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
  91. package/apps/lib/components/DataViews/filters/values.ts +0 -173
  92. package/apps/lib/components/DataViews/header.tsx +0 -220
  93. package/apps/lib/components/DataViews/hooks/index.ts +0 -5
  94. package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
  95. package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
  96. package/apps/lib/components/DataViews/index.ts +0 -88
  97. package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
  98. package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
  99. package/apps/lib/components/DataViews/panel/index.ts +0 -3
  100. package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
  101. package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
  102. package/apps/lib/components/DataViews/panel/section.tsx +0 -81
  103. package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
  104. package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
  105. package/apps/lib/components/DataViews/slots.ts +0 -72
  106. package/apps/lib/components/DataViews/states.tsx +0 -73
  107. package/apps/lib/components/DataViews/types.ts +0 -510
  108. package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
  109. package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
  110. package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
  111. package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
  112. package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
  113. package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
  114. package/apps/lib/components/DatePicker.tsx +0 -232
  115. package/apps/lib/components/Dialog.tsx +0 -116
  116. package/apps/lib/components/Divider.tsx +0 -28
  117. package/apps/lib/components/Drawer.tsx +0 -451
  118. package/apps/lib/components/DropdownMenu.tsx +0 -554
  119. package/apps/lib/components/FieldHint.tsx +0 -69
  120. package/apps/lib/components/Form.tsx +0 -182
  121. package/apps/lib/components/FormBuilder/context.ts +0 -85
  122. package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
  123. package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
  124. package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
  125. package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
  126. package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
  127. package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
  128. package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -168
  129. package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
  130. package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
  131. package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
  132. package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
  133. package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
  134. package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -114
  135. package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
  136. package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
  137. package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
  138. package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
  139. package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
  140. package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
  141. package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
  142. package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
  143. package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
  144. package/apps/lib/components/FormBuilder/index.ts +0 -31
  145. package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
  146. package/apps/lib/components/FormBuilder/submit.tsx +0 -67
  147. package/apps/lib/components/FormBuilder/types.ts +0 -316
  148. package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -250
  149. package/apps/lib/components/FormRenderer/detail.tsx +0 -256
  150. package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -358
  151. package/apps/lib/components/FormRenderer/header.tsx +0 -88
  152. package/apps/lib/components/FormRenderer/index.ts +0 -17
  153. package/apps/lib/components/FormRenderer/notch-action.tsx +0 -64
  154. package/apps/lib/components/FormRenderer/section.tsx +0 -39
  155. package/apps/lib/components/FormRenderer/stepper.tsx +0 -393
  156. package/apps/lib/components/FormRenderer/types.ts +0 -115
  157. package/apps/lib/components/FormSummary.tsx +0 -282
  158. package/apps/lib/components/HeaderBar.tsx +0 -117
  159. package/apps/lib/components/ImageAttachment.tsx +0 -209
  160. package/apps/lib/components/InnerLabelField.tsx +0 -154
  161. package/apps/lib/components/Input.tsx +0 -224
  162. package/apps/lib/components/InputField.tsx +0 -147
  163. package/apps/lib/components/InputOTP.tsx +0 -84
  164. package/apps/lib/components/Label.tsx +0 -129
  165. package/apps/lib/components/LabelField.tsx +0 -76
  166. package/apps/lib/components/LabeledCheckBox.tsx +0 -51
  167. package/apps/lib/components/LabeledRadio.tsx +0 -51
  168. package/apps/lib/components/LinkButton.tsx +0 -94
  169. package/apps/lib/components/LoginButton.tsx +0 -51
  170. package/apps/lib/components/PasswordLevel.tsx +0 -58
  171. package/apps/lib/components/Popover.tsx +0 -312
  172. package/apps/lib/components/ProfileMenu.tsx +0 -85
  173. package/apps/lib/components/Radio.tsx +0 -59
  174. package/apps/lib/components/RadioCard.tsx +0 -50
  175. package/apps/lib/components/ScrollArea.tsx +0 -54
  176. package/apps/lib/components/SearchField.tsx +0 -62
  177. package/apps/lib/components/SearchableSelect.tsx +0 -318
  178. package/apps/lib/components/SearchableTable.tsx +0 -344
  179. package/apps/lib/components/SearchableTree.tsx +0 -485
  180. package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
  181. package/apps/lib/components/SectionBlock.tsx +0 -168
  182. package/apps/lib/components/Select.tsx +0 -347
  183. package/apps/lib/components/SimpleSelect.tsx +0 -225
  184. package/apps/lib/components/Skeleton.tsx +0 -12
  185. package/apps/lib/components/SlideDatePicker.tsx +0 -255
  186. package/apps/lib/components/SpinLoading.tsx +0 -174
  187. package/apps/lib/components/Stepper.tsx +0 -480
  188. package/apps/lib/components/Switch.tsx +0 -82
  189. package/apps/lib/components/TabFormItem.tsx +0 -153
  190. package/apps/lib/components/TabSwitch.tsx +0 -172
  191. package/apps/lib/components/Table.tsx +0 -597
  192. package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
  193. package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
  194. package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
  195. package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
  196. package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
  197. package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
  198. package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
  199. package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
  200. package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
  201. package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
  202. package/apps/lib/components/TextEditor/index.ts +0 -7
  203. package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
  204. package/apps/lib/components/Textarea.tsx +0 -117
  205. package/apps/lib/components/Timeline.tsx +0 -263
  206. package/apps/lib/components/Toast.tsx +0 -87
  207. package/apps/lib/components/Toggle.tsx +0 -125
  208. package/apps/lib/components/ToggleButton.tsx +0 -140
  209. package/apps/lib/components/Tooltip.tsx +0 -116
  210. package/apps/lib/components/TransparentLabel.tsx +0 -71
  211. package/apps/lib/components/TreeDropDown.tsx +0 -115
  212. package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
  213. package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
  214. package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
  215. package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
  216. package/apps/lib/components/TreeFolder/icons.tsx +0 -60
  217. package/apps/lib/components/TreeFolder/index.ts +0 -24
  218. package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
  219. package/apps/lib/components/TreeFolder/types.ts +0 -77
  220. package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
  221. package/apps/lib/hooks/useActiveTreeItem.ts +0 -61
  222. package/apps/lib/hooks/useClickOutside.ts +0 -27
  223. package/apps/lib/hooks/useDragDrop.tsx +0 -365
  224. package/apps/lib/hooks/useHtmlDir.ts +0 -31
  225. package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
  226. package/apps/lib/hooks/useIsMobile.ts +0 -21
  227. package/apps/lib/hooks/useResize.ts +0 -67
  228. package/apps/lib/hooks/useTagSelection.ts +0 -300
  229. package/apps/lib/layouts/CNLayout.tsx +0 -372
  230. package/apps/lib/layouts/DataViewCard.tsx +0 -62
  231. package/apps/lib/layouts/FieldSection.tsx +0 -91
  232. package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
  233. package/apps/lib/providers/ThemeProvider.tsx +0 -84
  234. package/apps/lib/registry.json +0 -1217
  235. package/apps/lib/tsconfig.json +0 -9
  236. package/apps/lib/tsconfig.tsbuildinfo +0 -1
  237. package/apps/lib/utils/cn.ts +0 -6
  238. package/apps/lib/utils/color.ts +0 -175
  239. package/apps/lib/utils/dataViews/path.ts +0 -67
  240. package/apps/lib/utils/dataViews/query.ts +0 -73
  241. package/apps/lib/utils/dataViews/types.ts +0 -187
  242. package/apps/lib/utils/dateFormat.ts +0 -108
  243. package/apps/lib/utils/resize.ts +0 -31
  244. package/apps/lib/utils/scroller.ts +0 -26
  245. package/apps/lib/utils/types.ts +0 -16
  246. package/docs/BLOCKS.md +0 -129
  247. package/docs/CHANGELOG-1.1.16.md +0 -108
  248. package/docs/Cover.png +0 -0
  249. package/docs/README.md +0 -215
  250. package/docs/components/action-button.md +0 -638
  251. package/docs/components/actions-group.md +0 -708
  252. package/docs/components/alert-dialog.md +0 -920
  253. package/docs/components/avatar.md +0 -709
  254. package/docs/components/badge-field.md +0 -738
  255. package/docs/components/badge.md +0 -301
  256. package/docs/components/breadcrumb.md +0 -930
  257. package/docs/components/button-group.md +0 -650
  258. package/docs/components/button.md +0 -639
  259. package/docs/components/calendar.md +0 -555
  260. package/docs/components/card.md +0 -622
  261. package/docs/components/chart-block-tool.md +0 -129
  262. package/docs/components/checkbox.md +0 -699
  263. package/docs/components/cn-layout.md +0 -854
  264. package/docs/components/color-picker.md +0 -101
  265. package/docs/components/conclusion-header.md +0 -80
  266. package/docs/components/context-menu.md +0 -483
  267. package/docs/components/count-badge.md +0 -560
  268. package/docs/components/data-table.md +0 -854
  269. package/docs/components/data-views/backend-response.md +0 -324
  270. package/docs/components/data-views/examples/a11y-rtl.md +0 -250
  271. package/docs/components/data-views/examples/api-orders-route.md +0 -130
  272. package/docs/components/data-views/examples/fields.md +0 -362
  273. package/docs/components/data-views/examples/filters.md +0 -307
  274. package/docs/components/data-views/examples/inbox-routing.md +0 -218
  275. package/docs/components/data-views/examples/index.md +0 -29
  276. package/docs/components/data-views/examples/overview.md +0 -244
  277. package/docs/components/data-views/examples/panel.md +0 -212
  278. package/docs/components/data-views/examples/scale.md +0 -231
  279. package/docs/components/data-views/examples/server-side.md +0 -210
  280. package/docs/components/data-views/examples/state.md +0 -250
  281. package/docs/components/data-views/examples/tree-custom.md +0 -388
  282. package/docs/components/data-views/examples/view-registry.md +0 -313
  283. package/docs/components/data-views/examples/views.md +0 -534
  284. package/docs/components/data-views/guide.md +0 -405
  285. package/docs/components/data-views/index.md +0 -1521
  286. package/docs/components/data-views/migration.md +0 -81
  287. package/docs/components/date-picker.md +0 -857
  288. package/docs/components/dialog.md +0 -929
  289. package/docs/components/divider.md +0 -766
  290. package/docs/components/drawer.md +0 -654
  291. package/docs/components/dropdown-menu.md +0 -668
  292. package/docs/components/field-hint.md +0 -898
  293. package/docs/components/field-section.md +0 -781
  294. package/docs/components/form-builder.md +0 -284
  295. package/docs/components/form-renderer.md +0 -396
  296. package/docs/components/form-summary.md +0 -138
  297. package/docs/components/form.md +0 -785
  298. package/docs/components/header-bar.md +0 -188
  299. package/docs/components/image-attachment.md +0 -906
  300. package/docs/components/inner-label-field.md +0 -819
  301. package/docs/components/input-field.md +0 -623
  302. package/docs/components/input-otp.md +0 -756
  303. package/docs/components/input.md +0 -634
  304. package/docs/components/label-field.md +0 -770
  305. package/docs/components/label.md +0 -761
  306. package/docs/components/labeled-check-box.md +0 -642
  307. package/docs/components/labeled-radio.md +0 -796
  308. package/docs/components/link-button.md +0 -685
  309. package/docs/components/login-button.md +0 -872
  310. package/docs/components/password-level.md +0 -803
  311. package/docs/components/popover.md +0 -649
  312. package/docs/components/profile-menu.md +0 -656
  313. package/docs/components/radio-card.md +0 -801
  314. package/docs/components/radio.md +0 -735
  315. package/docs/components/scroll-area.md +0 -691
  316. package/docs/components/search-field.md +0 -702
  317. package/docs/components/searchable-select.md +0 -368
  318. package/docs/components/searchable-table.md +0 -438
  319. package/docs/components/searchable-tree-dialog.md +0 -190
  320. package/docs/components/searchable-tree.md +0 -200
  321. package/docs/components/section-block.md +0 -483
  322. package/docs/components/select.md +0 -709
  323. package/docs/components/simple-select.md +0 -741
  324. package/docs/components/skeleton.md +0 -706
  325. package/docs/components/slide-date-picker.md +0 -837
  326. package/docs/components/spin-loading.md +0 -696
  327. package/docs/components/stepper.md +0 -316
  328. package/docs/components/switch.md +0 -770
  329. package/docs/components/tab-form-item.md +0 -773
  330. package/docs/components/tab-switch.md +0 -170
  331. package/docs/components/table-dnd-wrapper.md +0 -107
  332. package/docs/components/table.md +0 -1088
  333. package/docs/components/text-editor.md +0 -735
  334. package/docs/components/textarea.md +0 -681
  335. package/docs/components/timeline.md +0 -254
  336. package/docs/components/toast.md +0 -773
  337. package/docs/components/toggle-button.md +0 -643
  338. package/docs/components/toggle.md +0 -882
  339. package/docs/components/tooltip.md +0 -513
  340. package/docs/components/transparent-label.md +0 -721
  341. package/docs/components/tree-drop-down.md +0 -740
  342. package/docs/components/tree-folder.md +0 -110
  343. package/docs/components/tree-sub-layout.md +0 -707
  344. package/docs/explanation/architecture.md +0 -54
  345. package/docs/explanation/design-system.md +0 -52
  346. package/docs/how-to/form-and-list-recipes.md +0 -386
  347. package/docs/how-to/forms-with-form-builder.md +0 -472
  348. package/docs/how-to/guides.md +0 -1027
  349. package/docs/migration/changelog.md +0 -60
  350. package/docs/migration/form-builder-2.5.2.md +0 -113
  351. package/docs/reference/cli.md +0 -112
  352. package/docs/reference/components.md +0 -572
  353. package/docs/reference/hooks.md +0 -1523
  354. package/docs/reference/providers.md +0 -866
  355. package/docs/reference/tailwind-plugins.md +0 -942
  356. package/docs/reference/theme.md +0 -85
  357. package/docs/reference/types.md +0 -1016
  358. package/docs/reference/utilities.md +0 -726
  359. package/docs/tutorials/building-first-form.md +0 -846
  360. package/docs/tutorials/component-composition.md +0 -882
  361. package/docs/tutorials/getting-started.md +0 -302
  362. package/docs/tutorials/theming-basics.md +0 -785
@@ -1,22 +0,0 @@
1
- "use client";
2
-
3
- import type { Row } from "../../../utils/dataViews/types";
4
- import { useDataViewsData, useDataViewsView } from "../context";
5
-
6
- /**
7
- * The row the inbox (or board, or tree) has open, ready to render in a detail pane. Returns
8
- * `null` when nothing is selected.
9
- *
10
- * ```tsx
11
- * function Detail() {
12
- * const row = useActiveRow();
13
- * return row ? <h2>{row.subject}</h2> : null;
14
- * }
15
- * ```
16
- */
17
- export function useActiveRow(): Row | null {
18
- const { rows, getRowId } = useDataViewsData();
19
- const { activeId } = useDataViewsView();
20
- if (activeId === null) return null;
21
- return rows.find((row, i) => getRowId(row, i) === activeId) ?? null;
22
- }
@@ -1,52 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useRef, useState } from "react";
4
-
5
- /**
6
- * One controlled/uncontrolled pair, written once.
7
- *
8
- * Pass `value` to control it; omit `value` to let the component keep its own. `onChange` fires
9
- * either way, so a consumer can observe without taking ownership.
10
- *
11
- * `set` accepts an updater, because the thing this now holds — the query — is patched rather than
12
- * replaced: changing a filter has to read the page it is resetting.
13
- */
14
- export function useControllable<T>(
15
- value: T | undefined,
16
- onChange: ((next: T) => void) | undefined,
17
- fallback: T,
18
- ): [T, (next: T | ((prev: T) => T)) => void] {
19
- const [internal, setInternal] = useState<T>(fallback);
20
-
21
- // `value !== undefined` decides the mode. Latch the first answer so a consumer that
22
- // accidentally flips between the two gets a warning-free, stable component rather than
23
- // React's "changing an uncontrolled input to controlled" class of bug.
24
- const controlledRef = useRef(value !== undefined);
25
- const isControlled = controlledRef.current;
26
-
27
- const current = isControlled ? (value as T) : internal;
28
-
29
- /**
30
- * The value an updater builds on.
31
- *
32
- * Reset to `current` on every render, and advanced *synchronously* by `set` — so two patches in
33
- * one tick chain instead of racing. Without that, restoring a saved view (which puts back the
34
- * sort and the filters one after the other) silently drops the first: both would read the value
35
- * from the last render, and the second would win.
36
- */
37
- const pendingRef = useRef(current);
38
- pendingRef.current = current;
39
-
40
- const set = useCallback(
41
- (next: T | ((prev: T) => T)) => {
42
- const resolved =
43
- typeof next === "function" ? (next as (prev: T) => T)(pendingRef.current) : next;
44
- pendingRef.current = resolved;
45
- if (!controlledRef.current) setInternal(resolved);
46
- onChange?.(resolved);
47
- },
48
- [onChange],
49
- );
50
-
51
- return [current, set];
52
- }
@@ -1,88 +0,0 @@
1
- // Enumerated, never `export *` — the same convention as `FormBuilder/index.ts`, so what this
2
- // folder offers is readable in one screen.
3
- //
4
- // Almost everything is reached through the compound root: `DataViews.Table`, `DataViews.Panel`,
5
- // `DataViews.Filters`, and so on. The loose exports below are the pieces you need when writing a
6
- // part of your own.
7
-
8
- export { DataViews } from "./data-views";
9
-
10
- // The query's wire format, both directions. A page needs the first two; a route handler that
11
- // serves one of these lists needs `parseQuery`.
12
- export { emptyQuery, parseQuery, queryToParams } from "../../utils/dataViews/query";
13
-
14
- // Reach into the component's state from inside a custom child — a detail pane, a bespoke filter,
15
- // a toolbar button that clears the selection.
16
- export {
17
- useDataViewsData,
18
- useDataViewsFilters,
19
- useDataViewsPanel,
20
- useDataViewsPanelTabs,
21
- useDataViewsView,
22
- } from "./context";
23
- export { useActiveRow } from "./hooks";
24
-
25
- // Paint one field the way the views paint it, in your own layout.
26
- export { Cell } from "./cell";
27
-
28
- // A view of your own gets the loading state the built-in four get: read `loading` from
29
- // `useDataViewsData()` and lay these out in your own shape.
30
- //
31
- // `DataViews.Empty` (LOCAL PATCH, Contact Center) is the counterpart upstream omits: a slot that
32
- // renders IN PLACE OF the view once a query has settled on no rows. It is opt-in and carries no
33
- // design of its own — see `states.tsx` for why it does not reintroduce the "announced nothing
34
- // matched before anything was asked for" bug that kept it out.
35
- export { SkeletonBar, skeletonKeys, Empty } from "./states";
36
-
37
- // Wrapping a part in a component of your own — a preset panel, a project-standard header — hides
38
- // the marker the root recognises it by, so the wrapper has to carry the marker itself:
39
- //
40
- // ```tsx
41
- // const AppPanel = markPanel(function AppPanel() { return <DataViews.Panel>…</DataViews.Panel>; });
42
- // ```
43
- export { markEmpty, markHeader, markPanel, markView } from "./slots";
44
- export { resolveBadgeVariant } from "./badge";
45
-
46
- export type { ResolvedBadgeProps } from "./badge";
47
- export type {
48
- DataContextValue,
49
- FiltersContextValue,
50
- PanelContextValue,
51
- PanelTab,
52
- PanelTabsContextValue,
53
- RegisteredView,
54
- ViewContextValue,
55
- } from "./context";
56
- export type * from "./types";
57
-
58
- // The vocabulary — the shapes **you** construct and hand in: a row, a field, the query, a tree of
59
- // nodes, a board's groups. They live in `utils/dataViews` because the route handler that serves
60
- // these lists imports them too, and are re-exported here so that one import line is enough:
61
- // every prop above is typed in terms of them.
62
- export type {
63
- BadgeVariant,
64
- ColumnColor,
65
- ColumnState,
66
- CurrencyOptions,
67
- DataViewsQuery,
68
- FieldConfig,
69
- FieldType,
70
- FilterFieldDescriptor,
71
- FilterState,
72
- FilterValue,
73
- MoveIntent,
74
- Path,
75
- Preset,
76
- Row,
77
- RowGroup,
78
- Sort,
79
- TreeNode,
80
- } from "../../utils/dataViews/types";
81
-
82
- // Reading a value the way `Cell` reads it — dotted paths included — and the id rule the component
83
- // falls back to. A custom view or a `renderCell` that has to reach a second field needs these.
84
- export { defaultGetRowId, formatPathLabel, getByPath, getString } from "../../utils/dataViews/path";
85
-
86
- // The board's card body, so a card of your own — in the board or the tree's pane — is built from
87
- // the same pairs the built-in one uses.
88
- export { buildCardRows } from "./views/card-rows";
@@ -1,153 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { cn } from "../../../utils/cn";
5
- import { DragList, useDragDrop, useDragItem } from "../../../hooks/useDragDrop";
6
- import { formatPathLabel } from "../../../utils/dataViews/path";
7
- import type { ColumnState } from "../../../utils/dataViews/types";
8
- import { useDataViewsData, useDataViewsView } from "../context";
9
- import { DataViewsSwitch } from "./controls";
10
- import { Section } from "./section";
11
- import type { PanelColumnsProps } from "../types";
12
-
13
- /** The 2×3 grip dots on a draggable column row. Hand-drawn — there is no icon for this shape. */
14
- function GripDots() {
15
- return (
16
- <svg aria-hidden width="16" height="16" viewBox="0 0 16 16" className="text-white/60" fill="currentColor">
17
- {[5.33, 9.33].flatMap((cx) =>
18
- [3.33, 8, 12.67].map((cy) => <circle key={`${cx}-${cy}`} cx={cx} cy={cy} r="1" />),
19
- )}
20
- </svg>
21
- );
22
- }
23
-
24
- /** The insertion line shown between rows while dragging one. */
25
- function DropLine() {
26
- return (
27
- <div className="pointer-events-none relative h-0">
28
- <div className="absolute -top-[1px] left-0 right-0 h-[2px] rounded-full bg-[#005ECC]" />
29
- </div>
30
- );
31
- }
32
-
33
- /**
34
- * `DataViews.Panel.Columns` — show/hide and reorder the columns.
35
- *
36
- * The column list is the root's, read and written through `useDataViewsView()` — this part takes
37
- * no `value`/`onValueChange` of its own. The root is what turns `columns` into the ordered
38
- * `visibleFields` every view paints from, so hiding a column here also retitles the board's cards. When `columns` has never been set, the list is seeded from
39
- * `fields` on first edit, so you are not forced to declare a redundant array to get this working.
40
- */
41
- export function Columns({
42
- title = "Table Columns",
43
- // Figma writes this line under the header; it is the section's own words, so it is the default
44
- // rather than something every caller has to remember to pass.
45
- description = "Show or hide columns in table view",
46
- className,
47
- }: PanelColumnsProps) {
48
- const { fields } = useDataViewsData();
49
- const { columns, setColumns } = useDataViewsView();
50
-
51
- // What the panel shows: the user's arrangement if there is one, otherwise the declared fields.
52
- const current: ColumnState[] =
53
- columns.length > 0
54
- ? columns.slice()
55
- : fields
56
- .filter((f) => f.type !== "hidden")
57
- .map((f) => ({
58
- path: f.path,
59
- label: f.label ?? formatPathLabel(f.path),
60
- visible: f.visible !== false,
61
- }));
62
-
63
- // Rows are identified by path — the same key the table and every other view uses.
64
- const ids = current.map((c) => c.path);
65
-
66
- const { DndContext, contextProps, activeId, overId } = useDragDrop({
67
- mode: "list",
68
- onMove: ({ id, to }) => {
69
- const from = ids.indexOf(id);
70
- const target = ids.indexOf(String(to));
71
- if (from < 0 || target < 0 || from === target) return;
72
- const next = current.slice();
73
- const [moved] = next.splice(from, 1);
74
- next.splice(target, 0, moved);
75
- setColumns(next);
76
- },
77
- });
78
-
79
- const toggle = (path: string) =>
80
- setColumns(current.map((c) => (c.path === path ? { ...c, visible: !c.visible } : c)));
81
-
82
- return (
83
- <Section title={title} description={description} className={className}>
84
- <DndContext {...contextProps}>
85
- <DragList ids={ids}>
86
- <div data-theme="dark" className="flex flex-col gap-2">
87
- {current.map((column, index) => (
88
- <ColumnRow
89
- key={`${column.path}-${index}`}
90
- column={column}
91
- onToggle={() => toggle(column.path)}
92
- showDropLine={overId === column.path && activeId !== null && activeId !== column.path}
93
- />
94
- ))}
95
- </div>
96
- </DragList>
97
- </DndContext>
98
- </Section>
99
- );
100
- }
101
-
102
- /**
103
- * One column row.
104
- *
105
- * A separate component because `useDragItem` is a hook, and a hook cannot be called inside the
106
- * `.map()` that paints the list.
107
- */
108
- function ColumnRow({
109
- column,
110
- onToggle,
111
- showDropLine,
112
- }: {
113
- column: ColumnState;
114
- onToggle: () => void;
115
- showDropLine: boolean;
116
- }) {
117
- const { ref, handleProps, style, isDragging } = useDragItem(column.path);
118
-
119
- return (
120
- <React.Fragment>
121
- {showDropLine && <DropLine />}
122
- <div
123
- ref={ref}
124
- style={style}
125
- {...handleProps}
126
- className={cn(
127
- // SB-Column-Item: a standalone #1C1D1F pill with a #252729 border, rounded hard
128
- // on the trailing edge and softly on the leading one.
129
- "flex cursor-grab items-center gap-2 rounded-e-[99px] rounded-s-[60px] border",
130
- "border-[#252729] bg-[#1C1D1F] p-[8.8px] transition-colors active:cursor-grabbing",
131
- isDragging ? "opacity-50" : "hover:bg-[#252729]",
132
- )}
133
- >
134
- <span className="flex shrink-0 items-center justify-center">
135
- <GripDots />
136
- </span>
137
- <span className="flex-1 text-[14px] text-white">{column.label}</span>
138
- {/* Stop the switch from starting a drag: the row is the handle, and a press on the
139
- toggle is not a press on the row. */}
140
- <span
141
- className="flex shrink-0 items-center"
142
- onPointerDown={(e) => e.stopPropagation()}
143
- >
144
- <DataViewsSwitch
145
- checked={column.visible}
146
- onCheckedChange={onToggle}
147
- aria-label={`Show ${column.label}`}
148
- />
149
- </span>
150
- </div>
151
- </React.Fragment>
152
- );
153
- }
@@ -1,106 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
5
- import { cn } from "../../../utils/cn";
6
- import { Switch } from "../../Switch";
7
-
8
- /**
9
- * The form controls the settings rail is built from.
10
- *
11
- * The rail is wrapped in `data-theme="dark"`, so themed components resolve dark tokens on their
12
- * own. The literals below are the exceptions — values chosen against pure black in Figma that
13
- * sit outside the theme system entirely.
14
- */
15
-
16
- /** The bright-green checked track from the Figma Switcher-1.0 "On" state. */
17
- const SWITCH_GREEN = "data-[state=checked]:bg-[#0AC713] data-[state=checked]:border-[#0AC713]";
18
-
19
- export function DataViewsSwitch(props: React.ComponentProps<typeof Switch>) {
20
- return <Switch {...props} className={cn(SWITCH_GREEN, props.className)} />;
21
- }
22
-
23
- /**
24
- * A radio row. The whole 32px row is the Radix item, so the label is part of the click target
25
- * rather than something you have to hit the 14px ring for.
26
- */
27
- export function DataViewRadio({
28
- value,
29
- label,
30
- children,
31
- className,
32
- }: {
33
- value: string;
34
- label?: string;
35
- children?: React.ReactNode;
36
- className?: string;
37
- }) {
38
- return (
39
- <RadioGroupPrimitive.Item
40
- value={value}
41
- className={cn(
42
- "group flex h-[32px] w-full items-center gap-1.5 py-1 ps-2",
43
- "cursor-pointer rounded-[8px] text-left outline-none transition-colors",
44
- "hover:bg-background-presentation-action-contstyle-hover focus-visible:bg-background-presentation-action-contstyle-hover",
45
- className,
46
- )}
47
- >
48
- <span
49
- className={cn(
50
- "flex h-[14px] w-[14px] shrink-0 items-center justify-center rounded-full",
51
- // Literals so the indicator stays dark inside the rail regardless of the host theme,
52
- // matching the always-dark panel chrome. Unselected ring is the CheckBox-Primary border
53
- // (#626467) over the BorderStyle fill; selected is the focus blue.
54
- "border border-[#626467] bg-white/5 transition-colors",
55
- "group-data-[state=checked]:border-transparent",
56
- "group-data-[state=checked]:bg-[#0075FF]",
57
- )}
58
- >
59
- <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
60
- <span className="h-[6px] w-[6px] rounded-full bg-white" />
61
- </RadioGroupPrimitive.Indicator>
62
- </span>
63
- <span className="typography-body-medium-regular text-content-presentation-global-primary flex-1">
64
- {children ?? label}
65
- </span>
66
- </RadioGroupPrimitive.Item>
67
- );
68
- }
69
-
70
- /**
71
- * A `#1C1D1F` pill holding a list of radio rows, with hairlines between them.
72
- *
73
- * The two `:has()` rules hide the hairline above and below the row being hovered, so the hover
74
- * highlight reads as one continuous block instead of being sliced by a line.
75
- */
76
- export function RadioGroup({
77
- value,
78
- onValueChange,
79
- items,
80
- className,
81
- }: {
82
- value: string;
83
- onValueChange: (value: string) => void;
84
- items: readonly { value: string; label: string }[];
85
- className?: string;
86
- }) {
87
- return (
88
- <RadioGroupPrimitive.Root
89
- value={value}
90
- onValueChange={onValueChange}
91
- className={cn(
92
- "flex flex-col space-y-0 rounded-[12px] bg-[#1C1D1F] p-1",
93
- "[&>div:has(>[role=radio]:hover)>.dv-divider]:opacity-0",
94
- "[&>div:has(>[role=radio]:hover)+div>.dv-divider]:opacity-0",
95
- className,
96
- )}
97
- >
98
- {items.map((item, i) => (
99
- <div key={item.value}>
100
- {i > 0 && <div className="dv-divider h-px bg-[#2C2D2E]" />}
101
- <DataViewRadio value={item.value} label={item.label} />
102
- </div>
103
- ))}
104
- </RadioGroupPrimitive.Root>
105
- );
106
- }
@@ -1,3 +0,0 @@
1
- // The rail. `panel.tsx` assembles the compound surface; the rest is one component per file, the
2
- // same shape as `views/`.
3
- export { Panel } from "./panel";
@@ -1,164 +0,0 @@
1
- "use client";
2
-
3
- import React, { Children, useEffect, useMemo, useRef, useState } from "react";
4
- import { X } from "lucide-react";
5
- import { cn } from "../../../utils/cn";
6
- import { PanelTabsContext, useDataViewsPanel, type PanelTab } from "../context";
7
- import { markPanel } from "../slots";
8
- import { Columns } from "./columns";
9
- import { SavedViews } from "./saved-views";
10
- import { Section } from "./section";
11
- import { Sort } from "./sort";
12
- import { Tab, isTabElement } from "./tab";
13
- import type { PanelProps } from "../types";
14
-
15
- /**
16
- * `DataViews.Panel` — the settings rail, opened by `DataViews.PanelToggle`.
17
- *
18
- * Always dark: `data-theme="dark"` on the root makes the Buttons, Switches and Radios inside
19
- * resolve dark tokens against the black, even when the host app runs light. The width animates
20
- * from 0 so the content beside it reflows rather than being covered.
21
- *
22
- * Tabs, like views, exist because you rendered them: the strip is built from the `Panel.Tab`
23
- * children found here and disappears when there is only one.
24
- *
25
- * Open/closed lives on the root, because the toggle that drives it is in the header — this
26
- * component's sibling. Which tab is showing lives here, because nothing outside this rail cares.
27
- */
28
- function PanelRoot({ children, defaultTab, title, className }: PanelProps) {
29
- const { open, setOpen } = useDataViewsPanel();
30
-
31
- // Mount at width 0, then flip to the open width on the next frame so the transition has two
32
- // values to animate between; on close, keep it mounted until the animation finishes.
33
- const [mounted, setMounted] = useState(open);
34
- const [expanded, setExpanded] = useState(false);
35
- const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
36
-
37
- useEffect(() => {
38
- if (open) {
39
- if (closeTimer.current) clearTimeout(closeTimer.current);
40
- setMounted(true);
41
- const raf = requestAnimationFrame(() => requestAnimationFrame(() => setExpanded(true)));
42
- return () => cancelAnimationFrame(raf);
43
- }
44
- setExpanded(false);
45
- closeTimer.current = setTimeout(() => setMounted(false), 300);
46
- return () => {
47
- if (closeTimer.current) clearTimeout(closeTimer.current);
48
- };
49
- }, [open]);
50
-
51
- const childArray = Children.toArray(children);
52
- const tabElements = childArray.filter(isTabElement);
53
- const loose = childArray.filter((n) => !isTabElement(n));
54
-
55
- // Keyed on the tab identities rather than the (always-new) child array — same reasoning as the
56
- // view registry in `data-views.tsx`.
57
- const tabKey = tabElements.map((el) => `${el.props.value}|${el.props.label}`).join(",");
58
- const tabs = useMemo<PanelTab[]>(
59
- () =>
60
- tabElements.map((el) => ({ value: el.props.value, label: el.props.label, icon: el.props.icon })),
61
- // eslint-disable-next-line react-hooks/exhaustive-deps -- keyed on `tabKey`, see above
62
- [tabKey],
63
- );
64
-
65
- const [currentTab, setTab] = useState(defaultTab ?? "");
66
- const known = tabs.some((t) => t.value === currentTab);
67
- const fallbackTab = tabs[0]?.value ?? "";
68
- // A tab that stops being rendered falls back to the first, which also covers the first render
69
- // when no `defaultTab` was given.
70
- const activeTab = known ? currentTab : fallbackTab;
71
-
72
- const value = useMemo(() => ({ tab: activeTab, setTab, tabs }), [activeTab, setTab, tabs]);
73
-
74
- if (!mounted) return null;
75
-
76
- return (
77
- <PanelTabsContext.Provider value={value}>
78
- <div
79
- className={cn(
80
- "shrink-0 overflow-hidden transition-[width] duration-300 ease-in-out",
81
- expanded ? "w-[260px]" : "w-0",
82
- )}
83
- >
84
- <aside
85
- data-theme="dark"
86
- data-state={expanded ? "open" : "closed"}
87
- className={cn(
88
- "flex h-full w-[260px] flex-col overflow-hidden rounded-[16px] bg-black",
89
- "transition-opacity duration-200 ease-in-out",
90
- expanded ? "opacity-100" : "opacity-0",
91
- className,
92
- )}
93
- >
94
- <div className="flex items-center gap-2 px-3 py-3">
95
- {tabs.length > 1 ? (
96
- <div className="flex flex-1 items-center gap-[2px] rounded-[10px] bg-[#252729] p-[2px] shadow-[inset_0_0_5px_0_rgba(0,0,0,0.16)]">
97
- {tabs.map((t) => {
98
- const active = t.value === activeTab;
99
- return (
100
- <button
101
- key={t.value}
102
- type="button"
103
- role="tab"
104
- aria-selected={active}
105
- onClick={() => setTab(t.value)}
106
- className={cn(
107
- "flex h-6 flex-1 items-center justify-center gap-1 rounded-[8px] px-3",
108
- "text-[14px] font-[510] leading-none transition-all duration-200 ease-in-out",
109
- active
110
- ? "bg-white text-black shadow-[0_0_10px_2px_rgba(0,0,0,0.25)]"
111
- : "bg-transparent text-white hover:bg-white/5",
112
- )}
113
- >
114
- {t.icon && (
115
- <span className="flex h-[14px] w-[14px] items-center justify-center [&_svg]:h-[14px] [&_svg]:w-[14px]">
116
- {t.icon}
117
- </span>
118
- )}
119
- {t.label}
120
- </button>
121
- );
122
- })}
123
- </div>
124
- ) : (
125
- <span className="flex-1 text-[18px] font-[510] leading-[1.32] tracking-[-0.01em] text-white">
126
- {title ?? tabs[0]?.label ?? ""}
127
- </span>
128
- )}
129
-
130
- <button
131
- type="button"
132
- aria-label="Close settings panel"
133
- onClick={() => setOpen(false)}
134
- className="hover:bg-background-presentation-state-negative-primary flex h-7 w-7 shrink-0 items-center justify-center rounded-[8px] bg-white/[0.15] text-white transition-colors hover:text-white"
135
- >
136
- <X className="h-[18px] w-[18px]" />
137
- </button>
138
- </div>
139
-
140
- <div className="h-px w-full bg-[#2C2D2E]" />
141
-
142
- <div className="flex flex-1 flex-col gap-6 overflow-y-auto px-3 py-4">
143
- {tabElements}
144
- {loose}
145
- </div>
146
- </aside>
147
- </div>
148
- </PanelTabsContext.Provider>
149
- );
150
- }
151
-
152
-
153
- markPanel(PanelRoot);
154
-
155
- /**
156
- * The rail's compound surface, assembled in one place so what it offers is readable at a glance.
157
- */
158
- export const Panel = Object.assign(PanelRoot, {
159
- Tab,
160
- Section,
161
- Columns,
162
- Sort,
163
- SavedViews,
164
- });
@@ -1,67 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
- import { Plus } from "lucide-react";
5
- import { Button } from "../../Button";
6
- import { useDataViewsFilters, useDataViewsView } from "../context";
7
- import { RadioGroup } from "./controls";
8
- import { Section } from "./section";
9
- import type { PanelSavedViewsProps } from "../types";
10
-
11
- /**
12
- * `DataViews.Panel.SavedViews` — pick a saved arrangement, or save the current one.
13
- *
14
- * Persistence is yours. `onSave` is handed the full snapshot — filters, sort and columns — which
15
- * is the part the old panel got wrong: its save callback took no arguments, so there was nothing
16
- * a host could actually store.
17
- */
18
- export function SavedViews({
19
- title = "Saved View",
20
- views = [],
21
- onValueChange,
22
- onSave,
23
- saveLabel = "Save a New View",
24
- className,
25
- }: PanelSavedViewsProps) {
26
- const { sort, setSort, columns, setColumns } = useDataViewsView();
27
- const { filters, setFilters } = useDataViewsFilters();
28
- // Which view is selected is UI state like any other — the caller stores the snapshots, not the
29
- // cursor into them.
30
- const [active, setActive] = useState("");
31
-
32
- /** Selecting a view is the other half of saving one: put back exactly what was stored. */
33
- const restore = (id: string) => {
34
- setActive(id);
35
- const snapshot = views.find((v) => v.id === id)?.snapshot;
36
- if (snapshot) {
37
- setColumns(snapshot.columns);
38
- setSort(snapshot.sort);
39
- setFilters(snapshot.filters);
40
- }
41
- onValueChange?.(id);
42
- };
43
-
44
- return (
45
- <Section title={title} className={className}>
46
- {views.length > 0 && (
47
- <RadioGroup
48
- value={active}
49
- onValueChange={restore}
50
- items={views.map((v) => ({ value: v.id, label: v.label }))}
51
- />
52
- )}
53
- {onSave && (
54
- <Button
55
- type="button"
56
- variant="BorderStyle"
57
- size="M"
58
- className="w-full"
59
- onClick={() => onSave({ filters, sort, columns })}
60
- >
61
- <Plus className="h-4 w-4" />
62
- {saveLabel}
63
- </Button>
64
- )}
65
- </Section>
66
- );
67
- }