torch-glare 2.4.1 → 2.4.3

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 (85) hide show
  1. package/apps/lib/components/Button.tsx +1 -1
  2. package/apps/lib/components/Card.tsx +47 -20
  3. package/apps/lib/components/ColorPicker.tsx +441 -0
  4. package/apps/lib/components/ConclusionHeader.tsx +148 -0
  5. package/apps/lib/components/DatePicker.tsx +2 -0
  6. package/apps/lib/components/Drawer.tsx +66 -24
  7. package/apps/lib/components/FormBuilder/context.ts +68 -0
  8. package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +60 -0
  9. package/apps/lib/components/FormBuilder/fields/ColorField.tsx +59 -0
  10. package/apps/lib/components/FormBuilder/fields/CustomField.tsx +11 -0
  11. package/apps/lib/components/FormBuilder/fields/DateField.tsx +32 -0
  12. package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +74 -0
  13. package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +148 -0
  14. package/apps/lib/components/FormBuilder/fields/FileField.tsx +39 -0
  15. package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +132 -0
  16. package/apps/lib/components/FormBuilder/fields/OtpField.tsx +31 -0
  17. package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +83 -0
  18. package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +31 -0
  19. package/apps/lib/components/FormBuilder/fields/SelectField.tsx +91 -0
  20. package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +157 -0
  21. package/apps/lib/components/FormBuilder/fields/SliderField.tsx +67 -0
  22. package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +41 -0
  23. package/apps/lib/components/FormBuilder/fields/TableField.tsx +308 -0
  24. package/apps/lib/components/FormBuilder/fields/TextField.tsx +213 -0
  25. package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +43 -0
  26. package/apps/lib/components/FormBuilder/fields/countries.ts +303 -0
  27. package/apps/lib/components/FormBuilder/fields/index.ts +25 -0
  28. package/apps/lib/components/FormBuilder/form-builder.tsx +279 -0
  29. package/apps/lib/components/FormBuilder/header.tsx +101 -0
  30. package/apps/lib/components/FormBuilder/index.ts +33 -0
  31. package/apps/lib/components/FormBuilder/numberFormat.ts +16 -0
  32. package/apps/lib/components/FormBuilder/stepper.tsx +290 -0
  33. package/apps/lib/components/FormBuilder/submit.tsx +38 -0
  34. package/apps/lib/components/FormBuilder/types.ts +261 -0
  35. package/apps/lib/components/FormRenderer/FormDrawer.tsx +128 -0
  36. package/apps/lib/components/FormRenderer/form-renderer.tsx +111 -0
  37. package/apps/lib/components/FormRenderer/index.ts +4 -0
  38. package/apps/lib/components/FormRenderer/types.ts +77 -0
  39. package/apps/lib/components/FormSummary.tsx +282 -0
  40. package/apps/lib/components/ImageAttachment.tsx +36 -61
  41. package/apps/lib/components/Label.tsx +49 -42
  42. package/apps/lib/components/Popover.tsx +6 -2
  43. package/apps/lib/components/RadioCard.tsx +2 -0
  44. package/apps/lib/components/SearchableSelect.tsx +16 -5
  45. package/apps/lib/components/SectionBlock.tsx +16 -8
  46. package/apps/lib/components/Select.tsx +41 -120
  47. package/apps/lib/components/TextEditor/RichTextField.tsx +46 -0
  48. package/apps/lib/components/{TextEditor.tsx → TextEditor/TextEditor.tsx} +63 -9
  49. package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +429 -0
  50. package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +70 -0
  51. package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +50 -0
  52. package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +48 -0
  53. package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +98 -0
  54. package/apps/lib/{types → components/TextEditor}/editorjs.d.ts +19 -0
  55. package/apps/lib/components/TextEditor/index.ts +7 -0
  56. package/apps/lib/components/Textarea.tsx +1 -1
  57. package/apps/lib/layouts/FieldSection.tsx +25 -22
  58. package/apps/lib/registry.json +51 -58
  59. package/apps/lib/tsconfig.tsbuildinfo +1 -0
  60. package/apps/lib/utils/color.ts +175 -0
  61. package/dist/src/shared/tailwindInit.d.ts.map +1 -1
  62. package/dist/src/shared/tailwindInit.js +3 -0
  63. package/dist/src/shared/tailwindInit.js.map +1 -1
  64. package/docs/components/card.md +4 -2
  65. package/docs/components/chart-block-tool.md +5 -4
  66. package/docs/components/color-picker.md +101 -0
  67. package/docs/components/conclusion-header.md +80 -0
  68. package/docs/components/drawer.md +153 -102
  69. package/docs/components/form-builder.md +260 -0
  70. package/docs/components/form-renderer.md +234 -0
  71. package/docs/components/form-summary.md +123 -0
  72. package/docs/components/image-attachment.md +10 -4
  73. package/docs/components/searchable-select.md +50 -46
  74. package/docs/components/table-dnd-wrapper.md +5 -3
  75. package/docs/components/text-editor.md +18 -0
  76. package/docs/how-to/form-and-list-recipes.md +26 -19
  77. package/docs/how-to/forms-with-form-builder.md +411 -0
  78. package/docs/how-to/guides.md +153 -179
  79. package/docs/reference/tailwind-plugins.md +11 -1
  80. package/docs/tutorials/building-first-form.md +150 -159
  81. package/docs/tutorials/getting-started.md +9 -0
  82. package/package.json +1 -1
  83. /package/apps/lib/components/{ChartBlockTool.ts → TextEditor/ChartBlockTool.ts} +0 -0
  84. /package/apps/lib/components/{TableDnDWrapper.ts → TextEditor/TableDnDWrapper.ts} +0 -0
  85. /package/apps/lib/{utils → components/TextEditor}/markdownParser.ts +0 -0
@@ -168,70 +168,73 @@ function ArabicPicker({ options, value, onValueChange }) {
168
168
 
169
169
  ### SearchableSelect
170
170
 
171
- | Prop | Type | Default | Description |
172
- |------|------|---------|-------------|
173
- | `options` | `SearchableSelectOption[]` | Required | The list of selectable options. In server mode (`filterClientSide={false}`) these are rendered as-is. |
174
- | `value` | `string \| null` | - | Controlled selected value. The matching option's label is shown as solid text in the input. |
175
- | `onValueChange` | `(value: string, option: SearchableSelectOption) => void` | - | Called when an option is selected. Receives the value and the full option object. |
176
- | `placeholder` | `string` | `'Search…'` | Placeholder text for the search input. |
177
- | `size` | `'XS' \| 'S' \| 'M'` | `'M'` | Field size. |
178
- | `variant` | `'PresentationStyle'` | `'PresentationStyle'` | Visual style variant for the field and dropdown surface. |
179
- | `icon` | `ReactNode` | - | Optional leading icon rendered inside the field. |
180
- | `theme` | `'dark' \| 'light' \| 'default'` | - | Theme variant, applied via `data-theme`. |
181
- | `dir` | `string` | - | Text direction (e.g. `'rtl'`) for the field and dropdown. |
182
- | `className` | `string` | - | Additional CSS classes for the field group. |
183
- | `filterClientSide` | `boolean` | `true` | When `true`, filters `options` locally by label. Set `false` for server-side search — `options` are rendered as-is and refetched via `onSearchChange`. |
184
- | `onSearchChange` | `(query: string) => void` | - | Called (debounced) with the trimmed query as the user types. Refetch your data here for server-side search. |
185
- | `searchDebounceMs` | `number` | `300` | Debounce delay (ms) before `onSearchChange` fires. |
186
- | `hasMore` | `boolean` | `false` | Whether more pages are available; gates the infinite-scroll loader. |
187
- | `loading` | `boolean` | `false` | Whether a fetch is in flight; shows a loading row and blocks `onLoadMore`. |
188
- | `onLoadMore` | `() => void` | - | Called when the scroll viewport nears the bottom and `hasMore && !loading`. |
189
- | `maxVisibleItems` | `number` | `5` | Maximum rows visible before the list scrolls internally. |
171
+ | Prop | Type | Default | Description |
172
+ | ------------------ | --------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
173
+ | `options` | `SearchableSelectOption[]` | Required | The list of selectable options. In server mode (`filterClientSide={false}`) these are rendered as-is. |
174
+ | `value` | `string \| null` | - | Controlled selected value. The matching option's label is shown as solid text in the input. |
175
+ | `onValueChange` | `(value: string, option: SearchableSelectOption) => void` | - | Called when an option is selected. Receives the value and the full option object. |
176
+ | `placeholder` | `string` | `'Search…'` | Placeholder text for the search input. |
177
+ | `size` | `'XS' \| 'S' \| 'M'` | `'M'` | Field size. |
178
+ | `variant` | `'PresentationStyle'` | `'PresentationStyle'` | Visual style variant for the field and dropdown surface. |
179
+ | `icon` | `ReactNode` | - | Optional leading icon rendered inside the field. |
180
+ | `theme` | `'dark' \| 'light' \| 'default'` | - | Theme variant, applied via `data-theme`. |
181
+ | `dir` | `string` | - | Text direction (e.g. `'rtl'`) for the field and dropdown. |
182
+ | `className` | `string` | - | Additional CSS classes for the field group. |
183
+ | `filterClientSide` | `boolean` | `true` | When `true`, filters `options` locally by label. Set `false` for server-side search — `options` are rendered as-is and refetched via `onSearchChange`. |
184
+ | `onSearchChange` | `(query: string) => void` | - | Called (debounced) with the trimmed query as the user types. Refetch your data here for server-side search. |
185
+ | `searchDebounceMs` | `number` | `300` | Debounce delay (ms) before `onSearchChange` fires. |
186
+ | `hasMore` | `boolean` | `false` | Whether more pages are available; gates the infinite-scroll loader. |
187
+ | `loading` | `boolean` | `false` | Whether a fetch is in flight; shows a loading row and blocks `onLoadMore`. |
188
+ | `onLoadMore` | `() => void` | - | Called when the scroll viewport nears the bottom and `hasMore && !loading`. |
189
+ | `maxVisibleItems` | `number` | `5` | Maximum rows visible before the list scrolls internally. |
190
190
 
191
191
  ### SearchableSelectOption
192
192
 
193
- | Prop | Type | Default | Description |
194
- |------|------|---------|-------------|
195
- | `value` | `string` | Required | Unique value for the option; matched against the `value` prop. |
196
- | `label` | `string` | Required | Display text; also used for client-side label filtering. |
197
- | `icon` | `ReactNode` | - | Optional leading icon rendered in the row. |
193
+ | Prop | Type | Default | Description |
194
+ | ------------ | ----------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
195
+ | `value` | `string` | Required | Unique value for the option; matched against the `value` prop. |
196
+ | `label` | `string` | Required | Display text; also the default target for client-side filtering. |
197
+ | `icon` | `ReactNode` | - | Optional leading icon rendered in the row. |
198
+ | `searchText` | `string` | `label` | Text used for client-side filtering. Set it to match on a **subset** of the label — e.g. a country name when the label also shows a dial code, so typing the dial doesn't match. |
198
199
 
199
200
  ## TypeScript
200
201
 
201
202
  ### Type Definitions
202
203
 
203
204
  ```typescript
204
- import { ReactNode } from 'react'
205
+ import { ReactNode } from "react";
205
206
 
206
207
  export interface SearchableSelectOption {
207
- value: string
208
- label: string
209
- icon?: ReactNode
208
+ value: string;
209
+ label: string;
210
+ icon?: ReactNode;
211
+ /** Text used for client-side filtering. Defaults to `label`. */
212
+ searchText?: string;
210
213
  }
211
214
 
212
215
  interface SearchableSelectProps {
213
- options: SearchableSelectOption[]
214
- value?: string | null
215
- onValueChange?: (value: string, option: SearchableSelectOption) => void
216
- placeholder?: string
217
- size?: 'XS' | 'S' | 'M'
218
- variant?: 'PresentationStyle'
219
- icon?: ReactNode
220
- theme?: 'dark' | 'light' | 'default'
221
- dir?: string
222
- className?: string
216
+ options: SearchableSelectOption[];
217
+ value?: string | null;
218
+ onValueChange?: (value: string, option: SearchableSelectOption) => void;
219
+ placeholder?: string;
220
+ size?: "XS" | "S" | "M";
221
+ variant?: "PresentationStyle";
222
+ icon?: ReactNode;
223
+ theme?: "dark" | "light" | "default";
224
+ dir?: string;
225
+ className?: string;
223
226
 
224
227
  // Async / backend pagination (all optional; static `options` still work)
225
- filterClientSide?: boolean
226
- onSearchChange?: (query: string) => void
227
- searchDebounceMs?: number
228
- hasMore?: boolean
229
- loading?: boolean
230
- onLoadMore?: () => void
231
- maxVisibleItems?: number
228
+ filterClientSide?: boolean;
229
+ onSearchChange?: (query: string) => void;
230
+ searchDebounceMs?: number;
231
+ hasMore?: boolean;
232
+ loading?: boolean;
233
+ onLoadMore?: () => void;
234
+ maxVisibleItems?: number;
232
235
  }
233
236
 
234
- export function SearchableSelect(props: SearchableSelectProps): JSX.Element
237
+ export function SearchableSelect(props: SearchableSelectProps): JSX.Element;
235
238
  ```
236
239
 
237
240
  ## Common Patterns
@@ -340,6 +343,7 @@ function UserPicker() {
340
343
  ## Best Practices
341
344
 
342
345
  1. **Always control `value`** — pass `value` and `onValueChange` so the input can display the selected label.
346
+
343
347
  ```typescript
344
348
  <SearchableSelect value={value} onValueChange={setValue} options={options} />
345
349
  ```
@@ -27,13 +27,15 @@ TORCH Glare is a copy-in library: the CLI copies this module's source into your
27
27
 
28
28
  ```bash
29
29
  npx torch-glare@latest init
30
- npx torch-glare@latest add TableDnDWrapper
30
+ npx torch-glare@latest add TextEditor
31
31
  ```
32
32
 
33
+ `createTableDnDClass` ships as part of the `TextEditor` folder, so `add TextEditor` copies it in.
34
+
33
35
  ## Import
34
36
 
35
37
  ```typescript
36
- import createTableDnDClass from "@/components/TableDnDWrapper";
38
+ import { createTableDnDClass } from "@/components/TextEditor";
37
39
  ```
38
40
 
39
41
  ## Quick Examples
@@ -43,7 +45,7 @@ import createTableDnDClass from "@/components/TableDnDWrapper";
43
45
  ```typescript
44
46
  import EditorJS from "@editorjs/editorjs";
45
47
  import Table from "@editorjs/table";
46
- import createTableDnDClass from "@/components/TableDnDWrapper";
48
+ import { createTableDnDClass } from "@/components/TextEditor";
47
49
 
48
50
  // Wrap the original table tool to add row/column drag-and-drop.
49
51
  const TableWithDnD = createTableDnDClass(Table);
@@ -260,8 +260,26 @@ function MarkdownEditor() {
260
260
  | `tools` | `Record<string, any>` | Default 18+ tools | Override the Editor.js tools configuration |
261
261
  | `minHeight` | `number` | - | Custom min-height in pixels (overrides size) |
262
262
  | `disabled` | `boolean` | `false` | Disables interaction with reduced opacity |
263
+ | `toolbar` | `boolean` | `true` | Show the fixed formatting toolbar. Auto-hidden when `readOnly`/`disabled`. |
263
264
  | `className` | `string` | - | Additional CSS classes |
264
265
 
266
+ ### Formatting toolbar
267
+
268
+ A fixed, sticky toolbar sits at the top of the editor (shown by default; pass `toolbar={false}`
269
+ to hide it, and it is automatically hidden in `readOnly`/`disabled` editors). It drives the
270
+ underlying Editor.js instance and offers:
271
+
272
+ - **History** — undo / redo (via `editorjs-undo`; also bound to `Ctrl/⌘+Z` / `Ctrl/⌘+Y`).
273
+ - **Block type** — a dropdown to switch between Normal text and Heading 1–3 (`blocks.convert`).
274
+ - **Alignment** — left / center / right (a block tune persisted on each block).
275
+ - **Text color** — a swatch palette.
276
+ - **Inline** — bold, italic, underline, strikethrough, clear formatting.
277
+ - **Lists** — bullet and ordered.
278
+ - **Insert image** — from a local file (inserted as an `image` block).
279
+
280
+ Strikethrough and color are backed by small custom inline tools whose `sanitize` allowlists let
281
+ that markup survive `save()`; alignment persists as a block tune.
282
+
265
283
  ### Ref Methods (TextEditorRef)
266
284
 
267
285
  | Method | Signature | Description |
@@ -10,6 +10,13 @@ Battle-tested layouts and component combinations from production frontend work.
10
10
  Use these as the starting point for create dialogs, list/filter pages,
11
11
  line-item grids, and login flows.
12
12
 
13
+ > **For actual forms, reach for [`FormBuilder`](../components/form-builder.md) first.** The
14
+ > multi-column form rows below are a layout escape hatch for the rare case that needs bespoke
15
+ > positioning — they are **not** the default way to build a form. A normal create/edit form is
16
+ > `FormBuilder` fields as JSX children with a resolver; see the
17
+ > [Forms with FormBuilder](./forms-with-form-builder.md) guide. Don't hand-wire `FormField` /
18
+ > `InputField` rows or hold field state in `useState` when `FormBuilder` would do it.
19
+
13
20
  > All examples use the `presentation` color tokens. Never substitute
14
21
  > `*-system-*` tokens or `variant="SystemStyle"` — see the rules banner at
15
22
  > the top of every doc response.
@@ -76,7 +83,9 @@ the same filter bar — a search input + one or more select filters above a
76
83
  data table.
77
84
 
78
85
  ```tsx
79
- {/* Filter bar */}
86
+ {
87
+ /* Filter bar */
88
+ }
80
89
  <div className="flex items-center gap-3">
81
90
  <div className="flex-1 max-w-sm">
82
91
  <InputField
@@ -99,9 +108,11 @@ data table.
99
108
  ]}
100
109
  placeholder="All Statuses"
101
110
  />
102
- </div>
111
+ </div>;
103
112
 
104
- {/* Data table */}
113
+ {
114
+ /* Data table */
115
+ }
105
116
  <Card className="p-0 overflow-hidden">
106
117
  <CardContent className="p-0 overflow-x-auto">
107
118
  <Table className="w-full">
@@ -122,9 +133,7 @@ data table.
122
133
  >
123
134
  <i className="ri-inbox-line text-4xl opacity-60" />
124
135
  <p className="typography-body-medium-regular">No vouchers</p>
125
- <p className="typography-body-small-regular opacity-80">
126
- Try adjusting your filters
127
- </p>
136
+ <p className="typography-body-small-regular opacity-80">Try adjusting your filters</p>
128
137
  </TableCell>
129
138
  </TableRow>
130
139
  ) : (
@@ -144,7 +153,7 @@ data table.
144
153
  </TableBody>
145
154
  </Table>
146
155
  </CardContent>
147
- </Card>
156
+ </Card>;
148
157
  ```
149
158
 
150
159
  Key rules:
@@ -263,15 +272,15 @@ hierarchy. Adding a relevant icon makes dialogs instantly recognizable.
263
272
 
264
273
  Pick an icon that matches the entity:
265
274
 
266
- | Entity | Icon |
267
- |---|---|
268
- | Account | `ri-bank-line` |
269
- | Fiscal period / year | `ri-calendar-line` |
270
- | Voucher / journal | `ri-receipt-line` |
271
- | Number series | `ri-hashtag` |
272
- | Posting rule | `ri-settings-3-line` |
273
- | Exchange rate | `ri-exchange-line` |
274
- | Bank / cash account | `ri-bank-card-line` |
275
+ | Entity | Icon |
276
+ | -------------------- | -------------------- |
277
+ | Account | `ri-bank-line` |
278
+ | Fiscal period / year | `ri-calendar-line` |
279
+ | Voucher / journal | `ri-receipt-line` |
280
+ | Number series | `ri-hashtag` |
281
+ | Posting rule | `ri-settings-3-line` |
282
+ | Exchange rate | `ri-exchange-line` |
283
+ | Bank / cash account | `ri-bank-card-line` |
275
284
 
276
285
  ---
277
286
 
@@ -297,9 +306,7 @@ export function LoginPage() {
297
306
  "to-background-presentation-state-information/10",
298
307
  ].join(" ")}
299
308
  >
300
- <h1 className="typography-headers-large-medium">
301
- Welcome to Torch Finance
302
- </h1>
309
+ <h1 className="typography-headers-large-medium">Welcome to Torch Finance</h1>
303
310
  <ul className="flex flex-col gap-3">
304
311
  {features.map((f) => (
305
312
  <li key={f.title} className="flex items-start gap-3">