@santi020k/lumen-react 3.0.1 → 4.0.0
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 +666 -13
- package/dist/ai-surfaces.d.ts +49 -0
- package/dist/ai-surfaces.d.ts.map +1 -0
- package/dist/ai-surfaces.js +88 -0
- package/dist/amount-field.d.ts +11 -0
- package/dist/amount-field.d.ts.map +1 -0
- package/dist/amount-field.js +37 -0
- package/dist/attachments.d.ts +17 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +23 -0
- package/dist/bullet-chart.d.ts +14 -0
- package/dist/bullet-chart.d.ts.map +1 -0
- package/dist/bullet-chart.js +22 -0
- package/dist/change-summary.d.ts +14 -0
- package/dist/change-summary.d.ts.map +1 -0
- package/dist/change-summary.js +4 -0
- package/dist/chart-inspection.d.ts +10 -0
- package/dist/chart-inspection.d.ts.map +1 -0
- package/dist/chart-inspection.js +11 -0
- package/dist/chart-interaction.d.ts +17 -0
- package/dist/chart-interaction.d.ts.map +1 -0
- package/dist/chart-interaction.js +50 -0
- package/dist/chart-label.d.ts +3 -0
- package/dist/chart-label.d.ts.map +1 -0
- package/dist/chart-label.js +1 -0
- package/dist/chart-recipes.d.ts +8 -0
- package/dist/chart-recipes.d.ts.map +1 -1
- package/dist/chart-recipes.js +35 -0
- package/dist/combobox.d.ts +9 -0
- package/dist/combobox.d.ts.map +1 -0
- package/dist/combobox.js +137 -0
- package/dist/comparison-chart.d.ts +13 -0
- package/dist/comparison-chart.d.ts.map +1 -0
- package/dist/comparison-chart.js +18 -0
- package/dist/components.d.ts +106 -70
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +4 -1949
- package/dist/dashboard.d.ts +20 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +19 -0
- package/dist/data-table-range-model.d.ts +8 -0
- package/dist/data-table-range-model.d.ts.map +1 -0
- package/dist/data-table-range-model.js +31 -0
- package/dist/data-table-range.d.ts +17 -0
- package/dist/data-table-range.d.ts.map +1 -0
- package/dist/data-table-range.js +8 -0
- package/dist/data-table-saved-views.d.ts +30 -0
- package/dist/data-table-saved-views.d.ts.map +1 -0
- package/dist/data-table-saved-views.js +49 -0
- package/dist/data-table-selection-model.d.ts +23 -0
- package/dist/data-table-selection-model.d.ts.map +1 -0
- package/dist/data-table-selection-model.js +36 -0
- package/dist/data-table-selection.d.ts +11 -0
- package/dist/data-table-selection.d.ts.map +1 -0
- package/dist/data-table-selection.js +10 -0
- package/dist/data-table-state.d.ts +6 -0
- package/dist/data-table-state.d.ts.map +1 -0
- package/dist/data-table-state.js +38 -0
- package/dist/data-table-view.d.ts +88 -0
- package/dist/data-table-view.d.ts.map +1 -0
- package/dist/data-table-view.js +1 -0
- package/dist/data-table.d.ts +60 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +1 -0
- package/dist/date-range-calendar.d.ts +29 -0
- package/dist/date-range-calendar.d.ts.map +1 -0
- package/dist/date-range-calendar.js +69 -0
- package/dist/date-range-input.d.ts +25 -0
- package/dist/date-range-input.d.ts.map +1 -0
- package/dist/date-range-input.js +195 -0
- package/dist/device-frame.d.ts +13 -0
- package/dist/device-frame.d.ts.map +1 -0
- package/dist/device-frame.js +23 -0
- package/dist/dialog-lifecycle.d.ts +3 -0
- package/dist/dialog-lifecycle.d.ts.map +1 -0
- package/dist/dialog-lifecycle.js +70 -0
- package/dist/expanded-charts.d.ts +26 -0
- package/dist/expanded-charts.d.ts.map +1 -0
- package/dist/expanded-charts.js +46 -0
- package/dist/floating-panel.d.ts +11 -0
- package/dist/floating-panel.d.ts.map +1 -0
- package/dist/floating-panel.js +1 -0
- package/dist/form-workflow.d.ts +77 -0
- package/dist/form-workflow.d.ts.map +1 -0
- package/dist/form-workflow.js +337 -0
- package/dist/hooks.d.ts +24 -21
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +1 -2468
- package/dist/image-comparison.d.ts +20 -0
- package/dist/image-comparison.d.ts.map +1 -0
- package/dist/image-comparison.js +55 -0
- package/dist/index.d.ts +25 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/interval-charts.d.ts +21 -0
- package/dist/interval-charts.d.ts.map +1 -0
- package/dist/interval-charts.js +23 -0
- package/dist/media-selection.d.ts +18 -0
- package/dist/media-selection.d.ts.map +1 -0
- package/dist/media-selection.js +12 -0
- package/dist/media-viewport.d.ts +16 -0
- package/dist/media-viewport.d.ts.map +1 -0
- package/dist/media-viewport.js +37 -0
- package/dist/motion.d.ts +597 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +22 -0
- package/dist/review-workflow.d.ts +32 -0
- package/dist/review-workflow.d.ts.map +1 -0
- package/dist/review-workflow.js +76 -0
- package/dist/rich-text-editor.d.ts +21 -0
- package/dist/rich-text-editor.d.ts.map +1 -0
- package/dist/rich-text-editor.js +143 -0
- package/dist/select-form.d.ts +3 -0
- package/dist/select-form.d.ts.map +1 -0
- package/dist/select-form.js +1 -0
- package/dist/server-components.d.ts +24 -4
- package/dist/server-components.d.ts.map +1 -1
- package/dist/server-components.js +11 -3
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -0
- package/dist/toast-context.d.ts +4 -0
- package/dist/toast-context.d.ts.map +1 -0
- package/dist/toast-context.js +10 -0
- package/dist/toast-provider.d.ts +3 -0
- package/dist/toast-provider.d.ts.map +1 -0
- package/dist/toast-provider.js +3 -0
- package/dist/use-copy-feedback.d.ts +17 -0
- package/dist/use-copy-feedback.d.ts.map +1 -0
- package/dist/use-copy-feedback.js +54 -0
- package/dist/virtual-list-data.d.ts +13 -0
- package/dist/virtual-list-data.d.ts.map +1 -0
- package/dist/virtual-list-data.js +87 -0
- package/dist/virtual-list.d.ts +14 -0
- package/dist/virtual-list.d.ts.map +1 -0
- package/dist/virtual-list.js +24 -0
- package/dist/visual-interactions.d.ts +16 -0
- package/dist/visual-interactions.d.ts.map +1 -0
- package/dist/visual-interactions.js +30 -0
- package/dist/world-map.d.ts +26 -0
- package/dist/world-map.d.ts.map +1 -0
- package/dist/world-map.js +81 -0
- package/package.json +99 -11
- package/styles/critical.css +634 -61
- package/styles/data-table-view.css +36 -0
package/README.md
CHANGED
|
@@ -1,12 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://lumen.santi020k.com">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/santi020k/lumen/main/docs/assets/readme/package-dark.svg">
|
|
5
|
+
<img src="https://raw.githubusercontent.com/santi020k/lumen/main/docs/assets/readme/package-light.svg" alt="Lumen UI — Web. Native. Thoughtfully connected." width="1200" height="184">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<h1 align="center">Lumen UI · React</h1>
|
|
11
|
+
|
|
12
|
+
<p align="center">React primitives · Shared styles · Typed component APIs</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://www.npmjs.com/package/@santi020k/lumen-react"><img src="https://img.shields.io/npm/v/@santi020k/lumen-react?style=flat-square&color=0369a0" alt="npm version"></a>
|
|
16
|
+
<a href="https://github.com/santi020k/lumen/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-13967e?style=flat-square" alt="MIT license"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="https://lumen.santi020k.com/docs/frameworks/react">Documentation</a>
|
|
21
|
+
·
|
|
22
|
+
<a href="https://www.npmjs.com/package/@santi020k/lumen-react">npm</a>
|
|
23
|
+
·
|
|
24
|
+
<a href="https://github.com/santi020k/lumen/tree/main/packages/react">Source</a>
|
|
25
|
+
·
|
|
26
|
+
<a href="https://github.com/santi020k/lumen/issues">Issues</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
**Package:** `@santi020k/lumen-react`
|
|
30
|
+
|
|
31
|
+
**On this page:** [Install](#install) · [Usage](#usage) · [Appearance presets](#appearance-presets) · [Resources](#resources)
|
|
32
|
+
|
|
33
|
+
<details>
|
|
34
|
+
<summary>Browse all sections</summary>
|
|
35
|
+
|
|
36
|
+
- [Install](#install)
|
|
37
|
+
- [Selective imports](#selective-imports)
|
|
38
|
+
- [Appearance presets](#appearance-presets)
|
|
39
|
+
- [Usage](#usage)
|
|
40
|
+
- [Dropdown menus](#dropdown-menus)
|
|
41
|
+
- [Language selection](#language-selection)
|
|
42
|
+
- [Forms](#forms)
|
|
43
|
+
- [Error states](#error-states)
|
|
44
|
+
- [Data visualization](#data-visualization)
|
|
45
|
+
- [Next.js and server components](#nextjs-and-server-components)
|
|
46
|
+
- [Compatibility wrappers](#compatibility-wrappers)
|
|
47
|
+
- [Context navigation](#context-navigation)
|
|
48
|
+
- [Optimized images](#optimized-images)
|
|
49
|
+
- [Kanban boards](#kanban-boards)
|
|
50
|
+
- [Motion](#motion)
|
|
51
|
+
- [Glass surfaces](#glass-surfaces)
|
|
52
|
+
- [Semantic stat roots](#semantic-stat-roots)
|
|
53
|
+
- [Consumer composition recipes](#consumer-composition-recipes)
|
|
54
|
+
- [Exact amount fields](#exact-amount-fields)
|
|
55
|
+
- [Inline date range calendar](#inline-date-range-calendar)
|
|
56
|
+
- [Input-attached date range selection](#input-attached-date-range-selection)
|
|
57
|
+
- [Phone presentation in v4](#phone-presentation-in-v4)
|
|
58
|
+
- [Combobox keyboard behavior](#combobox-keyboard-behavior)
|
|
59
|
+
- [Content flow](#content-flow)
|
|
60
|
+
- [Attachment composition](#attachment-composition)
|
|
61
|
+
- [Chart datum actions](#chart-datum-actions)
|
|
62
|
+
- [Dashboard composition](#dashboard-composition)
|
|
63
|
+
- [Hook state updates](#hook-state-updates)
|
|
64
|
+
- [Advanced table views](#advanced-table-views)
|
|
65
|
+
- [Advanced form workflows](#advanced-form-workflows)
|
|
66
|
+
- [Device demonstrations](#device-demonstrations)
|
|
67
|
+
- [Visual interactions](#visual-interactions)
|
|
68
|
+
- [World map](#world-map)
|
|
69
|
+
- [Operational workflows](#operational-workflows)
|
|
70
|
+
- [Studio media workspace](#studio-media-workspace)
|
|
71
|
+
- [Resources](#resources)
|
|
72
|
+
|
|
73
|
+
</details>
|
|
74
|
+
|
|
75
|
+
React components and behavior hooks for Lumen UI, using the shared standalone stylesheet.
|
|
76
|
+
Start with one CSS import, then compose public primitives in your existing React application.
|
|
77
|
+
|
|
78
|
+
See the [shared web form contracts](https://github.com/santi020k/lumen/blob/main/docs/form-controls.md) for value ownership, reset,
|
|
79
|
+
submission, disabled state, and event behavior.
|
|
80
|
+
|
|
81
|
+
Form controls use `visualSize` (`visual-size` in Elements) with `default`, `sm` and `lg`.
|
|
82
|
+
Select, PhoneInput and Segmented follow Input and NativeSelect; numeric input/select `size` keeps
|
|
83
|
+
its native meaning. See the [v4 migration guide](https://github.com/santi020k/lumen/blob/main/docs/migrating-v3-to-v4.md#form-control-visual-sizing).
|
|
7
84
|
|
|
8
85
|
## Install
|
|
9
86
|
|
|
87
|
+
Requires React 19 or newer in the consuming application.
|
|
88
|
+
|
|
10
89
|
```bash
|
|
11
90
|
pnpm add @santi020k/lumen-react
|
|
12
91
|
```
|
|
@@ -32,15 +111,41 @@ The stylesheet defaults `--ui-font` to `"Montserrat", "Avenir Next", "Segoe UI",
|
|
|
32
111
|
It declares the family stack but does not bundle or load font files. Load Montserrat once through
|
|
33
112
|
your preferred delivery path, or override `--ui-font` in application CSS.
|
|
34
113
|
|
|
114
|
+
## Selective imports
|
|
115
|
+
|
|
116
|
+
Production builds compact component JavaScript without renaming identifiers or changing the
|
|
117
|
+
ES2022 target. Declaration files and public imports retain their existing contracts.
|
|
118
|
+
|
|
119
|
+
Root imports remain supported. Standalone component entrypoints include `/components/attachments`,
|
|
120
|
+
`/components/bullet-chart`, `/components/comparison-chart`, `/components/data-table`,
|
|
121
|
+
`/components/date-range-calendar`, `/components/date-range-input`, `/components/expanded-charts`,
|
|
122
|
+
`/components/image-comparison`, `/components/interval-charts`, and `/components/virtual-list`.
|
|
123
|
+
Import behavior hooks from `/hooks`; use `/server` for the server-safe primitive catalog.
|
|
124
|
+
Load the existing stylesheet once, regardless of the import path.
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
import { ImageComparison } from '@santi020k/lumen-react/components/image-comparison'
|
|
128
|
+
import { VirtualList } from '@santi020k/lumen-react/components/virtual-list'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
These entries use the same implementation and types as root imports. Interactive entries retain
|
|
132
|
+
`use client` for React Server Component consumers. A smaller module graph does not guarantee a
|
|
133
|
+
smaller final bundle: a bundler can already remove unused root exports. Run the repository's
|
|
134
|
+
`pnpm run measure:selective-imports` benchmark for the measured comparison.
|
|
135
|
+
|
|
136
|
+
## Appearance presets
|
|
137
|
+
|
|
138
|
+
Use a scoped `data-lumen-preset="studio"` container, or select a preset with `useThemeBuilder`. See [appearance presets](https://github.com/santi020k/lumen/blob/main/docs/appearance-presets.md) for theme overrides and explicit glass surfaces.
|
|
139
|
+
|
|
35
140
|
## Usage
|
|
36
141
|
|
|
37
142
|
```tsx
|
|
38
|
-
import { Button, Card, Input } from "@santi020k/lumen-react";
|
|
143
|
+
import { Button, Card, Input, Label } from "@santi020k/lumen-react";
|
|
39
144
|
|
|
40
145
|
export function SubscribeForm() {
|
|
41
146
|
return (
|
|
42
147
|
<Card>
|
|
43
|
-
<
|
|
148
|
+
<Label htmlFor="email">Email</Label>
|
|
44
149
|
<Input id="email" type="email" placeholder="you@example.com" />
|
|
45
150
|
<Button>Subscribe</Button>
|
|
46
151
|
</Card>
|
|
@@ -66,6 +171,13 @@ Compose dropdown menus from the public trigger, content, item, and separator par
|
|
|
66
171
|
menu after a successful selection; preventing the item's click event keeps it open. Disabled items
|
|
67
172
|
remain unavailable, and `status` adds short trailing context to the item.
|
|
68
173
|
|
|
174
|
+
Disclosure keyboard navigation skips hidden or inert regions, invisible controls, and native
|
|
175
|
+
disabled controls, including a disabled fieldset. Available controls in a fieldset's first legend
|
|
176
|
+
retain their native keyboard behavior; removing `inert` makes a region available again.
|
|
177
|
+
|
|
178
|
+
Mentions keeps suggestion navigation on the textarea through `aria-activedescendant`; suggestion
|
|
179
|
+
buttons are excluded from the Tab sequence while Enter and pointer selection still insert a mention.
|
|
180
|
+
|
|
69
181
|
```tsx
|
|
70
182
|
import {
|
|
71
183
|
DropdownMenu,
|
|
@@ -122,6 +234,13 @@ and Spanish defaults when `locales` is omitted.
|
|
|
122
234
|
accessibility contract without replacing form state. Native-backed controls forward refs to their
|
|
123
235
|
submitted DOM controls and work directly with React Hook Form's `register()`.
|
|
124
236
|
|
|
237
|
+
Native form resets defer past the browser's default action and honor a cancelled `reset` event:
|
|
238
|
+
`DatePicker`, `DateRangeInput`, `PhoneInput`, and `Combobox` only restore uncontrolled defaults when
|
|
239
|
+
the reset is not prevented, and leave a controlled `value` untouched. `DatePicker` calendar
|
|
240
|
+
selection fires the native `onChange` exactly once, matching typed input. `DateRangeInput` attaches
|
|
241
|
+
its reset listener even without `name`, honoring an explicit `form` id as well as the nearest
|
|
242
|
+
ancestor form.
|
|
243
|
+
|
|
125
244
|
For controlled composites, install the optional adapter:
|
|
126
245
|
|
|
127
246
|
```bash
|
|
@@ -152,7 +271,7 @@ diagnostics, or decide whether retrying is safe.
|
|
|
152
271
|
/>
|
|
153
272
|
```
|
|
154
273
|
|
|
155
|
-
See the repository [React error-handling guide](
|
|
274
|
+
See the repository [React error-handling guide](https://github.com/santi020k/lumen/blob/main/docs/error-handling.md#react) for the complete
|
|
156
275
|
example, error-boundary ownership, announcement behavior, and verification guidance.
|
|
157
276
|
|
|
158
277
|
For long articles, `Anchor` accepts optional `depth`, `index`, and `description` metadata plus an
|
|
@@ -188,15 +307,29 @@ either a `value` or a `target` selector; `toast` opts into Lumen Toast feedback.
|
|
|
188
307
|
customize its visible feedback while the localized label props remain the accessible announcement.
|
|
189
308
|
Stable `data-slot` hooks expose the idle, copied, and error parts.
|
|
190
309
|
|
|
310
|
+
Wrap React copy actions in `ToastProvider` to display their optional toast feedback. Target selectors
|
|
311
|
+
resolve in the clicked button's owning document, including iframe portals. Updating a closing or moved
|
|
312
|
+
toast reapplies the destination viewport limit without dismissing toasts in another placement.
|
|
313
|
+
|
|
191
314
|
## Data visualization
|
|
192
315
|
|
|
316
|
+
The web visualization milestone adds `WaterfallChart` for signed changes and explicit totals, and
|
|
317
|
+
`Histogram` for precomputed numeric bins (`frequency="density"` for unequal widths). Line charts
|
|
318
|
+
support explicit continuous axes, annotations, optional keyboard/pointer/touch inspection, and
|
|
319
|
+
synchronized cursors. Heatmaps show labeled axes, a color legend, and explicit missing cells.
|
|
320
|
+
See the [visualization contracts](https://github.com/santi020k/lumen/blob/main/docs/data-visualization.md) and
|
|
321
|
+
[interactive web example](https://lumen.santi020k.com/docs/web/data-visualization).
|
|
322
|
+
|
|
323
|
+
Use `interactive`, `syncGroup`, and optional `cursor`/`onCursorChange` on `LineChart`. A supplied
|
|
324
|
+
`cursor` is controlled; the owner must accept requests before the selection changes.
|
|
325
|
+
|
|
193
326
|
`Sparkline`, `BarChart`, `LineChart`, `PieChart`, `ScatterChart`, `Heatmap`, `RangeChart`, and
|
|
194
327
|
`ComboChart` use the shared chart contracts and
|
|
195
328
|
render without an external charting dependency. Data charts expose a revealable semantic table by
|
|
196
329
|
default. `PieChart` accepts one series and defaults to a donut presentation.
|
|
197
330
|
|
|
198
331
|
Every chart includes a factual screen-reader summary by default and accepts `summary` for more
|
|
199
|
-
useful domain context. See [data visualization](
|
|
332
|
+
useful domain context. See [data visualization](https://github.com/santi020k/lumen/blob/main/docs/data-visualization.md) for selection,
|
|
200
333
|
missing-data, live-data, and accessibility guidance.
|
|
201
334
|
|
|
202
335
|
```tsx
|
|
@@ -384,16 +517,22 @@ ARIA, keyboard, Escape, dismissal, context menu, form
|
|
|
384
517
|
validation, calendar grids, OTP segmentation, date range syncing, rich text command, schedule
|
|
385
518
|
drag/drop, controlled Kanban move requests, theme export and switching, resizable pane sizing, and
|
|
386
519
|
toast controller semantics for React applications.
|
|
387
|
-
|
|
520
|
+
Toast timeouts pause while hovered or focused and resume only after both interactions end;
|
|
521
|
+
moving focus between a toast's controls preserves its remaining duration. Updating a closing toast
|
|
522
|
+
reopens it with a fresh lifetime using its current duration.
|
|
523
|
+
`useRichTextEditor` honors consumer event cancellation before toolbar and shortcut commands.
|
|
524
|
+
It also provides `getEditableProps`, value-bearing commands, common formatting
|
|
388
525
|
shortcuts, active toolbar state, and `{ html, text }` change details.
|
|
389
526
|
`DataTable` can render structured `columns` and `rows`; sortable columns use native header buttons,
|
|
390
527
|
update `aria-sort`, and order string or numeric values without mutating the supplied rows. The
|
|
391
528
|
shared selectable/sortable data attributes remain available for app-level adapters, and
|
|
392
|
-
`VirtualList`
|
|
529
|
+
`VirtualList` provides built-in fixed-height windowing with the shared sizing attributes.
|
|
393
530
|
`useTabs` keeps the selected trigger visible when a narrow horizontal list scrolls. The package
|
|
394
531
|
also exports `LumenTabsChangeDetail` and `LumenTabsChangeEvent` for integrations that consume the
|
|
395
532
|
shared `ui:tabs-change` contract.
|
|
396
533
|
|
|
534
|
+
Keyboard navigation stays within the current tab group when tabs are nested and skips disabled triggers.
|
|
535
|
+
|
|
397
536
|
## Kanban boards
|
|
398
537
|
|
|
399
538
|
Use `KanbanBoard`, `KanbanColumn`, and ordinary `Card` items for status-based workspaces. The
|
|
@@ -446,7 +585,7 @@ or `variant="glass"` for selective translucency.
|
|
|
446
585
|
|
|
447
586
|
## Consumer composition recipes
|
|
448
587
|
|
|
449
|
-
See [consumer UI recipes](
|
|
588
|
+
See [consumer UI recipes](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md) for static React icons, responsive
|
|
450
589
|
record tables, keyboard-aware native sheets, whole-unit amount fields, adaptive editors, and
|
|
451
590
|
asynchronous action states. Each recipe identifies the public primitives and the behavior that
|
|
452
591
|
remains owned by the application.
|
|
@@ -462,3 +601,517 @@ import { Icon, Search } from '@santi020k/lumen-react/icons'
|
|
|
462
601
|
The existing root `Icon name="search"` remains supported for runtime-selected names and icon packs.
|
|
463
602
|
`Table layout="records"` opts into the responsive record recipe; its semantic child markup and
|
|
464
603
|
shared mobile labels are documented in the consumer recipe linked above.
|
|
604
|
+
|
|
605
|
+
## Exact amount fields
|
|
606
|
+
|
|
607
|
+
`AmountField` accepts editable ASCII decimal strings, formats a requested locale, and submits a
|
|
608
|
+
complete decimal string through its named hidden input. Use `defaultValue` for an uncontrolled
|
|
609
|
+
field or `value` with `onValueChange` for application-owned drafts. It preserves precision and
|
|
610
|
+
never rounds through a JavaScript number. Updating `defaultValue` changes the next reset baseline
|
|
611
|
+
without replacing the active draft. Currency rules and limits remain application-owned.
|
|
612
|
+
|
|
613
|
+
```tsx
|
|
614
|
+
<AmountField name="amount" locale="es-CO" defaultValue="1234.50" aria-label="Amount COP" />
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
See [consumer workflows](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md#executable-consumer-workflows) for
|
|
618
|
+
validation, reset, operational-record actions and opt-in MessageScroller following.
|
|
619
|
+
|
|
620
|
+
## Inline date range calendar
|
|
621
|
+
|
|
622
|
+
`DateRangeCalendar` is a controlled React range editor with two visible calendars,
|
|
623
|
+
inclusive range highlighting, a preset sidebar and the keyboard behavior of `useCalendar`,
|
|
624
|
+
including inherited RTL arrow navigation and focus movement in iframe documents.
|
|
625
|
+
On narrow screens the presets scroll horizontally and the calendars stack. It uses the shared Lumen stylesheet.
|
|
626
|
+
|
|
627
|
+
```tsx
|
|
628
|
+
const [range, setRange] = useState({ start: '2026-09-01', end: '2026-09-30' })
|
|
629
|
+
|
|
630
|
+
<DateRangeCalendar
|
|
631
|
+
value={range}
|
|
632
|
+
onValueChange={setRange}
|
|
633
|
+
locale="en-US"
|
|
634
|
+
min="2000-01-01"
|
|
635
|
+
max="2100-12-31"
|
|
636
|
+
labels={{ start: 'From', end: 'To', presets: 'Quick range' }}
|
|
637
|
+
presets={[{ label: 'September', value: { start: '2026-09-01', end: '2026-09-30' } }]}
|
|
638
|
+
/>
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Supply valid ISO date endpoints in ascending order. Choosing a start after the end,
|
|
642
|
+
or an end before the start, moves the opposite endpoint to the chosen day.
|
|
643
|
+
Presets outside `min`/`max` or in descending order are disabled. Only one matching
|
|
644
|
+
preset is highlighted, including when multiple presets resolve to the same range. `formatDate` can customize
|
|
645
|
+
the endpoint summaries without changing ISO values. The consumer owns draft state,
|
|
646
|
+
Apply/Cancel actions and domain limits such as maximum report duration. Labels are required;
|
|
647
|
+
`locale` controls month, weekday, navigation and day announcements. React date controls default
|
|
648
|
+
to English on both the server and browser; pass the application locale explicitly for localized
|
|
649
|
+
SSR and hydration.
|
|
650
|
+
|
|
651
|
+
## Input-attached date range selection
|
|
652
|
+
|
|
653
|
+
`DateRangeInput` wraps `DateRangeCalendar` in an anchored, non-modal popover.
|
|
654
|
+
It measures and observes its owning viewport, including iframe documents. Apply and Cancel restore
|
|
655
|
+
trigger focus, and native reset follows the current associated form. Outside-focus dismissal
|
|
656
|
+
follows the owning document, including same-origin iframe and portal rendering. Use it
|
|
657
|
+
when the range should be edited directly from an input-like control. It keeps draft
|
|
658
|
+
changes internal and calls `onValueChange` only when the user chooses Apply.
|
|
659
|
+
The existing `DateRangePicker` and inline `DateRangeCalendar` remain available.
|
|
660
|
+
|
|
661
|
+
```tsx
|
|
662
|
+
import { useState } from 'react'
|
|
663
|
+
import { DateRangeInput } from '@santi020k/lumen-react'
|
|
664
|
+
import '@santi020k/lumen-react/styles.css'
|
|
665
|
+
|
|
666
|
+
export function ReportPeriod() {
|
|
667
|
+
const [range, setRange] = useState({ start: '2026-09-01', end: '2026-09-30' })
|
|
668
|
+
|
|
669
|
+
return (
|
|
670
|
+
<DateRangeInput
|
|
671
|
+
value={range}
|
|
672
|
+
onValueChange={setRange}
|
|
673
|
+
label="Report period"
|
|
674
|
+
locale="en-US"
|
|
675
|
+
labels={{ start: 'From', end: 'To', presets: 'Quick ranges', apply: 'Apply', cancel: 'Cancel' }}
|
|
676
|
+
presets={[{ label: 'September', value: { start: '2026-09-01', end: '2026-09-30' } }]}
|
|
677
|
+
name={{ start: 'from', end: 'to' }}
|
|
678
|
+
validate={draft => draft.start < '2026-01-01' ? 'Choose dates in 2026 or later.' : undefined}
|
|
679
|
+
renderSummary={draft => `${draft.start} through ${draft.end}`}
|
|
680
|
+
/>
|
|
681
|
+
)
|
|
682
|
+
}
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
- `value` must contain real, ascending ISO dates (`YYYY-MM-DD`). `min`, `max`,
|
|
686
|
+
`presets`, `locale`, and `formatDate` follow the inline calendar contract.
|
|
687
|
+
- `label` names both the trigger and dialog. Supply localized start, end, presets,
|
|
688
|
+
apply, and cancel labels. For Spanish, use `Desde`, `Hasta`, `Períodos`, `Aplicar`,
|
|
689
|
+
and `Cancelar` with `locale="es-CO"`. Navigation announcements follow `locale`.
|
|
690
|
+
- `validate` runs on the draft; return a localized error to disable Apply. The error
|
|
691
|
+
is announced politely and associated with the Apply button. Keep validation pure.
|
|
692
|
+
- `renderSummary` optionally renders localized draft details. `formatDate` changes
|
|
693
|
+
visible dates, while optional hidden form fields always submit the applied ISO values.
|
|
694
|
+
- Cancel, Escape, outside pointer interaction, or moving focus outside discard the
|
|
695
|
+
draft. Apply, Cancel, and Escape return focus to the trigger. Opening again starts
|
|
696
|
+
from the latest controlled value. Calendar arrows retain their date-navigation behavior.
|
|
697
|
+
- The panel uses the browser Popover API top layer without a modal backdrop or focus
|
|
698
|
+
trap. A fixed-position fallback works where the API is unavailable; ancestor clipping
|
|
699
|
+
can affect that fallback. The page remains interactive.
|
|
700
|
+
- The panel tracks viewport changes, scroll, and trigger size. Narrow screens scroll
|
|
701
|
+
the trigger into view, stack the calendars, and scroll presets horizontally.
|
|
702
|
+
Only the body scrolls vertically; confirmation actions stay visible.
|
|
703
|
+
- `disabled` disables the trigger and optional form entries. `className` styles the
|
|
704
|
+
outer container. Import the shared stylesheet once at the application boundary.
|
|
705
|
+
|
|
706
|
+
This component is currently React-only. Publication is separate from local implementation.
|
|
707
|
+
|
|
708
|
+
### Accessible code examples
|
|
709
|
+
|
|
710
|
+
`Code` and `CodeTabs` accept `copyLabel`, `copiedLabel`, `errorLabel`, and
|
|
711
|
+
`codeLabel`. Copy controls work directly in React, emit `ui:copy-success` or
|
|
712
|
+
`ui:copy-error`, and announce localized success or recovery guidance. Repeated
|
|
713
|
+
clicks restart feedback; unmounting clears its timer. No Astro runtime is needed.
|
|
714
|
+
|
|
715
|
+
Unwrapped code uses a named, keyboard-focusable region. `codeLabel` defaults to
|
|
716
|
+
`Code example`; set a descriptive localized name when several examples are
|
|
717
|
+
present. Highlighted `pre` children receive the same behavior while retaining
|
|
718
|
+
authored names and tab order. Wrapped code does not add an extra tab stop.
|
|
719
|
+
|
|
720
|
+
### Server-sorted tables
|
|
721
|
+
|
|
722
|
+
`DataTable` accepts `sort` and `onSortChange` for controlled sorting, or
|
|
723
|
+
`defaultSort` for an initial uncontrolled sort. A `DataTableSort` contains a
|
|
724
|
+
column `key` and `direction: 'ascending' | 'descending'`; `null` means unsorted.
|
|
725
|
+
Header buttons request the next direction, and `aria-sort` describes the applied
|
|
726
|
+
state. Replacing `rows` does not reset that state.
|
|
727
|
+
|
|
728
|
+
Use `sortMode="manual"` with server pagination. In this mode the table preserves
|
|
729
|
+
the supplied row order, even when a header is activated. Apply the requested sort
|
|
730
|
+
to the complete dataset on the server before selecting the page, then supply the
|
|
731
|
+
returned rows and controlled sort. Keep authentication, query validation, loading
|
|
732
|
+
state, and network errors in the application. The default `sortMode="client"`
|
|
733
|
+
sorts a copy of the supplied rows.
|
|
734
|
+
|
|
735
|
+
### Dialog dismissal and focus
|
|
736
|
+
|
|
737
|
+
`Dialog`, `AlertDialog`, and `useDialog` accept `dismissOnOutsidePress` and
|
|
738
|
+
`dismissOnEscape`. Ordinary dialogs allow both by default; alert dialogs ignore
|
|
739
|
+
outside presses by default. Set both to `false` while an application requires an
|
|
740
|
+
explicit decision or is completing a pending mutation. These policies govern
|
|
741
|
+
implicit dismissal; explicit close actions remain under application control.
|
|
742
|
+
|
|
743
|
+
Native Escape requests `onOpenChange(false)` without overriding a controlled
|
|
744
|
+
`open` value. Content padding and a drag that begins inside the dialog do not
|
|
745
|
+
count as backdrop dismissal. Consumer `onCancel` or `onClick` handlers can prevent
|
|
746
|
+
the corresponding default action.
|
|
747
|
+
|
|
748
|
+
A controlled dialog can open without hook trigger props: it captures the focused
|
|
749
|
+
opener before opening and returns focus on close or unmount, including when rendered into an iframe.
|
|
750
|
+
Focus capture and restoration use the dialog's own document. StrictMode replay
|
|
751
|
+
preserves that opener, and cleanup does not steal focus from a nested or
|
|
752
|
+
replacement dialog. Hook trigger props remain useful when the same component
|
|
753
|
+
owns the opener and dialog. Keep an accessible dialog name and logical initial
|
|
754
|
+
focus; native `autoFocus` can select the initial control.
|
|
755
|
+
|
|
756
|
+
### Virtual list and editor ownership
|
|
757
|
+
|
|
758
|
+
`VirtualList` displays fixed-height rows with inert spacers that retain the full scroll extent.
|
|
759
|
+
Rows stay mounted; use pagination when the initial DOM cost matters. Scrolling, resizing, sizing
|
|
760
|
+
changes and direct row changes refresh the window. Focused rows remain available. See the
|
|
761
|
+
[fixed-height list contract](https://github.com/santi020k/lumen/blob/main/docs/ai-usage.md#fixed-height-virtual-lists).
|
|
762
|
+
|
|
763
|
+
External rich-text engines should handle the cancelable `ui:editor-command-request` event before
|
|
764
|
+
execution and use `ui:editor-command` only for completion notifications. React also supports
|
|
765
|
+
`useRichTextEditor({ commandHandler })`. Disable native toolbar state syncing when the external
|
|
766
|
+
engine owns it. See the [editor guidance](https://github.com/santi020k/lumen/blob/main/docs/ai-usage.md).
|
|
767
|
+
|
|
768
|
+
With native state enabled, `useRichTextEditor` initializes toolbar toggle states on mount,
|
|
769
|
+
including `aria-pressed`, before the first editing interaction. External command handlers
|
|
770
|
+
disable this synchronization by default so the application can own toolbar state.
|
|
771
|
+
Native toolbar and keyboard commands execute in the editor root's owning document, including
|
|
772
|
+
editors portaled into a same-origin iframe.
|
|
773
|
+
|
|
774
|
+
## Phone presentation in v4
|
|
775
|
+
|
|
776
|
+
Phone inputs bundle the same offline flag artwork on every platform. The selected country shows
|
|
777
|
+
its flag and calling code inside one continuous input border. Country names remain in the native
|
|
778
|
+
picker and its accessible name; flags are supplementary. Unknown flag codes fall back to text.
|
|
779
|
+
|
|
780
|
+
Astro and React `PhoneInput` accept `disabled`, `readOnly`, `required`, `errorMessage`,
|
|
781
|
+
`showValidationError`, and `inputProps`. Their `id` targets the number input in v4; React also
|
|
782
|
+
accepts `inputRef`. Web Components use `disabled`, `readonly`, `required`, `error-message`,
|
|
783
|
+
`show-validation-error="false"`, and `input-id`, with native input attributes on the host.
|
|
784
|
+
Both controls lock together and validation remains associated with the input. React forwards
|
|
785
|
+
`inputProps.form` to the country picker and read-only country value as well as the number input,
|
|
786
|
+
so an external form receives both values. Legacy `countries` pickers also retain their selected
|
|
787
|
+
country while read-only and restore it after an accepted native form reset.
|
|
788
|
+
|
|
789
|
+
The `phone-input`, `phone-country`, and `country-flag` styling parts plus `--ui-phone-height`,
|
|
790
|
+
`--ui-phone-padding`, and `--ui-phone-country-gap` replace consumer CSS overlays.
|
|
791
|
+
|
|
792
|
+
Astro and React also export `CountryFlag` (`regionCode`, optional `decorative`) and `PhoneNumber`
|
|
793
|
+
(`value: LumenPhoneNumber`, optional `link`). A telephone link is rendered only for a complete
|
|
794
|
+
E.164 value. Use the model returned by the phone normalizer; keep domain persistence in your app.
|
|
795
|
+
Artwork attribution is shipped with the core package in `PHONE_FLAG_LICENSE.txt`.
|
|
796
|
+
|
|
797
|
+
## Combobox keyboard behavior
|
|
798
|
+
|
|
799
|
+
Decoded Combobox options must be a dense string collection; invalid collections expose no options.
|
|
800
|
+
In v4, Combobox retains input focus and exposes its active option through `aria-activedescendant`.
|
|
801
|
+
Enter commits an active option; text editing and composition remain native. Escape dismisses one
|
|
802
|
+
nested control at a time. See the [shared keyboard contract](https://github.com/santi020k/lumen/blob/main/docs/ai-usage.md#combobox-keyboard-behavior-in-v4)
|
|
803
|
+
for dynamic options, controlled inputs and migration guidance.
|
|
804
|
+
|
|
805
|
+
Combobox also supports native form reset: resetting the owning form restores an uncontrolled
|
|
806
|
+
`defaultValue`, closes the open option list, and clears the active selection without emitting
|
|
807
|
+
`onChange`. A controlled `value` is left unchanged.
|
|
808
|
+
|
|
809
|
+
## Content flow
|
|
810
|
+
|
|
811
|
+
Stack and Grid own sibling spacing. Their gap accepts `related`, `group` (default) and `section`,
|
|
812
|
+
or canonical `none`, `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl` sizes. Card owns the inset and gap
|
|
813
|
+
between its visible parts; use `density="compact"`, `"comfortable"` (default) or `"spacious"`.
|
|
814
|
+
Elements uses the same names as attributes. Use a nested Stack for CardContent groups and Field
|
|
815
|
+
for label/control/feedback. See [content flow](https://github.com/santi020k/lumen/blob/main/docs/content-flow.md) and the
|
|
816
|
+
[v4 migration guide](https://github.com/santi020k/lumen/blob/main/docs/migrating-to-lumen.md) for ownership and changed explicit gaps.
|
|
817
|
+
|
|
818
|
+
### Reading and complete compositions
|
|
819
|
+
|
|
820
|
+
Prose and Typography trim outer child margins and separate headings from preceding text.
|
|
821
|
+
Container gutters grow from 16px to 32px with viewport width; override `--ui-container-gutter`
|
|
822
|
+
when a product needs fixed gutters. Card allows interactive overflow; use AspectRatio to clip media.
|
|
823
|
+
Install `content-flow-header`, `content-flow-settings`, `content-flow-list` or `content-flow-actions`
|
|
824
|
+
with `lumen add <recipe> --target astro|react|elements`. MCP returns the same complete examples.
|
|
825
|
+
Connect application actions and replace sample IDs before reuse. See
|
|
826
|
+
[content flow](https://github.com/santi020k/lumen/blob/main/docs/content-flow.md) for composition and migration guidance.
|
|
827
|
+
|
|
828
|
+
### Large fixed-height collections
|
|
829
|
+
|
|
830
|
+
React `VirtualList` accepts typed `items`, `getKey` and `renderItem` for data mode.
|
|
831
|
+
Only the visible window, overscan and focused neighbors mount. Stable keys retain row identity;
|
|
832
|
+
applications own offscreen editing state. See [data rendering](https://github.com/santi020k/lumen/blob/main/docs/virtual-list-data.md) for
|
|
833
|
+
setup, lifecycle, accessibility and the mounted-mode tradeoff.
|
|
834
|
+
|
|
835
|
+
### Compound dialog tasks
|
|
836
|
+
|
|
837
|
+
`DialogHeader`, `DialogTitle`, `DialogBody`, `DialogFooter`, and `DialogClose`
|
|
838
|
+
compose long forms with fixed actions and an independently scrolling body. Keep
|
|
839
|
+
`DialogBody` directly inside `Dialog`. Give `DialogTitle` an `id` and reference it
|
|
840
|
+
from `Dialog aria-labelledby`; `as` supports `h2`, `h3`, and `h4`.
|
|
841
|
+
`DialogClose` accepts Button props, honors `onClick` cancellation, and requests
|
|
842
|
+
closure through the enclosing Dialog controller, including controlled dialogs.
|
|
843
|
+
The four static structural parts are also exported from `@santi020k/lumen-react/server`.
|
|
844
|
+
|
|
845
|
+
```tsx
|
|
846
|
+
<Dialog open={open} onOpenChange={setOpen} aria-labelledby="record-title">
|
|
847
|
+
<DialogHeader><DialogTitle id="record-title">Edit record</DialogTitle></DialogHeader>
|
|
848
|
+
<DialogBody><Form id="record-form"><Input name="name" aria-label="Name" /></Form></DialogBody>
|
|
849
|
+
<DialogFooter>
|
|
850
|
+
<DialogClose variant="outline">Cancel</DialogClose>
|
|
851
|
+
<Button type="submit" form="record-form">Save</Button>
|
|
852
|
+
</DialogFooter>
|
|
853
|
+
</Dialog>
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
`FileUpload selectedFilesLabel` accepts localized text containing `{count}`.
|
|
857
|
+
FileUpload keeps its native file input uncontrolled: `value` and `defaultValue` are excluded from its props and ignored in decoded JavaScript input.
|
|
858
|
+
Reset feedback follows the current native form owner, including replaced external forms.
|
|
859
|
+
Accepted native form resets clear selected-file feedback; cancelled resets preserve it.
|
|
860
|
+
|
|
861
|
+
### Rich description rows
|
|
862
|
+
|
|
863
|
+
`DescriptionItem`, `DescriptionTerm`, and `DescriptionDetail` accept native props
|
|
864
|
+
and refs and render `div`, `dt`, and `dd`. Compose them inside `Descriptions` for
|
|
865
|
+
rich values, alongside the existing `items` array when needed. The three static
|
|
866
|
+
parts are also available from `@santi020k/lumen-react/server` for use inside a native `dl`.
|
|
867
|
+
|
|
868
|
+
```tsx
|
|
869
|
+
<Descriptions>
|
|
870
|
+
<DescriptionItem>
|
|
871
|
+
<DescriptionTerm>Status</DescriptionTerm>
|
|
872
|
+
<DescriptionDetail><Badge variant="success">Active</Badge></DescriptionDetail>
|
|
873
|
+
</DescriptionItem>
|
|
874
|
+
</Descriptions>
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
## Attachment composition
|
|
878
|
+
|
|
879
|
+
Use `AttachmentList` to group native `li` children and `AttachmentPreview` for browser-owned images
|
|
880
|
+
with localized loading, error, and unsupported-file states. Compose independent actions rather
|
|
881
|
+
than nesting controls inside a linked Attachment. The application retains file validation,
|
|
882
|
+
authorization, persistence, and object URL cleanup. See the
|
|
883
|
+
[attachment composition recipe](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md#attachment-previews-and-file-lists)
|
|
884
|
+
for adapter props, slots, child contracts, retry identity, and safe state events.
|
|
885
|
+
|
|
886
|
+
## Chart datum actions
|
|
887
|
+
|
|
888
|
+
Pass `onDatumActivate(detail)` to BarChart, LineChart, PieChart, ScatterChart, ComboChart, Heatmap,
|
|
889
|
+
or RangeChart to enable drilldown. The callback receives `LumenChartDatumActivationDetail`,
|
|
890
|
+
exported from this package, with raw axes and optional datum IDs. Applications own navigation,
|
|
891
|
+
filtering, detail views, and authorization. React charts use their own event handling and do not
|
|
892
|
+
require `UIPrimitives`.
|
|
893
|
+
|
|
894
|
+
Each available plotted datum has an equivalent native button in the actions disclosure, even
|
|
895
|
+
with `showTable={false}` or hidden line markers. Translate `labels.exploreData` and
|
|
896
|
+
`labels.formatDatumAction(context)` alongside the chart's existing labels and value formatters.
|
|
897
|
+
Missing observations have no action and never reach datum-action value formatters; pie actions cover only positive slices. Updated values and
|
|
898
|
+
callbacks take effect on rerender, while stable datum identities retain focused action buttons.
|
|
899
|
+
Chart activation uses the owning document, including iframe rendering.
|
|
900
|
+
The chart's native `onClick` can cancel activation with `event.preventDefault()`.
|
|
901
|
+
|
|
902
|
+
## Dashboard composition
|
|
903
|
+
|
|
904
|
+
`FilterBar` groups host-owned filtering controls, active criteria, reset actions, and a polite
|
|
905
|
+
result announcement. `ChangeSummary` presents explicit before/after values and application-owned
|
|
906
|
+
changed state. Neither component owns requests, persistence, parsing, or financial policy.
|
|
907
|
+
Omit `FilterBar.open` for native disclosure ownership. Unrelated rerenders preserve native toggles
|
|
908
|
+
when `defaultOpen` is unchanged. Pass `open` and `onOpenChange` for application-controlled disclosure.
|
|
909
|
+
|
|
910
|
+
ScatterChart supports independent X/Y formatting, explicit domains, logarithmic positive X values,
|
|
911
|
+
and labeled reference lines/regions. See [consumer UI recipes](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md)
|
|
912
|
+
for dashboard tables, freshness, import review, activity inbox, and persistent Kanban patterns.
|
|
913
|
+
|
|
914
|
+
React DataTable adds `layout="records"`, rich `column.render`, and expandable `renderDetails`.
|
|
915
|
+
Use stable record IDs and controlled `expandedRowIds` across pages. Row identity uses `rowValue`,
|
|
916
|
+
then `id`, then a legacy `value` fallback; ordinary value cells do not override explicit IDs.
|
|
917
|
+
Rows without an explicit identity keep their original input index across client sorting.
|
|
918
|
+
Decoded row and column collections are validated before sorting or rendering. Invalid rows, columns, identities,
|
|
919
|
+
cell shapes, empty identities, and duplicate resolved identities fail closed to an empty table while
|
|
920
|
+
the column headers remain available. Client sorting only applies to columns marked `sortable`.
|
|
921
|
+
`DataTableSortControls` shares
|
|
922
|
+
`sort`/`onSortChange` with table headers; manual sorting preserves server page order.
|
|
923
|
+
Rows without an explicit `rowValue`, `value`, or `id` use their original input index as identity
|
|
924
|
+
during client sorting, preserving expanded details and local edits. Supply stable IDs when replacing,
|
|
925
|
+
filtering, or paginating the input rows.
|
|
926
|
+
|
|
927
|
+
Popover and DropdownMenu support anchored top-layer placement, viewport collision handling, logical
|
|
928
|
+
start/end alignment, and focus handoff in their owning document, including iframes.
|
|
929
|
+
Set `positioning="none"` for application-owned placement. Context menus dismiss outside pointer
|
|
930
|
+
presses; tooltips close when focus leaves their owner and cancel pending opening timers.
|
|
931
|
+
|
|
932
|
+
### Actual-versus-target charts
|
|
933
|
+
|
|
934
|
+
`BulletChart` compares a nullable actual `value` with a finite `target` and optional
|
|
935
|
+
labeled `ranges`. A strong actual bar, target marker, readable value labels, and expandable exact
|
|
936
|
+
data work together. Domains include zero and all measurements; invalid inputs fail closed.
|
|
937
|
+
Invalid measurements do not reach `formatValue`.
|
|
938
|
+
Null values stay distinct from zero. See the [chart guide](https://github.com/santi020k/lumen/blob/main/docs/data-visualization.md#actual-values-and-targets)
|
|
939
|
+
for the input, localization, and domain contracts.
|
|
940
|
+
|
|
941
|
+
### Rankings and paired comparisons
|
|
942
|
+
|
|
943
|
+
Use `LollipopChart` for zero-based rankings and `DumbbellChart` for paired measurements (native
|
|
944
|
+
`LumenLollipopChart` and `LumenDumbbellChart`). Supply ordered comparison data with `id`, `label`,
|
|
945
|
+
nullable `value`, optional nullable `reference`, and optional `tone`. Both charts preserve missing
|
|
946
|
+
values and expose exact data. See the [shared visualization contract](https://github.com/santi020k/lumen/blob/main/docs/data-visualization.md#rankings-and-paired-comparisons).
|
|
947
|
+
|
|
948
|
+
### Calendar activity, ordered stages and distributions
|
|
949
|
+
|
|
950
|
+
`CalendarHeatmap`, `FunnelChart`, and `BoxPlot` share validated geometry with every Lumen adapter.
|
|
951
|
+
CalendarHeatmap takes date-only UTC `startDate`/`endDate`, nullable `{ date, value }` data and optional
|
|
952
|
+
`weekStartsOn` (0 for Sunday or 1 for Monday). It fills omitted dates as missing, keeps zero distinct,
|
|
953
|
+
and limits the inclusive range to 3,660 days. `weekdayLabels` always indexes Sunday through Saturday;
|
|
954
|
+
`formatDate` customizes readable dates without changing their identity.
|
|
955
|
+
|
|
956
|
+
FunnelChart takes ordered `{ id, label, value, tone? }` stages with nonnegative nullable values.
|
|
957
|
+
Stages retain the supplied order, including increasing values; the chart derives no conversion rates.
|
|
958
|
+
BoxPlot takes precomputed `{ id, label, min, q1, median, q3, max, outliers?, tone? }` statistics.
|
|
959
|
+
Statistics must be ordered and finite, or all five must be null for a missing row. Explicit domains
|
|
960
|
+
must contain all observations and outliers. `statisticLabels` localizes the six statistic names.
|
|
961
|
+
|
|
962
|
+
All three accept `formatValue`, chart `labels`, `summary`, and `showTable` (default true).
|
|
963
|
+
Exact data and missing measurements remain readable; invalid input fails closed instead of dropping
|
|
964
|
+
observations or clipping the domain. Prefer retaining the data table for complete visual inspection.
|
|
965
|
+
|
|
966
|
+
```tsx
|
|
967
|
+
import { BoxPlot, CalendarHeatmap, FunnelChart } from '@santi020k/lumen-react'
|
|
968
|
+
|
|
969
|
+
<CalendarHeatmap heading="Daily visits" startDate="2026-01-01" endDate="2026-01-31"
|
|
970
|
+
data={[{ date: '2026-01-01', value: 42 }]} />
|
|
971
|
+
<FunnelChart heading="Checkout stages" data={[
|
|
972
|
+
{ id: 'view', label: 'Viewed', value: 120 },
|
|
973
|
+
{ id: 'paid', label: 'Paid', value: 32 }
|
|
974
|
+
]} />
|
|
975
|
+
<BoxPlot heading="Response times" data={[
|
|
976
|
+
{ id: 'api', label: 'API', min: 20, q1: 45, median: 60, q3: 90, max: 140, outliers: [210] }
|
|
977
|
+
]} />
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
## Hook state updates
|
|
981
|
+
|
|
982
|
+
Public hook setters accept React functional updates. In uncontrolled mode, consecutive calls in
|
|
983
|
+
one event compose against the latest pending value. Change callbacks run once per setter call,
|
|
984
|
+
including under Strict Mode. Controlled values remain owned by the application.
|
|
985
|
+
|
|
986
|
+
`useToast().dismiss()` closes only the newest open toast. Pass an ID to dismiss a specific toast.
|
|
987
|
+
|
|
988
|
+
Highlighted Code updates generated region labels and removes its generated focus attributes when
|
|
989
|
+
wrapping is enabled, while preserving consumer-owned accessibility attributes.
|
|
990
|
+
|
|
991
|
+
## Advanced table views
|
|
992
|
+
|
|
993
|
+
`DataTableView` is an opt-in TanStack Table companion for application-owned record tables. It adds
|
|
994
|
+
search, exact column filters, column visibility, density, pagination and controlled sorting state
|
|
995
|
+
while preserving your cells, details, actions and query ownership. Column keys must be nonempty
|
|
996
|
+
and unique; column labels, accessors, boolean flags and dense filter-option arrays are validated before
|
|
997
|
+
controls are constructed. Restored controlled and default snapshots require string search/filter values,
|
|
998
|
+
boolean visibility/sort directions, valid density and integer pagination; malformed state is rejected
|
|
999
|
+
before table processing. Import it from
|
|
1000
|
+
`@santi020k/lumen-react/components/data-table-view` or the package root. Load
|
|
1001
|
+
`@santi020k/lumen-react/styles/data-table-view.css` after the base stylesheet. See the
|
|
1002
|
+
[composition and server-mode guide](https://github.com/santi020k/lumen/blob/main/docs/data-table-views.md).
|
|
1003
|
+
|
|
1004
|
+
Existing `Table` and `DataTable` APIs remain available. This integration is React-specific and does
|
|
1005
|
+
not change the Astro or Elements runtime.
|
|
1006
|
+
## Advanced form workflows
|
|
1007
|
+
|
|
1008
|
+
Use the optional `@santi020k/lumen-react/forms` entry point for validation, dependent fields,
|
|
1009
|
+
unsaved edit tracking, step navigation, stable repeatable rows, and cancelable asynchronous checks.
|
|
1010
|
+
Controls associated from outside the form through `form="id"` participate in edit tracking,
|
|
1011
|
+
blur validation and dependent-field validation. Portaled controls use React form callbacks without
|
|
1012
|
+
repeating validation through native document listeners. Each native edit is processed once, and
|
|
1013
|
+
controls associated with another form are ignored even when React bubbles their portal events.
|
|
1014
|
+
Adopted native controls retain checkbox, multiple-selection and file details in dirty-state tracking.
|
|
1015
|
+
|
|
1016
|
+
Accepted native reset buttons refresh dirty state after the browser restores defaults; canceled resets
|
|
1017
|
+
preserve the draft, errors, and attempted state, including cancellation by a native ancestor after
|
|
1018
|
+
React dispatch. `PromptComposer` keeps its standard `id` on the form for external submit controls
|
|
1019
|
+
and derives a separate labelled textarea ID.
|
|
1020
|
+
|
|
1021
|
+
See [composable form workflows](https://github.com/santi020k/lumen/blob/main/docs/powerful-forms.md). Applications retain schemas, financial
|
|
1022
|
+
rules, requests, draft storage, and authorization. Do not combine validation owners on one form.
|
|
1023
|
+
|
|
1024
|
+
`useResizable` accepts finite `panelCount` values up to 1,000. Fractions round down and negative values
|
|
1025
|
+
normalize to zero; non-finite or larger counts throw `RangeError` before allocating panel state.
|
|
1026
|
+
Context-menu item activation and keyboard focus follow the menu's owning document, including iframe
|
|
1027
|
+
portals. Date-range synchronization clamps an earlier end date before updating both input constraints.
|
|
1028
|
+
|
|
1029
|
+
## Device demonstrations
|
|
1030
|
+
|
|
1031
|
+
`DeviceFrame` presents slotted HTML, an image, or a titled iframe inside `macbook-pro`, `macbook-air`, `imac`,
|
|
1032
|
+
`iphone`, `pixel`, and `ipad-pro` frames, with generic `laptop`, `desktop`, `android`, and `tablet` options.
|
|
1033
|
+
Device-specific enclosures include a MacBook Pro display notch and full front edge, a tapered MacBook Air deck, curved iMac
|
|
1034
|
+
stand and chin, rounded phone glass with separate rails and buttons, and an iPad Pro with even
|
|
1035
|
+
bezels and no Home button. The generic `tablet` retains its classic enclosure.
|
|
1036
|
+
Shells are decorative and do not emulate device hardware. `orientation` selects portrait or landscape; `tone` selects
|
|
1037
|
+
light or dark chrome independently of the screen content. Use `color="white"`,
|
|
1038
|
+
`color="black"`, or a 3-, 4-, 6-, or 8-digit hex color such as `color="#a9b8ac"` for
|
|
1039
|
+
a custom hardware finish. `color` takes precedence over `tone`; invalid values fall back to the
|
|
1040
|
+
tone. The finish stays independent of the content theme. For CSS-driven updates, set
|
|
1041
|
+
`--ui-device-color` to a CSS color on the frame.
|
|
1042
|
+
|
|
1043
|
+
Iframe layouts use the preset screen viewport and scale to the available width. Override
|
|
1044
|
+
`screenWidth` and `screenHeight` for a custom viewport (1–16384 CSS pixels). Slotted HTML shares
|
|
1045
|
+
the host viewport; container queries can adapt it to the screen. Images preserve their proportions.
|
|
1046
|
+
`scroll={false}` clips HTML overflow; an iframe manages its own scrolling.
|
|
1047
|
+
|
|
1048
|
+
Supply image alternative text and iframe titles. Consumers own iframe `sandbox`, `allow`,
|
|
1049
|
+
loading, and referrer policies. Remote sites can refuse embedding through their response headers.
|
|
1050
|
+
The decorative shell does not alter focus or intercept interactions. Camera and home-indicator
|
|
1051
|
+
details occupy separate chrome outside live HTML and iframe viewports. Direct phone images extend
|
|
1052
|
+
under the decorative camera and home indicator for a full-bleed presentation.
|
|
1053
|
+
Screen presets are 1280 × 800 for MacBook Pro and MacBook Air, 1440 × 810 for iMac, 390 × 844 for iPhone,
|
|
1054
|
+
412 × 915 for Pixel, and 834 × 1194 for iPad Pro (1194 × 834 in landscape). These are demonstration
|
|
1055
|
+
viewports, not physical display specifications.
|
|
1056
|
+
|
|
1057
|
+
```tsx
|
|
1058
|
+
import { DeviceFrame } from '@santi020k/lumen-react/components/device-frame'
|
|
1059
|
+
|
|
1060
|
+
<DeviceFrame device="laptop" screenWidth={1440} screenHeight={900}>
|
|
1061
|
+
<iframe src="/demo" title="Application demo" loading="lazy" />
|
|
1062
|
+
</DeviceFrame>
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
This component uses a client effect to maintain the scaled iframe viewport.
|
|
1066
|
+
## Visual interactions
|
|
1067
|
+
|
|
1068
|
+
`MotionGroup`, `ChartMotion`, `VisualEffect`, `PromptComposer`, `StreamMessage`, `SourceCitation`,
|
|
1069
|
+
`ToolActivity`, and `ApprovalCard` are exported by the main package. `Tabs` accepts `indicator` for
|
|
1070
|
+
an optional moving selection underline. See [visual interactions](https://github.com/santi020k/lumen/blob/main/docs/visual-interactions.md).
|
|
1071
|
+
Install `motion@^14.0.0` only when using `@santi020k/lumen-react/motion`; its Motion wrappers remain
|
|
1072
|
+
separate from normal imports.
|
|
1073
|
+
|
|
1074
|
+
## World map
|
|
1075
|
+
|
|
1076
|
+
WorldMap supports highlighted countries, location markers, dotted or solid styles, country selection,
|
|
1077
|
+
and theme customization. Use `initialView="highlighted"` (Elements: `initial-view`) to start with a
|
|
1078
|
+
regional view. Zoom toward the cursor with Ctrl/Cmd-scroll, or fit highlighted countries using the
|
|
1079
|
+
map controls. Import geography explicitly from
|
|
1080
|
+
`@santi020k/lumen-core/world-map-data`; it is excluded from root exports. See the
|
|
1081
|
+
[WorldMap usage guide](https://github.com/santi020k/lumen/blob/main/docs/world-map.md) for adapter examples, events, localization,
|
|
1082
|
+
accessibility, and customization.
|
|
1083
|
+
|
|
1084
|
+
For controlled selection, pair `selectedCountry` with `onSelectedCountryChange(countryId)` and
|
|
1085
|
+
store the requested value in application state. An empty string clears the selection while keeping
|
|
1086
|
+
the map controlled. `onCountrySelect(detail)` remains the country-detail callback for nonempty selections.
|
|
1087
|
+
|
|
1088
|
+
## Operational workflows
|
|
1089
|
+
|
|
1090
|
+
Extend `DataTableView` with inclusive numeric/date ranges and explicit page-scoped selection.
|
|
1091
|
+
Use `DataTableSavedViews` for named preferences through application-owned persistence callbacks;
|
|
1092
|
+
`parseDataTableViewState` validates external preferences without retaining records or selection.
|
|
1093
|
+
See [table views](https://github.com/santi020k/lumen/blob/main/docs/data-table-views.md) for server pagination and selection boundaries.
|
|
1094
|
+
|
|
1095
|
+
`useLumenReviewWorkflow` from the root or `/forms` guards review, confirmation, stale revisions,
|
|
1096
|
+
duplicate submission and uncertain outcomes. Compose it with the installable React
|
|
1097
|
+
`review-workflow`, `import-review` and `record-workspace` recipes.
|
|
1098
|
+
See [operational recipes](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md#installable-operational-workflows).
|
|
1099
|
+
|
|
1100
|
+
## Studio media workspace
|
|
1101
|
+
|
|
1102
|
+
Compose MediaViewport, MediaThumbnail, MediaFilmstrip and ImageComparison modes with the
|
|
1103
|
+
[Studio media workspace recipes](https://github.com/santi020k/lumen/blob/main/docs/studio-media-workspaces.md). Applications retain
|
|
1104
|
+
media loading, selection, adjustment algorithms, processing, export and persistence.
|
|
1105
|
+
|
|
1106
|
+
## Resources
|
|
1107
|
+
|
|
1108
|
+
| Guide | What you will find |
|
|
1109
|
+
| --- | --- |
|
|
1110
|
+
| [Consumer UI recipes](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md) | Complete product compositions and application-owned behavior. |
|
|
1111
|
+
| [React Hook Form adapters](https://github.com/santi020k/lumen/blob/main/packages/react-hook-form/README.md) | Managed fields, composite controls, and schema validation. |
|
|
1112
|
+
| [Import and icon performance](https://github.com/santi020k/lumen/blob/main/docs/import-and-icon-performance.md) | Selective imports and reproducible bundle measurements. |
|
|
1113
|
+
| [Contributing](https://github.com/santi020k/lumen/blob/main/CONTRIBUTING.md) | Setup, checks, and contribution workflow. |
|
|
1114
|
+
| [Release history](https://github.com/santi020k/lumen/releases) | Published releases and version notes. |
|
|
1115
|
+
|
|
1116
|
+
Part of [Lumen UI](https://lumen.santi020k.com), created by [Santiago Molina](https://santi020k.com).
|
|
1117
|
+
Licensed under [MIT](https://github.com/santi020k/lumen/blob/main/LICENSE); third-party artwork retains its own notices.
|