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,108 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useEffect, useRef } from "react";
4
-
5
- /**
6
- * Ask for the next page when the user scrolls near the end.
7
- *
8
- * Lives here rather than in a view because three of them need it — the table, the board's columns
9
- * and the inbox list — and "near the end" has to mean the same thing in all three.
10
- *
11
- * It is an `IntersectionObserver` on a sentinel element, not a scroll listener. A scroll handler
12
- * has to be throttled, reads layout on every frame to work out how close the bottom is, and stops
13
- * being correct the moment the container resizes. The observer is told once and answers all three
14
- * for free.
15
- *
16
- * Like everything else here it only *asks*. Nothing loads until you hand back more rows.
17
- */
18
- export interface UseInfiniteScrollOptions {
19
- /** Fetch the next page and append it. */
20
- onLoadMore?: () => void;
21
- /** Whether there is a next page at all. */
22
- hasMore: boolean;
23
- /** True while a page is in flight. */
24
- loading?: boolean;
25
- /**
26
- * How far before the end to fire, in px. The default aims to have the next page arriving before
27
- * the user reaches the gap, rather than after they have already stopped at it.
28
- */
29
- rootMargin?: number;
30
- }
31
-
32
- /**
33
- * The element the sentinel actually scrolls inside, or `null` for the viewport.
34
- *
35
- * Walks up looking at `overflow-y` rather than at class names, so it keeps working whatever a
36
- * view calls its container — the table, the board's columns and the inbox list all differ.
37
- */
38
- function scrollParentOf(el: HTMLElement): HTMLElement | null {
39
- let node = el.parentElement;
40
- while (node) {
41
- const overflow = getComputedStyle(node).overflowY;
42
- if (overflow === "auto" || overflow === "scroll") return node;
43
- node = node.parentElement;
44
- }
45
- return null;
46
- }
47
-
48
- export function useInfiniteScroll({
49
- onLoadMore,
50
- hasMore,
51
- loading = false,
52
- rootMargin = 400,
53
- }: UseInfiniteScrollOptions) {
54
- const sentinelRef = useRef<HTMLElement | null>(null);
55
-
56
- /**
57
- * The guard against asking twice for the same page.
58
- *
59
- * The observer fires on intersection, but the rows that answer it do not arrive for a round
60
- * trip — and until they do, the sentinel is still on screen. Reading `loading` alone is not
61
- * enough either: a caller that sets it a tick late leaves a window where a second fire gets
62
- * through. So the hook latches when it asks, and only unlatches once the sentinel has actually
63
- * left the viewport again.
64
- */
65
- const askedRef = useRef(false);
66
-
67
- const ready = Boolean(onLoadMore) && hasMore && !loading;
68
-
69
- const handle = useCallback(
70
- (entries: IntersectionObserverEntry[]) => {
71
- const visible = entries.some((e) => e.isIntersecting);
72
- if (!visible) {
73
- askedRef.current = false;
74
- return;
75
- }
76
- if (askedRef.current || !ready) return;
77
- askedRef.current = true;
78
- onLoadMore?.();
79
- },
80
- [ready, onLoadMore],
81
- );
82
-
83
- useEffect(() => {
84
- const el = sentinelRef.current;
85
- if (!el || typeof IntersectionObserver === "undefined") return;
86
-
87
- const observer = new IntersectionObserver(handle, {
88
- // The scroller has to be named. `root: null` means the *viewport*, not the nearest
89
- // scrollable ancestor — so inside a scrolling panel the sentinel is clipped away and
90
- // `rootMargin` expands the wrong box, which reads as "infinite scroll simply never fires".
91
- // Finding it here rather than asking for it keeps the call sites free of plumbing.
92
- root: scrollParentOf(el),
93
- rootMargin: `0px 0px ${rootMargin}px 0px`,
94
- });
95
- observer.observe(el);
96
- return () => observer.disconnect();
97
- }, [handle, rootMargin]);
98
-
99
- // The latch is released by the sentinel leaving, and by nothing else.
100
- //
101
- // Releasing it when `loading` went false instead — which is the obvious thing to write — burns
102
- // several pages on one flick to the bottom: the flag drops before the new rows have painted, so
103
- // the sentinel is still on screen and the next observer callback asks again, and again. Tying
104
- // the release to visibility makes one arrival at the end cost exactly one page, because the
105
- // rows that arrive are what push the sentinel out of view.
106
-
107
- return { sentinelRef };
108
- }
@@ -1,21 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
-
5
- const MOBILE_BREAKPOINT = 768;
6
-
7
- export function useIsMobile() {
8
- const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
9
-
10
- React.useEffect(() => {
11
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
12
- const onChange = () => {
13
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14
- };
15
- mql.addEventListener("change", onChange);
16
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
17
- return () => mql.removeEventListener("change", onChange);
18
- }, []);
19
-
20
- return !!isMobile;
21
- }
@@ -1,67 +0,0 @@
1
- import { MutableRefObject, RefObject, useEffect, useState } from "react";
2
- import { calculateNewWidthFromMouse, calculateNewWidthFromTouch } from "../utils/resize";
3
-
4
- // Hook to handle resizing with RTL support
5
- export const useResize = (resizableRef: MutableRefObject<HTMLElement> | RefObject<HTMLElement>) => {
6
- const [width, setWidth] = useState<number>();
7
- const [isResizing, setIsResizing] = useState<boolean>(false);
8
- const [isRTL, setIsRTL] = useState<boolean>(false);
9
-
10
- // Start the resize process
11
- const handleStartResize = () => {
12
- setIsResizing(true);
13
- };
14
-
15
- // Stop the resize process
16
- const handleStopResize = () => {
17
- setIsResizing(false);
18
- };
19
-
20
- // Handle mouse move events
21
- const handleMouseMove = (event: MouseEvent) => {
22
- if (!isResizing) return;
23
- const newWidth = calculateNewWidthFromMouse(event, resizableRef, isRTL);
24
- setWidth(newWidth);
25
- };
26
-
27
- // Handle touch move events
28
- const handleTouchMove = (event: TouchEvent) => {
29
- if (!isResizing) return;
30
- event.preventDefault(); // Prevent scrolling or other touch-related behaviors
31
- const newWidth = calculateNewWidthFromTouch(event, resizableRef, isRTL);
32
- setWidth(newWidth);
33
- };
34
-
35
- useEffect(() => {
36
- let htmlDir = "";
37
- if (document) {
38
- htmlDir = document.documentElement.getAttribute("dir") || "ltr";
39
- }
40
- // Determine the direction of the document
41
- setIsRTL(htmlDir === "rtl");
42
- }, []);
43
-
44
- useEffect(() => {
45
- if (!resizableRef.current) return;
46
-
47
- // Add event listeners for mouse and touch events
48
- document.addEventListener("mousemove", handleMouseMove);
49
- document.addEventListener("mouseup", handleStopResize);
50
- document.addEventListener("touchmove", handleTouchMove, { passive: false });
51
- document.addEventListener("touchend", handleStopResize);
52
-
53
- // Cleanup event listeners on unmount
54
- return () => {
55
- document.removeEventListener("mousemove", handleMouseMove);
56
- document.removeEventListener("mouseup", handleStopResize);
57
- document.removeEventListener("touchmove", handleTouchMove);
58
- document.removeEventListener("touchend", handleStopResize);
59
- };
60
- }, [isResizing, isRTL]); // Depend on `isRtl` to handle direction changes dynamically
61
-
62
- return {
63
- width,
64
- isResizing,
65
- handleStartResize,
66
- };
67
- };
@@ -1,300 +0,0 @@
1
- import { useState, useEffect, useRef } from "react";
2
-
3
- export interface Tag {
4
- id: string;
5
- name: string;
6
- variant?: string;
7
- value?: string;
8
- isSelected: boolean;
9
- [key: string]: unknown;
10
- }
11
-
12
- /** Stable key for a selection, used to tell an external change from one we just made. */
13
- const signatureOf = (tags: Tag[]) => tags.map((t) => t.id).join("\0");
14
-
15
- export const useTagSelection = ({
16
- Tags,
17
- onTagsChange,
18
- inputRef,
19
- singleSelect = false,
20
- creatable = false,
21
- }: {
22
- Tags: Tag[];
23
- onTagsChange?: (selectedTags: Tag[]) => void;
24
- inputRef?: React.RefObject<HTMLInputElement | null>;
25
- singleSelect?: boolean;
26
- /** Allow typed text to become a selected tag that was never in `Tags`. */
27
- creatable?: boolean;
28
- }) => {
29
- // Split initial tags into selected and unselected
30
- const initialSelectedTags = Tags.filter((tag) => tag.isSelected);
31
- const initialUnselectedTags = Tags.filter((tag) => !tag.isSelected);
32
-
33
- // Initialize with available tags (excluding any initially selected ones)
34
- const [tags, setTags] = useState<Tag[]>(initialUnselectedTags);
35
-
36
- // Initialize with any pre-selected tags
37
- const [selectedTagsStack, setSelectedTagsStack] = useState<Tag[]>(
38
- singleSelect && initialSelectedTags.length > 0 ? [initialSelectedTags[0]] : initialSelectedTags,
39
- );
40
- const [searchTags, filterTagsBySearch] = useState("");
41
- const [focusedTagIndex, setFocusedTagIndex] = useState<number | null>(null);
42
- const [focusedPopoverIndex, setFocusedPopoverIndex] = useState<number | null>(null);
43
- const [isPopoverOpen, setIsPopoverOpen] = useState(false);
44
-
45
- // LOCAL PATCH (Contact Center): key both effects below off a SIGNATURE of `Tags`, not the array
46
- // reference. A caller that builds its tag list inline — `MultiSelectField` does, from the form
47
- // value — hands over a fresh array every render, so the upstream `[Tags]` dependency changed on
48
- // every pass: effect → setTags → re-render → new array → effect, an infinite render loop.
49
- const tagsSignature = Tags.map((tag) => `${tag.id}:${tag.isSelected ? 1 : 0}`).join(" ");
50
-
51
- // Update internal state when Tags actually changes.
52
- //
53
- // Filter against the INCOMING selection as well as the one we hold: on an external sync (the
54
- // hydration case below) `selectedTagsStack` is still the pre-sync value at this point, so
55
- // filtering by it alone left the freshly selected values sitting in the dropdown as if they
56
- // were still available to add.
57
- useEffect(() => {
58
- const selectedIds = new Set([
59
- ...selectedTagsStack.map((tag) => tag.id),
60
- ...Tags.filter((tag) => tag.isSelected).map((tag) => tag.id),
61
- ]);
62
- setTags(Tags.filter((tag) => !selectedIds.has(tag.id)));
63
- }, [tagsSignature]);
64
-
65
- // LOCAL PATCH (Contact Center): follow the incoming selection.
66
- //
67
- // Upstream seeded `selectedTagsStack` from `Tags` ONCE, and the effect above refreshed only the
68
- // AVAILABLE list — never the selection. That made the component effectively uncontrolled: on an
69
- // edit form, react-hook-form's `reset()` hydration lands after mount, so a person's saved emails
70
- // and tags rendered as an empty field. Re-sync whenever the incoming selected set differs from
71
- // what we hold, and mark the change as external so it isn't echoed straight back to the parent.
72
- const incomingSelected = Tags.filter((tag) => tag.isSelected);
73
- const incomingSignature = signatureOf(incomingSelected);
74
- const lastSyncedRef = useRef<string | null>(null);
75
- // Starts true so the mount pass below is swallowed — see the notify effect.
76
- const skipNotifyRef = useRef(true);
77
-
78
- useEffect(() => {
79
- if (lastSyncedRef.current === incomingSignature) return;
80
- lastSyncedRef.current = incomingSignature;
81
- // Already matches (we made this change ourselves) — don't re-set state, so the notify flag
82
- // stays untouched and the user's next real edit still reaches the parent.
83
- if (signatureOf(selectedTagsStack) === incomingSignature) return;
84
- skipNotifyRef.current = true;
85
- setSelectedTagsStack(
86
- singleSelect && incomingSelected.length > 0 ? [incomingSelected[0]] : incomingSelected,
87
- );
88
- }, [incomingSignature]);
89
-
90
- // Notify parent component when tags change.
91
- //
92
- // LOCAL PATCH (Contact Center): upstream fired this on MOUNT too, so an untouched field wrote
93
- // `[]` into the form — marking it dirty and adding an empty-array key to the request payload for
94
- // a value nobody entered. It also fires for a sync from the parent, which would echo the value
95
- // straight back. Both are skipped via the flag.
96
- useEffect(() => {
97
- if (skipNotifyRef.current) {
98
- skipNotifyRef.current = false;
99
- return;
100
- }
101
- onTagsChange?.(selectedTagsStack);
102
- }, [selectedTagsStack]);
103
-
104
- // Filter tags based on search input
105
- const filteredTags = tags.filter((tag) =>
106
- tag.name.toLowerCase().includes(searchTags.toLowerCase()),
107
- );
108
-
109
- // Filter selected tags based on search input
110
- const filteredSelectedTags =
111
- searchTags.length > 0
112
- ? selectedTagsStack.filter((tag) => tag.name.toLowerCase().includes(searchTags.toLowerCase()))
113
- : selectedTagsStack;
114
-
115
- const handleSelectTag = (id: string) => {
116
- const tagToSelect = tags.find((tag) => tag.id === id);
117
- if (tagToSelect) {
118
- // If in single select mode, replace the current selection
119
- if (singleSelect) {
120
- // Move any currently selected tag back to available tags
121
- if (selectedTagsStack.length > 0) {
122
- const currentSelected = selectedTagsStack[0];
123
- setTags((prev) => [...prev, { ...currentSelected, isSelected: false }]);
124
- }
125
- setSelectedTagsStack([{ ...tagToSelect, isSelected: true }]);
126
- setTags((prev) => prev.filter((tag) => tag.id !== id));
127
- } else {
128
- // Multi-select behavior (original)
129
- setSelectedTagsStack((prev) => [...prev, { ...tagToSelect, isSelected: true }]);
130
- setTags((prev) => prev.filter((tag) => tag.id !== id));
131
- }
132
- }
133
- filterTagsBySearch("");
134
- setFocusedPopoverIndex(null);
135
- };
136
-
137
- const handleUnselectTag = (id: string) => {
138
- const tagToUnselect = selectedTagsStack.find((tag) => tag.id === id);
139
- if (tagToUnselect) {
140
- setSelectedTagsStack((prev) => prev.filter((tag) => tag.id !== id));
141
- setTags((prev) => [...prev, { ...tagToUnselect, isSelected: false }]);
142
- }
143
- setFocusedTagIndex(null);
144
- };
145
-
146
- /**
147
- * LOCAL PATCH (Contact Center): turn typed text into a selected tag.
148
- *
149
- * Upstream had no way in but `handleSelectTag(id)` against the fixed `Tags` list, so a free-text
150
- * list (a person's emails, an organization's aliases) could not be expressed as a badge field at
151
- * all — which is why those lists were built as one-column tables instead. Matching an existing
152
- * tag by name selects it rather than creating a duplicate; the id IS the text, so a value the
153
- * caller round-trips keeps a stable identity.
154
- */
155
- const handleCreateTag = (rawName: string) => {
156
- const name = rawName.trim();
157
- if (!name) return;
158
- const sameName = (tag: Tag) => tag.name.toLowerCase() === name.toLowerCase();
159
-
160
- // Already chosen — just clear the box so the user sees their text was accepted.
161
- if (selectedTagsStack.some(sameName)) {
162
- filterTagsBySearch("");
163
- return;
164
- }
165
- // Offered in the list — select it instead of creating a look-alike.
166
- const existing = tags.find(sameName);
167
- if (existing) {
168
- handleSelectTag(existing.id);
169
- return;
170
- }
171
-
172
- const created: Tag = { id: name, name, value: name, isSelected: true };
173
- setSelectedTagsStack((prev) => (singleSelect ? [created] : [...prev, created]));
174
- filterTagsBySearch("");
175
- setFocusedPopoverIndex(null);
176
- };
177
-
178
- // Reset the hook state with new data
179
- const reset = (newTags: Tag[] = [], newSelectedTags: Tag[] = []) => {
180
- // In single select mode, ensure we only have at most one selected tag
181
- const selectedTags =
182
- singleSelect && newSelectedTags.length > 0 ? [newSelectedTags[0]] : newSelectedTags;
183
-
184
- setTags(newTags);
185
- setSelectedTagsStack(selectedTags);
186
- filterTagsBySearch("");
187
- setFocusedTagIndex(null);
188
- setFocusedPopoverIndex(null);
189
- };
190
-
191
- const handleNavigationWithinSelectedTags = (e: React.KeyboardEvent<HTMLElement>) => {
192
- if (e.key === "ArrowLeft") {
193
- e.preventDefault();
194
- setFocusedTagIndex((prev: number | null) =>
195
- prev === 0 ? selectedTagsStack.length - 1 : prev! - 1,
196
- );
197
- } else if (e.key === "ArrowRight") {
198
- e.preventDefault();
199
- setFocusedTagIndex((prev: number | null) =>
200
- prev === selectedTagsStack.length - 1 ? 0 : prev! + 1,
201
- );
202
- } else if (e.key === "Delete" || e.key === "Backspace") {
203
- e.preventDefault();
204
- const tagToRemove = selectedTagsStack[focusedTagIndex!];
205
- handleUnselectTag(tagToRemove.id);
206
- if (selectedTagsStack.length > 1) {
207
- setFocusedTagIndex(Math.min(focusedTagIndex!, selectedTagsStack.length - 2));
208
- } else {
209
- setFocusedTagIndex(null);
210
- }
211
- } else if (e.key === "Escape") {
212
- e.preventDefault();
213
- setFocusedTagIndex(null);
214
- } else if (e.key === "ArrowDown") {
215
- e.preventDefault();
216
- setIsPopoverOpen(true);
217
- setFocusedPopoverIndex(0);
218
- setFocusedTagIndex(null);
219
- } else {
220
- inputRef?.current?.focus();
221
- }
222
- };
223
-
224
- const handleNavigationWithinPopover = (e: React.KeyboardEvent<HTMLElement>) => {
225
- if (e.key === "ArrowUp") {
226
- e.preventDefault();
227
- if (focusedPopoverIndex === 0 || focusedPopoverIndex === null) {
228
- if (selectedTagsStack.length > 0) {
229
- setIsPopoverOpen(false);
230
- setFocusedTagIndex(0);
231
- setFocusedPopoverIndex(null);
232
- } else {
233
- setFocusedPopoverIndex(filteredTags.length - 1);
234
- }
235
- } else {
236
- setFocusedPopoverIndex((prev) => (prev === null ? 0 : prev - 1));
237
- }
238
- } else if (e.key === "ArrowDown") {
239
- e.preventDefault();
240
- setFocusedPopoverIndex((prev) =>
241
- prev === null ? 0 : prev === filteredTags.length - 1 ? 0 : prev + 1,
242
- );
243
- } else if (e.key === "Enter" && focusedPopoverIndex !== null) {
244
- e.preventDefault();
245
- handleSelectTag(filteredTags[focusedPopoverIndex].id);
246
- } else if (e.key === "Escape") {
247
- e.preventDefault();
248
- setIsPopoverOpen(false);
249
- setFocusedPopoverIndex(null);
250
- } else {
251
- inputRef?.current?.focus();
252
- }
253
- };
254
-
255
- const handleInitialFocus = (e: React.KeyboardEvent<HTMLElement>) => {
256
- if ((e.key === "ArrowLeft" || e.key === "ArrowRight") && selectedTagsStack.length > 0) {
257
- e.preventDefault();
258
- setFocusedTagIndex(e.key === "ArrowLeft" ? selectedTagsStack.length - 1 : 0);
259
- } else if (e.key === "ArrowDown" && !isPopoverOpen && filteredTags.length > 0) {
260
- e.preventDefault();
261
- setIsPopoverOpen(true);
262
- setFocusedPopoverIndex(0);
263
- } else {
264
- inputRef?.current?.focus();
265
- }
266
- };
267
-
268
- const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
269
- if (focusedTagIndex !== null && !isPopoverOpen) {
270
- handleNavigationWithinSelectedTags(e);
271
- } else if (isPopoverOpen && filteredTags.length > 0) {
272
- handleNavigationWithinPopover(e);
273
- } else {
274
- handleInitialFocus(e);
275
- }
276
- };
277
-
278
- return {
279
- tags,
280
- selectedTagsStack,
281
- searchTags,
282
- handleSelectTag,
283
- handleUnselectTag,
284
- // LOCAL PATCH (Contact Center) — see above.
285
- handleCreateTag,
286
- creatable,
287
- handleKeyDown,
288
- setFocusedTagIndex,
289
- setFocusedPopoverIndex,
290
- filterTagsBySearch,
291
- filteredTags,
292
- filteredSelectedTags,
293
- focusedTagIndex,
294
- focusedPopoverIndex,
295
- isPopoverOpen,
296
- setIsPopoverOpen,
297
- reset,
298
- singleSelect,
299
- };
300
- };