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
@@ -13,6 +13,12 @@ related:
13
13
 
14
14
  Practical, step-by-step guides for accomplishing common tasks with TORCH Glare.
15
15
 
16
+ > **Building a form? Use [`FormBuilder`](../components/form-builder.md).** The Form Validation
17
+ > section below shows the low-level, hand-wired resolver plumbing for understanding — but in an
18
+ > app you author fields as `FormBuilder` JSX children and pass a react-hook-form resolver, rather
19
+ > than tracking field state yourself. See the [Forms with FormBuilder](./forms-with-form-builder.md)
20
+ > guide.
21
+
16
22
  ## Table of Contents
17
23
 
18
24
  1. [Custom Themes](#custom-themes)
@@ -37,18 +43,18 @@ export default {
37
43
  theme: {
38
44
  extend: {
39
45
  colors: {
40
- 'brand-primary': '#4200FF',
41
- 'brand-secondary': '#5215CC',
42
- 'brand-accent': '#CFBEFF',
43
- 'brand-dark': '#0D0F4E',
44
- 'brand-light': '#F9F9F9',
46
+ "brand-primary": "#4200FF",
47
+ "brand-secondary": "#5215CC",
48
+ "brand-accent": "#CFBEFF",
49
+ "brand-dark": "#0D0F4E",
50
+ "brand-light": "#F9F9F9",
45
51
  },
46
52
  },
47
53
  },
48
54
  plugins: [
49
- require('mapping-color-system'),
50
- require('glare-torch-mode'),
51
- require('glare-typography'),
55
+ require("mapping-color-system"),
56
+ require("glare-torch-mode"),
57
+ require("glare-typography"),
52
58
  ],
53
59
  } satisfies Config;
54
60
  ```
@@ -63,15 +69,15 @@ export default {
63
69
 
64
70
  @layer base {
65
71
  [data-theme="light"] {
66
- --background-presentation-action-primary: #4200FF;
67
- --content-presentation-action-light-primary: #FFFFFF;
68
- --border-presentation-action-primary: #5215CC;
72
+ --background-presentation-action-primary: #4200ff;
73
+ --content-presentation-action-light-primary: #ffffff;
74
+ --border-presentation-action-primary: #5215cc;
69
75
  }
70
76
 
71
77
  [data-theme="dark"] {
72
- --background-presentation-action-primary: #5215CC;
73
- --content-presentation-action-light-primary: #F9F9F9;
74
- --border-presentation-action-primary: #CFBEFF;
78
+ --background-presentation-action-primary: #5215cc;
79
+ --content-presentation-action-light-primary: #f9f9f9;
80
+ --border-presentation-action-primary: #cfbeff;
75
81
  }
76
82
  }
77
83
  ```
@@ -80,17 +86,17 @@ export default {
80
86
 
81
87
  ```tsx
82
88
  // components/BrandButton.tsx
83
- import { Button } from '@torch-ai/torch-glare';
84
- import { cn } from '@torch-ai/torch-glare/utils';
89
+ import { Button } from "@/components/Button";
90
+ import { cn } from "@/utils/cn";
85
91
 
86
92
  export function BrandButton({ children, ...props }: any) {
87
93
  return (
88
94
  <Button
89
95
  {...props}
90
96
  className={cn(
91
- 'bg-brand-primary hover:bg-brand-secondary',
92
- 'text-white border-brand-accent',
93
- props.className
97
+ "bg-brand-primary hover:bg-brand-secondary",
98
+ "text-white border-brand-accent",
99
+ props.className,
94
100
  )}
95
101
  >
96
102
  {children}
@@ -103,22 +109,22 @@ export function BrandButton({ children, ...props }: any) {
103
109
 
104
110
  ```tsx
105
111
  // hooks/useCustomTheme.ts
106
- import { useTheme } from '@torch-ai/torch-glare';
107
- import { useEffect } from 'react';
112
+ import { useTheme } from "@/providers/ThemeProvider";
113
+ import { useEffect } from "react";
108
114
 
109
115
  export function useCustomTheme() {
110
116
  const { theme, updateTheme } = useTheme();
111
117
 
112
118
  useEffect(() => {
113
119
  // Apply custom theme classes
114
- if (theme === 'light') {
115
- document.documentElement.classList.add('brand-light-theme');
120
+ if (theme === "light") {
121
+ document.documentElement.classList.add("brand-light-theme");
116
122
  } else {
117
- document.documentElement.classList.add('brand-dark-theme');
123
+ document.documentElement.classList.add("brand-dark-theme");
118
124
  }
119
125
 
120
126
  return () => {
121
- document.documentElement.classList.remove('brand-light-theme', 'brand-dark-theme');
127
+ document.documentElement.classList.remove("brand-light-theme", "brand-dark-theme");
122
128
  };
123
129
  }, [theme]);
124
130
 
@@ -130,14 +136,12 @@ export function useCustomTheme() {
130
136
 
131
137
  ```tsx
132
138
  // providers/BrandThemeProvider.tsx
133
- import { ThemeProvider } from '@torch-ai/torch-glare';
139
+ import { ThemeProvider } from "@/providers/ThemeProvider";
134
140
 
135
141
  export function BrandThemeProvider({ children }: { children: React.ReactNode }) {
136
142
  return (
137
143
  <ThemeProvider defaultTheme="light" defaultThemeMode="TORCH">
138
- <div className="brand-theme-wrapper">
139
- {children}
140
- </div>
144
+ <div className="brand-theme-wrapper">{children}</div>
141
145
  </ThemeProvider>
142
146
  );
143
147
  }
@@ -147,20 +151,20 @@ export function BrandThemeProvider({ children }: { children: React.ReactNode })
147
151
 
148
152
  ```tsx
149
153
  // __tests__/BrandButton.test.tsx
150
- import { render } from '@testing-library/react';
151
- import { ThemeProvider } from '@torch-ai/torch-glare';
152
- import { BrandButton } from '../components/BrandButton';
154
+ import { render } from "@testing-library/react";
155
+ import { ThemeProvider } from "@/providers/ThemeProvider";
156
+ import { BrandButton } from "../components/BrandButton";
153
157
 
154
- describe('BrandButton', () => {
155
- it('applies custom brand colors', () => {
158
+ describe("BrandButton", () => {
159
+ it("applies custom brand colors", () => {
156
160
  const { container } = render(
157
161
  <ThemeProvider defaultTheme="light">
158
162
  <BrandButton>Click me</BrandButton>
159
- </ThemeProvider>
163
+ </ThemeProvider>,
160
164
  );
161
165
 
162
- const button = container.querySelector('button');
163
- expect(button).toHaveClass('bg-brand-primary');
166
+ const button = container.querySelector("button");
167
+ expect(button).toHaveClass("bg-brand-primary");
164
168
  });
165
169
  });
166
170
  ```
@@ -175,7 +179,7 @@ Implement comprehensive form validation with error handling.
175
179
 
176
180
  ```tsx
177
181
  // hooks/useFormValidation.ts
178
- import { useState, useCallback } from 'react';
182
+ import { useState, useCallback } from "react";
179
183
 
180
184
  type ValidationRules<T> = {
181
185
  [K in keyof T]?: Array<(value: T[K]) => string | undefined>;
@@ -183,7 +187,7 @@ type ValidationRules<T> = {
183
187
 
184
188
  export function useFormValidation<T extends Record<string, any>>(
185
189
  initialValues: T,
186
- rules: ValidationRules<T>
190
+ rules: ValidationRules<T>,
187
191
  ) {
188
192
  const [values, setValues] = useState<T>(initialValues);
189
193
  const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({});
@@ -200,7 +204,7 @@ export function useFormValidation<T extends Record<string, any>>(
200
204
  }
201
205
  return undefined;
202
206
  },
203
- [rules]
207
+ [rules],
204
208
  );
205
209
 
206
210
  const handleChange = useCallback(
@@ -213,7 +217,7 @@ export function useFormValidation<T extends Record<string, any>>(
213
217
  setErrors((prev) => ({ ...prev, [field]: error }));
214
218
  }
215
219
  },
216
- [touched, validateField]
220
+ [touched, validateField],
217
221
  );
218
222
 
219
223
  const handleBlur = useCallback(
@@ -222,7 +226,7 @@ export function useFormValidation<T extends Record<string, any>>(
222
226
  const error = validateField(field, values[field]);
223
227
  setErrors((prev) => ({ ...prev, [field]: error }));
224
228
  },
225
- [values, validateField]
229
+ [values, validateField],
226
230
  );
227
231
 
228
232
  const validateForm = useCallback((): boolean => {
@@ -238,9 +242,7 @@ export function useFormValidation<T extends Record<string, any>>(
238
242
  });
239
243
 
240
244
  setErrors(newErrors);
241
- setTouched(
242
- Object.keys(rules).reduce((acc, field) => ({ ...acc, [field]: true }), {})
243
- );
245
+ setTouched(Object.keys(rules).reduce((acc, field) => ({ ...acc, [field]: true }), {}));
244
246
 
245
247
  return isValid;
246
248
  }, [rules, values, validateField]);
@@ -267,16 +269,16 @@ export function useFormValidation<T extends Record<string, any>>(
267
269
 
268
270
  ```tsx
269
271
  // utils/validationRules.ts
270
- export const required = (message = 'This field is required') => {
272
+ export const required = (message = "This field is required") => {
271
273
  return (value: any) => {
272
- if (!value || (typeof value === 'string' && !value.trim())) {
274
+ if (!value || (typeof value === "string" && !value.trim())) {
273
275
  return message;
274
276
  }
275
277
  return undefined;
276
278
  };
277
279
  };
278
280
 
279
- export const email = (message = 'Invalid email address') => {
281
+ export const email = (message = "Invalid email address") => {
280
282
  return (value: string) => {
281
283
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
282
284
  if (value && !emailRegex.test(value)) {
@@ -327,52 +329,47 @@ export const matchField = (otherField: string, message?: string) => {
327
329
 
328
330
  ```tsx
329
331
  // components/RegistrationForm.tsx
330
- 'use client';
332
+ "use client";
331
333
 
332
- import { useFormValidation } from '../hooks/useFormValidation';
333
- import { required, email, minLength } from '../utils/validationRules';
334
- import { LabelField, Button, toast } from '@torch-ai/torch-glare';
334
+ import { useFormValidation } from "../hooks/useFormValidation";
335
+ import { required, email, minLength } from "../utils/validationRules";
336
+ import { Button } from "@/components/Button";
337
+ import { LabelField } from "@/components/LabelField";
338
+ import { toast } from "@/components/Toast";
335
339
 
336
340
  export default function RegistrationForm() {
337
- const {
338
- values,
339
- errors,
340
- touched,
341
- handleChange,
342
- handleBlur,
343
- validateForm,
344
- reset,
345
- } = useFormValidation(
346
- {
347
- email: '',
348
- password: '',
349
- confirmPassword: '',
350
- },
351
- {
352
- email: [required(), email()],
353
- password: [required(), minLength(8, 'Password must be at least 8 characters')],
354
- confirmPassword: [
355
- required(),
356
- (value) => {
357
- if (value !== values.password) {
358
- return 'Passwords must match';
359
- }
360
- return undefined;
361
- },
362
- ],
363
- }
364
- );
341
+ const { values, errors, touched, handleChange, handleBlur, validateForm, reset } =
342
+ useFormValidation(
343
+ {
344
+ email: "",
345
+ password: "",
346
+ confirmPassword: "",
347
+ },
348
+ {
349
+ email: [required(), email()],
350
+ password: [required(), minLength(8, "Password must be at least 8 characters")],
351
+ confirmPassword: [
352
+ required(),
353
+ (value) => {
354
+ if (value !== values.password) {
355
+ return "Passwords must match";
356
+ }
357
+ return undefined;
358
+ },
359
+ ],
360
+ },
361
+ );
365
362
 
366
363
  const handleSubmit = async (e: React.FormEvent) => {
367
364
  e.preventDefault();
368
365
 
369
366
  if (!validateForm()) {
370
- toast.error('Please fix validation errors');
367
+ toast.error("Please fix validation errors");
371
368
  return;
372
369
  }
373
370
 
374
371
  // Submit form
375
- toast.success('Registration successful!');
372
+ toast.success("Registration successful!");
376
373
  reset();
377
374
  };
378
375
 
@@ -384,8 +381,8 @@ export default function RegistrationForm() {
384
381
  requiredLabel="*"
385
382
  type="email"
386
383
  value={values.email}
387
- onChange={handleChange('email')}
388
- onBlur={handleBlur('email')}
384
+ onChange={handleChange("email")}
385
+ onBlur={handleBlur("email")}
389
386
  errorMessage={touched.email ? errors.email : undefined}
390
387
  />
391
388
 
@@ -395,8 +392,8 @@ export default function RegistrationForm() {
395
392
  requiredLabel="*"
396
393
  type="password"
397
394
  value={values.password}
398
- onChange={handleChange('password')}
399
- onBlur={handleBlur('password')}
395
+ onChange={handleChange("password")}
396
+ onBlur={handleBlur("password")}
400
397
  errorMessage={touched.password ? errors.password : undefined}
401
398
  />
402
399
 
@@ -406,8 +403,8 @@ export default function RegistrationForm() {
406
403
  requiredLabel="*"
407
404
  type="password"
408
405
  value={values.confirmPassword}
409
- onChange={handleChange('confirmPassword')}
410
- onBlur={handleBlur('confirmPassword')}
406
+ onChange={handleChange("confirmPassword")}
407
+ onBlur={handleBlur("confirmPassword")}
411
408
  errorMessage={touched.confirmPassword ? errors.confirmPassword : undefined}
412
409
  />
413
410
 
@@ -423,7 +420,7 @@ export default function RegistrationForm() {
423
420
 
424
421
  ```tsx
425
422
  // Example: Check if email is available
426
- export const emailAvailable = (message = 'Email already taken') => {
423
+ export const emailAvailable = (message = "Email already taken") => {
427
424
  return async (value: string) => {
428
425
  if (!value) return undefined;
429
426
 
@@ -435,7 +432,7 @@ export const emailAvailable = (message = 'Email already taken') => {
435
432
  return message;
436
433
  }
437
434
  } catch (error) {
438
- console.error('Email validation error:', error);
435
+ console.error("Email validation error:", error);
439
436
  }
440
437
 
441
438
  return undefined;
@@ -453,10 +450,11 @@ Implement comprehensive dark mode support.
453
450
 
454
451
  ```tsx
455
452
  // components/DarkModeToggle.tsx
456
- 'use client';
453
+ "use client";
457
454
 
458
- import { useTheme, Button } from '@torch-ai/torch-glare';
459
- import { useEffect, useState } from 'react';
455
+ import { Button } from "@/components/Button";
456
+ import { useTheme } from "@/providers/ThemeProvider";
457
+ import { useEffect, useState } from "react";
460
458
 
461
459
  export default function DarkModeToggle() {
462
460
  const { theme, updateTheme } = useTheme();
@@ -469,7 +467,7 @@ export default function DarkModeToggle() {
469
467
 
470
468
  if (!mounted) {
471
469
  return (
472
- <Button theme="light" variant="ContStyle" buttonType="icon">
470
+ <Button theme="light" variant="PrimeContStyle" buttonType="icon">
473
471
  <div className="w-5 h-5" />
474
472
  </Button>
475
473
  );
@@ -478,12 +476,12 @@ export default function DarkModeToggle() {
478
476
  return (
479
477
  <Button
480
478
  theme={theme as any}
481
- variant="ContStyle"
479
+ variant="PrimeContStyle"
482
480
  buttonType="icon"
483
- onClick={() => updateTheme(theme === 'light' ? 'dark' : 'light')}
484
- aria-label={`Switch to ${theme === 'light' ? 'dark' : 'light'} mode`}
481
+ onClick={() => updateTheme(theme === "light" ? "dark" : "light")}
482
+ aria-label={`Switch to ${theme === "light" ? "dark" : "light"} mode`}
485
483
  >
486
- {theme === 'light' ? (
484
+ {theme === "light" ? (
487
485
  <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
488
486
  <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
489
487
  </svg>
@@ -505,29 +503,29 @@ export default function DarkModeToggle() {
505
503
 
506
504
  ```tsx
507
505
  // hooks/useSystemTheme.ts
508
- import { useEffect } from 'react';
509
- import { useTheme } from '@torch-ai/torch-glare';
506
+ import { useEffect } from "react";
507
+ import { useTheme } from "@/providers/ThemeProvider";
510
508
 
511
509
  export function useSystemTheme() {
512
510
  const { theme, updateTheme } = useTheme();
513
511
 
514
512
  useEffect(() => {
515
513
  // Only sync with system if theme is 'default'
516
- if (theme !== 'default') return;
514
+ if (theme !== "default") return;
517
515
 
518
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
516
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
519
517
 
520
518
  const handleChange = (e: MediaQueryListEvent) => {
521
- updateTheme(e.matches ? 'dark' : 'light');
519
+ updateTheme(e.matches ? "dark" : "light");
522
520
  };
523
521
 
524
522
  // Set initial value
525
- updateTheme(mediaQuery.matches ? 'dark' : 'light');
523
+ updateTheme(mediaQuery.matches ? "dark" : "light");
526
524
 
527
525
  // Listen for changes
528
- mediaQuery.addEventListener('change', handleChange);
526
+ mediaQuery.addEventListener("change", handleChange);
529
527
 
530
- return () => mediaQuery.removeEventListener('change', handleChange);
528
+ return () => mediaQuery.removeEventListener("change", handleChange);
531
529
  }, [theme, updateTheme]);
532
530
  }
533
531
  ```
@@ -536,8 +534,8 @@ export function useSystemTheme() {
536
534
 
537
535
  ```tsx
538
536
  // components/ThemedImage.tsx
539
- import { useTheme } from '@torch-ai/torch-glare';
540
- import Image from 'next/image';
537
+ import { useTheme } from "@/providers/ThemeProvider";
538
+ import Image from "next/image";
541
539
 
542
540
  interface ThemedImageProps {
543
541
  lightSrc: string;
@@ -558,7 +556,7 @@ export function ThemedImage({
558
556
 
559
557
  return (
560
558
  <Image
561
- src={theme === 'dark' ? darkSrc : lightSrc}
559
+ src={theme === "dark" ? darkSrc : lightSrc}
562
560
  alt={alt}
563
561
  width={width}
564
562
  height={height}
@@ -572,33 +570,33 @@ export function ThemedImage({
572
570
 
573
571
  ```tsx
574
572
  // __tests__/DarkMode.test.tsx
575
- import { render } from '@testing-library/react';
576
- import { ThemeProvider } from '@torch-ai/torch-glare';
577
- import userEvent from '@testing-library/user-event';
578
- import DarkModeToggle from '../components/DarkModeToggle';
573
+ import { render } from "@testing-library/react";
574
+ import { ThemeProvider } from "@/providers/ThemeProvider";
575
+ import userEvent from "@testing-library/user-event";
576
+ import DarkModeToggle from "../components/DarkModeToggle";
579
577
 
580
- describe('Dark Mode', () => {
581
- it('switches between light and dark themes', async () => {
578
+ describe("Dark Mode", () => {
579
+ it("switches between light and dark themes", async () => {
582
580
  const user = userEvent.setup();
583
581
 
584
582
  const { getByRole } = render(
585
583
  <ThemeProvider defaultTheme="light">
586
584
  <DarkModeToggle />
587
- </ThemeProvider>
585
+ </ThemeProvider>,
588
586
  );
589
587
 
590
- const toggle = getByRole('button');
588
+ const toggle = getByRole("button");
591
589
 
592
590
  // Initial theme is light
593
- expect(document.documentElement.getAttribute('data-theme')).toBe('light');
591
+ expect(document.documentElement.getAttribute("data-theme")).toBe("light");
594
592
 
595
593
  // Click to switch to dark
596
594
  await user.click(toggle);
597
- expect(document.documentElement.getAttribute('data-theme')).toBe('dark');
595
+ expect(document.documentElement.getAttribute("data-theme")).toBe("dark");
598
596
 
599
597
  // Click to switch back to light
600
598
  await user.click(toggle);
601
- expect(document.documentElement.getAttribute('data-theme')).toBe('light');
599
+ expect(document.documentElement.getAttribute("data-theme")).toBe("light");
602
600
  });
603
601
  });
604
602
  ```
@@ -613,17 +611,17 @@ Ensure your application is accessible to all users.
613
611
 
614
612
  ```tsx
615
613
  // components/AccessibleMenu.tsx
616
- 'use client';
614
+ "use client";
617
615
 
618
- import { useState, useRef, useEffect } from 'react';
619
- import { Button } from '@torch-ai/torch-glare';
616
+ import { useState, useRef, useEffect } from "react";
617
+ import { Button } from "@/components/Button";
620
618
 
621
619
  export default function AccessibleMenu() {
622
620
  const [isOpen, setIsOpen] = useState(false);
623
621
  const [focusedIndex, setFocusedIndex] = useState(0);
624
622
  const menuRef = useRef<HTMLDivElement>(null);
625
623
 
626
- const menuItems = ['Profile', 'Settings', 'Logout'];
624
+ const menuItems = ["Profile", "Settings", "Logout"];
627
625
 
628
626
  useEffect(() => {
629
627
  if (isOpen) {
@@ -634,22 +632,22 @@ export default function AccessibleMenu() {
634
632
 
635
633
  const handleKeyDown = (e: React.KeyboardEvent) => {
636
634
  switch (e.key) {
637
- case 'ArrowDown':
635
+ case "ArrowDown":
638
636
  e.preventDefault();
639
637
  setFocusedIndex((prev) => (prev + 1) % menuItems.length);
640
638
  break;
641
- case 'ArrowUp':
639
+ case "ArrowUp":
642
640
  e.preventDefault();
643
641
  setFocusedIndex((prev) => (prev - 1 + menuItems.length) % menuItems.length);
644
642
  break;
645
- case 'Escape':
643
+ case "Escape":
646
644
  setIsOpen(false);
647
645
  break;
648
- case 'Home':
646
+ case "Home":
649
647
  e.preventDefault();
650
648
  setFocusedIndex(0);
651
649
  break;
652
- case 'End':
650
+ case "End":
653
651
  e.preventDefault();
654
652
  setFocusedIndex(menuItems.length - 1);
655
653
  break;
@@ -712,18 +710,16 @@ export default function AccessibleMenu() {
712
710
 
713
711
  ```tsx
714
712
  // components/AccessibleForm.tsx
715
- import { LabelField, Button } from '@torch-ai/torch-glare';
716
- import { useState } from 'react';
713
+ import { Button } from "@/components/Button";
714
+ import { LabelField } from "@/components/LabelField";
715
+ import { useState } from "react";
717
716
 
718
717
  export default function AccessibleForm() {
719
- const [email, setEmail] = useState('');
720
- const [error, setError] = useState('');
718
+ const [email, setEmail] = useState("");
719
+ const [error, setError] = useState("");
721
720
 
722
721
  return (
723
- <form
724
- aria-label="Contact form"
725
- onSubmit={(e) => e.preventDefault()}
726
- >
722
+ <form aria-label="Contact form" onSubmit={(e) => e.preventDefault()}>
727
723
  <LabelField
728
724
  theme="light"
729
725
  label="Email"
@@ -732,7 +728,7 @@ export default function AccessibleForm() {
732
728
  value={email}
733
729
  onChange={(e) => setEmail(e.target.value)}
734
730
  aria-invalid={!!error}
735
- aria-describedby={error ? 'email-error' : undefined}
731
+ aria-describedby={error ? "email-error" : undefined}
736
732
  />
737
733
 
738
734
  {error && (
@@ -745,12 +741,7 @@ export default function AccessibleForm() {
745
741
  </p>
746
742
  )}
747
743
 
748
- <Button
749
- theme="light"
750
- variant="PrimeStyle"
751
- type="submit"
752
- aria-label="Submit contact form"
753
- >
744
+ <Button theme="light" variant="PrimeStyle" type="submit" aria-label="Submit contact form">
754
745
  Submit
755
746
  </Button>
756
747
  </form>
@@ -762,7 +753,7 @@ export default function AccessibleForm() {
762
753
 
763
754
  ```tsx
764
755
  // hooks/useFocusTrap.ts
765
- import { useEffect, useRef } from 'react';
756
+ import { useEffect, useRef } from "react";
766
757
 
767
758
  export function useFocusTrap<T extends HTMLElement>(isActive: boolean) {
768
759
  const ref = useRef<T>(null);
@@ -774,14 +765,14 @@ export function useFocusTrap<T extends HTMLElement>(isActive: boolean) {
774
765
  if (!element) return;
775
766
 
776
767
  const focusableElements = element.querySelectorAll(
777
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
768
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
778
769
  );
779
770
 
780
771
  const firstElement = focusableElements[0] as HTMLElement;
781
772
  const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
782
773
 
783
774
  const handleTabKey = (e: KeyboardEvent) => {
784
- if (e.key !== 'Tab') return;
775
+ if (e.key !== "Tab") return;
785
776
 
786
777
  if (e.shiftKey && document.activeElement === firstElement) {
787
778
  e.preventDefault();
@@ -792,11 +783,11 @@ export function useFocusTrap<T extends HTMLElement>(isActive: boolean) {
792
783
  }
793
784
  };
794
785
 
795
- element.addEventListener('keydown', handleTabKey);
786
+ element.addEventListener("keydown", handleTabKey);
796
787
  firstElement?.focus();
797
788
 
798
789
  return () => {
799
- element.removeEventListener('keydown', handleTabKey);
790
+ element.removeEventListener("keydown", handleTabKey);
800
791
  };
801
792
  }, [isActive]);
802
793
 
@@ -808,7 +799,7 @@ export function useFocusTrap<T extends HTMLElement>(isActive: boolean) {
808
799
 
809
800
  ```tsx
810
801
  // components/AccessibleButton.tsx
811
- import { Button } from '@torch-ai/torch-glare';
802
+ import { Button } from "@/components/Button";
812
803
 
813
804
  interface AccessibleButtonProps {
814
805
  onClick: () => void;
@@ -816,11 +807,7 @@ interface AccessibleButtonProps {
816
807
  children: React.ReactNode;
817
808
  }
818
809
 
819
- export function AccessibleButton({
820
- onClick,
821
- isLoading,
822
- children,
823
- }: AccessibleButtonProps) {
810
+ export function AccessibleButton({ onClick, isLoading, children }: AccessibleButtonProps) {
824
811
  return (
825
812
  <Button
826
813
  theme="light"
@@ -828,7 +815,7 @@ export function AccessibleButton({
828
815
  onClick={onClick}
829
816
  disabled={isLoading}
830
817
  aria-busy={isLoading}
831
- aria-label={isLoading ? 'Loading...' : undefined}
818
+ aria-label={isLoading ? "Loading..." : undefined}
832
819
  >
833
820
  {isLoading ? (
834
821
  <>
@@ -865,32 +852,34 @@ export type FormTouched<T> = Partial<Record<keyof T, boolean>>;
865
852
 
866
853
  ```tsx
867
854
  // components/TypeSafeForm.tsx
868
- import { useState } from 'react';
869
- import { LabelField, Button, toast } from '@torch-ai/torch-glare';
870
- import type { ContactForm, FormErrors, FormTouched } from '../types/forms';
855
+ import { useState } from "react";
856
+ import { Button } from "@/components/Button";
857
+ import { LabelField } from "@/components/LabelField";
858
+ import { toast } from "@/components/Toast";
859
+ import type { ContactForm, FormErrors, FormTouched } from "../types/forms";
871
860
 
872
861
  export default function TypeSafeForm() {
873
862
  const [formData, setFormData] = useState<ContactForm>({
874
- name: '',
875
- email: '',
876
- message: '',
863
+ name: "",
864
+ email: "",
865
+ message: "",
877
866
  });
878
867
 
879
868
  const [errors, setErrors] = useState<FormErrors<ContactForm>>({});
880
869
  const [touched, setTouched] = useState<FormTouched<ContactForm>>({});
881
870
 
882
- const handleChange = <K extends keyof ContactForm>(field: K) => (
883
- e: React.ChangeEvent<HTMLInputElement>
884
- ) => {
885
- setFormData((prev) => ({
886
- ...prev,
887
- [field]: e.target.value,
888
- }));
889
- };
871
+ const handleChange =
872
+ <K extends keyof ContactForm>(field: K) =>
873
+ (e: React.ChangeEvent<HTMLInputElement>) => {
874
+ setFormData((prev) => ({
875
+ ...prev,
876
+ [field]: e.target.value,
877
+ }));
878
+ };
890
879
 
891
880
  const handleSubmit = (e: React.FormEvent) => {
892
881
  e.preventDefault();
893
- toast.success('Form submitted!');
882
+ toast.success("Form submitted!");
894
883
  };
895
884
 
896
885
  return (
@@ -899,7 +888,7 @@ export default function TypeSafeForm() {
899
888
  theme="light"
900
889
  label="Name"
901
890
  value={formData.name}
902
- onChange={handleChange('name')}
891
+ onChange={handleChange("name")}
903
892
  errorMessage={touched.name ? errors.name : undefined}
904
893
  />
905
894
 
@@ -923,17 +912,11 @@ interface ListProps<T> {
923
912
  keyExtractor: (item: T) => string;
924
913
  }
925
914
 
926
- export function TypedList<T>({
927
- items,
928
- renderItem,
929
- keyExtractor,
930
- }: ListProps<T>) {
915
+ export function TypedList<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
931
916
  return (
932
917
  <div className="space-y-2">
933
918
  {items.map((item) => (
934
- <div key={keyExtractor(item)}>
935
- {renderItem(item)}
936
- </div>
919
+ <div key={keyExtractor(item)}>{renderItem(item)}</div>
937
920
  ))}
938
921
  </div>
939
922
  );
@@ -944,14 +927,11 @@ export function TypedList<T>({
944
927
 
945
928
  ```tsx
946
929
  // hooks/useTypedLocalStorage.ts
947
- import { useState, useEffect } from 'react';
930
+ import { useState, useEffect } from "react";
948
931
 
949
- export function useTypedLocalStorage<T>(
950
- key: string,
951
- initialValue: T
952
- ): [T, (value: T) => void] {
932
+ export function useTypedLocalStorage<T>(key: string, initialValue: T): [T, (value: T) => void] {
953
933
  const [storedValue, setStoredValue] = useState<T>(() => {
954
- if (typeof window === 'undefined') return initialValue;
934
+ if (typeof window === "undefined") return initialValue;
955
935
 
956
936
  try {
957
937
  const item = window.localStorage.getItem(key);
@@ -965,7 +945,7 @@ export function useTypedLocalStorage<T>(
965
945
  const setValue = (value: T) => {
966
946
  try {
967
947
  setStoredValue(value);
968
- if (typeof window !== 'undefined') {
948
+ if (typeof window !== "undefined") {
969
949
  window.localStorage.setItem(key, JSON.stringify(value));
970
950
  }
971
951
  } catch (error) {
@@ -981,7 +961,7 @@ export function useTypedLocalStorage<T>(
981
961
 
982
962
  ```tsx
983
963
  // types/components.ts
984
- import type { ButtonProps } from '@torch-ai/torch-glare';
964
+ import type { ButtonProps } from "@/components/LoginButton";
985
965
 
986
966
  export interface ExtendedButtonProps extends ButtonProps {
987
967
  isLoading?: boolean;
@@ -991,12 +971,12 @@ export interface ExtendedButtonProps extends ButtonProps {
991
971
 
992
972
  ```tsx
993
973
  // components/ExtendedButton.tsx
994
- import { Button } from '@torch-ai/torch-glare';
995
- import type { ExtendedButtonProps } from '../types/components';
974
+ import { Button } from "@/components/Button";
975
+ import type { ExtendedButtonProps } from "../types/components";
996
976
 
997
977
  export function ExtendedButton({
998
978
  isLoading,
999
- loadingText = 'Loading...',
979
+ loadingText = "Loading...",
1000
980
  children,
1001
981
  ...props
1002
982
  }: ExtendedButtonProps) {
@@ -1012,19 +992,19 @@ export function ExtendedButton({
1012
992
 
1013
993
  ```tsx
1014
994
  // utils/typeGuards.ts
1015
- import type { User } from '../types';
995
+ import type { User } from "../types";
1016
996
 
1017
997
  export function isValidEmail(value: unknown): value is string {
1018
- return typeof value === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
998
+ return typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
1019
999
  }
1020
1000
 
1021
1001
  export function isUser(value: unknown): value is User {
1022
1002
  return (
1023
- typeof value === 'object' &&
1003
+ typeof value === "object" &&
1024
1004
  value !== null &&
1025
- 'id' in value &&
1026
- 'email' in value &&
1027
- 'name' in value
1005
+ "id" in value &&
1006
+ "email" in value &&
1007
+ "name" in value
1028
1008
  );
1029
1009
  }
1030
1010
  ```