torch-glare 2.4.0 → 2.4.2

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 (318) hide show
  1. package/README.md +8 -0
  2. package/apps/lib/components/ActionButton.tsx +7 -12
  3. package/apps/lib/components/ActionsGroup.tsx +4 -15
  4. package/apps/lib/components/AlertDialog.tsx +173 -191
  5. package/apps/lib/components/Avatar.tsx +13 -16
  6. package/apps/lib/components/Badge.tsx +1 -3
  7. package/apps/lib/components/BadgeField.tsx +76 -71
  8. package/apps/lib/components/Breadcrumb.tsx +49 -85
  9. package/apps/lib/components/Button.tsx +21 -20
  10. package/apps/lib/components/ButtonGroup.tsx +31 -41
  11. package/apps/lib/components/Calendar.tsx +51 -29
  12. package/apps/lib/components/Card.tsx +40 -24
  13. package/apps/lib/components/Checkbox.tsx +9 -16
  14. package/apps/lib/components/ColorPicker.tsx +441 -0
  15. package/apps/lib/components/ConclusionHeader.tsx +148 -0
  16. package/apps/lib/components/ContextMenu.tsx +97 -96
  17. package/apps/lib/components/CountBadge.tsx +4 -6
  18. package/apps/lib/components/DataTable.tsx +196 -216
  19. package/apps/lib/components/DataViews/DataViewRadio.tsx +1 -6
  20. package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +13 -47
  21. package/apps/lib/components/DataViews/DataViewsHeader.tsx +1 -3
  22. package/apps/lib/components/DataViews/DataViewsLayout.tsx +5 -12
  23. package/apps/lib/components/DataViews/FilterPanel.tsx +155 -149
  24. package/apps/lib/components/DataViews/HeaderSearch.tsx +1 -5
  25. package/apps/lib/components/DataViews/InboxView.tsx +22 -68
  26. package/apps/lib/components/DataViews/InboxViewCard.tsx +68 -77
  27. package/apps/lib/components/DataViews/KanbanView.tsx +8 -25
  28. package/apps/lib/components/DataViews/PanelControls.tsx +3 -13
  29. package/apps/lib/components/DataViews/SettingsPanel.tsx +83 -89
  30. package/apps/lib/components/DataViews/TableView.tsx +8 -28
  31. package/apps/lib/components/DataViews/TreeView.tsx +12 -40
  32. package/apps/lib/components/DataViews/badgeAdapter.ts +32 -28
  33. package/apps/lib/components/DataViews/fieldRenderers.tsx +106 -141
  34. package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +30 -23
  35. package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +39 -32
  36. package/apps/lib/components/DataViews/filters/PresetChips.tsx +15 -15
  37. package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +69 -58
  38. package/apps/lib/components/DataViews/index.ts +26 -26
  39. package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +12 -16
  40. package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +28 -31
  41. package/apps/lib/components/DataViews/types.ts +104 -115
  42. package/apps/lib/components/DatePicker.tsx +200 -196
  43. package/apps/lib/components/Dialog.tsx +92 -105
  44. package/apps/lib/components/Divider.tsx +21 -24
  45. package/apps/lib/components/Drawer.tsx +124 -142
  46. package/apps/lib/components/DropdownMenu.tsx +131 -171
  47. package/apps/lib/components/FieldHint.tsx +4 -11
  48. package/apps/lib/components/Form.tsx +146 -155
  49. package/apps/lib/components/FormBuilder/DisplayField.tsx +40 -0
  50. package/apps/lib/components/FormBuilder/context.ts +71 -0
  51. package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +65 -0
  52. package/apps/lib/components/FormBuilder/fields/ColorField.tsx +76 -0
  53. package/apps/lib/components/FormBuilder/fields/CustomField.tsx +16 -0
  54. package/apps/lib/components/FormBuilder/fields/DateField.tsx +34 -0
  55. package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +79 -0
  56. package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +174 -0
  57. package/apps/lib/components/FormBuilder/fields/FileField.tsx +40 -0
  58. package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +139 -0
  59. package/apps/lib/components/FormBuilder/fields/OtpField.tsx +32 -0
  60. package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +82 -0
  61. package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +37 -0
  62. package/apps/lib/components/FormBuilder/fields/SelectField.tsx +101 -0
  63. package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +175 -0
  64. package/apps/lib/components/FormBuilder/fields/SliderField.tsx +72 -0
  65. package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +42 -0
  66. package/apps/lib/components/FormBuilder/fields/TableField.tsx +312 -0
  67. package/apps/lib/components/FormBuilder/fields/TextField.tsx +222 -0
  68. package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +49 -0
  69. package/apps/lib/components/FormBuilder/fields/countries.ts +303 -0
  70. package/apps/lib/components/FormBuilder/fields/index.ts +25 -0
  71. package/apps/lib/components/FormBuilder/form-builder.tsx +292 -0
  72. package/apps/lib/components/FormBuilder/header.tsx +105 -0
  73. package/apps/lib/components/FormBuilder/index.ts +37 -0
  74. package/apps/lib/components/FormBuilder/numberFormat.ts +16 -0
  75. package/apps/lib/components/FormBuilder/stepper.tsx +217 -0
  76. package/apps/lib/components/FormBuilder/submit.tsx +41 -0
  77. package/apps/lib/components/FormBuilder/types.ts +264 -0
  78. package/apps/lib/components/FormBuilder/viewFormat.tsx +137 -0
  79. package/apps/lib/components/FormRenderer/FormDrawer.tsx +121 -0
  80. package/apps/lib/components/FormRenderer/form-renderer.tsx +113 -0
  81. package/apps/lib/components/FormRenderer/index.ts +9 -0
  82. package/apps/lib/components/FormRenderer/types.ts +79 -0
  83. package/apps/lib/components/FormStepper.tsx +9 -39
  84. package/apps/lib/components/FormSummary.tsx +282 -0
  85. package/apps/lib/components/HeaderBar.tsx +1 -9
  86. package/apps/lib/components/ImageAttachment.tsx +106 -93
  87. package/apps/lib/components/InnerLabelField.tsx +20 -16
  88. package/apps/lib/components/Input.tsx +171 -172
  89. package/apps/lib/components/InputField.tsx +44 -45
  90. package/apps/lib/components/InputOTP.tsx +68 -69
  91. package/apps/lib/components/Label.tsx +61 -58
  92. package/apps/lib/components/LabelField.tsx +4 -5
  93. package/apps/lib/components/LabeledCheckBox.tsx +8 -12
  94. package/apps/lib/components/LabeledRadio.tsx +7 -5
  95. package/apps/lib/components/LinkButton.tsx +2 -9
  96. package/apps/lib/components/LoginButton.tsx +4 -9
  97. package/apps/lib/components/PasswordLevel.tsx +5 -5
  98. package/apps/lib/components/Popover.tsx +15 -33
  99. package/apps/lib/components/ProfileMenu.tsx +67 -72
  100. package/apps/lib/components/Radio.tsx +1 -5
  101. package/apps/lib/components/RadioCard.tsx +11 -28
  102. package/apps/lib/components/ScrollArea.tsx +45 -43
  103. package/apps/lib/components/SearchField.tsx +49 -39
  104. package/apps/lib/components/SearchableSelect.tsx +16 -16
  105. package/apps/lib/components/SearchableTable.tsx +108 -118
  106. package/apps/lib/components/SearchableTree.tsx +469 -0
  107. package/apps/lib/components/SearchableTreeDialog.tsx +493 -0
  108. package/apps/lib/components/SectionBlock.tsx +19 -23
  109. package/apps/lib/components/Select.tsx +80 -186
  110. package/apps/lib/components/SimpleSelect.tsx +196 -187
  111. package/apps/lib/components/Skeleton.tsx +9 -12
  112. package/apps/lib/components/SlideDatePicker.tsx +215 -166
  113. package/apps/lib/components/SpinLoading.tsx +33 -49
  114. package/apps/lib/components/Stepper.tsx +13 -56
  115. package/apps/lib/components/Switch.tsx +8 -10
  116. package/apps/lib/components/TabFormItem.tsx +3 -12
  117. package/apps/lib/components/TabSwitch.tsx +7 -34
  118. package/apps/lib/components/Table.tsx +60 -75
  119. package/apps/lib/components/{ChartBlockTool.ts → TextEditor/ChartBlockTool.ts} +17 -52
  120. package/apps/lib/components/TextEditor/RichTextField.tsx +46 -0
  121. package/apps/lib/components/{TableDnDWrapper.ts → TextEditor/TableDnDWrapper.ts} +15 -48
  122. package/apps/lib/components/{TextEditor.tsx → TextEditor/TextEditor.tsx} +156 -113
  123. package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +429 -0
  124. package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +70 -0
  125. package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +50 -0
  126. package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +48 -0
  127. package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +98 -0
  128. package/apps/lib/{types → components/TextEditor}/editorjs.d.ts +19 -0
  129. package/apps/lib/components/TextEditor/index.ts +7 -0
  130. package/apps/lib/{utils → components/TextEditor}/markdownParser.ts +2 -7
  131. package/apps/lib/components/Textarea.tsx +9 -13
  132. package/apps/lib/components/Timeline.tsx +21 -41
  133. package/apps/lib/components/Toast.tsx +83 -83
  134. package/apps/lib/components/Toggle.tsx +112 -114
  135. package/apps/lib/components/ToggleButton.tsx +1 -1
  136. package/apps/lib/components/Tooltip.tsx +24 -19
  137. package/apps/lib/components/TransparentLabel.tsx +61 -62
  138. package/apps/lib/components/TreeDropDown.tsx +86 -52
  139. package/apps/lib/components/TreeFolder/TreeFolder.tsx +15 -48
  140. package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +16 -21
  141. package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +9 -20
  142. package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +3 -3
  143. package/apps/lib/components/TreeFolder/icons.tsx +14 -17
  144. package/apps/lib/components/TreeFolder/index.ts +15 -8
  145. package/apps/lib/components/TreeFolder/treeFolderUtils.ts +47 -52
  146. package/apps/lib/components/TreeFolder/types.ts +32 -32
  147. package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +117 -123
  148. package/apps/lib/hooks/useActiveTreeItem.ts +52 -55
  149. package/apps/lib/hooks/useClickOutside.ts +21 -20
  150. package/apps/lib/hooks/useDataViewsState.ts +86 -80
  151. package/apps/lib/hooks/useIsMobile.ts +12 -12
  152. package/apps/lib/hooks/useResize.ts +54 -65
  153. package/apps/lib/hooks/useTagSelection.ts +201 -201
  154. package/apps/lib/layouts/CNLayout.tsx +181 -140
  155. package/apps/lib/layouts/DataViewCard.tsx +4 -18
  156. package/apps/lib/layouts/FieldSection.tsx +2 -6
  157. package/apps/lib/layouts/TreeSubLayout.tsx +24 -38
  158. package/apps/lib/providers/ThemeProvider.tsx +8 -23
  159. package/apps/lib/registry.json +997 -0
  160. package/apps/lib/tsconfig.json +9 -0
  161. package/apps/lib/tsconfig.tsbuildinfo +1 -0
  162. package/apps/lib/utils/cn.ts +1 -1
  163. package/apps/lib/utils/color.ts +175 -0
  164. package/apps/lib/utils/dataViews/columnUtils.ts +46 -44
  165. package/apps/lib/utils/dataViews/fieldUtils.ts +70 -71
  166. package/apps/lib/utils/dataViews/nestedDataUtils.tsx +129 -122
  167. package/apps/lib/utils/dataViews/pathUtils.ts +74 -67
  168. package/apps/lib/utils/dataViews/rangeUtils.ts +121 -112
  169. package/apps/lib/utils/dataViews/treeUtils.ts +204 -211
  170. package/apps/lib/utils/dateFormat.ts +64 -54
  171. package/apps/lib/utils/resize.ts +21 -25
  172. package/apps/lib/utils/types.ts +13 -13
  173. package/dist/bin/index.js +8 -2
  174. package/dist/bin/index.js.map +1 -1
  175. package/dist/src/shared/getAvailableFiles.d.ts.map +1 -1
  176. package/dist/src/shared/getAvailableFiles.js +6 -1
  177. package/dist/src/shared/getAvailableFiles.js.map +1 -1
  178. package/dist/src/shared/loadRegistry.d.ts +7 -0
  179. package/dist/src/shared/loadRegistry.d.ts.map +1 -0
  180. package/dist/src/shared/loadRegistry.js +31 -0
  181. package/dist/src/shared/loadRegistry.js.map +1 -0
  182. package/dist/src/shared/resolveInstallPlan.d.ts +12 -0
  183. package/dist/src/shared/resolveInstallPlan.d.ts.map +1 -0
  184. package/dist/src/shared/resolveInstallPlan.js +39 -0
  185. package/dist/src/shared/resolveInstallPlan.js.map +1 -0
  186. package/dist/src/types/main.d.ts +24 -0
  187. package/dist/src/types/main.d.ts.map +1 -1
  188. package/docs/README.md +10 -2
  189. package/docs/components/action-button.md +30 -24
  190. package/docs/components/actions-group.md +26 -20
  191. package/docs/components/alert-dialog.md +45 -45
  192. package/docs/components/avatar.md +6 -2
  193. package/docs/components/badge-field.md +6 -2
  194. package/docs/components/badge.md +7 -1
  195. package/docs/components/breadcrumb.md +15 -40
  196. package/docs/components/button-group.md +13 -10
  197. package/docs/components/button.md +58 -33
  198. package/docs/components/calendar.md +26 -19
  199. package/docs/components/card.md +23 -18
  200. package/docs/components/chart-block-tool.md +129 -0
  201. package/docs/components/checkbox.md +16 -8
  202. package/docs/components/cn-layout.md +7 -1
  203. package/docs/components/color-picker.md +101 -0
  204. package/docs/components/conclusion-header.md +80 -0
  205. package/docs/components/context-menu.md +18 -25
  206. package/docs/components/count-badge.md +7 -1
  207. package/docs/components/data-table.md +45 -33
  208. package/docs/components/data-views-config-panel.md +15 -11
  209. package/docs/components/data-views-layout.md +13 -16
  210. package/docs/components/date-picker.md +30 -23
  211. package/docs/components/dialog.md +43 -42
  212. package/docs/components/divider.md +10 -4
  213. package/docs/components/drawer.md +161 -135
  214. package/docs/components/dropdown-menu.md +25 -34
  215. package/docs/components/field-hint.md +37 -25
  216. package/docs/components/field-section.md +9 -3
  217. package/docs/components/form-builder.md +270 -0
  218. package/docs/components/form-renderer.md +228 -0
  219. package/docs/components/form-stepper.md +6 -0
  220. package/docs/components/form-summary.md +123 -0
  221. package/docs/components/form.md +17 -20
  222. package/docs/components/header-bar.md +6 -0
  223. package/docs/components/image-attachment.md +43 -45
  224. package/docs/components/inbox-view.md +16 -5
  225. package/docs/components/inner-label-field.md +34 -24
  226. package/docs/components/input-field.md +18 -10
  227. package/docs/components/input-otp.md +14 -11
  228. package/docs/components/input.md +22 -16
  229. package/docs/components/kanban-view.md +15 -5
  230. package/docs/components/label-field.md +32 -22
  231. package/docs/components/label.md +43 -32
  232. package/docs/components/labeled-check-box.md +16 -8
  233. package/docs/components/labeled-radio.md +18 -11
  234. package/docs/components/link-button.md +7 -1
  235. package/docs/components/login-button.md +8 -2
  236. package/docs/components/password-level.md +37 -24
  237. package/docs/components/popover.md +26 -23
  238. package/docs/components/profile-menu.md +38 -27
  239. package/docs/components/radio-card.md +16 -9
  240. package/docs/components/radio.md +16 -8
  241. package/docs/components/scroll-area.md +6 -2
  242. package/docs/components/search-field.md +14 -6
  243. package/docs/components/searchable-select.md +19 -14
  244. package/docs/components/searchable-table.md +18 -13
  245. package/docs/components/searchable-tree-dialog.md +190 -0
  246. package/docs/components/searchable-tree.md +200 -0
  247. package/docs/components/section-block.md +12 -4
  248. package/docs/components/select.md +23 -18
  249. package/docs/components/simple-select.md +14 -10
  250. package/docs/components/skeleton.md +43 -33
  251. package/docs/components/slide-date-picker.md +37 -29
  252. package/docs/components/spin-loading.md +32 -23
  253. package/docs/components/stepper.md +6 -0
  254. package/docs/components/switch.md +14 -6
  255. package/docs/components/tab-form-item.md +7 -1
  256. package/docs/components/tab-switch.md +13 -6
  257. package/docs/components/table-dnd-wrapper.md +107 -0
  258. package/docs/components/table-view.md +15 -5
  259. package/docs/components/table.md +28 -28
  260. package/docs/components/text-editor.md +37 -13
  261. package/docs/components/textarea.md +15 -7
  262. package/docs/components/timeline.md +6 -0
  263. package/docs/components/toast.md +35 -26
  264. package/docs/components/toggle-button.md +24 -21
  265. package/docs/components/toggle.md +23 -15
  266. package/docs/components/tooltip.md +42 -30
  267. package/docs/components/transparent-label.md +29 -20
  268. package/docs/components/tree-drop-down.md +31 -23
  269. package/docs/components/tree-sub-layout.md +6 -2
  270. package/docs/components/tree-view.md +16 -5
  271. package/docs/explanation/architecture.md +54 -0
  272. package/docs/explanation/design-system.md +52 -0
  273. package/docs/how-to/data-views-from-backend-response.md +6 -4
  274. package/docs/how-to/form-and-list-recipes.md +26 -19
  275. package/docs/how-to/forms-with-form-builder.md +408 -0
  276. package/docs/how-to/guides.md +177 -197
  277. package/docs/migration/changelog.md +38 -0
  278. package/docs/reference/cli.md +87 -0
  279. package/docs/reference/components.md +11 -12
  280. package/docs/reference/hooks.md +8 -8
  281. package/docs/reference/providers.md +22 -22
  282. package/docs/reference/tailwind-plugins.md +2 -2
  283. package/docs/reference/theme.md +85 -0
  284. package/docs/reference/types.md +4 -4
  285. package/docs/reference/utilities.md +19 -26
  286. package/docs/tutorials/building-first-form.md +170 -172
  287. package/docs/tutorials/component-composition.md +34 -50
  288. package/docs/tutorials/getting-started.md +2 -2
  289. package/docs/tutorials/theming-basics.md +13 -10
  290. package/package.json +31 -3
  291. package/dist/src/commands/block.d.ts +0 -5
  292. package/dist/src/commands/block.d.ts.map +0 -1
  293. package/dist/src/commands/block.js +0 -255
  294. package/dist/src/commands/block.js.map +0 -1
  295. package/dist/src/shared/configureFonts.d.ts +0 -6
  296. package/dist/src/shared/configureFonts.d.ts.map +0 -1
  297. package/dist/src/shared/configureFonts.js +0 -106
  298. package/dist/src/shared/configureFonts.js.map +0 -1
  299. package/dist/src/shared/configureGlobalCss.d.ts +0 -6
  300. package/dist/src/shared/configureGlobalCss.d.ts.map +0 -1
  301. package/dist/src/shared/configureGlobalCss.js +0 -154
  302. package/dist/src/shared/configureGlobalCss.js.map +0 -1
  303. package/dist/src/shared/configureTailwind.d.ts +0 -7
  304. package/dist/src/shared/configureTailwind.d.ts.map +0 -1
  305. package/dist/src/shared/configureTailwind.js +0 -163
  306. package/dist/src/shared/configureTailwind.js.map +0 -1
  307. package/dist/src/shared/detectFramework.d.ts +0 -23
  308. package/dist/src/shared/detectFramework.d.ts.map +0 -1
  309. package/dist/src/shared/detectFramework.js +0 -119
  310. package/dist/src/shared/detectFramework.js.map +0 -1
  311. package/dist/src/shared/installBaseUtils.d.ts +0 -5
  312. package/dist/src/shared/installBaseUtils.d.ts.map +0 -1
  313. package/dist/src/shared/installBaseUtils.js +0 -79
  314. package/dist/src/shared/installBaseUtils.js.map +0 -1
  315. package/dist/src/shared/resolveAliases.d.ts +0 -24
  316. package/dist/src/shared/resolveAliases.d.ts.map +0 -1
  317. package/dist/src/shared/resolveAliases.js +0 -98
  318. package/dist/src/shared/resolveAliases.js.map +0 -1
@@ -0,0 +1,222 @@
1
+ "use client";
2
+
3
+ import { ReactNode, useEffect, useLayoutEffect, useRef, useState, type ChangeEvent } from "react";
4
+ import type { ControllerRenderProps, FieldValues } from "react-hook-form";
5
+
6
+ import { InputField } from "../../InputField";
7
+ import { Textarea } from "../../Textarea";
8
+ import { PasswordLevel } from "../../PasswordLevel";
9
+ import { useLoading, useCell } from "../context";
10
+ import { formatFieldView } from "../viewFormat";
11
+ import { formatNumber } from "../numberFormat";
12
+ import type { BaseFieldProps, CurrencyFieldProps, PasswordFieldProps } from "../types";
13
+ import { FieldShell } from "./FieldShell";
14
+
15
+ // Run before paint on the client; fall back to useEffect on the server (no SSR warning).
16
+ const useIsoLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
17
+
18
+ /**
19
+ * A number input that shows a **live** thousands-separated value (e.g. "1,299")
20
+ * while storing the raw `number` in the form. Commas are inserted as you type and
21
+ * the caret is preserved; decimals (and a trailing ".") are kept intact.
22
+ */
23
+ function NumberInput({
24
+ field,
25
+ icon,
26
+ placeholder,
27
+ disabled,
28
+ onTable,
29
+ }: {
30
+ field: ControllerRenderProps<FieldValues, string>;
31
+ icon?: ReactNode;
32
+ placeholder?: string;
33
+ disabled?: boolean;
34
+ onTable?: boolean;
35
+ }) {
36
+ const inputRef = useRef<HTMLInputElement | null>(null);
37
+ const caretRef = useRef<number | null>(null);
38
+ const [text, setText] = useState<string>(() => formatNumber(field.value));
39
+
40
+ // Reflect external value changes (e.g. edit data loading) while not editing.
41
+ useEffect(() => {
42
+ if (document.activeElement === inputRef.current) return;
43
+ setText(formatNumber(field.value));
44
+ }, [field.value]);
45
+
46
+ // Restore the caret after a live reformat (commas shift positions).
47
+ useIsoLayoutEffect(() => {
48
+ if (caretRef.current != null && inputRef.current) {
49
+ inputRef.current.setSelectionRange(caretRef.current, caretRef.current);
50
+ caretRef.current = null;
51
+ }
52
+ });
53
+
54
+ const setRefs = (el: HTMLInputElement | null) => {
55
+ inputRef.current = el;
56
+ if (typeof field.ref === "function") field.ref(el);
57
+ };
58
+
59
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
60
+ const raw = e.target.value;
61
+ const caret = e.target.selectionStart ?? raw.length;
62
+ const digitsBeforeCaret = raw.slice(0, caret).replace(/\D/g, "").length;
63
+
64
+ // Keep digits and a single decimal point.
65
+ let cleaned = raw.replace(/[^\d.]/g, "");
66
+ const dot = cleaned.indexOf(".");
67
+ if (dot !== -1) {
68
+ cleaned = cleaned.slice(0, dot + 1) + cleaned.slice(dot + 1).replace(/\./g, "");
69
+ }
70
+
71
+ let formatted = "";
72
+ if (cleaned !== "") {
73
+ const [intPart, decPart] = cleaned.split(".");
74
+ const intFmt = intPart === "" ? "" : Number(intPart).toLocaleString("en-US");
75
+ formatted = decPart !== undefined ? `${intFmt}.${decPart}` : intFmt;
76
+ }
77
+
78
+ // Caret goes after the same count of digits, skipping the inserted commas.
79
+ let pos = 0;
80
+ let seen = 0;
81
+ while (pos < formatted.length && seen < digitsBeforeCaret) {
82
+ if (/\d/.test(formatted[pos])) seen++;
83
+ pos++;
84
+ }
85
+ caretRef.current = pos;
86
+
87
+ setText(formatted);
88
+ field.onChange(cleaned === "" || cleaned === "." ? undefined : Number(cleaned));
89
+ };
90
+
91
+ return (
92
+ <InputField
93
+ name={field.name}
94
+ ref={setRefs}
95
+ type="text"
96
+ inputMode="decimal"
97
+ icon={icon}
98
+ value={text}
99
+ placeholder={placeholder}
100
+ disabled={disabled}
101
+ onTable={onTable}
102
+ className="w-full"
103
+ onChange={handleChange}
104
+ onBlur={() => field.onBlur()}
105
+ />
106
+ );
107
+ }
108
+
109
+ function TextLike({ props, type }: { props: BaseFieldProps; type: "text" | "email" | "password" }) {
110
+ const loading = useLoading();
111
+ const cell = useCell();
112
+ return (
113
+ <FieldShell {...props} view={(v) => formatFieldView({ kind: "text", value: v })}>
114
+ {(field) => (
115
+ <InputField
116
+ {...field}
117
+ type={type}
118
+ value={field.value ?? ""}
119
+ placeholder={props.placeholder}
120
+ disabled={props.disabled || loading}
121
+ onTable={cell}
122
+ className="w-full"
123
+ />
124
+ )}
125
+ </FieldShell>
126
+ );
127
+ }
128
+
129
+ export function TextField(props: BaseFieldProps) {
130
+ return <TextLike props={props} type="text" />;
131
+ }
132
+ export function EmailField(props: BaseFieldProps) {
133
+ return <TextLike props={props} type="email" />;
134
+ }
135
+ export function PasswordField(props: PasswordFieldProps) {
136
+ const loading = useLoading();
137
+ const cell = useCell();
138
+ return (
139
+ <FieldShell
140
+ {...props}
141
+ view={(v) => formatFieldView({ kind: "text", value: v ? "••••••••" : "" })}
142
+ >
143
+ {(field) => (
144
+ <div className="flex w-full flex-col gap-2">
145
+ <InputField
146
+ {...field}
147
+ type="password"
148
+ value={field.value ?? ""}
149
+ placeholder={props.placeholder}
150
+ disabled={props.disabled || loading}
151
+ onTable={cell}
152
+ className="w-full"
153
+ />
154
+ {props.strengthMeter && <PasswordLevel value={field.value ?? ""} />}
155
+ </div>
156
+ )}
157
+ </FieldShell>
158
+ );
159
+ }
160
+
161
+ export function NumberField(props: BaseFieldProps) {
162
+ const loading = useLoading();
163
+ const cell = useCell();
164
+ return (
165
+ <FieldShell {...props} view={(v) => formatFieldView({ kind: "number", value: v })}>
166
+ {(field) => (
167
+ <NumberInput
168
+ field={field}
169
+ placeholder={props.placeholder}
170
+ disabled={props.disabled || loading}
171
+ onTable={cell}
172
+ />
173
+ )}
174
+ </FieldShell>
175
+ );
176
+ }
177
+
178
+ export function CurrencyField(props: CurrencyFieldProps) {
179
+ const loading = useLoading();
180
+ const cell = useCell();
181
+ return (
182
+ <FieldShell
183
+ {...props}
184
+ view={(v) =>
185
+ formatFieldView({ kind: "currency", value: v, currencySymbol: props.currencySymbol })
186
+ }
187
+ >
188
+ {(field) => (
189
+ <NumberInput
190
+ field={field}
191
+ icon={
192
+ props.currencySymbol ? (
193
+ <span className="typography-body-small-medium">{props.currencySymbol}</span>
194
+ ) : undefined
195
+ }
196
+ placeholder={props.placeholder}
197
+ disabled={props.disabled || loading}
198
+ onTable={cell}
199
+ />
200
+ )}
201
+ </FieldShell>
202
+ );
203
+ }
204
+
205
+ export function TextareaField(props: BaseFieldProps & { rows?: number }) {
206
+ const loading = useLoading();
207
+ return (
208
+ <FieldShell {...props} view={(v) => formatFieldView({ kind: "text", value: v })}>
209
+ {(field, fieldState) => (
210
+ <Textarea
211
+ {...field}
212
+ value={field.value ?? ""}
213
+ rows={props.rows}
214
+ placeholder={props.placeholder}
215
+ disabled={props.disabled || loading}
216
+ state={fieldState.error ? "negative" : undefined}
217
+ className="w-full"
218
+ />
219
+ )}
220
+ </FieldShell>
221
+ );
222
+ }
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import { SearchableTree } from "../../SearchableTree";
4
+ import type { TreeSelectFieldProps } from "../types";
5
+ import { FieldShell } from "./FieldShell";
6
+
7
+ /**
8
+ * `FormBuilder.TreeSelect` — hierarchical single-select (Glare `SearchableTree`).
9
+ * Stores the selected node's id; seeds the picker + view label by finding the
10
+ * node back from that id.
11
+ */
12
+ export function TreeSelectField<T>(props: TreeSelectFieldProps<T>) {
13
+ const findById = (id: unknown): T | null => {
14
+ const target = String(id ?? "");
15
+ if (!target) return null;
16
+ // Works for both nested (getNodeChildren) and flat node lists.
17
+ const stack: T[] = [...props.nodes];
18
+ while (stack.length) {
19
+ const node = stack.pop() as T;
20
+ if (props.getNodeId(node) === target) return node;
21
+ const kids = props.getNodeChildren?.(node);
22
+ if (kids && kids.length) stack.push(...kids);
23
+ }
24
+ return null;
25
+ };
26
+
27
+ return (
28
+ <FieldShell
29
+ {...props}
30
+ view={(v) => {
31
+ const node = findById(v);
32
+ return { value: node ? String(props.getNodeLabel(node)) : "" };
33
+ }}
34
+ >
35
+ {(field) => (
36
+ <SearchableTree
37
+ nodes={props.nodes}
38
+ getNodeId={props.getNodeId}
39
+ getNodeLabel={props.getNodeLabel}
40
+ getNodeChildren={props.getNodeChildren}
41
+ parentIdKey={props.parentIdKey as (keyof T & string) | undefined}
42
+ selectableFolders={props.selectableFolders}
43
+ value={findById(field.value)}
44
+ onSelect={(node) => field.onChange(props.getNodeId(node))}
45
+ />
46
+ )}
47
+ </FieldShell>
48
+ );
49
+ }
@@ -0,0 +1,303 @@
1
+ /**
2
+ * ISO 3166-1 countries + their E.164 calling codes, for `FormBuilder.Phone`.
3
+ *
4
+ * Data is stored compactly as `[isoCode, name, dial]`; the flag emoji is derived from the ISO code
5
+ * (regional-indicator letters) rather than stored. Dial codes are NOT unique (US/Canada share +1,
6
+ * etc.) — that's why the picker keys options by the unique ISO `code`, and `countryByDial` resolves
7
+ * a stored dial back to a representative country.
8
+ */
9
+
10
+ export interface Country {
11
+ /** ISO 3166-1 alpha-2 code, unique — e.g. "US". */
12
+ code: string;
13
+ name: string;
14
+ /** E.164 calling code with leading "+", e.g. "+1". */
15
+ dial: string;
16
+ }
17
+
18
+ // [ISO code, name, dial(no +)]
19
+ const DATA: ReadonlyArray<readonly [string, string, string]> = [
20
+ ["AF", "Afghanistan", "93"],
21
+ ["AX", "Åland Islands", "358"],
22
+ ["AL", "Albania", "355"],
23
+ ["DZ", "Algeria", "213"],
24
+ ["AS", "American Samoa", "1"],
25
+ ["AD", "Andorra", "376"],
26
+ ["AO", "Angola", "244"],
27
+ ["AI", "Anguilla", "1"],
28
+ ["AG", "Antigua and Barbuda", "1"],
29
+ ["AR", "Argentina", "54"],
30
+ ["AM", "Armenia", "374"],
31
+ ["AW", "Aruba", "297"],
32
+ ["AU", "Australia", "61"],
33
+ ["AT", "Austria", "43"],
34
+ ["AZ", "Azerbaijan", "994"],
35
+ ["BS", "Bahamas", "1"],
36
+ ["BH", "Bahrain", "973"],
37
+ ["BD", "Bangladesh", "880"],
38
+ ["BB", "Barbados", "1"],
39
+ ["BY", "Belarus", "375"],
40
+ ["BE", "Belgium", "32"],
41
+ ["BZ", "Belize", "501"],
42
+ ["BJ", "Benin", "229"],
43
+ ["BM", "Bermuda", "1"],
44
+ ["BT", "Bhutan", "975"],
45
+ ["BO", "Bolivia", "591"],
46
+ ["BA", "Bosnia and Herzegovina", "387"],
47
+ ["BW", "Botswana", "267"],
48
+ ["BR", "Brazil", "55"],
49
+ ["IO", "British Indian Ocean Territory", "246"],
50
+ ["VG", "British Virgin Islands", "1"],
51
+ ["BN", "Brunei", "673"],
52
+ ["BG", "Bulgaria", "359"],
53
+ ["BF", "Burkina Faso", "226"],
54
+ ["BI", "Burundi", "257"],
55
+ ["KH", "Cambodia", "855"],
56
+ ["CM", "Cameroon", "237"],
57
+ ["CA", "Canada", "1"],
58
+ ["CV", "Cape Verde", "238"],
59
+ ["KY", "Cayman Islands", "1"],
60
+ ["CF", "Central African Republic", "236"],
61
+ ["TD", "Chad", "235"],
62
+ ["CL", "Chile", "56"],
63
+ ["CN", "China", "86"],
64
+ ["CX", "Christmas Island", "61"],
65
+ ["CC", "Cocos (Keeling) Islands", "61"],
66
+ ["CO", "Colombia", "57"],
67
+ ["KM", "Comoros", "269"],
68
+ ["CG", "Congo - Brazzaville", "242"],
69
+ ["CD", "Congo - Kinshasa", "243"],
70
+ ["CK", "Cook Islands", "682"],
71
+ ["CR", "Costa Rica", "506"],
72
+ ["CI", "Côte d’Ivoire", "225"],
73
+ ["HR", "Croatia", "385"],
74
+ ["CU", "Cuba", "53"],
75
+ ["CW", "Curaçao", "599"],
76
+ ["CY", "Cyprus", "357"],
77
+ ["CZ", "Czechia", "420"],
78
+ ["DK", "Denmark", "45"],
79
+ ["DJ", "Djibouti", "253"],
80
+ ["DM", "Dominica", "1"],
81
+ ["DO", "Dominican Republic", "1"],
82
+ ["EC", "Ecuador", "593"],
83
+ ["EG", "Egypt", "20"],
84
+ ["SV", "El Salvador", "503"],
85
+ ["GQ", "Equatorial Guinea", "240"],
86
+ ["ER", "Eritrea", "291"],
87
+ ["EE", "Estonia", "372"],
88
+ ["SZ", "Eswatini", "268"],
89
+ ["ET", "Ethiopia", "251"],
90
+ ["FK", "Falkland Islands", "500"],
91
+ ["FO", "Faroe Islands", "298"],
92
+ ["FJ", "Fiji", "679"],
93
+ ["FI", "Finland", "358"],
94
+ ["FR", "France", "33"],
95
+ ["GF", "French Guiana", "594"],
96
+ ["PF", "French Polynesia", "689"],
97
+ ["GA", "Gabon", "241"],
98
+ ["GM", "Gambia", "220"],
99
+ ["GE", "Georgia", "995"],
100
+ ["DE", "Germany", "49"],
101
+ ["GH", "Ghana", "233"],
102
+ ["GI", "Gibraltar", "350"],
103
+ ["GR", "Greece", "30"],
104
+ ["GL", "Greenland", "299"],
105
+ ["GD", "Grenada", "1"],
106
+ ["GP", "Guadeloupe", "590"],
107
+ ["GU", "Guam", "1"],
108
+ ["GT", "Guatemala", "502"],
109
+ ["GG", "Guernsey", "44"],
110
+ ["GN", "Guinea", "224"],
111
+ ["GW", "Guinea-Bissau", "245"],
112
+ ["GY", "Guyana", "592"],
113
+ ["HT", "Haiti", "509"],
114
+ ["HN", "Honduras", "504"],
115
+ ["HK", "Hong Kong", "852"],
116
+ ["HU", "Hungary", "36"],
117
+ ["IS", "Iceland", "354"],
118
+ ["IN", "India", "91"],
119
+ ["ID", "Indonesia", "62"],
120
+ ["IR", "Iran", "98"],
121
+ ["IQ", "Iraq", "964"],
122
+ ["IE", "Ireland", "353"],
123
+ ["IM", "Isle of Man", "44"],
124
+ ["IT", "Italy", "39"],
125
+ ["JM", "Jamaica", "1"],
126
+ ["JP", "Japan", "81"],
127
+ ["JE", "Jersey", "44"],
128
+ ["JO", "Jordan", "962"],
129
+ ["KZ", "Kazakhstan", "7"],
130
+ ["KE", "Kenya", "254"],
131
+ ["KI", "Kiribati", "686"],
132
+ ["XK", "Kosovo", "383"],
133
+ ["KW", "Kuwait", "965"],
134
+ ["KG", "Kyrgyzstan", "996"],
135
+ ["LA", "Laos", "856"],
136
+ ["LV", "Latvia", "371"],
137
+ ["LB", "Lebanon", "961"],
138
+ ["LS", "Lesotho", "266"],
139
+ ["LR", "Liberia", "231"],
140
+ ["LY", "Libya", "218"],
141
+ ["LI", "Liechtenstein", "423"],
142
+ ["LT", "Lithuania", "370"],
143
+ ["LU", "Luxembourg", "352"],
144
+ ["MO", "Macau", "853"],
145
+ ["MG", "Madagascar", "261"],
146
+ ["MW", "Malawi", "265"],
147
+ ["MY", "Malaysia", "60"],
148
+ ["MV", "Maldives", "960"],
149
+ ["ML", "Mali", "223"],
150
+ ["MT", "Malta", "356"],
151
+ ["MH", "Marshall Islands", "692"],
152
+ ["MQ", "Martinique", "596"],
153
+ ["MR", "Mauritania", "222"],
154
+ ["MU", "Mauritius", "230"],
155
+ ["YT", "Mayotte", "262"],
156
+ ["MX", "Mexico", "52"],
157
+ ["FM", "Micronesia", "691"],
158
+ ["MD", "Moldova", "373"],
159
+ ["MC", "Monaco", "377"],
160
+ ["MN", "Mongolia", "976"],
161
+ ["ME", "Montenegro", "382"],
162
+ ["MS", "Montserrat", "1"],
163
+ ["MA", "Morocco", "212"],
164
+ ["MZ", "Mozambique", "258"],
165
+ ["MM", "Myanmar (Burma)", "95"],
166
+ ["NA", "Namibia", "264"],
167
+ ["NR", "Nauru", "674"],
168
+ ["NP", "Nepal", "977"],
169
+ ["NL", "Netherlands", "31"],
170
+ ["NC", "New Caledonia", "687"],
171
+ ["NZ", "New Zealand", "64"],
172
+ ["NI", "Nicaragua", "505"],
173
+ ["NE", "Niger", "227"],
174
+ ["NG", "Nigeria", "234"],
175
+ ["NU", "Niue", "683"],
176
+ ["NF", "Norfolk Island", "672"],
177
+ ["KP", "North Korea", "850"],
178
+ ["MK", "North Macedonia", "389"],
179
+ ["MP", "Northern Mariana Islands", "1"],
180
+ ["NO", "Norway", "47"],
181
+ ["OM", "Oman", "968"],
182
+ ["PK", "Pakistan", "92"],
183
+ ["PW", "Palau", "680"],
184
+ ["PS", "Palestine", "970"],
185
+ ["PA", "Panama", "507"],
186
+ ["PG", "Papua New Guinea", "675"],
187
+ ["PY", "Paraguay", "595"],
188
+ ["PE", "Peru", "51"],
189
+ ["PH", "Philippines", "63"],
190
+ ["PL", "Poland", "48"],
191
+ ["PT", "Portugal", "351"],
192
+ ["PR", "Puerto Rico", "1"],
193
+ ["QA", "Qatar", "974"],
194
+ ["RE", "Réunion", "262"],
195
+ ["RO", "Romania", "40"],
196
+ ["RU", "Russia", "7"],
197
+ ["RW", "Rwanda", "250"],
198
+ ["WS", "Samoa", "685"],
199
+ ["SM", "San Marino", "378"],
200
+ ["ST", "São Tomé and Príncipe", "239"],
201
+ ["SA", "Saudi Arabia", "966"],
202
+ ["SN", "Senegal", "221"],
203
+ ["RS", "Serbia", "381"],
204
+ ["SC", "Seychelles", "248"],
205
+ ["SL", "Sierra Leone", "232"],
206
+ ["SG", "Singapore", "65"],
207
+ ["SX", "Sint Maarten", "1"],
208
+ ["SK", "Slovakia", "421"],
209
+ ["SI", "Slovenia", "386"],
210
+ ["SB", "Solomon Islands", "677"],
211
+ ["SO", "Somalia", "252"],
212
+ ["ZA", "South Africa", "27"],
213
+ ["KR", "South Korea", "82"],
214
+ ["SS", "South Sudan", "211"],
215
+ ["ES", "Spain", "34"],
216
+ ["LK", "Sri Lanka", "94"],
217
+ ["BL", "St. Barthélemy", "590"],
218
+ ["SH", "St. Helena", "290"],
219
+ ["KN", "St. Kitts and Nevis", "1"],
220
+ ["LC", "St. Lucia", "1"],
221
+ ["MF", "St. Martin", "590"],
222
+ ["PM", "St. Pierre and Miquelon", "508"],
223
+ ["VC", "St. Vincent and the Grenadines", "1"],
224
+ ["SD", "Sudan", "249"],
225
+ ["SR", "Suriname", "597"],
226
+ ["SE", "Sweden", "46"],
227
+ ["CH", "Switzerland", "41"],
228
+ ["SY", "Syria", "963"],
229
+ ["TW", "Taiwan", "886"],
230
+ ["TJ", "Tajikistan", "992"],
231
+ ["TZ", "Tanzania", "255"],
232
+ ["TH", "Thailand", "66"],
233
+ ["TL", "Timor-Leste", "670"],
234
+ ["TG", "Togo", "228"],
235
+ ["TK", "Tokelau", "690"],
236
+ ["TO", "Tonga", "676"],
237
+ ["TT", "Trinidad and Tobago", "1"],
238
+ ["TN", "Tunisia", "216"],
239
+ ["TR", "Turkey", "90"],
240
+ ["TM", "Turkmenistan", "993"],
241
+ ["TC", "Turks and Caicos Islands", "1"],
242
+ ["TV", "Tuvalu", "688"],
243
+ ["UG", "Uganda", "256"],
244
+ ["UA", "Ukraine", "380"],
245
+ ["AE", "United Arab Emirates", "971"],
246
+ ["GB", "United Kingdom", "44"],
247
+ ["US", "United States", "1"],
248
+ ["UY", "Uruguay", "598"],
249
+ ["UZ", "Uzbekistan", "998"],
250
+ ["VU", "Vanuatu", "678"],
251
+ ["VA", "Vatican City", "39"],
252
+ ["VE", "Venezuela", "58"],
253
+ ["VN", "Vietnam", "84"],
254
+ ["VI", "U.S. Virgin Islands", "1"],
255
+ ["WF", "Wallis and Futuna", "681"],
256
+ ["YE", "Yemen", "967"],
257
+ ["ZM", "Zambia", "260"],
258
+ ["ZW", "Zimbabwe", "263"],
259
+ ];
260
+
261
+ /** The full list, sorted by name. */
262
+ export const COUNTRIES: Country[] = DATA.map(([code, name, dial]) => ({
263
+ code,
264
+ name,
265
+ dial: `+${dial}`,
266
+ })).sort((a, b) => a.name.localeCompare(b.name));
267
+
268
+ const BY_CODE = new Map(COUNTRIES.map((c) => [c.code, c]));
269
+
270
+ /** Flag emoji from an ISO 3166-1 alpha-2 code (regional-indicator letters). */
271
+ export function flagEmoji(code: string): string {
272
+ return code
273
+ .toUpperCase()
274
+ .replace(/[^A-Z]/g, "")
275
+ .replace(/./g, (c) => String.fromCodePoint(127397 + c.charCodeAt(0)));
276
+ }
277
+
278
+ export function countryByCode(code: string): Country | undefined {
279
+ return BY_CODE.get(code);
280
+ }
281
+
282
+ // For dial codes shared by several countries, the one to show when resolving a stored dial back.
283
+ const PREFERRED_BY_DIAL: Record<string, string> = {
284
+ "+964": "IQ",
285
+ "+1": "US",
286
+ "+7": "RU",
287
+ "+44": "GB",
288
+ "+61": "AU",
289
+ "+39": "IT",
290
+ "+212": "MA",
291
+ "+262": "RE",
292
+ "+358": "FI",
293
+ "+590": "GP",
294
+ "+596": "MQ",
295
+ "+599": "CW",
296
+ };
297
+
298
+ /** A representative country for a dial code (dial codes aren't unique). */
299
+ export function countryByDial(dial: string): Country | undefined {
300
+ const preferred = PREFERRED_BY_DIAL[dial];
301
+ if (preferred) return BY_CODE.get(preferred);
302
+ return COUNTRIES.find((c) => c.dial === dial);
303
+ }
@@ -0,0 +1,25 @@
1
+ export {
2
+ TextField,
3
+ EmailField,
4
+ PasswordField,
5
+ NumberField,
6
+ CurrencyField,
7
+ TextareaField,
8
+ } from "./TextField";
9
+ export { SelectField, SearchableSelectField, MultiSelectField } from "./SelectField";
10
+ export { CheckboxField, RadioCardsField } from "./ChoiceFields";
11
+ export { RadioListField, CheckboxGroupField } from "./OptionListFields";
12
+ export { SwitchBoxField } from "./SwitchBoxField";
13
+ export { DateField } from "./DateField";
14
+ export { OtpField } from "./OtpField";
15
+ export { TreeSelectField } from "./TreeSelectField";
16
+ export { SliderField } from "./SliderField";
17
+ export { ColorField } from "./ColorField";
18
+ export { SignatureField } from "./SignatureField";
19
+ export { PhoneField } from "./PhoneField";
20
+ export { FieldArray } from "./FieldArray";
21
+ export { TableField } from "./TableField";
22
+ export { FileField } from "./FileField";
23
+ export { RichTextField } from "./RichTextEditorField";
24
+ export { CustomField } from "./CustomField";
25
+ export { FieldShell } from "./FieldShell";