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,228 @@
1
+ ---
2
+ title: FormRenderer
3
+ description: A thin wrapper around FormBuilder. Author fields as JSX children; FormRenderer owns page-vs-drawer display, the absolute title header, and drawer field layout. You compose the Save and pass it via the actions prop.
4
+ component: true
5
+ group: Forms
6
+ keywords: [form-renderer, form, drawer, header, display, view-mode, react-hook-form]
7
+ ---
8
+
9
+ # FormRenderer
10
+
11
+ A thin wrapper around the compound [FormBuilder](./form-builder.md). You author the
12
+ fields as **JSX children** exactly as you would with `FormBuilder`; `FormRenderer`
13
+ takes care of the surrounding concerns:
14
+
15
+ - **page vs drawer** display (`display="drawer"` hosts the form in a `FormDrawer`),
16
+ - the **absolute title header** + action bar (page display),
17
+ - **vertical field layout** inside a drawer.
18
+
19
+ FormRenderer never manufactures a Submit — **you compose the Save and hand it to `actions`**.
20
+ It renders in the form's header action pill (page) or the drawer header (drawer), and a bare
21
+ `<FormBuilder.Submit>` auto-targets this form (even though the header sits outside the `<form>`).
22
+
23
+ Reach for `FormBuilder` directly when you just want the form. Reach for
24
+ `FormRenderer` when you want the same form to render as a page _or_ a drawer with
25
+ the standard chrome.
26
+
27
+ ```tsx
28
+ <FormRenderer
29
+ onSubmit={save}
30
+ resolver={zodResolver(schema)}
31
+ defaultValues={d}
32
+ header={{ title: "Item", variant: "new" }}
33
+ actions={<FormBuilder.Submit>Save</FormBuilder.Submit>}
34
+ >
35
+ <FormBuilder.Section title="Identity" color="Blue">
36
+ <FormBuilder.Text name="name" label="Name" required />
37
+ <FormBuilder.Currency name="price" label="Price" currencySymbol="$" />
38
+ </FormBuilder.Section>
39
+ </FormRenderer>
40
+ ```
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ npx torch-glare@latest init
46
+ npx torch-glare@latest add FormRenderer
47
+ ```
48
+
49
+ `add` also pulls in `FormBuilder`, which FormRenderer renders through.
50
+
51
+ ## Imports
52
+
53
+ ```tsx
54
+ import { FormRenderer, FormDrawer } from "@/components/FormRenderer";
55
+ import { FormBuilder } from "@/components/FormBuilder";
56
+ ```
57
+
58
+ ## Props
59
+
60
+ | Prop | Type | Notes |
61
+ | -------------------------------------------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
62
+ | `children` | `ReactNode` | The form body — `FormBuilder.Section` / field / `FormBuilder.Stepper` JSX. |
63
+ | `onSubmit` / `onInvalid` | fns | Submit / validation-fail callbacks. |
64
+ | `resolver` | `Resolver` | Any react-hook-form resolver, e.g. `zodResolver(schema)`. |
65
+ | `defaultValues` / `values` | `DefaultValues` / `T` | Initial values; `values` re-syncs on change (edit). |
66
+ | `mode` | `'edit' \| 'view'` | `'view'` renders read-only, no Submit. |
67
+ | `loading` / `resetOnSuccess` | `boolean` | Forwarded to `FormBuilder`. |
68
+ | `fieldDirection` | `'horizontal' \| 'vertical'` | Defaults to vertical inside a drawer. |
69
+ | `form` | `UseFormReturn<T>` | A hoisted `useForm` to bind to — pass when a sibling (e.g. a `summary` `FormSummary`) must read the same live values; the caller owns `resolver`/`defaultValues` on it. Omit to let FormRenderer create its own. |
70
+ | `display` | `'page' \| 'drawer'` | `'drawer'` wraps the form in `FormDrawer`. |
71
+ | `header` | `{ title; label?; variant? }` | Absolute title header + action bar (page display); `actions` render in it. |
72
+ | `summary` | `ReactNode` | A live panel (typically `FormSummary`) rendered beside the form (page) or in the drawer tray (drawer). Give the same hoisted `form` so it reads live values. On a page, a `summary` **plus** a `FormBuilder.Stepper` lays out as three columns — stepper nav · fields · summary. |
73
+ | `actions` | `ReactNode` | The form's action bar — rendered in the header action pill (page) or drawer header (drawer). Put the Save here: `actions={<FormBuilder.Submit>Save</FormBuilder.Submit>}`. A bare `FormBuilder.Submit` auto-targets this form. |
74
+ | `id` | `string` | `id` on the underlying `<form>`. Optional — FormRenderer generates and wires one otherwise. |
75
+ | `open` / `onOpenChange` / `title` / `badge` / `onOpenInNewTab` | — | Drawer control (when `display="drawer"`). `title` / `badge` are strings that override `header.title` / `header.label`. |
76
+
77
+ ## Drawer & view
78
+
79
+ ```tsx
80
+ // drawer — pass the Save via `actions`; it renders in the drawer header
81
+ <FormRenderer
82
+ display="drawer" open={open} onOpenChange={setOpen} title="New item" badge="New"
83
+ onSubmit={save} resolver={r} defaultValues={d}
84
+ actions={<FormBuilder.Submit>Save</FormBuilder.Submit>}
85
+ >
86
+ {fields}
87
+ </FormRenderer>
88
+
89
+ // read-only view — same children, omit `actions` (a view has no Save)
90
+ <FormRenderer mode="view" values={entity} onSubmit={() => {}}>
91
+ {fields}
92
+ </FormRenderer>
93
+ ```
94
+
95
+ ## Stepper
96
+
97
+ Drop a `FormBuilder.Stepper` in as the child. The Save lives in the header `actions` and
98
+ submits every step's registered fields at once (steps stay mounted, so the whole form is live).
99
+
100
+ ```tsx
101
+ <FormRenderer
102
+ onSubmit={save}
103
+ resolver={r}
104
+ defaultValues={d}
105
+ header={{ title: "New item", variant: "new" }}
106
+ actions={<FormBuilder.Submit>Save</FormBuilder.Submit>}
107
+ >
108
+ <FormBuilder.Stepper>
109
+ <FormBuilder.Step title="Basics">
110
+ <FormBuilder.Text name="name" label="Name" required />
111
+ </FormBuilder.Step>
112
+ </FormBuilder.Stepper>
113
+ </FormRenderer>
114
+ ```
115
+
116
+ ## Summary panel
117
+
118
+ Pass a hoisted `useForm` as `form` and a `FormSummary` as `summary` — FormRenderer binds
119
+ the form to that instance and lays the panel beside the form (page) or in the drawer tray
120
+ (drawer), so it recomputes live as fields change.
121
+
122
+ ```tsx
123
+ const form = useForm<Invoice>({ resolver, defaultValues })
124
+
125
+ <FormRenderer
126
+ form={form}
127
+ onSubmit={save}
128
+ header={{ title: 'Invoice', variant: 'new' }}
129
+ actions={<FormBuilder.Submit>Save invoice</FormBuilder.Submit>}
130
+ summary={
131
+ <FormSummary form={form} title="Invoice" subtitle="Summary">
132
+ <FormSummary.Group title="Total">
133
+ <FormSummary.Row label="Overall Total" emphasized compute={overallTotal} />
134
+ </FormSummary.Group>
135
+ </FormSummary>
136
+ }
137
+ >
138
+ {fields}
139
+ </FormRenderer>
140
+ ```
141
+
142
+ Works with `display="drawer"` too — the summary moves into the drawer's tray.
143
+
144
+ ## `FormDrawer` — the drawer wrapper
145
+
146
+ `FormRenderer` uses `FormDrawer` internally for `display: 'drawer'`. It's also exported
147
+ so you can put a hand-composed `FormBuilder` in a drawer directly. Since the header sits
148
+ outside the `<form>`, wire the Save button to the form via `id` / `form={id}`:
149
+
150
+ ```tsx
151
+ <FormDrawer
152
+ open={open}
153
+ onOpenChange={setOpen}
154
+ title="New item"
155
+ badge="New"
156
+ actions={
157
+ <Button type="submit" form="item-form" is_loading={saving}>
158
+ Save
159
+ </Button>
160
+ }
161
+ >
162
+ <FormBuilder
163
+ id="item-form"
164
+ onSubmit={save}
165
+ resolver={r}
166
+ defaultValues={d}
167
+ fieldDirection="vertical"
168
+ >
169
+ …fields…
170
+ </FormBuilder>
171
+ </FormDrawer>
172
+ ```
173
+
174
+ `FormDrawer` props: `open`, `onOpenChange`, `title`, `badge`, `variant`, `actions`,
175
+ `onOpenInNewTab`, `children`, `summary`. It owns no form state.
176
+
177
+ ### The title
178
+
179
+ The drawer renders the **same floating header as the page form** — a [HeaderBar](./header-bar.md)
180
+ title pill on the left, a dark action pill on the right — so a form's title looks identical in
181
+ either display. `title` is the plain (uppercased) text, `badge` the colored emphasis pill, and
182
+ `variant` (`new` / `edit` / `detail`) picks the badge colors; `badge` defaults from it
183
+ (New / Edit / View).
184
+
185
+ ```tsx
186
+ <FormDrawer title="Sales Invoice" badge="New" variant="new" … />
187
+ ```
188
+
189
+ Driving it through `FormRenderer`, the `header` prop feeds both displays — including
190
+ `header.variant`, which the drawer previously ignored:
191
+
192
+ ```tsx
193
+ <FormRenderer display="drawer" header={{ title: "Sales Invoice", variant: "edit" }} … />
194
+ ```
195
+
196
+ `title` and `badge` are **plain strings** (they were `ReactNode` before this shared-header
197
+ change) because they render through `HeaderBar`'s uppercase text treatment.
198
+
199
+ ### A summary beside the form
200
+
201
+ `summary` renders a conclusion panel — typically a [FormSummary](./form-summary.md) — _beside_
202
+ the form rather than inside its scrollable body. `FormDrawer` puts the form in a
203
+ [`DrawerPanel`](./drawer.md#drawerpanel) (the light surface) and the summary next to it with a
204
+ 6px gutter; the tray paints nothing, so the summary keeps its own dark background and full
205
+ height, scrolling internally when it outruns the drawer.
206
+
207
+ Hoist the form so both read the same instance:
208
+
209
+ ```tsx
210
+ const form = useForm({ resolver, defaultValues })
211
+
212
+ <FormDrawer
213
+ open={open} onOpenChange={setOpen} title="New item" badge="New"
214
+ summary={
215
+ <FormSummary form={form} title="Item" subtitle="Summary">
216
+ <FormSummary.Group title="Pricing">…rows…</FormSummary.Group>
217
+ </FormSummary>
218
+ }
219
+ >
220
+ <FormBuilder form={form} id="item-form" onSubmit={save} fieldDirection="vertical">
221
+ …fields…
222
+ </FormBuilder>
223
+ </FormDrawer>
224
+ ```
225
+
226
+ > `childrenOutside` is the deprecated former name for `summary`. It still works.
227
+
228
+ `FormRenderer` does **not** forward `summary` — use `FormDrawer` directly when you need one.
@@ -14,10 +14,16 @@ The component is composed of `FormStepper`, `FormStep`, `FormStepIndicator`, and
14
14
 
15
15
  ## Installation
16
16
 
17
+ TORCH Glare is a copy-in library: the CLI copies this component's source into your project
18
+ (you do **not** install it from the npm package). Run `init` once, then `add`:
19
+
17
20
  ```bash
21
+ npx torch-glare@latest init
18
22
  npx torch-glare@latest add FormStepper
19
23
  ```
20
24
 
25
+ `add` also copies any components, hooks, and utilities that `FormStepper` depends on.
26
+
21
27
  ## Imports
22
28
 
23
29
  ```typescript
@@ -0,0 +1,123 @@
1
+ ---
2
+ title: FormSummary
3
+ description: A read-only calculation panel displayed beside a form. Each row declares a compute(values) that runs against the live form values, so totals recalculate as the user types.
4
+ component: true
5
+ group: Forms
6
+ keywords: [form-summary, summary, totals, calculation, invoice, panel, react-hook-form, useWatch]
7
+ ---
8
+
9
+ # FormSummary
10
+
11
+ A read-only **calculation panel** that sits **beside a form** — the invoice-summary
12
+ look: grouped rows of computed totals, right-aligned, in Glare's dark `SystemStyle`
13
+ fields.
14
+
15
+ Each `FormSummary.Row` declares a **`compute(values)`** that runs against the **live**
16
+ form values, so every total recalculates as the user types.
17
+
18
+ The panel renders **outside** the form, beside it. Both read the same form, so
19
+ **hoist `useForm`** and hand the instance to each:
20
+
21
+ ```tsx
22
+ const form = useForm({ resolver: zodResolver(schema), defaultValues })
23
+
24
+ <div className="flex gap-4">
25
+ <FormBuilder form={form} onSubmit={save} className="min-w-0 flex-1">
26
+ <FormBuilder.Section title="Line items">…fields…</FormBuilder.Section>
27
+ </FormBuilder>
28
+
29
+ <FormSummary form={form} title="Invoice" subtitle="Summary">
30
+ <FormSummary.Group title="Total">
31
+ <FormSummary.Row label="Total Discount" compute={totalDiscount} />
32
+ <FormSummary.Row label="Overall Total" emphasized compute={overallTotal} />
33
+ <FormSummary.Row label="Overall Total" currency="IQD" tone="success"
34
+ compute={v => overallTotal(v) * v.iqdRate} decimals={0} />
35
+ <FormSummary.Row label="Overall Total" currency="USD" tone="info" compute={overallTotal} />
36
+ </FormSummary.Group>
37
+ </FormSummary>
38
+ </div>
39
+ ```
40
+
41
+ `FormBuilder` stays purely an input renderer — it knows nothing about the panel, and
42
+ **you** own the side-by-side layout. Passing `form` to `FormBuilder` makes it use that
43
+ instance instead of creating its own.
44
+
45
+ ### Height
46
+
47
+ The panel is `h-full` and fills whatever height its parent gives it, scrolling its groups
48
+ (header pinned) once they outrun it. That means **the parent has to have a height** — the
49
+ usual mistake is `items-start` on the flex row, which collapses the panel to its content
50
+ instead. Leave the row at its default `items-stretch`, as above.
51
+
52
+ To make the panel own the viewport rather than grow with the form, bound the row:
53
+
54
+ ```tsx
55
+ <div className="flex h-[calc(100vh-2rem)] gap-4">
56
+ <FormBuilder … className="min-w-0 flex-1 overflow-y-auto" />
57
+ <FormSummary … />
58
+ </div>
59
+ ```
60
+
61
+ > Hoisting the form means a remount `key` no longer resets it. Call `form.reset(defaults)`
62
+ > instead (e.g. when opening a drawer).
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ npx torch-glare@latest init
68
+ npx torch-glare@latest add FormSummary
69
+ ```
70
+
71
+ ## Imports
72
+
73
+ ```tsx
74
+ import { FormSummary } from '@/components/FormSummary'
75
+ ```
76
+
77
+ ## `FormSummary` props
78
+
79
+ | Prop | Type | Notes |
80
+ |---|---|---|
81
+ | `title` | `ReactNode` | Panel title, e.g. `"Invoice"`. |
82
+ | `subtitle` | `ReactNode` | Muted text beside the title, e.g. `"Summary"`. |
83
+ | `form` | `UseFormReturn` | The form to read values from — required when rendered outside the `<FormBuilder>`. |
84
+ | `width` | `number \| string` | Panel width; default `228`. |
85
+ | `children` | `ReactNode` | `FormSummary.Group` children. |
86
+
87
+ ## `FormSummary.Group` props
88
+
89
+ | Prop | Type | Notes |
90
+ |---|---|---|
91
+ | `title` | `ReactNode` | The group heading (Customer / Total / Tax / …). Groups are separated by a divider. |
92
+ | `collapsible` | `boolean` | When titled, the heading is a [ConclusionHeader](./conclusion-header.md) that opens/closes **this group's** rows; default `true`. |
93
+ | `defaultOpen` | `boolean` | Initial open state when collapsible; default `true`. |
94
+
95
+ The main panel title is a plain header — collapsing happens **per group**, not on the whole panel.
96
+
97
+ ## `FormSummary.Row` props
98
+
99
+ | Prop | Type | Notes |
100
+ |---|---|---|
101
+ | `label` | `ReactNode` | Row label, above the value. |
102
+ | `compute` | `(values) => number \| string` | **The calculation** — receives the live form values. |
103
+ | `value` | `number \| string` | Static value, when there's nothing to compute. |
104
+ | `currency` | `ReactNode` | Currency code, e.g. `"IQD"` — rendered **inside** the field's trailing edge. |
105
+ | `tone` | `'neutral' \| 'success' \| 'info'` | Color of the currency code (green / blue). |
106
+ | `emphasized` | `boolean` | The primary result — lighter, emphasized border. |
107
+ | `decimals` | `number` | Decimal places; default `2` (→ `0.00`). |
108
+ | `action` | `ReactNode` | Trailing slot inside the field, e.g. an `ActionButton`. Shares the slot with `currency`. |
109
+ | `format` | `(value) => string` | Override the default number formatting. |
110
+
111
+ ## Computing totals
112
+
113
+ `compute` is a plain function of the form values — keep the maths outside the JSX:
114
+
115
+ ```tsx
116
+ const subTotal = v => v.items.reduce((s, i) => s + i.qty * i.price, 0)
117
+ const totalDiscount = v => v.items.reduce((s, i) => s + i.discount, 0)
118
+ const taxable = v => Math.max(0, subTotal(v) - totalDiscount(v))
119
+ const totalTax = v => taxable(v) * (v.taxRate / 100)
120
+ const overallTotal = v => taxable(v) + totalTax(v)
121
+ ```
122
+
123
+ The panel is **read-only** — it contributes nothing to the submitted values.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Form
3
- version: 1.1.15
3
+ version: 2.4.0
4
4
  status: stable
5
5
  category: components/forms
6
6
  tags: [form, validation, react-hook-form, accessible, compound]
@@ -18,25 +18,22 @@ dependencies:
18
18
 
19
19
  ## Installation
20
20
 
21
+ TORCH Glare is a copy-in library: the CLI copies this component's source into your project
22
+ (you do **not** install it from the npm package). Run `init` once, then `add`:
23
+
21
24
  ```bash
22
- npm install torch-glare react-hook-form
25
+ npx torch-glare@latest init
26
+ npx torch-glare@latest add Form
23
27
  ```
24
28
 
29
+ `add` also copies any components, hooks, and utilities that `Form` depends on.
30
+
25
31
  ## Import
26
32
 
27
- ```typescript
28
- import {
29
- Form,
30
- FormField,
31
- FormItem,
32
- FormLabel,
33
- FormControl,
34
- FormDescription,
35
- FormMessage
36
- } from 'torch-glare/lib/components/Form'
33
+ Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
37
34
 
38
- // Also import from react-hook-form
39
- import { useForm } from 'react-hook-form'
35
+ ```tsx
36
+ import { Form } from "@/components/Form";
40
37
  ```
41
38
 
42
39
  ## Quick Examples
@@ -52,9 +49,9 @@ import {
52
49
  FormLabel,
53
50
  FormControl,
54
51
  FormMessage
55
- } from 'torch-glare/lib/components/Form'
56
- import { Input } from 'torch-glare/lib/components/Input'
57
- import { Button } from 'torch-glare/lib/components/Button'
52
+ } from '@/components/Form'
53
+ import { Input } from '@/components/Input'
54
+ import { Button } from '@/components/Button'
58
55
 
59
56
  function BasicForm() {
60
57
  const form = useForm({
@@ -213,9 +210,9 @@ function ValidatedForm() {
213
210
  ### With Multiple Field Types
214
211
 
215
212
  ```typescript
216
- import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from 'torch-glare/lib/components/Select'
217
- import { Checkbox } from 'torch-glare/lib/components/Checkbox'
218
- import { RadioGroup, RadioGroupItem } from 'torch-glare/lib/components/Radio'
213
+ import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/Select'
214
+ import { Checkbox } from '@/components/Checkbox'
215
+ import { RadioGroup, RadioGroupItem } from '@/components/Radio'
219
216
 
220
217
  function MultiFieldForm() {
221
218
  const form = useForm({
@@ -12,10 +12,16 @@ A presentational header chip used at the top of a form, page, or drawer to commu
12
12
 
13
13
  ## Installation
14
14
 
15
+ TORCH Glare is a copy-in library: the CLI copies this component's source into your project
16
+ (you do **not** install it from the npm package). Run `init` once, then `add`:
17
+
15
18
  ```bash
19
+ npx torch-glare@latest init
16
20
  npx torch-glare@latest add HeaderBar
17
21
  ```
18
22
 
23
+ `add` also copies any components, hooks, and utilities that `HeaderBar` depends on.
24
+
19
25
  ## Imports
20
26
 
21
27
  ```typescript
@@ -11,16 +11,22 @@ keywords: [image-attachment, file-upload, drag-drop, preview, modal, expandable]
11
11
 
12
12
  ## Installation
13
13
 
14
- No external dependencies required.
14
+ TORCH Glare is a copy-in library: the CLI copies this component's source into your project
15
+ (you do **not** install it from the npm package). Run `init` once, then `add`:
16
+
17
+ ```bash
18
+ npx torch-glare@latest init
19
+ npx torch-glare@latest add ImageAttachment
20
+ ```
21
+
22
+ `add` also copies any components, hooks, and utilities that `ImageAttachment` depends on.
15
23
 
16
24
  ## Import
17
25
 
18
- ```typescript
19
- import {
20
- ImageAttachment,
21
- ExpandableImage,
22
- AttachmentImagePreview
23
- } from '@torch-ui/components'
26
+ Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
27
+
28
+ ```tsx
29
+ import { ImageAttachment } from "@/components/ImageAttachment";
24
30
  ```
25
31
 
26
32
  ## Component Overview
@@ -36,7 +42,7 @@ The ImageAttachment suite consists of three components:
36
42
  ### Basic File Upload
37
43
 
38
44
  ```typescript
39
- import { ImageAttachment } from '@torch-ui/components'
45
+ import { ImageAttachment } from "@/components/ImageAttachment";
40
46
  import { useState } from 'react'
41
47
 
42
48
  function Example() {
@@ -64,7 +70,7 @@ function Example() {
64
70
  ### With Preview
65
71
 
66
72
  ```typescript
67
- import { ImageAttachment, ExpandableImage } from '@torch-ui/components'
73
+ import { ImageAttachment, ExpandableImage } from "@/components/ImageAttachment";
68
74
  import { useState } from 'react'
69
75
 
70
76
  function WithPreview() {
@@ -106,12 +112,8 @@ function WithPreview() {
106
112
  ### Complete Upload Flow
107
113
 
108
114
  ```typescript
109
- import {
110
- ImageAttachment,
111
- ExpandableImage,
112
- AttachmentImagePreview
113
- } from '@torch-ui/components'
114
- import { Button } from '@torch-ui/components'
115
+ import { ImageAttachment, ExpandableImage, AttachmentImagePreview } from "@/components/ImageAttachment";
116
+ import { Button } from "@/components/Button";
115
117
  import { useState } from 'react'
116
118
 
117
119
  function CompleteFlow() {
@@ -160,7 +162,7 @@ function CompleteFlow() {
160
162
  header={file?.name || 'Image Preview'}
161
163
  >
162
164
  <Button onClick={handleUpload}>Upload</Button>
163
- <Button variant="SecondaryStyle" onClick={handleRemove}>
165
+ <Button variant="BluSecStyle" onClick={handleRemove}>
164
166
  Remove
165
167
  </Button>
166
168
  </AttachmentImagePreview>
@@ -174,7 +176,7 @@ function CompleteFlow() {
174
176
  ### With Drag and Drop (React Dropzone)
175
177
 
176
178
  ```typescript
177
- import { ImageAttachment, ExpandableImage } from '@torch-ui/components'
179
+ import { ImageAttachment, ExpandableImage } from "@/components/ImageAttachment";
178
180
  import { useDropzone } from 'react-dropzone'
179
181
  import { useState } from 'react'
180
182
 
@@ -221,7 +223,7 @@ function WithDropzone() {
221
223
  ### Multiple File Upload
222
224
 
223
225
  ```typescript
224
- import { ImageAttachment, ExpandableImage } from '@torch-ui/components'
226
+ import { ImageAttachment, ExpandableImage } from "@/components/ImageAttachment";
225
227
  import { useState } from 'react'
226
228
 
227
229
  function MultipleFiles() {
@@ -267,8 +269,9 @@ function MultipleFiles() {
267
269
  ### With Validation
268
270
 
269
271
  ```typescript
270
- import { ImageAttachment } from '@torch-ui/components'
271
- import { FieldHint, toast } from '@torch-ui/components'
272
+ import { ImageAttachment } from "@/components/ImageAttachment";
273
+ import { FieldHint } from "@/components/FieldHint";
274
+ import { toast } from "@/components/Toast";
272
275
  import { useState } from 'react'
273
276
 
274
277
  function WithValidation() {
@@ -327,12 +330,9 @@ function WithValidation() {
327
330
  ### Profile Picture Upload
328
331
 
329
332
  ```typescript
330
- import {
331
- ImageAttachment,
332
- ExpandableImage,
333
- AttachmentImagePreview
334
- } from '@torch-ui/components'
335
- import { Avatar, Button } from '@torch-ui/components'
333
+ import { ImageAttachment, ExpandableImage, AttachmentImagePreview } from "@/components/ImageAttachment";
334
+ import { Avatar } from "@/components/Avatar";
335
+ import { Button } from "@/components/Button";
336
336
  import { useState } from 'react'
337
337
 
338
338
  function ProfilePictureUpload() {
@@ -400,8 +400,8 @@ function ProfilePictureUpload() {
400
400
  ### Gallery Upload
401
401
 
402
402
  ```typescript
403
- import { ImageAttachment, ExpandableImage } from '@torch-ui/components'
404
- import { Button } from '@torch-ui/components'
403
+ import { ImageAttachment, ExpandableImage } from "@/components/ImageAttachment";
404
+ import { Button } from "@/components/Button";
405
405
  import { useState } from 'react'
406
406
 
407
407
  function GalleryUpload() {
@@ -448,7 +448,7 @@ function GalleryUpload() {
448
448
  <Button
449
449
  size="S"
450
450
  buttonType="icon"
451
- variant="SecondaryStyle"
451
+ variant="BluSecStyle"
452
452
  className="absolute top-1 right-1 opacity-0 group-hover:opacity-100"
453
453
  onClick={() => handleRemove(image.id)}
454
454
  >
@@ -545,11 +545,7 @@ export const AttachmentImagePreview: React.FC<AttachmentImagePreviewProps>
545
545
  ### Usage with Types
546
546
 
547
547
  ```typescript
548
- import {
549
- ImageAttachment,
550
- ExpandableImage,
551
- AttachmentImagePreview
552
- } from '@torch-ui/components'
548
+ import { ImageAttachment, ExpandableImage, AttachmentImagePreview } from "@/components/ImageAttachment";
553
549
  import { useRef, useState } from 'react'
554
550
 
555
551
  function TypedExample() {
@@ -585,7 +581,7 @@ function TypedExample() {
585
581
  ### Upload with Progress
586
582
 
587
583
  ```typescript
588
- import { ImageAttachment } from '@torch-ui/components'
584
+ import { ImageAttachment } from "@/components/ImageAttachment";
589
585
  import { useState } from 'react'
590
586
 
591
587
  function UploadWithProgress() {
@@ -638,7 +634,7 @@ function UploadWithProgress() {
638
634
  ### Image Cropper Integration
639
635
 
640
636
  ```typescript
641
- import { ImageAttachment, ExpandableImage } from '@torch-ui/components'
637
+ import { ImageAttachment, ExpandableImage } from "@/components/ImageAttachment";
642
638
  import { useState } from 'react'
643
639
  import Cropper from 'react-easy-crop'
644
640
 
@@ -688,11 +684,7 @@ function ImageCropper() {
688
684
 
689
685
  ```typescript
690
686
  import { render, screen, fireEvent, waitFor } from '@testing-library/react'
691
- import {
692
- ImageAttachment,
693
- ExpandableImage,
694
- AttachmentImagePreview
695
- } from '@torch-ui/components'
687
+ import { ImageAttachment, ExpandableImage, AttachmentImagePreview } from "@/components/ImageAttachment";
696
688
 
697
689
  describe('ImageAttachment', () => {
698
690
  it('renders labels', () => {
@@ -883,10 +875,16 @@ describe('AttachmentImagePreview', () => {
883
875
 
884
876
  ### Default Styling
885
877
 
886
- - Drop Zone: 200px min-width, 65px height, dashed border
887
- - Preview: 180px max-width, 65px height, rounded corners
888
- - Active State: Background and border color change
889
- - Hover: Expand button overlay with icon
878
+ Matches the *Attachment-Field-1.0 / Pic-Container-1.0* design:
879
+
880
+ - **Field box** (`ImageAttachment`): a `#f9f9f9` (`background-presentation-form-field-primary`)
881
+ rounded container holding an optional preview and the drop zone, `gap-[10px]`.
882
+ - **Drop zone**: fills the box (`flex-1`), 65px tall, transparent with a dashed
883
+ `border-presentation-action-borderstyle` border; drag-active tints it gray.
884
+ - **Preview thumbnail** (`ExpandableImage`): a fixed **65×65** square, `object-cover`, rounded.
885
+ - **Placeholder** (no image): ocean fill (`badge-ocean-subtle`) + dashed `blue-purple-300`
886
+ border + paperclip icon; on hover it goes gray (`badge-gray-subtle` / `badge-gray`).
887
+ - **Hover (has image)**: a `black/50` overlay with a fullscreen icon + the `expandLabel`.
890
888
 
891
889
  ## Best Practices
892
890