@santi020k/lumen-elements 3.0.1 → 4.1.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.
Files changed (66) hide show
  1. package/README.md +518 -5
  2. package/dist/bullet-chart-html.d.ts +5 -0
  3. package/dist/bullet-chart-html.d.ts.map +1 -0
  4. package/dist/bullet-chart-html.js +56 -0
  5. package/dist/chart-activation.d.ts +15 -0
  6. package/dist/chart-activation.d.ts.map +1 -0
  7. package/dist/chart-activation.js +93 -0
  8. package/dist/chart-html.d.ts +22 -0
  9. package/dist/chart-html.d.ts.map +1 -0
  10. package/dist/chart-html.js +1 -0
  11. package/dist/comparison-chart-html.d.ts +4 -0
  12. package/dist/comparison-chart-html.d.ts.map +1 -0
  13. package/dist/comparison-chart-html.js +36 -0
  14. package/dist/components/ai-surfaces.d.ts +115 -0
  15. package/dist/components/ai-surfaces.d.ts.map +1 -0
  16. package/dist/components/ai-surfaces.js +270 -0
  17. package/dist/components/button.d.ts +55 -2
  18. package/dist/components/button.d.ts.map +1 -1
  19. package/dist/components/button.js +110 -2
  20. package/dist/components/card.d.ts +6 -0
  21. package/dist/components/card.d.ts.map +1 -1
  22. package/dist/components/card.js +6 -1
  23. package/dist/components/combobox.d.ts +1 -2
  24. package/dist/components/combobox.d.ts.map +1 -1
  25. package/dist/components/combobox.js +27 -121
  26. package/dist/components/dashboard.d.ts +41 -0
  27. package/dist/components/dashboard.d.ts.map +1 -0
  28. package/dist/components/dashboard.js +88 -0
  29. package/dist/components/device-frame.d.ts +31 -0
  30. package/dist/components/device-frame.d.ts.map +1 -0
  31. package/dist/components/device-frame.js +95 -0
  32. package/dist/components/foundations.d.ts +58 -18
  33. package/dist/components/foundations.d.ts.map +1 -1
  34. package/dist/components/foundations.js +160 -9
  35. package/dist/components/image-comparison.d.ts +33 -0
  36. package/dist/components/image-comparison.d.ts.map +1 -0
  37. package/dist/components/image-comparison.js +144 -0
  38. package/dist/components/media-selection.d.ts +41 -0
  39. package/dist/components/media-selection.d.ts.map +1 -0
  40. package/dist/components/media-selection.js +114 -0
  41. package/dist/components/media-viewport.d.ts +30 -0
  42. package/dist/components/media-viewport.d.ts.map +1 -0
  43. package/dist/components/media-viewport.js +108 -0
  44. package/dist/components/virtual-list.d.ts +38 -0
  45. package/dist/components/virtual-list.d.ts.map +1 -0
  46. package/dist/components/virtual-list.js +30 -0
  47. package/dist/components/visual-interactions.d.ts +65 -0
  48. package/dist/components/visual-interactions.d.ts.map +1 -0
  49. package/dist/components/visual-interactions.js +91 -0
  50. package/dist/components/world-map.d.ts +46 -0
  51. package/dist/components/world-map.d.ts.map +1 -0
  52. package/dist/components/world-map.js +312 -0
  53. package/dist/consumer-behaviors.d.ts +36 -0
  54. package/dist/consumer-behaviors.d.ts.map +1 -0
  55. package/dist/consumer-behaviors.js +1 -0
  56. package/dist/define.d.ts +229 -6
  57. package/dist/define.d.ts.map +1 -1
  58. package/dist/define.js +1 -1
  59. package/dist/element-base.js +1 -1
  60. package/dist/expanded-chart-html.d.ts +9 -0
  61. package/dist/expanded-chart-html.d.ts.map +1 -0
  62. package/dist/expanded-chart-html.js +61 -0
  63. package/dist/index.d.ts +2 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/package.json +34 -6
  66. package/styles/critical.css +696 -66
package/README.md CHANGED
@@ -1,9 +1,80 @@
1
- # @santi020k/lumen-elements
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 · Web Components</h1>
11
+
12
+ <p align="center">Custom elements · Browser-native composition · Shared styles</p>
13
+
14
+ <p align="center">
15
+ <a href="https://www.npmjs.com/package/@santi020k/lumen-elements"><img src="https://img.shields.io/npm/v/@santi020k/lumen-elements?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/elements">Documentation</a>
21
+ ·
22
+ <a href="https://www.npmjs.com/package/@santi020k/lumen-elements">npm</a>
23
+ ·
24
+ <a href="https://github.com/santi020k/lumen/tree/main/packages/elements">Source</a>
25
+ ·
26
+ <a href="https://github.com/santi020k/lumen/issues">Issues</a>
27
+ </p>
28
+
29
+ **Package:** `@santi020k/lumen-elements`
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
+ - [Appearance presets](#appearance-presets)
38
+ - [Usage](#usage)
39
+ - [Language selection](#language-selection)
40
+ - [Forms](#forms)
41
+ - [Context navigation](#context-navigation)
42
+ - [Statistics](#statistics)
43
+ - [Data visualization](#data-visualization)
44
+ - [Optimized images](#optimized-images)
45
+ - [Interactive behavior](#interactive-behavior)
46
+ - [Motion](#motion)
47
+ - [Glass surfaces](#glass-surfaces)
48
+ - [Consumer composition recipes](#consumer-composition-recipes)
49
+ - [Exact amount fields](#exact-amount-fields)
50
+ - [Phone presentation in v4](#phone-presentation-in-v4)
51
+ - [Combobox keyboard behavior](#combobox-keyboard-behavior)
52
+ - [Content flow](#content-flow)
53
+ - [Attachment composition](#attachment-composition)
54
+ - [Dashboard composition](#dashboard-composition)
55
+ - [Combobox lifecycle](#combobox-lifecycle)
56
+ - [Device demonstrations](#device-demonstrations)
57
+ - [Visual interactions and product blocks](#visual-interactions-and-product-blocks)
58
+ - [World map](#world-map)
59
+ - [Studio media workspace](#studio-media-workspace)
60
+ - [Resources](#resources)
61
+
62
+ </details>
2
63
 
3
64
  Web Components for Lumen UI.
4
65
 
5
66
  This package registers standards-based custom elements for the shared Lumen primitive catalog.
6
67
 
68
+ `ImageComparison` form resets restore the latest externally configured `value`; user range input
69
+ does not replace that reset baseline.
70
+
71
+ See the [shared web form contracts](https://github.com/santi020k/lumen/blob/main/docs/form-controls.md) for value ownership, reset,
72
+ submission, disabled state, and event behavior.
73
+
74
+ Form controls use `visualSize` (`visual-size` in Elements) with `default`, `sm` and `lg`.
75
+ Select, PhoneInput and Segmented follow Input and NativeSelect; numeric input/select `size` keeps
76
+ 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).
77
+
7
78
  ## Install
8
79
 
9
80
  ```bash
@@ -31,6 +102,10 @@ The stylesheet defaults `--ui-font` to `"Montserrat", "Avenir Next", "Segoe UI",
31
102
  It declares the family stack but does not bundle or load font files. Load Montserrat once through
32
103
  your preferred delivery path, or override `--ui-font` in application CSS.
33
104
 
105
+ ## Appearance presets
106
+
107
+ Wrap registered components in `data-lumen-preset="studio"`; ThemeBuilder preset buttons use `data-ui-theme-preset`. See [appearance presets](https://github.com/santi020k/lumen/blob/main/docs/appearance-presets.md).
108
+
34
109
  ## Usage
35
110
 
36
111
  Register the elements once per custom-element registry, then use `lumen-*` tags anywhere HTML is
@@ -45,8 +120,8 @@ independently from the document registry.
45
120
  </script>
46
121
 
47
122
  <lumen-card>
48
- <label for="email">Email</label>
49
- <lumen-input id="email" type="email" placeholder="you@example.com"></lumen-input>
123
+ <lumen-label id="email-label">Email</lumen-label>
124
+ <lumen-input aria-labelledby="email-label" id="email" type="email" placeholder="you@example.com"></lumen-input>
50
125
  <lumen-button>Subscribe</lumen-button>
51
126
  </lumen-card>
52
127
  ```
@@ -85,6 +160,18 @@ selection, dismissal, and focus behavior without importing the complete catalog.
85
160
  still use `defineLumenElements`; do not replace the full entrypoint when the application needs a
86
161
  behavior-backed element that does not yet have a granular module.
87
162
 
163
+ VirtualList also has an independent registration entrypoint, including windowing and cleanup:
164
+
165
+ ```ts
166
+ import { defineLumenVirtualList } from '@santi020k/lumen-elements/components/virtual-list'
167
+
168
+ defineLumenVirtualList()
169
+ ```
170
+
171
+ It registers the same constructor as the full catalog and accepts an optional registry. Pair it
172
+ with the matching stylesheet. `pnpm run measure:selective-imports` compares this entry with the
173
+ complete catalog using an equivalent single-component consumer.
174
+
88
175
  Foundation-only pages can register fifteen layout, composition, and accessibility elements as one
89
176
  small implementation-level bundle:
90
177
 
@@ -222,6 +309,19 @@ or `variant="glass"` for selective translucency.
222
309
 
223
310
  ## Data visualization
224
311
 
312
+ The web visualization milestone adds `WaterfallChart` for signed changes and explicit totals, and
313
+ `Histogram` for precomputed numeric bins (`frequency="density"` for unequal widths). Line charts
314
+ support explicit continuous axes, annotations, optional keyboard/pointer/touch inspection, and
315
+ synchronized cursors. Heatmaps show labeled axes, a color legend, and explicit missing cells.
316
+ Heatmap JSON is validated as a complete collection: a malformed row rejects the dataset instead
317
+ of displaying a partial result. Null and nonfinite numeric measurements remain missing cells.
318
+ See the [visualization contracts](https://github.com/santi020k/lumen/blob/main/docs/data-visualization.md) and
319
+ [interactive web example](https://lumen.santi020k.com/docs/web/data-visualization).
320
+
321
+ Use `<lumen-histogram bins="...">` and `<lumen-waterfall-chart data="...">` with JSON arrays.
322
+ `<lumen-line-chart interactive x-scale="time" sync-group="report">` emits
323
+ `ui:chart-cursor-change` with `{ x }`. Set `annotations` to a JSON array.
324
+
225
325
  Set serializable `series` data through the JavaScript property for application data. The JSON
226
326
  attribute form is useful for static HTML and server output.
227
327
 
@@ -276,6 +376,37 @@ document-level toast controller events.
276
376
 
277
377
  ## Interactive behavior
278
378
 
379
+ Internal behavior methods use native JavaScript private members. Public properties, events and
380
+ registration APIs retain their existing contracts.
381
+
382
+ Disclosure keyboard navigation skips hidden or inert regions, invisible controls, and native
383
+ disabled controls, including a disabled fieldset. Available controls in a fieldset's first legend
384
+ retain their native keyboard behavior; removing `inert` makes a region available again.
385
+
386
+ Enhanced DatePicker controls mirror native input `aria-invalid`, `aria-describedby`, and
387
+ `aria-errormessage` onto the visible trigger, including dynamic changes. Valid updates and
388
+ uncanceled form resets clear generated errors while preserving explicit application errors.
389
+
390
+ `lumen-skeleton` and `lumen-spinner` are decorative (`aria-hidden="true"`) until they have an
391
+ `aria-label` or `aria-labelledby`, then they become `role="status"`; explicit `aria-hidden` and
392
+ `role` values are kept. `lumen-skeleton` and `lumen-progress` render as blocks. Skeleton
393
+ `shape`, `width`, `height`, and `animation` attributes update and reset when changed or removed.
394
+ A `loading` `lumen-button` also sets `aria-busy="true"`.
395
+
396
+ Mentions keeps suggestion navigation on the textarea through `aria-activedescendant`; suggestion
397
+ buttons are excluded from the Tab sequence while Enter and pointer selection still insert a mention.
398
+
399
+ Select follows the Astro keyboard contract: Space opens the listbox or selects the focused option
400
+ unless it continues an active typeahead query, and moving focus outside the field closes the
401
+ listbox. The listbox shares the trigger's accessible name. Adding, removing, relabeling, or
402
+ disabling native options re-renders the listbox while preserving focus on an available option.
403
+ Toggling the native select's `disabled` state updates the trigger.
404
+
405
+ React and Elements can share a page. React DatePicker, Calendar, and InputOTP render
406
+ `data-ui-owner="react"` because React owns their behavior, so the document-wide Elements enhancers
407
+ skip them whether elements are registered before or after the React island mounts. Standards-based
408
+ `data-ui-*` markup without an owner, and `lumen-*` elements, are enhanced as before.
409
+
279
410
  Registering the elements wires behavior-heavy primitives without a framework runtime. DataTable,
280
411
  Dialog, Popover, DropdownMenu, ContextMenu, Tabs, Select, ThemeBuilder, Toast, Tooltip, forms,
281
412
  Calendar, InputOTP, DateRangePicker, RichTextEditor, Schedule, Resizable, and VirtualList track the
@@ -283,6 +414,10 @@ Astro runtime's data event, validation, calendar grids, OTP segmentation, date r
283
414
  text command, context menu, schedule drag/drop, resizable pane sizing, theme export, ARIA,
284
415
  keyboard, Escape, dismissal, and toast controller semantics while keeping markup declarative and
285
416
  Declarative-Shadow-DOM friendly.
417
+ Calendar attribute updates preserve the focused day in the owning document after iframe adoption.
418
+ Calendar form resets restore the latest configured `value` attribute; interactive date selections
419
+ do not replace that reset baseline. Form error summaries can focus associated native controls
420
+ outside the form subtree when their `form` attribute names that form.
286
421
  FileUpload, Tour, Anchor, CopyButton, Progress, ScrollProgress, Transfer, Mentions, Cascader, and TreeSelect also run directly through
287
422
  their registered custom elements; no Astro runtime or host controller is required.
288
423
  Rich text controls may provide `data-ui-editor-value` for commands such as `formatBlock` and
@@ -291,6 +426,9 @@ formatting shortcuts, and keep toggle controls synchronized through `aria-presse
291
426
  `lumen-tabs` keeps the selected trigger visible in narrow horizontal lists and emits
292
427
  `ui:tabs-change`; import `LumenTabsChangeDetail` or `LumenTabsChangeEvent` for its typed detail.
293
428
 
429
+ Nested `lumen-tabs` and `lumen-code-tabs` keep independent selection and panel state. Keyboard
430
+ navigation skips disabled triggers and stays within the active tab group.
431
+
294
432
  `<lumen-kanban-board>` and `<lumen-kanban-column value="…">` provide the same controlled board
295
433
  contract. Mark ordinary card items with `data-ui-kanban-item` and put `data-ui-kanban-handle` on a
296
434
  dedicated button. The board emits the cancellable `ui:kanban-move-request` event for keyboard,
@@ -326,7 +464,7 @@ Use `<lumen-error-state>` when a region or page cannot show its primary content.
326
464
  heading, explanation, optional safe reference, and recovery actions in light DOM, label the region
327
465
  with `aria-labelledby`, and use the documented `data-slot="error-state-*"` hooks. Lumen presents the
328
466
  failure; application code owns exception capture, logging, and retry policy. See the repository
329
- [Web Components error-handling guide](../../docs/error-handling.md#web-components) for the complete
467
+ [Web Components error-handling guide](https://github.com/santi020k/lumen/blob/main/docs/error-handling.md#web-components) for the complete
330
468
  light-DOM structure, ARIA ownership, retry boundary, and verification guidance.
331
469
 
332
470
  ## Motion
@@ -345,6 +483,36 @@ The elements adapter exposes the same motion vocabulary as Astro and React. Use
345
483
  <lumen-animated-number decimals="1" suffix="%" value="99.8"></lumen-animated-number>
346
484
  ```
347
485
 
486
+ ### Elements labels and dialogs
487
+
488
+ `lumen-input` owns an internal native control. Name that control using `aria-labelledby` pointing
489
+ at a visible label, or `aria-label` on the host. A native label's `for` pointing only at the custom
490
+ host does not name the internal input. Use the public `lumen-label` for visible label styling.
491
+ Do not type a custom host as `HTMLInputElement` or `HTMLButtonElement`; use its exported element
492
+ class and runtime narrowing when accessing element-specific methods.
493
+
494
+ Use `lumen-dialog` as the behavior owner. Its public methods are `show(trigger?)` and `close()`,
495
+ not `showModal()` on the custom host. A native `dialog` child is its documented modal contract:
496
+
497
+ ```html
498
+ <lumen-button data-ui-dialog-trigger="profile-dialog">Edit profile</lumen-button>
499
+ <lumen-dialog id="profile-dialog">
500
+ <dialog aria-labelledby="profile-title">
501
+ <h2 id="profile-title">Profile settings</h2>
502
+ <lumen-field>
503
+ <lumen-label id="profile-name-label">Display name</lumen-label>
504
+ <lumen-input aria-labelledby="profile-name-label" value="Ada"></lumen-input>
505
+ </lumen-field>
506
+ <lumen-button data-ui-dialog-close type="button">Cancel</lumen-button>
507
+ </dialog>
508
+ </lumen-dialog>
509
+ ```
510
+
511
+ Register `Button`, `Dialog`, `Field`, `Input`, and `Label` through `defineLumenElements` before use.
512
+ The dialog behavior focuses its first focusable control, handles Escape, traps focus, and returns
513
+ focus to its trigger. Keep draft state in the form control or application; closing does not reset it.
514
+ Do not replace this behavior with a parallel native-dialog controller.
515
+
348
516
  ## Glass surfaces
349
517
 
350
518
  Load `@santi020k/lumen-elements/styles.css` once, register the elements, then use the shared glass
@@ -360,7 +528,352 @@ attributes.
360
528
 
361
529
  ## Consumer composition recipes
362
530
 
363
- See [consumer UI recipes](../../docs/consumer-ui-recipes.md) for static React icons, responsive
531
+ See [consumer UI recipes](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md) for static React icons, responsive
364
532
  record tables, keyboard-aware native sheets, whole-unit amount fields, adaptive editors, and
365
533
  asynchronous action states. Each recipe identifies the public primitives and the behavior that
366
534
  remains owned by the application.
535
+
536
+ ## Exact amount fields
537
+
538
+ `lumen-amount-field` creates a visible localized input and a named hidden input containing the
539
+ complete ASCII decimal string. `ui:amount-change` reports `{ draft, value }`; incomplete drafts
540
+ have an undefined value. A host ID `amount` gives its visible input ID `amount-input` for labels.
541
+
542
+ ```html
543
+ <lumen-amount-field name="amount" locale="es-CO" default-value="1234.50"
544
+ aria-label="Amount COP"></lumen-amount-field>
545
+ ```
546
+
547
+ See [consumer workflows](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md#executable-consumer-workflows) for
548
+ validation, reset and `auto-scroll` activity feeds.
549
+
550
+ ### Accessible code examples
551
+
552
+ `<lumen-code variant="block" copy>` enhances its native `pre > code` child with a
553
+ copy button. Use `copy-label`, `copied-label`, and `error-label` for clipboard
554
+ feedback, and `code-label` to name its keyboard-scrollable source region. The same
555
+ labels can be placed on an enclosing `<lumen-code-tabs>`; child labels take
556
+ precedence. Copy emits `ui:copy-success` or `ui:copy-error` and announces feedback
557
+ in a live region. Clipboard failures leave the source available for manual copy.
558
+
559
+ Unwrapped `pre` children receive `tabindex="0"` and region semantics while keeping
560
+ authored accessible names. Generated names follow `code-label` updates and the current enclosing code tabs after reconnecting. Changing to `wrap="true"` removes only enhancer-added focus attributes.
561
+ Disabling `copy` removes only generated copy controls and cancels pending feedback.
562
+ With `wrap="true"`, the component does not add an extra
563
+ tab stop. Keep native `pre` and `code` children rather than placing source text in
564
+ HTML attributes.
565
+
566
+ ### Virtual list and editor ownership
567
+
568
+ `VirtualList` displays fixed-height rows with inert spacers that retain the full scroll extent.
569
+ Rows stay mounted; use pagination when the initial DOM cost matters. Scrolling, resizing, sizing
570
+ changes and direct row changes refresh the window. Focused rows remain available. See the
571
+ [fixed-height list contract](https://github.com/santi020k/lumen/blob/main/docs/ai-usage.md#fixed-height-virtual-lists).
572
+
573
+ External rich-text engines should handle the cancelable `ui:editor-command-request` event before
574
+ execution and use `ui:editor-command` only for completion notifications. React also supports
575
+ `useRichTextEditor({ commandHandler })`. Disable native toolbar state syncing when the external
576
+ engine owns it. See the [editor guidance](https://github.com/santi020k/lumen/blob/main/docs/ai-usage.md).
577
+
578
+ ## Phone presentation in v4
579
+
580
+ Phone inputs bundle the same offline flag artwork on every platform. The selected country shows
581
+ its flag and calling code inside one continuous input border. Country names remain in the native
582
+ picker and its accessible name; flags are supplementary. Unknown flag codes fall back to text.
583
+
584
+ Astro and React `PhoneInput` accept `disabled`, `readOnly`, `required`, `errorMessage`,
585
+ `showValidationError`, and `inputProps`. Their `id` targets the number input in v4; React also
586
+ accepts `inputRef`. Web Components use `disabled`, `readonly`, `required`, `error-message`,
587
+ `show-validation-error="false"`, and `input-id`, with native input attributes on the host.
588
+ Both controls lock together and validation remains associated with the input.
589
+
590
+ The `phone-input`, `phone-country`, and `country-flag` styling parts plus `--ui-phone-height`,
591
+ `--ui-phone-padding`, and `--ui-phone-country-gap` replace consumer CSS overlays.
592
+
593
+ Astro and React also export `CountryFlag` (`regionCode`, optional `decorative`) and `PhoneNumber`
594
+ (`value: LumenPhoneNumber`, optional `link`). A telephone link is rendered only for a complete
595
+ E.164 value. Use the model returned by the phone normalizer; keep domain persistence in your app.
596
+ Artwork attribution is shipped with the core package in `PHONE_FLAG_LICENSE.txt`.
597
+
598
+ When `PhoneInput` is registered, `defineLumenElements` also registers `lumen-country-flag`
599
+ (`country`, `decorative`, optional `label`) and `lumen-phone-number` (`country`, `value`, `link`,
600
+ optional `locale`). The read-only element normalizes its string value before creating a tel link.
601
+
602
+ ## Combobox keyboard behavior
603
+
604
+ In v4, Combobox retains input focus and exposes its active option through `aria-activedescendant`.
605
+ Enter commits an active option; text editing and composition remain native. Escape dismisses one
606
+ 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)
607
+ for dynamic options, controlled inputs and migration guidance.
608
+
609
+ ## Content flow
610
+
611
+ Stack and Grid own sibling spacing. Their gap accepts `related`, `group` (default) and `section`,
612
+ or canonical `none`, `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl` sizes. Card owns the inset and gap
613
+ between its visible parts; use `density="compact"`, `"comfortable"` (default) or `"spacious"`.
614
+ Elements uses the same names as attributes. Use a nested Stack for CardContent groups and Field
615
+ for label/control/feedback. See [content flow](https://github.com/santi020k/lumen/blob/main/docs/content-flow.md) and the
616
+ [v4 migration guide](https://github.com/santi020k/lumen/blob/main/docs/migrating-to-lumen.md) for ownership and changed explicit gaps.
617
+
618
+ ### Reading and complete compositions
619
+
620
+ Prose and Typography trim outer child margins and separate headings from preceding text.
621
+ Container gutters grow from 16px to 32px with viewport width; override `--ui-container-gutter`
622
+ when a product needs fixed gutters. Card allows interactive overflow; use AspectRatio to clip media.
623
+ Install `content-flow-header`, `content-flow-settings`, `content-flow-list` or `content-flow-actions`
624
+ with `lumen add <recipe> --target astro|react|elements`. MCP returns the same complete examples.
625
+ Connect application actions and replace sample IDs before reuse. See
626
+ [content flow](https://github.com/santi020k/lumen/blob/main/docs/content-flow.md) for composition and migration guidance.
627
+
628
+ ### Large fixed-height collections
629
+
630
+ `VirtualList` supports an empty `mode="data"` root with the public Core data controller.
631
+ Only the visible window, overscan and focused neighbors mount. Stable keys retain row identity;
632
+ applications own offscreen editing state. See [data rendering](https://github.com/santi020k/lumen/blob/main/docs/virtual-list-data.md) for
633
+ setup, lifecycle, accessibility and the mounted-mode tradeoff.
634
+
635
+ Forms validate native controls associated through the `form` attribute even outside the form tree.
636
+ Timed toasts retain their remaining duration until both pointer hover and keyboard focus leave.
637
+
638
+ ### Compound dialog tasks
639
+
640
+ Register `DialogHeader`, `DialogTitle`, `DialogBody`, `DialogFooter`, and
641
+ `DialogClose` with `Dialog`. Keep the body directly inside the dialog host for
642
+ independent scrolling. Use a native heading inside the title host and a native
643
+ button inside the close host; their semantics and disabled behavior remain native.
644
+ Associate the heading id with the dialog's `aria-labelledby`.
645
+
646
+ ```html
647
+ <lumen-dialog aria-labelledby="record-title">
648
+ <lumen-dialog-header>
649
+ <lumen-dialog-title><h2 id="record-title">Edit record</h2></lumen-dialog-title>
650
+ </lumen-dialog-header>
651
+ <lumen-dialog-body><form id="record-form"><label>Name <input name="name"></label></form></lumen-dialog-body>
652
+ <lumen-dialog-footer>
653
+ <lumen-dialog-close><button type="button">Cancel</button></lumen-dialog-close>
654
+ <button type="submit" form="record-form">Save</button>
655
+ </lumen-dialog-footer>
656
+ </lumen-dialog>
657
+ ```
658
+
659
+ A cancelled click or disabled native button does not dismiss the dialog. Nested
660
+ close actions only dismiss their own dialog. `lumen-file-upload` accepts
661
+ `selected-files-label` containing `{count}` for localized multiple-file feedback.
662
+
663
+ ### Rich description rows
664
+
665
+ Register `Descriptions`, `DescriptionItem`, `DescriptionTerm`, and `DescriptionDetail`
666
+ to compose rich values. The item, term, and detail hosts expose `group`, `term`, and
667
+ `definition` roles respectively. Use a labeled group for the overall collection and
668
+ associate the detail with its term when the relationship needs an explicit label.
669
+ These custom hosts provide ARIA semantics; they are not native `dl`, `dt`, or `dd` tags.
670
+
671
+ ```html
672
+ <lumen-descriptions role="group" aria-label="Record details">
673
+ <lumen-description-item>
674
+ <lumen-description-term id="status-label">Status</lumen-description-term>
675
+ <lumen-description-detail aria-labelledby="status-label"><strong>Active</strong></lumen-description-detail>
676
+ </lumen-description-item>
677
+ </lumen-descriptions>
678
+ ```
679
+
680
+ For native definition-list markup, place a complete native `dl` with `div`, `dt`,
681
+ and `dd` children inside `lumen-descriptions` instead of nesting custom hosts inside the `dl`.
682
+
683
+ ### Stepper progress
684
+
685
+ `lumen-stepper` is a generic element: it applies the shared `ui-stepper` presentation class and
686
+ `ui-stepper--vertical` for `orientation="vertical"`, but owns no step generation or current-step
687
+ behavior. Provide the complete step markup as light-DOM children:
688
+
689
+ ```html
690
+ <lumen-stepper role="list" aria-label="Setup steps">
691
+ <div class="ui-stepper__step" data-state="complete" role="listitem">
692
+ <span class="ui-stepper__marker">1</span>
693
+ <span class="ui-stepper__content"><span class="ui-stepper__title">Account</span></span>
694
+ </div>
695
+ <div aria-current="step" class="ui-stepper__step" data-state="current" role="listitem">
696
+ <span class="ui-stepper__marker">2</span>
697
+ <span class="ui-stepper__content"><span class="ui-stepper__title">Workspace</span></span>
698
+ </div>
699
+ </lumen-stepper>
700
+ ```
701
+
702
+ Each step is a native `div` with `role="listitem"`, `class="ui-stepper__step"`, and
703
+ `data-state="complete" | "current" | "upcoming"`. Give the current step `aria-current="step"`. Each
704
+ step holds a `ui-stepper__marker` span and a `ui-stepper__content` span containing a
705
+ `ui-stepper__title` span and an optional `ui-stepper__description` span.
706
+
707
+ ## Attachment composition
708
+
709
+ Use `AttachmentList` to group native `li` children and `AttachmentPreview` for browser-owned images
710
+ with localized loading, error, and unsupported-file states. Compose independent actions rather
711
+ than nesting controls inside a linked Attachment. The application retains file validation,
712
+ authorization, persistence, and object URL cleanup. See the
713
+ [attachment composition recipe](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md#attachment-previews-and-file-lists)
714
+ for adapter props, slots, child contracts, retry identity, and safe state events.
715
+
716
+ ### Chart datum actions
717
+
718
+ All seven data charts accept the opt-in `drilldown` attribute. Each plotted observation gains a
719
+ pointer target and a matching native button under an accessible disclosure, even with
720
+ `show-table="false"`. Listen for the bubbling, composed `ui:chart-datum-activate` event on the chart
721
+ host; its validated `LumenChartDatumActivationDetail` contains original data identities and values.
722
+ Missing measurements and invalid ranges have no actions; pie charts expose only positive slices.
723
+
724
+ ```html
725
+ <lumen-bar-chart drilldown explore-data-label="Explore chart data"
726
+ datum-action-prefix="Open details: " show-table="false"></lumen-bar-chart>
727
+ ```
728
+
729
+ Use the `explore-data-label` and `datum-action-prefix` attributes for localized text, or assign a
730
+ `datumActionFormatter(context)` property for a contextual label formatter. The exported
731
+ `LumenChartDatumActionsElement` type describes this host property contract. Updating series, data,
732
+ or labels preserves the open disclosure and restores focus to the same available action. Chart
733
+ hosts own their controller lifecycle across disconnect/reconnect; mixed Astro pages leave these
734
+ hosts to Elements. Application code owns navigation, requests, and filtering.
735
+
736
+ ## Dashboard composition
737
+
738
+ `FilterBar` groups host-owned filtering controls, active criteria, reset actions, and a polite
739
+ result announcement. `ChangeSummary` presents explicit before/after values and application-owned
740
+ changed state. Neither component owns requests, persistence, parsing, or financial policy.
741
+
742
+ ScatterChart supports independent X/Y formatting, explicit domains, logarithmic positive X values,
743
+ and labeled reference lines/regions. See [consumer UI recipes](https://github.com/santi020k/lumen/blob/main/docs/consumer-ui-recipes.md)
744
+ for dashboard tables, freshness, import review, activity inbox, and persistent Kanban patterns.
745
+
746
+ ### Actual-versus-target charts
747
+
748
+ `lumen-bullet-chart` compares a nullable actual `value` with a finite `target` and optional
749
+ labeled `ranges`. A strong actual bar, target marker, readable value labels, and expandable exact
750
+ data work together. Domains include zero and all measurements; invalid inputs fail closed.
751
+ 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)
752
+ for the input, localization, and domain contracts.
753
+
754
+ ### Rankings and paired comparisons
755
+
756
+ Use `LollipopChart` for zero-based rankings and `DumbbellChart` for paired measurements (native
757
+ `LumenLollipopChart` and `LumenDumbbellChart`). Supply ordered comparison data with `id`, `label`,
758
+ nullable `value`, optional nullable `reference`, and optional `tone`. Both charts preserve missing
759
+ values and expose exact data. Set `value-label` to name the current measurement and `reference-label`
760
+ to name the paired measurement; `summary` supplies an escaped accessible interpretation that remains
761
+ available when `show-table="false"`. See the [shared visualization contract](https://github.com/santi020k/lumen/blob/main/docs/data-visualization.md#rankings-and-paired-comparisons).
762
+
763
+ ### Calendar activity, ordered stages and distributions
764
+
765
+ `CalendarHeatmap`, `FunnelChart`, and `BoxPlot` share validated geometry with every Lumen adapter.
766
+ CalendarHeatmap takes date-only UTC `startDate`/`endDate`, nullable `{ date, value }` data and optional
767
+ `weekStartsOn` (0 for Sunday or 1 for Monday). It fills omitted dates as missing, keeps zero distinct,
768
+ and limits the inclusive range to 3,660 days. `weekdayLabels` always indexes Sunday through Saturday;
769
+ `dateFormatter` customizes readable dates without changing their identity.
770
+
771
+ FunnelChart takes ordered `{ id, label, value, tone? }` stages with nonnegative nullable values.
772
+ Stages retain the supplied order, including increasing values; the chart derives no conversion rates.
773
+ BoxPlot takes precomputed `{ id, label, min, q1, median, q3, max, outliers?, tone? }` statistics.
774
+ Statistics must be ordered and finite, or all five must be null for a missing row. Explicit domains
775
+ must contain all observations and outliers. `statisticLabels` localizes the six statistic names.
776
+
777
+ All three accept `valueFormatter`, chart `labels`, `summary`, and `show-table` (default true).
778
+ Exact data and missing measurements remain readable; invalid input fails closed instead of dropping
779
+ observations or clipping the domain. Prefer retaining the data table for complete visual inspection.
780
+
781
+ Register `CalendarHeatmap`, `FunnelChart`, and `BoxPlot` through `defineLumenElements`.
782
+ Use `<lumen-calendar-heatmap start-date="2026-01-01" end-date="2026-01-31">`,
783
+ `<lumen-funnel-chart>`, and `<lumen-box-plot>`. Assign typed `data`, `labels`, `valueFormatter`,
784
+ `dateFormatter`/`weekdayLabels` (calendar), and `statisticLabels` (box) properties, or supply JSON
785
+ `data` attributes. Calendar supports `week-starts-on` and JSON `weekday-labels`; domains use
786
+ `domain-min`/`domain-max`. Box statistic attributes are `min-label`, `q1-label`, `median-label`,
787
+ `q3-label`, `max-label`, and `outliers-label`. `show-table="false"` hides exact-data disclosure;
788
+ provide an application-owned summary when additional interpretation is useful.
789
+
790
+ ## Combobox lifecycle
791
+
792
+ `lumen-combobox` enhances its input and listbox when both are available. Children can arrive after
793
+ connection or be replaced by an application renderer. Disconnecting the host releases listeners
794
+ and observers; reconnecting binds the current children.
795
+
796
+ Decoded chart annotations ignore invalid supplied axes; omitted axes use the shared `y` default.
797
+
798
+ React hosts can assign `type` on scalar input elements before or after connection. The input
799
+ reflects that property to its native control without clearing the value. Register elements once
800
+ at the app boundary and handle their bubbling native input events.
801
+
802
+ `lumen-button` activates with Enter or a Space release. Canceled Enter events, canceled Space
803
+ keydown events before the host handles them, and canceled Space releases suppress activation. The
804
+ host consumes Space keydown to prevent scrolling; cancel its key release or click to suppress activation
805
+ from an ancestor after that keydown has been consumed. It blocks
806
+ disabled/loading activation, including direct clicks. Blocking flags expose `aria-disabled`;
807
+ removing them restores any prior application-supplied ARIA value. Native nested controls retain
808
+ their own keyboard path.
809
+
810
+ ## Device demonstrations
811
+
812
+ `DeviceFrame` presents slotted HTML, an image, or a titled iframe inside `macbook-pro`, `macbook-air`, `imac`,
813
+ `iphone`, `pixel`, and `ipad-pro` frames, with generic `laptop`, `desktop`, `android`, and `tablet` options.
814
+ Device-specific enclosures include a MacBook Pro display notch and full front edge, a tapered MacBook Air deck, curved iMac
815
+ stand and chin, rounded phone glass with separate rails and buttons, and an iPad Pro with even
816
+ bezels and no Home button. The generic `tablet` retains its classic enclosure.
817
+ Shells are decorative and do not emulate device hardware. `orientation` selects portrait or landscape; `tone` selects
818
+ light or dark chrome independently of the screen content. Use `color="white"`,
819
+ `color="black"`, or a 3-, 4-, 6-, or 8-digit hex color such as `color="#a9b8ac"` for
820
+ a custom hardware finish. `color` takes precedence over `tone`; invalid values fall back to the
821
+ tone. The finish stays independent of the content theme. For CSS-driven updates, set
822
+ `--ui-device-color` to a CSS color on the frame.
823
+
824
+ Iframe layouts use the preset screen viewport and scale to the available width. Override
825
+ `screenWidth` and `screenHeight` for a custom viewport (1–16384 CSS pixels). Slotted HTML shares
826
+ the host viewport; container queries can adapt it to the screen. Images preserve their proportions.
827
+ `scroll={false}` clips HTML overflow; an iframe manages its own scrolling.
828
+
829
+ Supply image alternative text and iframe titles. Consumers own iframe `sandbox`, `allow`,
830
+ loading, and referrer policies. Remote sites can refuse embedding through their response headers.
831
+ The decorative shell does not alter focus or intercept interactions. Camera and home-indicator
832
+ details occupy separate chrome outside live HTML and iframe viewports. Direct phone images extend
833
+ under the decorative camera and home indicator for a full-bleed presentation.
834
+ Screen presets are 1280 × 800 for MacBook Pro and MacBook Air, 1440 × 810 for iMac, 390 × 844 for iPhone,
835
+ 412 × 915 for Pixel, and 834 × 1194 for iPad Pro (1194 × 834 in landscape). These are demonstration
836
+ viewports, not physical display specifications.
837
+
838
+ ```html
839
+ <lumen-device-frame device="android" tone="light">
840
+ <iframe src="/demo" title="Mobile application demo" loading="lazy"></iframe>
841
+ </lumen-device-frame>
842
+ ```
843
+
844
+ Register with `defineLumenElements(['DeviceFrame'])` or `defineLumenDeviceFrame()` from
845
+ `@santi020k/lumen-elements/components/device-frame`. Use `screen-width`, `screen-height`, and
846
+ `scroll="false"` attributes. The element preserves the initial child nodes inside its screen;
847
+ append later content to `.ui-device-frame__screen`.
848
+ ## Visual interactions and product blocks
849
+
850
+ See [visual interactions](https://github.com/santi020k/lumen/blob/main/docs/visual-interactions.md) for keyed motion, semantic effects,
851
+ chart continuity, AI surfaces, optional SDK integrations, and the four installable product recipes.
852
+
853
+ ## World map
854
+
855
+ WorldMap supports highlighted countries, location markers, dotted or solid styles, country selection,
856
+ and theme customization. Use `initialView="highlighted"` (Elements: `initial-view`) to start with a
857
+ regional view. Zoom toward the cursor with Ctrl/Cmd-scroll, or fit highlighted countries using the
858
+ map controls. Import geography explicitly from
859
+ `@santi020k/lumen-core/world-map-data`; it is excluded from root exports. See the
860
+ [WorldMap usage guide](https://github.com/santi020k/lumen/blob/main/docs/world-map.md) for adapter examples, events, localization,
861
+ accessibility, and customization.
862
+
863
+ ## Studio media workspace
864
+
865
+ Compose MediaViewport, MediaThumbnail, MediaFilmstrip and ImageComparison modes with the
866
+ [Studio media workspace recipes](https://github.com/santi020k/lumen/blob/main/docs/studio-media-workspaces.md). Applications retain
867
+ media loading, selection, adjustment algorithms, processing, export and persistence.
868
+
869
+ ## Resources
870
+
871
+ | Guide | What you will find |
872
+ | --- | --- |
873
+ | [Styling contract](https://github.com/santi020k/lumen/blob/main/docs/styling-contract.md) | Stable styling parts, component variables, and overrides. |
874
+ | [Error handling](https://github.com/santi020k/lumen/blob/main/docs/error-handling.md) | Field feedback, summaries, alerts, and recovery surfaces. |
875
+ | [Contributing](https://github.com/santi020k/lumen/blob/main/CONTRIBUTING.md) | Setup, checks, and contribution workflow. |
876
+ | [Release history](https://github.com/santi020k/lumen/releases) | Published releases and version notes. |
877
+
878
+ Part of [Lumen UI](https://lumen.santi020k.com), created by [Santiago Molina](https://santi020k.com).
879
+ Licensed under [MIT](https://github.com/santi020k/lumen/blob/main/LICENSE); third-party artwork retains its own notices.
@@ -0,0 +1,5 @@
1
+ import { type LumenBulletRange, type LumenChartLabels } from '@santi020k/lumen-core';
2
+ export declare const bulletNumberAttribute: (element: HTMLElement, name: string) => number;
3
+ export declare const parseBulletRanges: (source: string | null) => readonly LumenBulletRange[];
4
+ export declare const bulletChartHtml: (element: HTMLElement, ranges: readonly LumenBulletRange[], text: Readonly<LumenChartLabels>, format: (value: number) => string) => string;
5
+ //# sourceMappingURL=bullet-chart-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bullet-chart-html.d.ts","sourceRoot":"","sources":["../src/bullet-chart-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyD,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAmB,MAAM,uBAAuB,CAAA;AAI5J,eAAO,MAAM,qBAAqB,GAAI,SAAS,WAAW,EAAE,MAAM,MAAM,KAAG,MAI1E,CAAA;AAgBD,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,SAAS,gBAAgB,EAelF,CAAA;AAED,eAAO,MAAM,eAAe,GAC1B,SAAS,WAAW,EAAE,QAAQ,SAAS,gBAAgB,EAAE,EAAE,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAC3F,QAAQ,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,KAChC,MA0BF,CAAA"}