torch-glare 2.5.5 → 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 (359) 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 -338
  69. package/apps/lib/components/Breadcrumb.tsx +0 -280
  70. package/apps/lib/components/Button.tsx +0 -317
  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 -383
  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 -84
  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 -63
  106. package/apps/lib/components/DataViews/states.tsx +0 -38
  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 -420
  118. package/apps/lib/components/DropdownMenu.tsx +0 -540
  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 -73
  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 -163
  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 -91
  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 -47
  147. package/apps/lib/components/FormBuilder/types.ts +0 -311
  148. package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -128
  149. package/apps/lib/components/FormRenderer/detail.tsx +0 -207
  150. package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -297
  151. package/apps/lib/components/FormRenderer/header.tsx +0 -88
  152. package/apps/lib/components/FormRenderer/index.ts +0 -15
  153. package/apps/lib/components/FormRenderer/section.tsx +0 -39
  154. package/apps/lib/components/FormRenderer/stepper.tsx +0 -339
  155. package/apps/lib/components/FormRenderer/types.ts +0 -78
  156. package/apps/lib/components/FormSummary.tsx +0 -282
  157. package/apps/lib/components/HeaderBar.tsx +0 -117
  158. package/apps/lib/components/ImageAttachment.tsx +0 -209
  159. package/apps/lib/components/InnerLabelField.tsx +0 -154
  160. package/apps/lib/components/Input.tsx +0 -224
  161. package/apps/lib/components/InputField.tsx +0 -147
  162. package/apps/lib/components/InputOTP.tsx +0 -84
  163. package/apps/lib/components/Label.tsx +0 -129
  164. package/apps/lib/components/LabelField.tsx +0 -76
  165. package/apps/lib/components/LabeledCheckBox.tsx +0 -51
  166. package/apps/lib/components/LabeledRadio.tsx +0 -51
  167. package/apps/lib/components/LinkButton.tsx +0 -94
  168. package/apps/lib/components/LoginButton.tsx +0 -51
  169. package/apps/lib/components/PasswordLevel.tsx +0 -58
  170. package/apps/lib/components/Popover.tsx +0 -312
  171. package/apps/lib/components/ProfileMenu.tsx +0 -85
  172. package/apps/lib/components/Radio.tsx +0 -59
  173. package/apps/lib/components/RadioCard.tsx +0 -50
  174. package/apps/lib/components/ScrollArea.tsx +0 -54
  175. package/apps/lib/components/SearchField.tsx +0 -62
  176. package/apps/lib/components/SearchableSelect.tsx +0 -318
  177. package/apps/lib/components/SearchableTable.tsx +0 -344
  178. package/apps/lib/components/SearchableTree.tsx +0 -485
  179. package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
  180. package/apps/lib/components/SectionBlock.tsx +0 -147
  181. package/apps/lib/components/Select.tsx +0 -347
  182. package/apps/lib/components/SimpleSelect.tsx +0 -225
  183. package/apps/lib/components/Skeleton.tsx +0 -12
  184. package/apps/lib/components/SlideDatePicker.tsx +0 -253
  185. package/apps/lib/components/SpinLoading.tsx +0 -174
  186. package/apps/lib/components/Stepper.tsx +0 -480
  187. package/apps/lib/components/Switch.tsx +0 -82
  188. package/apps/lib/components/TabFormItem.tsx +0 -153
  189. package/apps/lib/components/TabSwitch.tsx +0 -172
  190. package/apps/lib/components/Table.tsx +0 -610
  191. package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
  192. package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
  193. package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
  194. package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
  195. package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
  196. package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
  197. package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
  198. package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
  199. package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
  200. package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
  201. package/apps/lib/components/TextEditor/index.ts +0 -7
  202. package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
  203. package/apps/lib/components/Textarea.tsx +0 -117
  204. package/apps/lib/components/Timeline.tsx +0 -263
  205. package/apps/lib/components/Toast.tsx +0 -87
  206. package/apps/lib/components/Toggle.tsx +0 -125
  207. package/apps/lib/components/ToggleButton.tsx +0 -140
  208. package/apps/lib/components/Tooltip.tsx +0 -116
  209. package/apps/lib/components/TransparentLabel.tsx +0 -71
  210. package/apps/lib/components/TreeDropDown.tsx +0 -115
  211. package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
  212. package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
  213. package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
  214. package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
  215. package/apps/lib/components/TreeFolder/icons.tsx +0 -60
  216. package/apps/lib/components/TreeFolder/index.ts +0 -24
  217. package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
  218. package/apps/lib/components/TreeFolder/types.ts +0 -77
  219. package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
  220. package/apps/lib/hooks/useActiveTreeItem.ts +0 -58
  221. package/apps/lib/hooks/useClickOutside.ts +0 -27
  222. package/apps/lib/hooks/useDragDrop.tsx +0 -365
  223. package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
  224. package/apps/lib/hooks/useIsMobile.ts +0 -21
  225. package/apps/lib/hooks/useResize.ts +0 -67
  226. package/apps/lib/hooks/useTagSelection.ts +0 -214
  227. package/apps/lib/layouts/CNLayout.tsx +0 -372
  228. package/apps/lib/layouts/DataViewCard.tsx +0 -62
  229. package/apps/lib/layouts/FieldSection.tsx +0 -91
  230. package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
  231. package/apps/lib/providers/ThemeProvider.tsx +0 -84
  232. package/apps/lib/registry.json +0 -1201
  233. package/apps/lib/tsconfig.json +0 -9
  234. package/apps/lib/tsconfig.tsbuildinfo +0 -1
  235. package/apps/lib/utils/cn.ts +0 -6
  236. package/apps/lib/utils/color.ts +0 -175
  237. package/apps/lib/utils/dataViews/path.ts +0 -67
  238. package/apps/lib/utils/dataViews/query.ts +0 -73
  239. package/apps/lib/utils/dataViews/types.ts +0 -187
  240. package/apps/lib/utils/dateFormat.ts +0 -108
  241. package/apps/lib/utils/resize.ts +0 -31
  242. package/apps/lib/utils/types.ts +0 -16
  243. package/docs/BLOCKS.md +0 -129
  244. package/docs/CHANGELOG-1.1.16.md +0 -108
  245. package/docs/Cover.png +0 -0
  246. package/docs/README.md +0 -215
  247. package/docs/components/action-button.md +0 -638
  248. package/docs/components/actions-group.md +0 -708
  249. package/docs/components/alert-dialog.md +0 -920
  250. package/docs/components/avatar.md +0 -709
  251. package/docs/components/badge-field.md +0 -712
  252. package/docs/components/badge.md +0 -301
  253. package/docs/components/breadcrumb.md +0 -930
  254. package/docs/components/button-group.md +0 -650
  255. package/docs/components/button.md +0 -639
  256. package/docs/components/calendar.md +0 -555
  257. package/docs/components/card.md +0 -622
  258. package/docs/components/chart-block-tool.md +0 -129
  259. package/docs/components/checkbox.md +0 -699
  260. package/docs/components/cn-layout.md +0 -854
  261. package/docs/components/color-picker.md +0 -101
  262. package/docs/components/conclusion-header.md +0 -80
  263. package/docs/components/context-menu.md +0 -483
  264. package/docs/components/count-badge.md +0 -560
  265. package/docs/components/data-table.md +0 -854
  266. package/docs/components/data-views/backend-response.md +0 -324
  267. package/docs/components/data-views/examples/a11y-rtl.md +0 -250
  268. package/docs/components/data-views/examples/api-orders-route.md +0 -130
  269. package/docs/components/data-views/examples/fields.md +0 -362
  270. package/docs/components/data-views/examples/filters.md +0 -307
  271. package/docs/components/data-views/examples/inbox-routing.md +0 -218
  272. package/docs/components/data-views/examples/index.md +0 -29
  273. package/docs/components/data-views/examples/overview.md +0 -244
  274. package/docs/components/data-views/examples/panel.md +0 -212
  275. package/docs/components/data-views/examples/scale.md +0 -231
  276. package/docs/components/data-views/examples/server-side.md +0 -210
  277. package/docs/components/data-views/examples/state.md +0 -250
  278. package/docs/components/data-views/examples/tree-custom.md +0 -388
  279. package/docs/components/data-views/examples/view-registry.md +0 -313
  280. package/docs/components/data-views/examples/views.md +0 -534
  281. package/docs/components/data-views/guide.md +0 -405
  282. package/docs/components/data-views/index.md +0 -1495
  283. package/docs/components/data-views/migration.md +0 -79
  284. package/docs/components/date-picker.md +0 -857
  285. package/docs/components/dialog.md +0 -929
  286. package/docs/components/divider.md +0 -766
  287. package/docs/components/drawer.md +0 -654
  288. package/docs/components/dropdown-menu.md +0 -668
  289. package/docs/components/field-hint.md +0 -898
  290. package/docs/components/field-section.md +0 -781
  291. package/docs/components/form-builder.md +0 -276
  292. package/docs/components/form-renderer.md +0 -326
  293. package/docs/components/form-summary.md +0 -138
  294. package/docs/components/form.md +0 -785
  295. package/docs/components/header-bar.md +0 -188
  296. package/docs/components/image-attachment.md +0 -906
  297. package/docs/components/inner-label-field.md +0 -819
  298. package/docs/components/input-field.md +0 -623
  299. package/docs/components/input-otp.md +0 -756
  300. package/docs/components/input.md +0 -634
  301. package/docs/components/label-field.md +0 -770
  302. package/docs/components/label.md +0 -761
  303. package/docs/components/labeled-check-box.md +0 -642
  304. package/docs/components/labeled-radio.md +0 -796
  305. package/docs/components/link-button.md +0 -685
  306. package/docs/components/login-button.md +0 -872
  307. package/docs/components/password-level.md +0 -803
  308. package/docs/components/popover.md +0 -649
  309. package/docs/components/profile-menu.md +0 -656
  310. package/docs/components/radio-card.md +0 -801
  311. package/docs/components/radio.md +0 -735
  312. package/docs/components/scroll-area.md +0 -691
  313. package/docs/components/search-field.md +0 -702
  314. package/docs/components/searchable-select.md +0 -368
  315. package/docs/components/searchable-table.md +0 -438
  316. package/docs/components/searchable-tree-dialog.md +0 -190
  317. package/docs/components/searchable-tree.md +0 -200
  318. package/docs/components/section-block.md +0 -477
  319. package/docs/components/select.md +0 -709
  320. package/docs/components/simple-select.md +0 -741
  321. package/docs/components/skeleton.md +0 -706
  322. package/docs/components/slide-date-picker.md +0 -837
  323. package/docs/components/spin-loading.md +0 -696
  324. package/docs/components/stepper.md +0 -316
  325. package/docs/components/switch.md +0 -770
  326. package/docs/components/tab-form-item.md +0 -773
  327. package/docs/components/tab-switch.md +0 -170
  328. package/docs/components/table-dnd-wrapper.md +0 -107
  329. package/docs/components/table.md +0 -1088
  330. package/docs/components/text-editor.md +0 -735
  331. package/docs/components/textarea.md +0 -681
  332. package/docs/components/timeline.md +0 -254
  333. package/docs/components/toast.md +0 -773
  334. package/docs/components/toggle-button.md +0 -643
  335. package/docs/components/toggle.md +0 -882
  336. package/docs/components/tooltip.md +0 -513
  337. package/docs/components/transparent-label.md +0 -721
  338. package/docs/components/tree-drop-down.md +0 -740
  339. package/docs/components/tree-folder.md +0 -110
  340. package/docs/components/tree-sub-layout.md +0 -707
  341. package/docs/explanation/architecture.md +0 -54
  342. package/docs/explanation/design-system.md +0 -52
  343. package/docs/how-to/form-and-list-recipes.md +0 -386
  344. package/docs/how-to/forms-with-form-builder.md +0 -472
  345. package/docs/how-to/guides.md +0 -1027
  346. package/docs/migration/changelog.md +0 -54
  347. package/docs/migration/form-builder-2.5.2.md +0 -113
  348. package/docs/reference/cli.md +0 -112
  349. package/docs/reference/components.md +0 -572
  350. package/docs/reference/hooks.md +0 -1500
  351. package/docs/reference/providers.md +0 -866
  352. package/docs/reference/tailwind-plugins.md +0 -942
  353. package/docs/reference/theme.md +0 -85
  354. package/docs/reference/types.md +0 -1016
  355. package/docs/reference/utilities.md +0 -704
  356. package/docs/tutorials/building-first-form.md +0 -846
  357. package/docs/tutorials/component-composition.md +0 -882
  358. package/docs/tutorials/getting-started.md +0 -302
  359. package/docs/tutorials/theming-basics.md +0 -785
@@ -1,144 +0,0 @@
1
- "use client";
2
-
3
- import { createContext, useContext } from "react";
4
- import type {
5
- ColumnState,
6
- FieldConfig,
7
- FilterFieldDescriptor,
8
- FilterState,
9
- Row,
10
- Sort,
11
- } from "../../utils/dataViews/types";
12
-
13
- /**
14
- * Every context DataViews uses. As in `FormBuilder`, this is the only file that calls
15
- * `createContext` — a part never invents its own provider, so there is one place to look when
16
- * asking "where does this part get its data".
17
- */
18
-
19
- // ─── Data ─────────────────────────────────────────────────────────────────────
20
-
21
- export interface DataContextValue {
22
- /** The rows to paint, exactly as handed in. Already filtered and sorted by the app. */
23
- rows: readonly Row[];
24
- /** How to paint each field. */
25
- fields: readonly FieldConfig[];
26
- /** The visible fields, in the order the user arranged them. Resolved once by the root. */
27
- visibleFields: readonly FieldConfig[];
28
- /** Stable identity for a row — selection and drag both key off this. */
29
- getRowId: (row: Row, index: number) => string;
30
- loading: boolean;
31
- /** True while the *next* page is in flight — `loading` is the first one. */
32
- loadingMore: boolean;
33
- /** Whether there is a next page: derived from `rows.length < total`, never passed in. */
34
- hasMore: boolean;
35
- /** Ask for the next page. Undefined when the caller did not opt into scroll loading. */
36
- onLoadMore?: () => void;
37
- }
38
-
39
- export const DataContext = createContext<DataContextValue | null>(null);
40
-
41
- export function useDataViewsData(): DataContextValue {
42
- const ctx = useContext(DataContext);
43
- if (!ctx) throw new Error("DataViews parts must be rendered inside <DataViews>.");
44
- return ctx;
45
- }
46
-
47
- // ─── View ─────────────────────────────────────────────────────────────────────
48
-
49
- /** One entry in the switcher. Registered by rendering the view, never by a visibility map. */
50
- export interface RegisteredView {
51
- id: string;
52
- label: string;
53
- icon?: React.ReactNode;
54
- }
55
-
56
- /** The root's interaction state — everything the user can change that is not a row. */
57
- export interface ViewContextValue {
58
- view: string;
59
- setView: (id: string) => void;
60
- /** In the order the views were rendered. */
61
- views: readonly RegisteredView[];
62
- search: string;
63
- setSearch: (q: string) => void;
64
- sort: Sort;
65
- setSort: (sort: Sort) => void;
66
- selection: readonly string[];
67
- setSelection: (ids: readonly string[]) => void;
68
- /** The row the detail pane is showing, for the views that have one. */
69
- activeId: string | null;
70
- setActiveId: (id: string | null) => void;
71
- /** Column visibility and order. The panel edits these; the root paints from them. */
72
- columns: readonly ColumnState[];
73
- setColumns: (columns: readonly ColumnState[]) => void;
74
- }
75
-
76
- export const ViewContext = createContext<ViewContextValue | null>(null);
77
-
78
- export function useDataViewsView(): ViewContextValue {
79
- const ctx = useContext(ViewContext);
80
- if (!ctx) throw new Error("DataViews parts must be rendered inside <DataViews>.");
81
- return ctx;
82
- }
83
-
84
- // ─── Panel ────────────────────────────────────────────────────────────────────
85
-
86
- /**
87
- * Whether the settings panel is showing. Provided by the **root**, not by `Panel` — the toggle
88
- * lives in the header, which is `Panel`'s sibling, so neither can own the state the other needs.
89
- */
90
- export interface PanelContextValue {
91
- open: boolean;
92
- setOpen: (open: boolean) => void;
93
- }
94
-
95
- export const PanelContext = createContext<PanelContextValue | null>(null);
96
-
97
- export function useDataViewsPanel(): PanelContextValue {
98
- const ctx = useContext(PanelContext);
99
- if (!ctx) throw new Error("DataViews parts must be rendered inside <DataViews>.");
100
- return ctx;
101
- }
102
-
103
- /** One entry in the panel's tab strip, registered by rendering a `DataViews.Panel.Tab`. */
104
- export interface PanelTab {
105
- value: string;
106
- label: string;
107
- icon?: React.ReactNode;
108
- }
109
-
110
- /** Which tab the panel is on. Owned by `Panel`, because only its own children care. */
111
- export interface PanelTabsContextValue {
112
- tab: string;
113
- setTab: (tab: string) => void;
114
- tabs: readonly PanelTab[];
115
- }
116
-
117
- export const PanelTabsContext = createContext<PanelTabsContextValue | null>(null);
118
-
119
- export function useDataViewsPanelTabs(): PanelTabsContextValue {
120
- const ctx = useContext(PanelTabsContext);
121
- if (!ctx) throw new Error("DataViews.Panel parts must be rendered inside <DataViews.Panel>.");
122
- return ctx;
123
- }
124
-
125
- // ─── Filters ──────────────────────────────────────────────────────────────────
126
-
127
- export interface FiltersContextValue {
128
- filters: FilterState;
129
- setFilters: (filters: FilterState) => void;
130
- /**
131
- * What each filter control is, read off the `FormBuilder` children of `DataViews.Filters` —
132
- * never derived from the rows. The root collects them as well, so a consumer such as
133
- * `Filters.Presets` can resolve a field by path even when it is rendered outside `Filters`.
134
- */
135
- filterFields: readonly FilterFieldDescriptor[];
136
- }
137
-
138
- export const FiltersContext = createContext<FiltersContextValue | null>(null);
139
-
140
- export function useDataViewsFilters(): FiltersContextValue {
141
- const ctx = useContext(FiltersContext);
142
- if (!ctx) throw new Error("DataViews.Filters parts must be rendered inside <DataViews.Filters>.");
143
- return ctx;
144
- }
@@ -1,383 +0,0 @@
1
- "use client";
2
-
3
- import React, { Children, useCallback, useEffect, useMemo, useState } from "react";
4
- import { cn } from "../../utils/cn";
5
- import { defaultGetRowId } from "../../utils/dataViews/path";
6
- import { emptyQuery } from "../../utils/dataViews/query";
7
- import type {
8
- ColumnState,
9
- DataViewsQuery,
10
- FieldConfig,
11
- FilterState,
12
- Sort,
13
- } from "../../utils/dataViews/types";
14
- import {
15
- DataContext,
16
- FiltersContext,
17
- PanelContext,
18
- ViewContext,
19
- type RegisteredView,
20
- } from "./context";
21
- import { Actions, Header, PanelToggle, Search, ViewSwitch } from "./header";
22
- import {
23
- isHeaderElement,
24
- isPanelElement,
25
- isViewElement,
26
- viewMetaOf,
27
- } from "./slots";
28
- import { collectFilterFields, Filters } from "./filters";
29
- import { Panel } from "./panel";
30
- import { BoardView } from "./views/board-view";
31
- import { Detail, InboxView } from "./views/inbox-view";
32
- import { TableView } from "./views/table-view";
33
- import { TreeView } from "./views/tree-view";
34
- import { useControllable } from "./hooks/useControllable";
35
- import type { DataViewsRootProps } from "./types";
36
-
37
- /**
38
- * A cheap identity for a node used only as a memo key. React elements have no stable identity
39
- * across renders, so an inline `<i className="ri-table-line"/>` would look new every time; the
40
- * element's props are what actually distinguish one icon from another.
41
- */
42
- function iconKey(icon: React.ReactNode): string {
43
- if (icon === null || icon === undefined || typeof icon === "boolean") return "";
44
- if (React.isValidElement(icon)) return JSON.stringify(icon.props ?? {});
45
- return String(icon);
46
- }
47
-
48
- // ─── Root ─────────────────────────────────────────────────────────────────────
49
-
50
- /**
51
- * Resolve which fields to paint and in what order.
52
- *
53
- * The old code sorted `visibleFields` at five call sites with subtly different tie-breaks. There
54
- * is one rule now: if `columns` is supplied it decides both visibility and order; anything not
55
- * mentioned in it keeps its declaration order at the end.
56
- */
57
- function resolveVisibleFields(
58
- fields: readonly FieldConfig[],
59
- columns: readonly ColumnState[] | undefined,
60
- ): FieldConfig[] {
61
- if (!columns || columns.length === 0) {
62
- return fields.filter((f) => f.visible !== false && f.type !== "hidden");
63
- }
64
- const byPath = new Map(fields.map((f) => [f.path, f]));
65
- const ordered: FieldConfig[] = [];
66
- for (const col of columns) {
67
- const field = byPath.get(col.path);
68
- if (field && col.visible) ordered.push(field);
69
- byPath.delete(col.path);
70
- }
71
- for (const field of byPath.values()) {
72
- if (field.visible !== false && field.type !== "hidden") ordered.push(field);
73
- }
74
- return ordered;
75
- }
76
-
77
- function DataViewsRoot({
78
- rows,
79
- fields,
80
- children,
81
- getRowId = defaultGetRowId,
82
- total = 0,
83
- loading = false,
84
- onLoadMore,
85
- loadingMore = false,
86
- query,
87
- onQueryChange,
88
- defaultQuery,
89
- defaultView,
90
- defaultPanelOpen = false,
91
- onViewChange,
92
- onSelectionChange,
93
- onActiveIdChange,
94
- theme,
95
- className,
96
- }: DataViewsRootProps) {
97
- const childArray = Children.toArray(children);
98
-
99
- // A view exists because you rendered it. `Children.toArray` drops `false`/`null`, so
100
- // `{canSeeTree && <DataViews.Tree/>}` un-registers that view — which is the intent.
101
- const viewElements = childArray.filter(isViewElement);
102
- const headerEl = childArray.find(isHeaderElement);
103
- const panelEl = childArray.find(isPanelElement);
104
- // Anything the root does not position itself — a `Filters` bar, a toolbar of your own — sits
105
- // between the header and the views, in the order you wrote it.
106
- const extras = childArray.filter(
107
- (n) =>
108
- !isViewElement(n) && !isHeaderElement(n) && !isPanelElement(n),
109
- );
110
-
111
- // `viewElements` is a fresh array on every render, so memoising on its identity would never
112
- // hit. Key on what actually matters instead: which views are rendered and how they present.
113
- // `icon` is part of that — leave it out and swapping only an icon leaves a stale one showing.
114
- const viewKey = viewElements
115
- .map((el) => `${el.props.id}|${el.props.label}|${iconKey(el.props.icon)}`)
116
- .join(",");
117
- const registered = useMemo<RegisteredView[]>(
118
- () =>
119
- viewElements.map((el) => {
120
- const meta = viewMetaOf(el)!;
121
- return {
122
- id: el.props.id ?? meta.defaultId,
123
- label: el.props.label ?? meta.defaultLabel,
124
- icon: el.props.icon,
125
- };
126
- }),
127
- // eslint-disable-next-line react-hooks/exhaustive-deps -- keyed on `viewKey`, see above
128
- [viewKey],
129
- );
130
-
131
- const firstId = registered[0]?.id ?? "";
132
-
133
- // ── The query: the only state that leaves ──────────────────────────────────
134
- const [currentQuery, setQuery] = useControllable<DataViewsQuery>(
135
- query,
136
- onQueryChange,
137
- emptyQuery(defaultQuery),
138
- );
139
-
140
- /**
141
- * Change part of the query.
142
- *
143
- * Anything that changes *which* rows match starts a new result set, so the page goes back to 1 —
144
- * filter down to three rows while sitting on page 4 and there is no page 4 to stay on. Only the
145
- * component can do this: by the time a caller sees the change, the two have already been
146
- * conflated into one object.
147
- */
148
- const patchQuery = useCallback(
149
- (patch: Partial<DataViewsQuery>) => {
150
- setQuery((prev) => {
151
- const changesResultSet =
152
- ("search" in patch && patch.search !== prev.search) ||
153
- ("filters" in patch && patch.filters !== prev.filters) ||
154
- ("sort" in patch && patch.sort !== prev.sort) ||
155
- ("pageSize" in patch && patch.pageSize !== prev.pageSize);
156
- return { ...prev, ...patch, ...(changesResultSet ? { page: 1 } : null) };
157
- });
158
- },
159
- [setQuery],
160
- );
161
-
162
- // ── UI state: never leaves, so it is held rather than passed ───────────────
163
- const [currentView, setCurrentView] = useState(defaultView ?? firstId);
164
- const [currentColumns, setColumns] = useState<readonly ColumnState[]>([]);
165
- const [currentSelection, setSelectionState] = useState<readonly string[]>([]);
166
- const [currentActiveId, setActiveIdState] = useState<string | null>(null);
167
- const [isPanelOpen, setPanelOpen] = useState(defaultPanelOpen);
168
-
169
- // The observers are told, not asked: they report what the component decided, so an app can act
170
- // on a selection or follow the open row without owning either.
171
- const setSelection = useCallback(
172
- (ids: readonly string[]) => {
173
- setSelectionState(ids);
174
- onSelectionChange?.(ids);
175
- },
176
- [onSelectionChange],
177
- );
178
- const setActiveId = useCallback(
179
- (id: string | null) => {
180
- setActiveIdState(id);
181
- onActiveIdChange?.(id);
182
- },
183
- [onActiveIdChange],
184
- );
185
- const setView = useCallback(
186
- (id: string) => {
187
- setCurrentView(id);
188
- onViewChange?.(id);
189
- },
190
- [onViewChange],
191
- );
192
-
193
- // If the active view stops being rendered, converge on the first one — in an effect, never
194
- // during render, so a controlled consumer's state actually catches up.
195
- const known = registered.some((v) => v.id === currentView);
196
- useEffect(() => {
197
- if (!known && firstId) setView(firstId);
198
- }, [known, firstId, setView]);
199
-
200
- const activeView = known ? currentView : firstId;
201
- const activeElement = viewElements.find(
202
- (el) => (el.props.id ?? viewMetaOf(el)!.defaultId) === activeView,
203
- );
204
-
205
- const visibleFields = useMemo(
206
- () => resolveVisibleFields(fields, currentColumns),
207
- [fields, currentColumns],
208
- );
209
-
210
- const dataValue = useMemo(
211
- () => ({
212
- rows,
213
- fields,
214
- visibleFields,
215
- getRowId,
216
- loading,
217
- loadingMore,
218
- // Derived, never passed: the component has both halves already, and a `hasMore` prop that
219
- // disagreed with the rows on screen would be a second source of truth for the same fact.
220
- hasMore: rows.length < total,
221
- onLoadMore,
222
- }),
223
- [rows, fields, visibleFields, getRowId, loading, loadingMore, total, onLoadMore],
224
- );
225
-
226
- const setSearch = useCallback((search: string) => patchQuery({ search }), [patchQuery]);
227
- const setSort = useCallback((sort: Sort) => patchQuery({ sort }), [patchQuery]);
228
-
229
- const viewValue = useMemo(
230
- () => ({
231
- view: activeView,
232
- setView,
233
- views: registered,
234
- search: currentQuery.search,
235
- setSearch,
236
- sort: currentQuery.sort,
237
- setSort,
238
- selection: currentSelection,
239
- setSelection,
240
- activeId: currentActiveId,
241
- setActiveId,
242
- columns: currentColumns,
243
- setColumns,
244
- }),
245
- [
246
- activeView,
247
- setView,
248
- registered,
249
- currentQuery.search,
250
- setSearch,
251
- currentQuery.sort,
252
- setSort,
253
- currentSelection,
254
- setSelection,
255
- currentActiveId,
256
- setActiveId,
257
- currentColumns,
258
- setColumns,
259
- ],
260
- );
261
-
262
- const panelValue = useMemo(
263
- () => ({ open: isPanelOpen, setOpen: setPanelOpen }),
264
- [isPanelOpen, setPanelOpen],
265
- );
266
-
267
- // The descriptors as well as the value: a consumer such as `Filters.Presets` resolves a field by
268
- // path, and may be rendered outside `Filters` — above the table, in a toolbar — where it cannot
269
- // reach the context `Filters` provides to its own children.
270
- const filterFields = useMemo(() => collectFilterFields(children), [children]);
271
-
272
- const setFilters = useCallback(
273
- (filters: FilterState) => patchQuery({ filters }),
274
- [patchQuery],
275
- );
276
-
277
- const filtersValue = useMemo(
278
- () => ({ filters: currentQuery.filters, setFilters, filterFields }),
279
- [currentQuery.filters, setFilters, filterFields],
280
- );
281
-
282
- // The active view is always what renders. Nothing to show is shown as nothing — the view keeps
283
- // its chrome and paints no rows — and `loading` is answered by the view's own skeleton, so the
284
- // layout never swaps out from under the user.
285
- const body = activeElement;
286
-
287
- return (
288
- <DataContext.Provider value={dataValue}>
289
- <ViewContext.Provider value={viewValue}>
290
- <PanelContext.Provider value={panelValue}>
291
- <FiltersContext.Provider value={filtersValue}>
292
- <div
293
- data-theme={theme}
294
- className={cn(
295
- // The shell is always black: the dark header and the config rail sit on it, and
296
- // the Master Container is the light surface inside. `overflow-hidden` traps child
297
- // overflow — without it a tall panel body escapes and adds a page-level scrollbar
298
- // on top of the panel's own.
299
- "flex h-full min-h-0 gap-2 overflow-hidden bg-black",
300
- "text-content-presentation-global-primary",
301
- className,
302
- )}
303
- >
304
- {/* Left column: header + content. Shrinks as the panel expands. */}
305
- <div className="flex min-w-0 flex-1 flex-col gap-2">
306
- {headerEl}
307
- <main className="flex min-h-0 flex-1 overflow-hidden">
308
- {/* Master Container. It carries the surface — a form base and a 16px radius —
309
- so views paint over it where they want a different colour (the board reads
310
- grey, the split views black) and anything the root positions around one
311
- inherits it rather than landing on the black shell.
312
-
313
- No border: Figma draws one, but every view already brings its own edge — the
314
- table and the split views each draw their own panel border — so it only ever
315
- read as a second outline around the first. */}
316
- <div className="bg-background-presentation-form-base flex flex-1 overflow-hidden rounded-[16px]">
317
- {/* Clip the scrollable surface to the parent radius minus its 1px border
318
- (16 − 1). At the full 16px the opaque view background sits flush with the
319
- outer edge and bleeds past it as a hairline on the straight sides. */}
320
- <div className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-[15px]">
321
- {/* Anything the root does not position itself — a `Filters` bar, a toolbar
322
- of your own — sits above the view and *inside* the light surface, since
323
- its controls are host-themed and would be stranded on the black shell. */}
324
- {extras.length > 0 && (
325
- <div className="bg-background-presentation-form-base shrink-0">{extras}</div>
326
- )}
327
- {/* A column, so the active view stretches to the full width. As a row it
328
- would size each view to its content and leave the shell showing beside
329
- a narrow one. */}
330
- <div className="flex min-h-0 flex-1 flex-col overflow-auto">{body}</div>
331
- </div>
332
- </div>
333
- </main>
334
- </div>
335
-
336
- {/* The rail is a sibling of the content, not a layer over it, so opening it narrows
337
- the view rather than covering it. */}
338
- {panelEl}
339
- </div>
340
- </FiltersContext.Provider>
341
- </PanelContext.Provider>
342
- </ViewContext.Provider>
343
- </DataContext.Provider>
344
- );
345
- }
346
-
347
- /**
348
- * DataViews — a compound, composition-based multi-view data surface. Author a screen as JSX:
349
- *
350
- * ```tsx
351
- * <DataViews rows={rows} fields={fields} total={total} onQueryChange={setQuery}>
352
- * <DataViews.Header title="Orders">
353
- * <DataViews.ViewSwitch />
354
- * <DataViews.Search />
355
- * </DataViews.Header>
356
- * <DataViews.Table />
357
- * <DataViews.Board groups={groups} />
358
- * </DataViews>
359
- * ```
360
- *
361
- * A view exists **iff you render it** — there is no visibility map. DataViews is pure UI: it
362
- * never filters, searches, sorts, groups or mutates. Hand it rows and it paints them; it hands
363
- * you back what the user did so you can go and query.
364
- */
365
- export const DataViews = Object.assign(DataViewsRoot, {
366
- // shell
367
- Header,
368
- ViewSwitch,
369
- Search,
370
- Actions,
371
- PanelToggle,
372
- // panels
373
- Panel,
374
- Filters,
375
- // views
376
- Table: TableView,
377
- Board: BoardView,
378
- Inbox: InboxView,
379
- Tree: TreeView,
380
- Detail,
381
- // states
382
- // paging
383
- });
@@ -1,98 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { fieldKindOf } from "../../FormBuilder";
5
- import type { FilterFieldDescriptor } from "../../../utils/dataViews/types";
6
- import { toName } from "./values";
7
- import { Labelled } from "./labelled";
8
-
9
- /** How a FormBuilder field's value becomes a filter. Fields not listed here are not filters. */
10
- const AS_FILTER = {
11
- text: { kind: "text" } as const,
12
- choice: { kind: "choice", single: true } as const,
13
- multiChoice: { kind: "choice", single: false } as const,
14
- date: { kind: "date" } as const,
15
- slider: { kind: "number" } as const,
16
- };
17
-
18
- /**
19
- * Walk the children and describe every FormBuilder field among them.
20
- *
21
- * This is what `fields` used to be, except it is read from the controls you wrote rather than
22
- * declared twice. The walk follows `props.children`, so a field stays visible through a plain
23
- * wrapper; it cannot see through a component that builds the element itself, which is the same
24
- * limitation the layout markers have.
25
- *
26
- * `Checkbox`, `Number`, `File` and friends have no filter meaning — a boolean is not a query and a
27
- * file is not a value you can filter by — so they render but contribute nothing. `Filters.Custom`
28
- * is the way to drive a filter no FormBuilder field covers.
29
- */
30
- export function collectFilterFields(children: React.ReactNode): FilterFieldDescriptor[] {
31
- const out: FilterFieldDescriptor[] = [];
32
- const seen = new Set<string>();
33
-
34
- const walk = (node: React.ReactNode) => {
35
- if (Array.isArray(node)) {
36
- node.forEach(walk);
37
- return;
38
- }
39
- if (!React.isValidElement(node)) return;
40
-
41
- const props = node.props as {
42
- name?: string;
43
- label?: React.ReactNode;
44
- min?: number;
45
- max?: number;
46
- children?: React.ReactNode;
47
- };
48
- const kind = fieldKindOf(node);
49
- const as = kind ? AS_FILTER[kind as keyof typeof AS_FILTER] : undefined;
50
-
51
- if (as && props.name && !seen.has(props.name)) {
52
- seen.add(props.name);
53
- out.push({
54
- path: props.name,
55
- label: typeof props.label === "string" ? props.label : undefined,
56
- ...as,
57
- ...(as.kind === "number" ? { min: props.min ?? 0, max: props.max ?? 100 } : null),
58
- });
59
- }
60
-
61
- walk(props.children);
62
- };
63
-
64
- walk(children);
65
- return out;
66
- }
67
-
68
- /**
69
- * Render the children, with two changes to every field.
70
- *
71
- * The `name` is escaped, because RHF reads `customer.name` as object nesting — the author writes
72
- * the real path and `FilterState` stays keyed by it. Anything calling `setValue` on a filter has
73
- * to use `toName(path)` for the same reason.
74
- *
75
- * The `label` moves out of the field and into `Labelled` above it: `"bare"` mode exists precisely
76
- * to drop `FieldSection`'s label row, so a label left on the field would simply vanish.
77
- */
78
- export function renderFields(children: React.ReactNode): React.ReactNode {
79
- return React.Children.map(children, (child) => {
80
- if (!React.isValidElement(child)) return child;
81
-
82
- const props = child.props as { name?: string; label?: React.ReactNode; children?: React.ReactNode };
83
-
84
- if (fieldKindOf(child) && props.name) {
85
- return (
86
- <Labelled label={props.label}>
87
- {React.cloneElement(child, { name: toName(props.name), label: undefined } as never)}
88
- </Labelled>
89
- );
90
- }
91
-
92
- // Not a field — recurse so a control inside a wrapper still gets its name escaped.
93
- if (props.children) {
94
- return React.cloneElement(child, {} as never, renderFields(props.children));
95
- }
96
- return child;
97
- });
98
- }
@@ -1,34 +0,0 @@
1
- "use client";
2
-
3
- import { formatPathLabel } from "../../../utils/dataViews/path";
4
- import type { FilterValue } from "../../../utils/dataViews/types";
5
- import { useDataViewsFilters } from "../context";
6
- import { Labelled } from "./labelled";
7
- import type { FilterCustomProps } from "../types";
8
-
9
- /**
10
- * `Filters.Custom` — the escape hatch. Renders whatever you return against this filter's slot in
11
- * `FilterState`, bypassing the form entirely.
12
- *
13
- * Use it when no FormBuilder field produces the value you need — a bucket picker, a map region, a
14
- * tri-state toggle.
15
- *
16
- * ```tsx
17
- * <DataViews.Filters.Custom path="tags" render={({ value, setValue }) => (
18
- * <MyTagPicker value={value as string[]} onChange={setValue} />
19
- * )} />
20
- * ```
21
- */
22
- export function Custom({ path, label, render }: FilterCustomProps) {
23
- const { filters, setFilters } = useDataViewsFilters();
24
- const text = label ?? formatPathLabel(path);
25
-
26
- const setValue = (next: FilterValue | undefined) => {
27
- const copy = { ...filters };
28
- if (next === undefined) delete copy[path];
29
- else copy[path] = next;
30
- setFilters(copy);
31
- };
32
-
33
- return <Labelled label={text}>{render({ value: filters[path], setValue })}</Labelled>;
34
- }