@timeax/form-palette 0.1.16 → 0.1.18

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.
package/README.md CHANGED
@@ -1,132 +1,58 @@
1
- # Index
2
- Included Sections: 119
3
- - [Form Palette](#form-palette) 123-343
4
- - [Quick start](#quick-start) 133-161
5
- - [Installation:](#installation) 135-161
6
- - [Form](#form) 163-237
7
- - [Minimal “local” form](#minimal-local-form) 167-200
8
- - [Axios adapter](#axios-adapter) 202-217
9
- - [Inertia adapter](#inertia-adapter) 219-237
10
- - [InputField](#inputfield) 239-294
11
- - [Basic usage](#basic-usage) 252-263
12
- - [Helper slots](#helper-slots) 265-277
13
- - [Standalone mode](#standalone-mode) 279-294
14
- - [Adapters](#adapters) 296-331
15
- - [Built-in adapter keys](#built-in-adapter-keys) 300-304
16
- - [Registering adapters](#registering-adapters) 306-325
17
- - [Adapter-specific props](#adapter-specific-props) 327-331
18
- - [Recommended boot order](#recommended-boot-order) 333-343
19
- - [Variant props + InputField usage](#variant-props-inputfield-usage) 346-1707
20
- - [text](#text) 377-434
21
- - [Variant props](#variant-props) 379-399
22
- - [Sample usage (InputField)](#sample-usage-inputfield) 401-434
23
- - [textarea](#textarea) 436-465
24
- - [Variant props](#variant-props-1) 438-442
25
- - [Sample usage (InputField)](#sample-usage-inputfield-1) 444-465
26
- - [toggle-group](#toggle-group) 467-529
27
- - [Variant props](#variant-props-2) 469-499
28
- - [Sample usage (InputField)](#sample-usage-inputfield-2) 501-529
29
- - [number](#number) 531-559
30
- - [password](#password) 561-599
31
- - [phone](#phone) 601-638
32
- - [Slider (`slider`)](#slider-slider) 640-699
33
- - [Props](#props) 644-679
34
- - [Example](#example) 681-699
35
- - [Toggle (`toggle`)](#toggle-toggle) 701-734
36
- - [Props](#props-1) 705-719
37
- - [Example](#example-1) 721-734
38
- - [TreeSelect (`treeselect`)](#treeselect-treeselect) 736-849
39
- - [Base props](#base-props) 740-773
40
- - [Mode: default (`mode` omitted or "default")](#mode-default-mode-omitted-or-default) 775-793
41
- - [Mode: button (`mode="button"`)](#mode-button-modebutton) 795-811
42
- - [Example (default mode)](#example-default-mode) 813-833
43
- - [Example (multiple + button mode)](#example-multiple-button-mode) 835-849
44
- - [multi-select](#multi-select) 851-938
45
- - [Variant props](#variant-props-3) 853-884
46
- - [Mode and trigger props](#mode-and-trigger-props) 886-908
47
- - [Sample usage](#sample-usage) 910-938
48
- - [radio](#radio) 940-999
49
- - [Variant props](#variant-props-4) 942-967
50
- - [Supported option shapes](#supported-option-shapes) 969-972
51
- - [Sample usage](#sample-usage-1) 974-999
52
- - [select](#select) 1001-1077
53
- - [Variant props](#variant-props-5) 1003-1048
54
- - [Sample usage](#sample-usage-2) 1050-1077
55
- - [checkbox](#checkbox) 1079-1147
56
- - [chips](#chips) 1149-1202
57
- - [color](#color) 1204-1234
58
- - [date](#date) 1236-1283
59
- - [Variant props](#variant-props-6) 1238-1256
60
- - [Sample usage](#sample-usage-3) 1258-1283
61
- - [keyvalue](#keyvalue) 1285-1335
62
- - [Variant props](#variant-props-7) 1287-1307
63
- - [Sample usage](#sample-usage-4) 1309-1335
64
- - [editor](#editor) 1337-1381
65
- - [Variant props](#variant-props-8) 1339-1356
66
- - [Sample usage](#sample-usage-5) 1358-1381
67
- - [file](#file) 1383-1460
68
- - [Variant props](#variant-props-9) 1385-1411
69
- - [Mode and trigger props](#mode-and-trigger-props-1) 1413-1435
70
- - [Sample usage](#sample-usage-6) 1437-1460
71
- - [json-editor](#json-editor) 1462-1542
72
- - [Wrapper / trigger props](#wrapper-trigger-props) 1464-1482
73
- - [Editor props (passed into the JSON editor)](#editor-props-passed-into-the-json-editor) 1484-1504
74
- - [Sample usage](#sample-usage-7) 1506-1542
75
- - [lister](#lister) 1544-1644
76
- - [Data + mapping props](#data-mapping-props) 1546-1563
77
- - [Selection + behaviour props](#selection-behaviour-props) 1565-1584
78
- - [Trigger styling + container props](#trigger-styling-container-props) 1586-1614
79
- - [Sample usage](#sample-usage-8) 1616-1644
80
- - [custom](#custom) 1646-1707
81
- - [Variant props](#variant-props-10) 1648-1663
82
- - [Sample usage](#sample-usage-9) 1665-1707
83
- - [Form Palette — `extra` entrypoint (v2)](#form-palette-extra-entrypoint-v2) 1709-1723
84
- - [1) Lister (runtime)](#1-lister-runtime) 1725-1849
85
- - [What is Lister?](#what-is-lister) 1727-1738
86
- - [Building blocks (what you actually mount/call)](#building-blocks-what-you-actually-mountcall) 1740-1771
87
- - [✅ `ListerProvider`](#listerprovider) 1742-1747
88
- - [✅ `ListerUI`](#listerui) 1749-1752
89
- - [✅ `useLister()`](#uselister) 1754-1764
90
- - [✅ `useData()`](#usedata) 1766-1771
91
- - [Quick start (recommended)](#quick-start-recommended) 1773-1818
92
- - [Step 1 — Mount provider + UI once](#step-1-mount-provider-ui-once) 1775-1794
93
- - [Step 2 — Open a picker imperatively](#step-2-open-a-picker-imperatively) 1796-1818
94
- - [`ListerProvider` API](#listerprovider-api) 1820-1849
95
- - [`ListerProviderHost`](#listerproviderhost) 1832-1842
96
- - [Practical usage](#practical-usage) 1844-1849
97
- - [2) `useData()` — deep dive (extremely important)](#2-usedata-deep-dive-extremely-important) 1851-2247
98
- - [What `useData()` returns (mental model)](#what-usedata-returns-mental-model) 1865-1877
99
- - [`UseDataOptions` (inputs)](#usedataoptions-inputs) 1879-1910
100
- - [Selection config (`selection`)](#selection-config-selection) 1898-1910
101
- - [Search modes: remote vs local vs hybrid](#search-modes-remote-vs-local-vs-hybrid) 1912-1935
102
- - [✅ `remote` (default)](#remote-default) 1914-1919
103
- - [✅ `local`](#local) 1921-1926
104
- - [✅ `hybrid`](#hybrid) 1928-1935
105
- - [Search targeting (`searchTarget`)](#search-targeting-searchtarget) 1937-1947
106
- - [Core returned API (what you’ll use most)](#core-returned-api-what-youll-use-most) 1949-1984
107
- - [Data + status](#data-status) 1951-1954
108
- - [Search](#search) 1956-1960
109
- - [Filters](#filters) 1962-1966
110
- - [Fetch](#fetch) 1968-1971
111
- - [Selection (when enabled)](#selection-when-enabled) 1973-1984
112
- - [`useData()` — practical use cases (full examples)](#usedata-practical-use-cases-full-examples) 1986-2238
113
- - [Use case A — Remote search list (simple)](#use-case-a-remote-search-list-simple) 1988-2030
114
- - [Use case B — Local mode (fetch once, instant client filtering)](#use-case-b-local-mode-fetch-once-instant-client-filtering) 2032-2066
115
- - [Use case C — Filters with `patchFilters` (remote/hybrid auto-fetch)](#use-case-c-filters-with-patchfilters-remotehybrid-auto-fetch) 2068-2121
116
- - [Use case D — Constrain to a known allow-list (`searchTarget: mode="only"`)](#use-case-d-constrain-to-a-known-allow-list-searchtarget-modeonly) 2123-2159
117
- - [Use case E — Custom multi-select UI (selection enabled)](#use-case-e-custom-multi-select-ui-selection-enabled) 2161-2209
118
- - [Use case F — Advanced request shaping (`buildRequest`)](#use-case-f-advanced-request-shaping-buildrequest) 2211-2238
119
- - [Practical tips](#practical-tips) 2240-2247
120
- - [3) JsonEditor (overview)](#3-jsoneditor-overview) 2249-2280
121
- - [Standalone usage](#standalone-usage) 2259-2280
1
+ # Index
2
+ - [Form Palette](#form-palette)
3
+ - [Quick start](#quick-start)
4
+ - [Form](#form)
5
+ - [InputField](#inputfield)
6
+ - [Adapters](#adapters)
7
+ - [Recommended boot order](#recommended-boot-order)
8
+ - [Variant props + InputField usage](#variant-props-inputfield-usage)
9
+ - [text](#text)
10
+ - [textarea](#textarea)
11
+ - [toggle-group](#toggle-group)
12
+ - [number](#number)
13
+ - [password](#password)
14
+ - [phone](#phone)
15
+ - [Slider (`slider`)](#slider-slider)
16
+ - [Toggle (`toggle`)](#toggle-toggle)
17
+ - [TreeSelect (`treeselect`)](#treeselect-treeselect)
18
+ - [multi-select](#multi-select)
19
+ - [radio](#radio)
20
+ - [select](#select)
21
+ - [checkbox](#checkbox)
22
+ - [chips](#chips)
23
+ - [color](#color)
24
+ - [date](#date)
25
+ - [keyvalue](#keyvalue)
26
+ - [editor](#editor)
27
+ - [file](#file)
28
+ - [icon](#icon)
29
+ - [image-icon](#image-icon)
30
+ - [json-editor](#json-editor)
31
+ - [lister](#lister)
32
+ - [custom](#custom)
33
+ - [Form Palette - `extra` entrypoint (v2)](#form-palette-extra-entrypoint-v2)
34
+ - [1) Lister (runtime)](#1-lister-runtime)
35
+ - [What is Lister?](#what-is-lister)
36
+ - [Building blocks (what you actually mount/call)](#building-blocks-what-you-actually-mountcall)
37
+ - [Quick start (recommended)](#quick-start-recommended)
38
+ - [`ListerProvider` API](#listerprovider-api)
39
+ - [2) `useData()` - deep dive (extremely important)](#2-usedata-deep-dive-extremely-important)
40
+ - [`UseDataOptions` (inputs)](#usedataoptions-inputs)
41
+ - [Search modes: remote vs local vs hybrid](#search-modes-remote-vs-local-vs-hybrid)
42
+ - [Search targeting (`searchTarget`)](#search-targeting-searchtarget)
43
+ - [Core returned API (what you'll use most)](#core-returned-api-what-youll-use-most)
44
+ - [`useData()` - practical use cases (full examples)](#usedata-practical-use-cases-full-examples)
45
+ - [Practical tips](#practical-tips)
46
+ - [3) JsonEditor (overview)](#3-jsoneditor-overview)
47
+ - [Standalone usage](#standalone-usage)
122
48
 
123
49
  # Form Palette
124
50
 
125
51
  A small but powerful React form runtime built around three ideas:
126
52
 
127
53
  1. **A single `<Form />` shell** that wires up state, submission and validation.
128
- 2. **`<InputField />`** as the universal field wrapper that renders a registered **variant** (text, number, select, json-editor, etc.) and handles label / description / errors / layout.
129
- 3. **Adapters** that decide what submit means (`local`, `axios`, `inertia`, or your own).
54
+ 2. **`<InputField />`** as the universal “field wrapper” that renders a registered **variant** (text, number, select, json-editor, etc.) and handles label / description / errors / layout.
55
+ 3. **Adapters** that decide what “submit” means (`local`, `axios`, `inertia`, or your own).
130
56
 
131
57
  ---
132
58
 
@@ -164,7 +90,7 @@ await registerInertiaAdapter();
164
90
 
165
91
  `Form` is the main form component exported from the package entrypoint (it is `CoreShell`, re-exported as `Form`).
166
92
 
167
- ### Minimal local form
93
+ ### Minimal “local” form
168
94
 
169
95
  Use `adapter="local"` when you want submission to be handled purely in JS.
170
96
 
@@ -238,7 +164,7 @@ function Example() {
238
164
 
239
165
  ## InputField
240
166
 
241
- `InputField` is the form runtimes field wrapper”. It:
167
+ `InputField` is the form runtime’s “field wrapper”. It:
242
168
 
243
169
  * Pulls the chosen `variant` from the variant registry and renders it.
244
170
  * Connects to form state when used inside `<Form />` (by `name`).
@@ -299,9 +225,9 @@ Adapters define how the form submits.
299
225
 
300
226
  ### Built-in adapter keys
301
227
 
302
- * `local` no network; calls your callbacks.
303
- * `axios` HTTP submit via Axios.
304
- * `inertia` submit via Inertia.
228
+ * `local` – no network; calls your callbacks.
229
+ * `axios` – HTTP submit via Axios.
230
+ * `inertia` – submit via Inertia.
305
231
 
306
232
  ### Registering adapters
307
233
 
@@ -332,7 +258,7 @@ Some adapters expose additional props on `<Form />` (e.g. `url`, `method`, `conf
332
258
 
333
259
  ## Recommended boot order
334
260
 
335
- 1. Register variants (so InputField can resolve `variant` component).
261
+ 1. Register variants (so InputField can resolve `variant` → component).
336
262
  2. Register the adapters you will use.
337
263
  3. Render forms.
338
264
 
@@ -365,8 +291,10 @@ Below are the **variant-specific props** you can pass to `<InputField />` for:
365
291
  * `date`
366
292
  * `keyvalue`
367
293
  * `editor`
368
- * `json-editor`
369
294
  * `file`
295
+ * `icon`
296
+ * `image-icon`
297
+ * `json-editor`
370
298
  * `lister`
371
299
  * `custom`
372
300
 
@@ -380,22 +308,22 @@ Below are the **variant-specific props** you can pass to `<InputField />` for:
380
308
 
381
309
  | Prop | Description |
382
310
  | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
383
- | `trim?: boolean` | **boolean** If `true`, the value is trimmed **before validation** (visual input stays as typed). |
384
- | `minLength?: number` | **number** Minimum allowed length (after optional trimming). |
385
- | `maxLength?: number` | **number** Maximum allowed length (after optional trimming). |
386
- | `joinControls?: boolean` | **boolean** If `true` and there are controls, the input + controls share one box (border/radius/focus). |
387
- | `extendBoxToControls?: boolean` | **boolean** When `joinControls` is true, controls are either visually inside the same box (`true`) or separate (`false`). |
388
- | `inputClassName?: string` | **string** Extra classes for the **inner** `<input>` element (not the wrapper). |
389
- | `prefix?: string` | **string** Fixed prefix rendered as part of the visible input string (e.g. `₦`, `ID: `). |
390
- | `suffix?: string` | **string** Fixed suffix rendered as part of the visible input string (e.g. `%`, `kg`). |
391
- | `stripPrefix?: boolean` | **boolean** If `true` (default), the prefix is stripped from the emitted model value before calling `onValue` internally. |
392
- | `stripSuffix?: boolean` | **boolean** If `true` (default), the suffix is stripped from the emitted model value before calling `onValue` internally. |
393
- | `mask?: string` | **string** Mask pattern (PrimeReact style), e.g. `"99/99/9999"`, `"(999) 999-9999"`. |
394
- | `maskDefinitions?: Record<string, RegExp>` | **Record** Per-symbol slot definitions (kept for future custom engine; unused by current implementation). |
395
- | `slotChar?: string` | **string** Placeholder slot character (default `_`). |
396
- | `autoClear?: boolean` | **boolean** If `true`, empty masked values emit `""` instead of a fully-masked placeholder string. |
397
- | `unmask?: "raw" \| "masked" \| boolean` | **union** Controls whether the **model value** is raw vs masked. (`"raw"`/`true` emit unmasked; `"masked"`/`false`/`undefined` emit masked). |
398
- | `maskInsertMode?: "stream" \| "caret"` | **union** Reserved for future caret-mode logic (currently unused; kept for API compatibility). |
311
+ | `trim?: boolean` | **boolean** — If `true`, the value is trimmed **before validation** (visual input stays as typed). |
312
+ | `minLength?: number` | **number** — Minimum allowed length (after optional trimming). |
313
+ | `maxLength?: number` | **number** — Maximum allowed length (after optional trimming). |
314
+ | `joinControls?: boolean` | **boolean** — If `true` and there are controls, the input + controls share one box (border/radius/focus). |
315
+ | `extendBoxToControls?: boolean` | **boolean** — When `joinControls` is true, controls are either visually “inside” the same box (`true`) or separate (`false`). |
316
+ | `inputClassName?: string` | **string** — Extra classes for the **inner** `<input>` element (not the wrapper). |
317
+ | `prefix?: string` | **string** — Fixed prefix rendered as part of the visible input string (e.g. `₦`, `ID: `). |
318
+ | `suffix?: string` | **string** — Fixed suffix rendered as part of the visible input string (e.g. `%`, `kg`). |
319
+ | `stripPrefix?: boolean` | **boolean** — If `true` (default), the prefix is stripped from the emitted model value before calling `onValue` internally. |
320
+ | `stripSuffix?: boolean` | **boolean** — If `true` (default), the suffix is stripped from the emitted model value before calling `onValue` internally. |
321
+ | `mask?: string` | **string** — Mask pattern (PrimeReact style), e.g. `"99/99/9999"`, `"(999) 999-9999"`. |
322
+ | `maskDefinitions?: Record<string, RegExp>` | **Record** — Per-symbol slot definitions (kept for future custom engine; unused by current implementation). |
323
+ | `slotChar?: string` | **string** — Placeholder slot character (default `_`). |
324
+ | `autoClear?: boolean` | **boolean** — If `true`, “empty” masked values emit `""` instead of a fully-masked placeholder string. |
325
+ | `unmask?: "raw" \| "masked" \| boolean` | **union** — Controls whether the **model value** is raw vs masked. (`"raw"`/`true` ⇒ emit unmasked; `"masked"`/`false`/`undefined` ⇒ emit masked). |
326
+ | `maskInsertMode?: "stream" \| "caret"` | **union** — Reserved for future caret-mode logic (currently unused; kept for API compatibility). |
399
327
  | `...inputProps` | All other standard `React.InputHTMLAttributes<HTMLInputElement>` (except `value`, `defaultValue`, `onChange`, `size`) are forwarded. |
400
328
 
401
329
  ### Sample usage (InputField)
@@ -409,7 +337,7 @@ export function ExampleText() {
409
337
  variant="text"
410
338
  name="phone"
411
339
  label="Phone number"
412
- description="Well use this for account recovery."
340
+ description="We’ll use this for account recovery."
413
341
 
414
342
  // semantic validation flags (core layer)
415
343
  trim
@@ -471,17 +399,17 @@ export function ExampleTextarea() {
471
399
  | Prop | Description |
472
400
  | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
473
401
  | `options: (ToggleOption \| string \| number \| boolean)[]` | Options for the toggle group. You can pass full option objects or primitive shorthand (primitives are normalized to `{ value: String(x), label: String(x) }`). |
474
- | `multiple?: boolean` | **boolean** If `true`, enables multi-select (value becomes an array of strings internally). |
475
- | `variant?: "default" \| "outline"` | **union** Visual style passed to the underlying ToggleGroup. |
476
- | `layout?: "horizontal" \| "vertical" \| "grid"` | **union** Layout mode. |
477
- | `gridCols?: number` | **number** Column count when `layout="grid"` (defaults to `2` in the component). |
478
- | `fillWidth?: boolean` | **boolean** If `true`, makes the group/items stretch to fill available width (adds `w-full` and related item sizing). |
479
- | `optionValue?: string` | **string** When `options` are custom objects, the property name to read `value` from (fallback: `obj.value`). |
480
- | `optionLabel?: string` | **string** When `options` are custom objects, the property name to read `label` from (fallback: `obj.label` or `String(value)`). |
481
- | `optionIcon?: string` | **string** When `options` are custom objects, the property name to read `icon` from (fallback: `obj.icon`). |
482
- | `optionDisabled?: string` | **string** When `options` are custom objects, the property name to read disabled flag from (fallback: `obj.disabled`). |
483
- | `optionTooltip?: string` | **string** When `options` are custom objects, the property name to read tooltip content from (fallback: `obj.tooltip`). |
484
- | `optionMeta?: string` | **string** When `options` are custom objects, the property name to read meta from (fallback: `obj.meta`). |
402
+ | `multiple?: boolean` | **boolean** — If `true`, enables multi-select (value becomes an array of strings internally). |
403
+ | `variant?: "default" \| "outline"` | **union** — Visual style passed to the underlying ToggleGroup. |
404
+ | `layout?: "horizontal" \| "vertical" \| "grid"` | **union** — Layout mode. |
405
+ | `gridCols?: number` | **number** — Column count when `layout="grid"` (defaults to `2` in the component). |
406
+ | `fillWidth?: boolean` | **boolean** — If `true`, makes the group/items stretch to fill available width (adds `w-full` and related item sizing). |
407
+ | `optionValue?: string` | **string** — When `options` are custom objects, the property name to read `value` from (fallback: `obj.value`). |
408
+ | `optionLabel?: string` | **string** — When `options` are custom objects, the property name to read `label` from (fallback: `obj.label` or `String(value)`). |
409
+ | `optionIcon?: string` | **string** — When `options` are custom objects, the property name to read `icon` from (fallback: `obj.icon`). |
410
+ | `optionDisabled?: string` | **string** — When `options` are custom objects, the property name to read disabled flag from (fallback: `obj.disabled`). |
411
+ | `optionTooltip?: string` | **string** — When `options` are custom objects, the property name to read tooltip content from (fallback: `obj.tooltip`). |
412
+ | `optionMeta?: string` | **string** — When `options` are custom objects, the property name to read meta from (fallback: `obj.meta`). |
485
413
  | `renderOption?: (option, isSelected) => React.ReactNode` | Custom renderer per option (receives normalized option + selected state). |
486
414
  | `className?: string` | Class for the toggle group container. |
487
415
  | `itemClassName?: string` | Base class applied to **all** toggle items. |
@@ -532,13 +460,13 @@ export function ExampleToggleGroup() {
532
460
 
533
461
  | Prop | Description |
534
462
  | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
535
- | `showButtons` | When `true`, renders built-in step controls (±) alongside the number input. |
463
+ | `showButtons` | When `true`, renders built-in step controls (±) alongside the number input. |
536
464
  | `buttonLayout` | Layout for the step controls when `showButtons` is enabled. Supported layouts: `"stacked"` (vertical on the right) and `"inline"` (`-` left, `+` right). |
537
465
  | `step` | Step amount used by the built-in controls and stepping logic (forwarded to the underlying number input). |
538
466
  | `min` | Minimum numeric value constraint (used by the stepping logic and forwarded to the underlying number input). |
539
467
  | `max` | Maximum numeric value constraint (used by the stepping logic and forwarded to the underlying number input). |
540
468
 
541
- > Also accepts the rest of the underlying `InputNumberProps` (theyre forwarded to the number input).
469
+ > Also accepts the rest of the underlying `InputNumberProps` (they’re forwarded to the number input).
542
470
 
543
471
  **Sample**
544
472
 
@@ -614,7 +542,7 @@ export function ExampleToggleGroup() {
614
542
  | `dialCodeDelimiter` | Delimiter between dial code and the input number (e.g. `" "`, `"-"`). |
615
543
  | `valueMode` | Controls how the field value is emitted (e.g. E.164 vs local formats). |
616
544
  | `mask` | Optional input mask (string or resolver function). |
617
- | `lazy` | IMask lazy mode (placeholder chars hidden until typed). |
545
+ | `lazy` | IMask “lazy” mode (placeholder chars hidden until typed). |
618
546
  | `keepCharPositions` | IMask option to keep character positions stable. |
619
547
  | `unmask` | How the underlying mask value is emitted (IMask option). |
620
548
 
@@ -672,7 +600,7 @@ Value type: `number | undefined`
672
600
  | `leadingControlClassName` | Wrapper className for the leading control. |
673
601
  | `trailingControlClassName` | Wrapper className for the trailing control. |
674
602
  | `joinControls` | Join controls visually to the slider box. |
675
- | `extendBoxToControls` | Extend slider box background behind controls. |
603
+ | `extendBoxToControls` | Extend slider “box” background behind controls. |
676
604
  | `controlVariant` | Variant for the +/- controls (if shown). |
677
605
  | `controlStep` | Step used by +/- controls (falls back to `step`). |
678
606
  | `controlDecrementIcon` | Custom icon node for decrement control. |
@@ -790,7 +718,7 @@ Value type: `TreeKey | TreeKey[] | undefined` (where `TreeKey` is `string | numb
790
718
  | `joinControls` | Visually join controls to the trigger box (shared border). |
791
719
  | `extendBoxToControls` | Extend trigger background behind controls. |
792
720
  | `rootClassName` | Wrapper className around controls + trigger. |
793
- | `triggerInnerClassName` | ClassName for the triggers inner content. |
721
+ | `triggerInnerClassName` | ClassName for the trigger’s inner content. |
794
722
 
795
723
  ### Mode: button (`mode="button"`)
796
724
 
@@ -828,7 +756,7 @@ Value type: `TreeKey | TreeKey[] | undefined` (where `TreeKey` is `string | numb
828
756
  },
829
757
  ]}
830
758
  searchable
831
- placeholder="Pick one"
759
+ placeholder="Pick one…"
832
760
  />
833
761
  ```
834
762
 
@@ -865,9 +793,9 @@ Value type: `TreeKey | TreeKey[] | undefined` (where `TreeKey` is `string | numb
865
793
  | `searchable` | Enable search field in the list. |
866
794
  | `searchPlaceholder` | Placeholder for the search field. |
867
795
  | `emptySearchText` | Text when there are no matches for the current search. |
868
- | `showSelectAll` | Show a Select all row. |
869
- | `selectAllLabel` | Label for the Select all row. |
870
- | `selectAllPosition` | Where to render the Select all row. |
796
+ | `showSelectAll` | Show a “Select all” row. |
797
+ | `selectAllLabel` | Label for the “Select all” row. |
798
+ | `selectAllPosition` | Where to render the “Select all” row. |
871
799
  | `clearable` | Show a clear action when there is at least one selection. |
872
800
  | `placeholder` | Placeholder when nothing is selected. |
873
801
  | `renderOption` | Optional global renderer for an option row. (An option may also provide its own per-option `render`.) |
@@ -945,7 +873,7 @@ export function MultiSelectExample() {
945
873
  | ---------------------- | ------------------------------------------------------------------------------------------------------------------- |
946
874
  | `items` | Alias of `options` (list of items to render). |
947
875
  | `options` | Options to render. Supports `RadioItem` objects or custom items via mappers. |
948
- | `mappers` | Mapping functions for `TItem value/label/description/disabled/key/render`. Takes precedence over `option*` props. |
876
+ | `mappers` | Mapping functions for `TItem → value/label/description/disabled/key/render`. Takes precedence over `option*` props. |
949
877
  | `optionValue` | Shortcut mapping for **value** (used only if `mappers` is not provided). |
950
878
  | `optionLabel` | Shortcut mapping for **label** (used only if `mappers` is not provided). |
951
879
  | `renderOption` | Global option renderer (can be overridden per item via `item.render`). |
@@ -1016,7 +944,7 @@ export function RadioExample() {
1016
944
  | `searchPlaceholder` | Placeholder for the search field. |
1017
945
  | `emptySearchText` | Text shown when there are no matches for the current search. |
1018
946
  | `clearable` | Show a clear action (x) when a value is selected. |
1019
- | `emptyLabel` | Label to show when no value is selected (acts like none). |
947
+ | `emptyLabel` | Label to show when no value is selected (acts like “none”). |
1020
948
  | `placeholder` | Placeholder when no value is selected (and `emptyLabel` not shown). |
1021
949
  | `renderOption` | Optional global renderer for a list option. (An option may also provide its own per-option `render`.) |
1022
950
  | `renderValue` | Custom renderer for the trigger display (selected option). |
@@ -1086,13 +1014,13 @@ export function SelectExample() {
1086
1014
  | `options` | Option list for group mode. Accepts primitives or objects (normalized to `{ value, label, description?, disabled?, key? }`). | | |
1087
1015
  | `items` | Alias for `options` (alternate naming). | | |
1088
1016
  | `mappers` | Override normalization: `{ mapValue?, mapLabel?, mapDescription?, mapDisabled?, mapKey? }`. | | |
1089
- | `optionValue` | Map item option value (overrides `mappers.mapValue`). | | |
1090
- | `optionLabel` | Map item option label (overrides `mappers.mapLabel`). | | |
1091
- | `optionDescription` | Map item option description (overrides `mappers.mapDescription`). | | |
1092
- | `optionDisabled` | Map item disabled boolean (overrides `mappers.mapDisabled`). | | |
1093
- | `optionKey` | Map item stable React key (overrides `mappers.mapKey`). | | |
1017
+ | `optionValue` | Map item → option value (overrides `mappers.mapValue`). | | |
1018
+ | `optionLabel` | Map item → option label (overrides `mappers.mapLabel`). | | |
1019
+ | `optionDescription` | Map item → option description (overrides `mappers.mapDescription`). | | |
1020
+ | `optionDisabled` | Map item → disabled boolean (overrides `mappers.mapDisabled`). | | |
1021
+ | `optionKey` | Map item → stable React key (overrides `mappers.mapKey`). | | |
1094
1022
  | `renderOption` | Custom option renderer (gets `{ item, index, state, effectiveTristate, disabled, size, density, checkboxId, click(), checkbox }`). | | |
1095
- | `tristate` | Enable tri-state cycling for group options (`none true false none`). | | |
1023
+ | `tristate` | Enable tri-state cycling for group options (`none → true → false → none`). | | |
1096
1024
  | `layout` | Group layout: `"list"` or `"grid"`. | | |
1097
1025
  | `columns` | Grid columns when `layout="grid"` (default: `2`). | | |
1098
1026
  | `itemGapPx` | Gap between options in px (defaults vary by layout). | | |
@@ -1156,7 +1084,7 @@ export function SelectExample() {
1156
1084
  | `addOnTab` | Commit chips on **Tab**. Default: `true`. | |
1157
1085
  | `addOnBlur` | Commit chips on **blur**. Default: `true`. | |
1158
1086
  | `allowDuplicates` | When `false`, duplicate chips are ignored. Default: `false`. | |
1159
- | `maxChips` | Maximum number of chips allowed (`undefined` unlimited). | |
1087
+ | `maxChips` | Maximum number of chips allowed (`undefined` → unlimited). | |
1160
1088
  | `backspaceRemovesLast` | Remove last chip on Backspace when input is empty. Default: `true`. | |
1161
1089
  | `clearable` | Show a clear-all button. Default: `false`. | |
1162
1090
  | `onAddChips` | Callback: `(added, next) => void` after chips are added. | |
@@ -1184,7 +1112,7 @@ export function SelectExample() {
1184
1112
  name="tags"
1185
1113
  label="Tags"
1186
1114
  variant="chips"
1187
- placeholder="Add tags"
1115
+ placeholder="Add tags…"
1188
1116
  separators={[",", ";"]}
1189
1117
  maxChips={10}
1190
1118
  clearable
@@ -1240,14 +1168,14 @@ import { Palette } from "lucide-react";
1240
1168
  | Prop | Description | |
1241
1169
  | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
1242
1170
  | `mode` | Selection mode: `"single"` or `"range"`. | |
1243
- | `placeholder` | Placeholder content shown when theres no selection. | |
1171
+ | `placeholder` | Placeholder content shown when there’s no selection. | |
1244
1172
  | `clearable` | If `true`, shows a clear action when a value is set. | |
1245
1173
  | `minDate` | Minimum selectable date (inclusive). | |
1246
1174
  | `maxDate` | Maximum selectable date (inclusive). | |
1247
1175
  | `disabledDays` | Disabled-day matcher forwarded to the calendar wrapper (`Calendar["disabled"]`). | |
1248
1176
  | `formatSingle` | Display pattern for single values. Supports tokens: `yyyy`, `MM`, `dd`, `HH`, `mm`. Defaults depend on `kind`. | |
1249
1177
  | `formatRange` | Range display formatter: either a pattern string (same tokens as `formatSingle`) or a custom `(range) => string` formatter. | |
1250
- | `rangeSeparator` | Separator used between `from` and `to` when `formatRange` is a string pattern. Default: `" "`. | |
1178
+ | `rangeSeparator` | Separator used between `from` and `to` when `formatRange` is a string pattern. Default: `" – "`. | |
1251
1179
  | `stayOpenOnSelect` | If `true`, keeps the popover open after selecting. In range mode, stays open until both ends are chosen. | |
1252
1180
  | `open` | Controlled open state for the popover. | |
1253
1181
  | `onOpenChange` | Called when the popover open state changes. | |
@@ -1269,7 +1197,7 @@ export function DateRangeExample() {
1269
1197
  description="Select a date range."
1270
1198
  mode="range"
1271
1199
  kind="date"
1272
- placeholder="YYYY-MM-DD YYYY-MM-DD"
1200
+ placeholder="YYYY-MM-DD – YYYY-MM-DD"
1273
1201
  clearable
1274
1202
  minDate={new Date(2025, 0, 1)}
1275
1203
  maxDate={new Date(2025, 11, 31)}
@@ -1290,16 +1218,16 @@ export function DateRangeExample() {
1290
1218
  | ---------------- | ---------------------------------------------------------------------------------------------------------------- |
1291
1219
  | `min` | Minimum number of pairs allowed (enforced by the UI controls). |
1292
1220
  | `max` | Maximum number of pairs allowed. |
1293
- | `minVisible` | Minimum number of chips to show before collapsing into a more indicator. |
1294
- | `maxVisible` | Maximum number of chips to show before collapsing into a more indicator. |
1295
- | `showAddButton` | Toggle visibility of the Add action. |
1221
+ | `minVisible` | Minimum number of chips to show before collapsing into a “more” indicator. |
1222
+ | `maxVisible` | Maximum number of chips to show before collapsing into a “more” indicator. |
1223
+ | `showAddButton` | Toggle visibility of the “Add” action. |
1296
1224
  | `showMenuButton` | Toggle visibility of the overflow/menu action (if supported by the preset). |
1297
1225
  | `placeholder` | Placeholder shown when there are no items. |
1298
1226
  | `dialogTitle` | Title for the edit/add dialog UI. |
1299
- | `keyLabel` | Label used for the key input. |
1300
- | `valueLabel` | Label used for the value input. |
1227
+ | `keyLabel` | Label used for the “key” input. |
1228
+ | `valueLabel` | Label used for the “value” input. |
1301
1229
  | `submitLabel` | Text for the dialog submit button. |
1302
- | `moreLabel` | Label renderer for the collapsed more indicator: `(count) => ReactNode`. |
1230
+ | `moreLabel` | Label renderer for the collapsed “more” indicator: `(count) => ReactNode`. |
1303
1231
  | `emptyLabel` | Label shown when there are no entries (fallback text). |
1304
1232
  | `className` | Wrapper class for the whole variant. |
1305
1233
  | `chipsClassName` | Class for the chips container. |
@@ -1394,13 +1322,13 @@ export function EditorExample() {
1394
1322
  | `dropIcon` | Optional icon shown in the drop area. |
1395
1323
  | `dropTitle` | Title text shown in the drop area. |
1396
1324
  | `dropDescription` | Helper text shown in the drop area. |
1397
- | `custom` | Use a fully custom picker UI instead of the built-in drop/trigger. |
1325
+ | `custom` | Use a fully custom “picker” UI instead of the built-in drop/trigger. |
1398
1326
  | `asRaw` | Treat values as raw `File` objects (native picker flow). |
1399
1327
  | `renderDropArea` | Custom renderer for the drop area section. |
1400
1328
  | `renderFileItem` | Custom renderer for each file item row. |
1401
1329
  | `showCheckboxes` | Show checkboxes next to file items (when supported by the UI). |
1402
1330
  | `onFilesAdded` | Callback fired when files are added. |
1403
- | `customLoader` | Provide your own file loader (e.g. resolve URLs metadata). |
1331
+ | `customLoader` | Provide your own file loader (e.g. resolve URLs → metadata). |
1404
1332
  | `mergeMode` | Merge strategy when adding files (e.g. append/replace/dedupe). |
1405
1333
  | `formatFileName` | Custom formatter for displaying a file name. |
1406
1334
  | `formatFileSize` | Custom formatter for displaying a file size. |
@@ -1425,7 +1353,7 @@ export function EditorExample() {
1425
1353
  | `trailingControl` | Custom node on the far-right *outside* the trigger. |
1426
1354
  | `leadingControlClassName` | ClassName for the leading control wrapper. |
1427
1355
  | `trailingControlClassName` | ClassName for the trailing control wrapper. |
1428
- | `joinControls` | Visually joins leading/trailing controls with the trigger. |
1356
+ | `joinControls` | Visually “joins” leading/trailing controls with the trigger. |
1429
1357
  | `extendBoxToControls` | Extends the input box styling around joined controls. |
1430
1358
  | `button` | When `mode="button"`: explicit trigger node. |
1431
1359
  | `children` | When `mode="button"` and `button` is not provided: trigger content. |
@@ -1459,6 +1387,141 @@ export function FileExample() {
1459
1387
 
1460
1388
  ---
1461
1389
 
1390
+ ## icon
1391
+
1392
+ ### Variant props
1393
+
1394
+ | Prop | Description |
1395
+ | ------------------ | --------------------------------------------------------------------------- |
1396
+ | `multiple` | Allow selecting multiple icons (value becomes `string[]`). |
1397
+ | `url` | Iconify API base URL (defaults to registry `iconPicker.url`). |
1398
+ | `groups` | Icon groups to display (defaults to registry `iconPicker.groups`). |
1399
+ | `allowedGroupIds` | Restrict selectable groups by group id. |
1400
+ | `maxRender` | Max icons rendered in the grid (safety cap for large sets). |
1401
+ | `placeholder` | Placeholder text when nothing is selected. |
1402
+ | `className` | Wrapper class for the whole variant. |
1403
+ | `triggerClassName` | ClassName for the trigger (default mode). |
1404
+ | `popoverClassName` | ClassName for the popover content wrapper. |
1405
+
1406
+ ### Mode and trigger props
1407
+
1408
+ | Prop | Description |
1409
+ | ----------------------------- | ----------------------------------------------------------------------- |
1410
+ | `mode` | Trigger style: `"default"` (input-like) or `"button"` (custom trigger). |
1411
+ | `leadingIcons` | Icons shown before the selection (default mode). |
1412
+ | `trailingIcons` | Icons shown after the selection. |
1413
+ | `icon` | Single icon shorthand (falls into leading icons). |
1414
+ | `leadingControl` | Custom node on the far-left *outside* the trigger. |
1415
+ | `trailingControl` | Custom node on the far-right *outside* the trigger. |
1416
+ | `leadingControlClassName` | ClassName for the leading control wrapper. |
1417
+ | `trailingControlClassName` | ClassName for the trailing control wrapper. |
1418
+ | `joinControls` | Visually "joins" leading/trailing controls with the trigger. |
1419
+ | `extendBoxToControls` | Extends the input box styling around joined controls. |
1420
+ | `button` | When `mode="button"`: explicit trigger node. |
1421
+ | `children` | When `mode="button"` and `button` is not provided: trigger content. |
1422
+ | `selectedBadge` | Selected-count badge (button mode). |
1423
+ | `selectedBadgeHiddenWhenZero` | Hide badge when selected count is 0. |
1424
+ | `selectedBadgeVariant` | Badge style variant (button mode). |
1425
+ | `selectedBadgeClassName` | ClassName for the selected-count badge. |
1426
+ | `selectedBadgePlacement` | Where to place the badge relative to trigger content. |
1427
+
1428
+ > Note: In `mode="button"`, the icon/control props (`leadingIcons`, `trailingIcons`, `leadingControl`, etc.) are not supported.
1429
+ >
1430
+ > Value is an Iconify name string (e.g. `"mdi:home"`) or `string[]` when `multiple` is true.
1431
+
1432
+ ### Sample usage
1433
+
1434
+ ```tsx
1435
+ import { InputField } from "@timeax/form-palette";
1436
+
1437
+ export function IconExample() {
1438
+ return (
1439
+ <InputField
1440
+ variant="icon"
1441
+ name="app_icon"
1442
+ label="App icon"
1443
+ placeholder="Search icons..."
1444
+ />
1445
+ );
1446
+ }
1447
+ ```
1448
+
1449
+ ---
1450
+
1451
+ ## image-icon
1452
+
1453
+ ### Variant props
1454
+
1455
+ | Prop | Description |
1456
+ | --------------------- | ------------------------------------------------------------------------------------------------- |
1457
+ | `multiple` | Allow selecting multiple items (icons and/or images). |
1458
+ | `iconUrl` | Iconify API base URL for the icon picker (defaults to registry `iconPicker.url`). |
1459
+ | `iconGroups` | Icon groups to display (defaults to registry `iconPicker.groups`). |
1460
+ | `allowedIconGroupIds` | Restrict selectable icon groups by id. |
1461
+ | `iconMaxRender` | Max icons rendered in the grid (safety cap for large sets). |
1462
+ | `accept` | Accepted file types (input accept string / list). |
1463
+ | `maxFiles` | Max number of files allowed. |
1464
+ | `maxTotalSize` | Max total size allowed for all files (bytes). |
1465
+ | `customLoader` | Provide your own file loader (e.g. resolve URLs -> metadata). |
1466
+ | `mergeMode` | Merge strategy when adding files (`"append"` or `"replace"`). |
1467
+ | `formatFileName` | Custom formatter for displaying a file name. |
1468
+ | `formatFileSize` | Custom formatter for displaying a file size. |
1469
+ | `formatFileValue` | Convert a `FileItem` into a persisted string value (falls back to `url`, `path`, or native file). |
1470
+ | `placeholder` | Placeholder text when nothing is selected. |
1471
+ | `className` | Wrapper class for the whole variant. |
1472
+ | `triggerClassName` | ClassName for the trigger (default mode). |
1473
+ | `popoverClassName` | ClassName for the popover content wrapper. |
1474
+ | `showCheckboxes` | Show checkboxes next to items in the list (when supported by the UI). |
1475
+
1476
+ ### Mode and trigger props
1477
+
1478
+ | Prop | Description |
1479
+ | ----------------------------- | ----------------------------------------------------------------------- |
1480
+ | `mode` | Trigger style: `"default"` (input-like) or `"button"` (custom trigger). |
1481
+ | `leadingIcons` | Icons shown before the summary (default mode). |
1482
+ | `trailingIcons` | Icons shown after the summary / clear action. |
1483
+ | `icon` | Single icon shorthand (falls into leading icons). |
1484
+ | `leadingControl` | Custom node on the far-left *outside* the trigger. |
1485
+ | `trailingControl` | Custom node on the far-right *outside* the trigger. |
1486
+ | `leadingControlClassName` | ClassName for the leading control wrapper. |
1487
+ | `trailingControlClassName` | ClassName for the trailing control wrapper. |
1488
+ | `joinControls` | Visually "joins" leading/trailing controls with the trigger. |
1489
+ | `extendBoxToControls` | Extends the input box styling around joined controls. |
1490
+ | `button` | When `mode="button"`: explicit trigger node. |
1491
+ | `children` | When `mode="button"` and `button` is not provided: trigger content. |
1492
+ | `selectedBadge` | Selected-count badge (button mode). |
1493
+ | `selectedBadgeHiddenWhenZero` | Hide badge when selected count is 0. |
1494
+ | `selectedBadgeVariant` | Badge style variant (button mode). |
1495
+ | `selectedBadgeClassName` | ClassName for the selected-count badge. |
1496
+ | `selectedBadgePlacement` | Where to place the badge relative to trigger content. |
1497
+
1498
+ > Note: In `mode="button"`, the icon/control props (`leadingIcons`, `trailingIcons`, `leadingControl`, etc.) are not supported.
1499
+ >
1500
+ > Value accepts `string` or `File` (or arrays). Strings can be Iconify names (e.g. `"lucide:camera"`) or image/file URLs/paths.
1501
+
1502
+ ### Sample usage
1503
+
1504
+ ```tsx
1505
+ import { InputField } from "@timeax/form-palette";
1506
+
1507
+ export function ImageIconExample() {
1508
+ return (
1509
+ <InputField
1510
+ variant="image-icon"
1511
+ name="avatar"
1512
+ label="Avatar"
1513
+ placeholder="Pick an image or icon..."
1514
+ accept={["image/*", ".svg"]}
1515
+ iconGroups={[
1516
+ { id: "brand", label: "Brand", prefixes: ["simple-icons"] },
1517
+ ]}
1518
+ />
1519
+ );
1520
+ }
1521
+ ```
1522
+
1523
+ ---
1524
+
1462
1525
  ## json-editor
1463
1526
 
1464
1527
  ### Wrapper / trigger props
@@ -1486,13 +1549,13 @@ export function FileExample() {
1486
1549
  | Prop | Description |
1487
1550
  | ------------------ | ----------------------------------------------------------------------------------- |
1488
1551
  | `title` | Title displayed in the editor header. |
1489
- | `fieldMap` | Field mapping rules (wildcards supported) picks a field variant + props per path. |
1552
+ | `fieldMap` | Field mapping rules (wildcards supported) → picks a field variant + props per path. |
1490
1553
  | `layout` | Layout rules (grid/rows + route/page rules). |
1491
1554
  | `defaults` | Default values / behaviours for missing keys and created fields. |
1492
1555
  | `filters` | Include/exclude filters for routes/fields. |
1493
1556
  | `permissions` | Permissions (add/delete/view/edit raw, etc.). |
1494
1557
  | `callbacks` | Hooks for events like add/delete/edit / route changes. |
1495
- | `route` | Controlled page route (e.g. `"config.headers"`). |
1558
+ | `route` | Controlled “page route” (e.g. `"config.headers"`). |
1496
1559
  | `defaultRoute` | Starting route when uncontrolled. |
1497
1560
  | `onRouteChange` | Route change callback. |
1498
1561
  | `viewMode` | Controlled view mode (e.g. raw vs structured UI). |
@@ -1552,13 +1615,13 @@ export function JsonEditorExample() {
1552
1615
  | `method` | Inline HTTP method: `"GET"` or `"POST"`. |
1553
1616
  | `buildRequest` | Custom request builder (params/body/headers). |
1554
1617
  | `selector` | How to extract the array from the response (function or selector path). |
1555
- | `optionValue` | How to map a raw row option value (key or function). |
1556
- | `optionLabel` | How to map a raw row label. |
1557
- | `optionIcon` | How to map a raw row icon. |
1558
- | `optionDescription` | How to map a raw row description. |
1559
- | `optionDisabled` | How to map a raw row disabled. |
1560
- | `optionGroup` | How to map a raw row group label. |
1561
- | `optionMeta` | How to map a raw row meta payload. |
1618
+ | `optionValue` | How to map a raw row → option value (key or function). |
1619
+ | `optionLabel` | How to map a raw row → label. |
1620
+ | `optionIcon` | How to map a raw row → icon. |
1621
+ | `optionDescription` | How to map a raw row → description. |
1622
+ | `optionDisabled` | How to map a raw row → disabled. |
1623
+ | `optionGroup` | How to map a raw row → group label. |
1624
+ | `optionMeta` | How to map a raw row → meta payload. |
1562
1625
  | `search` | Search override (inline). |
1563
1626
  | `searchTarget` | Search target override (inline). |
1564
1627
 
@@ -1570,7 +1633,7 @@ export function JsonEditorExample() {
1570
1633
  | `confirm` | Optional confirm behaviour (e.g. confirm selection). |
1571
1634
  | `permissions` | Permissions object used by the lister UI (actions, views). |
1572
1635
  | `placeholder` | Placeholder text when nothing is selected. |
1573
- | `maxDisplayItems` | Max chips/labels to show before collapsing into “+N”. |
1636
+ | `maxDisplayItems` | Max chips/labels to show before collapsing into “+N”. |
1574
1637
  | `renderTrigger` | Custom trigger renderer. |
1575
1638
  | `title` | Title displayed when opening the lister UI. |
1576
1639
  | `searchMode` | Search mode for the open UI. |
@@ -1599,7 +1662,7 @@ export function JsonEditorExample() {
1599
1662
  | `trailingControl` | Custom node on the far-right *outside* the trigger. |
1600
1663
  | `leadingControlClassName` | ClassName for the leading control wrapper. |
1601
1664
  | `trailingControlClassName` | ClassName for the trailing control wrapper. |
1602
- | `joinControls` | Visually joins leading/trailing controls with the trigger. |
1665
+ | `joinControls` | Visually “joins” leading/trailing controls with the trigger. |
1603
1666
  | `extendBoxToControls` | Extends the input box styling around joined controls. |
1604
1667
  | `maxListHeight` | Max height for the open list/panel (px). |
1605
1668
  | `className` | Wrapper class for the whole variant. |
@@ -1706,12 +1769,12 @@ export function CustomExample() {
1706
1769
 
1707
1770
  ---
1708
1771
 
1709
- # Form Palette `extra` entrypoint (v2)
1772
+ # Form Palette — `extra` entrypoint (v2)
1710
1773
 
1711
- The `extra` entrypoint exposes two power tools that sit beside the normal **Form / InputField** flow:
1774
+ The `extra` entrypoint exposes two “power tools” that sit beside the normal **Form / InputField** flow:
1712
1775
 
1713
- 1. **Lister runtime** (provider + global UI + hooks) a reusable, app-wide **picker** system for single/multi selection with search/filter + **remote / local / hybrid** data.
1714
- 2. **JsonEditor** an interactive JSON editor UI (also used by the `json-editor` InputField variant).
1776
+ 1. **Lister runtime** (provider + global UI + hooks) — a reusable, app-wide **picker** system for single/multi selection with search/filter + **remote / local / hybrid** data.
1777
+ 2. **JsonEditor** — an interactive JSON editor UI (also used by the `json-editor` InputField variant).
1715
1778
 
1716
1779
  > This README is written against the `extra.ts` export surface:
1717
1780
  >
@@ -1728,30 +1791,30 @@ The `extra` entrypoint exposes two “power tools” that sit beside the normal
1728
1791
 
1729
1792
  Lister is a small runtime that lets you open a **picker UI** from anywhere in your app:
1730
1793
 
1731
- * **Single** selection (choose one user) or **multi** selection (choose many tags).
1794
+ * **Single** selection (“choose one user”) or **multi** selection (“choose many tags”).
1732
1795
  * **Local**, **remote**, or **hybrid** search.
1733
- * A consistent session model: **open search/filter select apply/cancel**.
1796
+ * A consistent session model: **open → search/filter → select → apply/cancel**.
1734
1797
  * App-level integration via a provider and a single UI renderer.
1735
1798
 
1736
- If you use the `lister` InputField variant, its powered by this same runtime.
1799
+ If you use the `lister` InputField variant, it’s powered by this same runtime.
1737
1800
 
1738
1801
  ---
1739
1802
 
1740
1803
  ## Building blocks (what you actually mount/call)
1741
1804
 
1742
- ### `ListerProvider`
1805
+ ### ✅ `ListerProvider`
1743
1806
 
1744
1807
  * Holds the Lister store/context.
1745
1808
  * Receives the **host** (permission checks + logging).
1746
1809
  * Can register a **presets map** (reusable picker definitions).
1747
1810
  * Supports provider-side remote debounce via `remoteDebounceMs` (default **300ms**).
1748
1811
 
1749
- ### `ListerUI`
1812
+ ### ✅ `ListerUI`
1750
1813
 
1751
1814
  * Renders any **open sessions** (popovers) from the provider store.
1752
1815
  * Mount this **once** under the provider.
1753
1816
 
1754
- ### `useLister()`
1817
+ ### ✅ `useLister()`
1755
1818
 
1756
1819
  * Imperative controller + access to store.
1757
1820
 
@@ -1763,7 +1826,7 @@ Provides:
1763
1826
  * search actions (setQuery/searchLocal/searchRemote)
1764
1827
  * filter helpers
1765
1828
 
1766
- ### `useData()`
1829
+ ### ✅ `useData()`
1767
1830
 
1768
1831
  * Lower-level hook used for **fetching + searching + filters + selection state**.
1769
1832
  * Exported so you can build custom list UIs that still behave like Lister.
@@ -1772,7 +1835,7 @@ Provides:
1772
1835
 
1773
1836
  ## Quick start (recommended)
1774
1837
 
1775
- ### Step 1 Mount provider + UI once
1838
+ ### Step 1 — Mount provider + UI once
1776
1839
 
1777
1840
  ```tsx
1778
1841
  import * as React from "react";
@@ -1793,7 +1856,7 @@ export function AppShell({ children }: { children: React.ReactNode }) {
1793
1856
  }
1794
1857
  ```
1795
1858
 
1796
- ### Step 2 Open a picker imperatively
1859
+ ### Step 2 — Open a picker imperatively
1797
1860
 
1798
1861
  ```tsx
1799
1862
  import * as React from "react";
@@ -1848,7 +1911,7 @@ export interface ListerProviderHost {
1848
1911
 
1849
1912
  ---
1850
1913
 
1851
- # 2) `useData()` deep dive (extremely important)
1914
+ # 2) `useData()` — deep dive (extremely important)
1852
1915
 
1853
1916
  `useData()` is the engine behind Lister-style **data fetching + searching + filtering + selection**.
1854
1917
 
@@ -1856,9 +1919,9 @@ Use it when:
1856
1919
 
1857
1920
  * You want a **custom picker UI** (your own layout, rows, pagination).
1858
1921
  * You want a **data-backed selection** UX but not the standard Lister popover.
1859
- * You want Listers semantics (remote/local/hybrid search + filters) in other UIs.
1922
+ * You want Lister’s semantics (remote/local/hybrid search + filters) in other UIs.
1860
1923
 
1861
- > It works only under `<ListerProvider />` because it uses the providers fetch engine.
1924
+ > It works only under `<ListerProvider />` because it uses the provider’s fetch engine.
1862
1925
 
1863
1926
  ---
1864
1927
 
@@ -1911,26 +1974,26 @@ It also returns **selection state** (optional) and **fetch/search/filter helpers
1911
1974
 
1912
1975
  ## Search modes: remote vs local vs hybrid
1913
1976
 
1914
- ### `remote` (default)
1977
+ ### ✅ `remote` (default)
1915
1978
 
1916
1979
  * Query changes trigger a **debounced fetch**.
1917
1980
  * The server is responsible for searching.
1918
1981
 
1919
1982
  Best for: **large datasets**, server ranking, true search endpoints.
1920
1983
 
1921
- ### `local`
1984
+ ### ✅ `local`
1922
1985
 
1923
1986
  * Switching to local fetches a **base list once** using an empty query.
1924
1987
  * After that, `visible` is filtered client-side.
1925
1988
 
1926
1989
  Best for: **small-medium datasets** you can cache (countries, categories, roles).
1927
1990
 
1928
- ### `hybrid`
1991
+ ### ✅ `hybrid`
1929
1992
 
1930
1993
  * Query changes still fetch remotely.
1931
1994
  * But `visible` also applies the local filtering rules.
1932
1995
 
1933
- Best for: server list + extra client constraints (e.g. `searchOnly`).
1996
+ Best for: “server list + extra client constraints” (e.g. `searchOnly`).
1934
1997
 
1935
1998
  ---
1936
1999
 
@@ -1938,15 +2001,15 @@ Best for: “server list + extra client constraints” (e.g. `searchOnly`).
1938
2001
 
1939
2002
  `useData()` supports Lister-style targeting via `searchTarget`:
1940
2003
 
1941
- * `mode: "all"` search across everything
1942
- * `mode: "subject"` search only against one subject field (e.g. `name`)
1943
- * `mode: "only"` constrain results to a known list of IDs
2004
+ * `mode: "all"` → search across everything
2005
+ * `mode: "subject"` → search only against one subject field (e.g. `name`)
2006
+ * `mode: "only"` → constrain results to a known list of IDs
1944
2007
 
1945
2008
  If you pass `search={{ default: "name" }}`, the default target becomes `mode:"subject"` on that key.
1946
2009
 
1947
2010
  ---
1948
2011
 
1949
- ## Core returned API (what youll use most)
2012
+ ## Core returned API (what you’ll use most)
1950
2013
 
1951
2014
  ### Data + status
1952
2015
 
@@ -1967,8 +2030,8 @@ If you pass `search={{ default: "name" }}`, the default target becomes `mode:"su
1967
2030
 
1968
2031
  ### Fetch
1969
2032
 
1970
- * `refresh()` refetch using current query/filters/target
1971
- * `fetch({ query?, filters?, searchTarget?, search? })` manual override fetch
2033
+ * `refresh()` — refetch using current query/filters/target
2034
+ * `fetch({ query?, filters?, searchTarget?, search? })` — manual override fetch
1972
2035
 
1973
2036
  ### Selection (when enabled)
1974
2037
 
@@ -1977,15 +2040,15 @@ If you pass `search={{ default: "name" }}`, the default target becomes `mode:"su
1977
2040
  * `selected` (array of objects resolved from cache)
1978
2041
  * `select(id)`, `deselect(id)`, `toggle(id)`, `clearSelection()`
1979
2042
  * `isSelected(id)`
1980
- * `getSelection()` returns the best current selection shape
2043
+ * `getSelection()` — returns the best current selection shape
1981
2044
 
1982
2045
  > Important: selection maintains an internal cache so selected objects can be returned even when the current page/list no longer contains them.
1983
2046
 
1984
2047
  ---
1985
2048
 
1986
- ## `useData()` practical use cases (full examples)
2049
+ ## `useData()` — practical use cases (full examples)
1987
2050
 
1988
- ### Use case A Remote search list (simple)
2051
+ ### Use case A — Remote search list (simple)
1989
2052
 
1990
2053
  ```tsx
1991
2054
  import * as React from "react";
@@ -2006,13 +2069,13 @@ export function RemoteUserSearch() {
2006
2069
  <input
2007
2070
  value={query}
2008
2071
  onChange={(e) => setQuery(e.target.value)}
2009
- placeholder="Search users"
2072
+ placeholder="Search users…"
2010
2073
  />
2011
2074
  <button onClick={refresh} disabled={loading}>
2012
2075
  Refresh
2013
2076
  </button>
2014
2077
 
2015
- {loading && <p>Loading…</p>}
2078
+ {loading && <p>Loading…</p>}
2016
2079
  {error && <p style={{ color: "crimson" }}>{String(error)}</p>}
2017
2080
 
2018
2081
  <ul>
@@ -2029,7 +2092,7 @@ export function RemoteUserSearch() {
2029
2092
 
2030
2093
  ---
2031
2094
 
2032
- ### Use case B Local mode (fetch once, instant client filtering)
2095
+ ### Use case B — Local mode (fetch once, instant client filtering)
2033
2096
 
2034
2097
  ```tsx
2035
2098
  import * as React from "react";
@@ -2051,7 +2114,7 @@ export function CountryPickerLocal() {
2051
2114
  <input
2052
2115
  value={query}
2053
2116
  onChange={(e) => setQuery(e.target.value)}
2054
- placeholder="Search countries"
2117
+ placeholder="Search countries…"
2055
2118
  />
2056
2119
  <ul>
2057
2120
  {visible.map((c) => (
@@ -2065,7 +2128,7 @@ export function CountryPickerLocal() {
2065
2128
 
2066
2129
  ---
2067
2130
 
2068
- ### Use case C Filters with `patchFilters` (remote/hybrid auto-fetch)
2131
+ ### Use case C — Filters with `patchFilters` (remote/hybrid auto-fetch)
2069
2132
 
2070
2133
  ```tsx
2071
2134
  import * as React from "react";
@@ -2120,7 +2183,7 @@ export function FilteredUsers() {
2120
2183
 
2121
2184
  ---
2122
2185
 
2123
- ### Use case D Constrain to a known allow-list (`searchTarget: mode="only"`)
2186
+ ### Use case D — Constrain to a known allow-list (`searchTarget: mode="only"`)
2124
2187
 
2125
2188
  ```tsx
2126
2189
  import * as React from "react";
@@ -2158,7 +2221,7 @@ export function AllowedIdsOnly() {
2158
2221
 
2159
2222
  ---
2160
2223
 
2161
- ### Use case E Custom multi-select UI (selection enabled)
2224
+ ### Use case E — Custom multi-select UI (selection enabled)
2162
2225
 
2163
2226
  ```tsx
2164
2227
  import * as React from "react";
@@ -2208,7 +2271,7 @@ selectedIds: {JSON.stringify(selectedIds, null, 2)}
2208
2271
 
2209
2272
  ---
2210
2273
 
2211
- ### Use case F Advanced request shaping (`buildRequest`)
2274
+ ### Use case F — Advanced request shaping (`buildRequest`)
2212
2275
 
2213
2276
  ```tsx
2214
2277
  import { useData } from "@timeax/form-palette/extra";
@@ -2239,10 +2302,10 @@ export function CustomPayloadExample() {
2239
2302
 
2240
2303
  ## Practical tips
2241
2304
 
2242
- * Want instant search UX and your dataset is small `searchMode: "local"`.
2243
- * Want selection to persist while users search remotely `selection.prune = "never"`.
2244
- * Want selection to strictly match whats visible in the current list `selection.prune = "missing"`.
2245
- * Want lazy fetch (open a modal first) `enabled: false`, then call `fetch()` when needed.
2305
+ * Want instant search UX and your dataset is small → `searchMode: "local"`.
2306
+ * Want selection to persist while users search remotely → `selection.prune = "never"`.
2307
+ * Want selection to strictly match what’s visible in the current list → `selection.prune = "missing"`.
2308
+ * Want lazy fetch (open a modal first) → `enabled: false`, then call `fetch()` when needed.
2246
2309
 
2247
2310
  ---
2248
2311
 
@@ -2278,3 +2341,5 @@ export function JsonEditorStandalone() {
2278
2341
  );
2279
2342
  }
2280
2343
  ```
2344
+
2345
+