@aceshooting/lyra-ui 1.1.0 → 1.2.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 (35) hide show
  1. package/README.md +1 -1
  2. package/custom-elements.json +9289 -8457
  3. package/dist/components/chart/chart.d.ts +11 -0
  4. package/dist/components/chart/chart.js +54 -2
  5. package/dist/components/chart/lite-chart.d.ts +9 -0
  6. package/dist/components/chart/lite-chart.js +41 -1
  7. package/dist/components/chart/lite-chart.stories.d.ts +2 -0
  8. package/dist/components/chart/lite-chart.stories.js +16 -0
  9. package/dist/components/combobox/combobox.js +1 -1
  10. package/dist/components/flag/flag.d.ts +26 -5
  11. package/dist/components/flag/flag.js +44 -3
  12. package/dist/components/flag/flag.stories.d.ts +1 -0
  13. package/dist/components/flag/flag.stories.js +14 -0
  14. package/dist/components/heatmap/heatmap.d.ts +15 -3
  15. package/dist/components/heatmap/heatmap.js +24 -7
  16. package/dist/components/heatmap/heatmap.stories.d.ts +5 -0
  17. package/dist/components/heatmap/heatmap.stories.js +25 -0
  18. package/dist/components/select/select.d.ts +3 -0
  19. package/dist/components/select/select.js +6 -42
  20. package/dist/components/select/select.stories.d.ts +2 -0
  21. package/dist/components/select/select.stories.js +16 -0
  22. package/dist/components/select/select.styles.js +26 -2
  23. package/dist/components/stat/stat.d.ts +16 -0
  24. package/dist/components/stat/stat.js +41 -1
  25. package/dist/components/stat/stat.stories.d.ts +1 -0
  26. package/dist/components/stat/stat.stories.js +17 -0
  27. package/dist/components/stat/stat.styles.js +20 -0
  28. package/dist/components/widget/widget.d.ts +10 -0
  29. package/dist/components/widget/widget.js +24 -1
  30. package/dist/components/widget/widget.stories.d.ts +2 -0
  31. package/dist/components/widget/widget.stories.js +33 -0
  32. package/dist/components/widget/widget.styles.js +9 -2
  33. package/dist/components/word-cloud/word-cloud.styles.js +1 -0
  34. package/llms-full.txt +90 -20
  35. package/package.json +3 -3
package/llms-full.txt CHANGED
@@ -211,6 +211,9 @@ another unnamed combobox in the same form.
211
211
  - naming drift from Web Awesome parity: the shipped attribute is **`with-clear`**, not
212
212
  `clearable` (which is what `<wa-combobox>` uses) — don't copy-paste WA docs assuming a 1:1
213
213
  attribute name here.
214
+ - a host-level `aria-label` attribute on `<lyra-combobox>` now takes priority over `label`/
215
+ `placeholder`/`"Combobox"` when resolving the accessible name on `[part="combobox-input"]` —
216
+ previously it was silently ignored. Matches the same fallback on `<lyra-select>`.
214
217
  - no `size` variant (small/medium/large) unlike sibling `lyra-toast-item`.
215
218
  - `aria-required` reflects `required` immediately; `aria-invalid`, by contrast, only reflects
216
219
  **after the field has been touched** (first `blur`) — a `required` field with a validity error
@@ -252,6 +255,8 @@ Single-select only, with no `filter`/`source`/`with-clear`/`max-options-visible`
252
255
  - `errorText: string = ''` (attribute `error-text` — static error copy shown below the hint;
253
256
  overridden by slotted `error` content when provided)
254
257
  - `open: boolean = false` (reflected)
258
+ - `size: 'xs'|'s'|'m'|'l'|'xl' = 'm'` (reflected — same scale as `lyra-toast-item`'s `size`, for
259
+ compact toolbar placements that don't fit the default trigger height)
255
260
  - `value: string` — a getter/setter; always a single string (no `multiple` mode)
256
261
 
257
262
  **Events:** `change` (native-style — selection changed), `input` (fired alongside `change` on every
@@ -293,6 +298,9 @@ secondary line, when `sub` is set), `expand-icon`, `error`, `hint`
293
298
  - `aria-required` on the trigger reflects `required` immediately; `aria-invalid` only reflects once
294
299
  the trigger has been blurred (touched) at least once, mirroring `lyra-combobox`'s own input.
295
300
  Blurring the trigger (Tab away) closes an open listbox, the same as a native `<select>`'s popup.
301
+ - The trigger's accessible name now checks a host-level `aria-label` attribute first, before falling
302
+ back to `label`/`placeholder`/`"Select"` — a plain `aria-label` on `<lyra-select>` is no longer
303
+ silently ignored.
296
304
 
297
305
  ---
298
306
 
@@ -588,9 +596,12 @@ Country/language flag image. Flag artwork ships in a **separate, optional peer p
588
596
  the small per-flag async hop when you already have the URL at build time, e.g. from
589
597
  `import frUrl from '@aceshooting/lyra-flags/flags/fr.svg?url'`. `label` is effectively required
590
598
  alongside `src` since there's no `country`/`language` to derive a fallback `alt` from.)
591
- - `label?: string` (accessible name / `alt` text — **defaults to the bare uppercase *resolved
592
- country* code if omitted**, see gotchas)
599
+ - `label?: string` (accessible name / `alt` text — **defaults to a localized, human-readable region
600
+ name derived from the *resolved country* code via `Intl.DisplayNames` if omitted**, see gotchas)
593
601
  - `round: boolean = false` (reflected — circular crop)
602
+ - `detailed: boolean = false` (reflected — requests the pristine, pre-optimization source SVG
603
+ instead of the default icon-optimized one; a no-op for the majority of codes whose source art was
604
+ never large enough to need optimizing. Has no effect when `src` is set. See gotchas.)
594
605
 
595
606
  **Events:** none.
596
607
 
@@ -627,11 +638,12 @@ pnpm add @aceshooting/lyra-flags # required peer — without it, <lyra-flag> r
627
638
  - Rendering is async even when the peer *is* installed: `src` resolves after an `import()` +
628
639
  resolver call, so there's a brief loading-skeleton window on first paint/attribute change — don't
629
640
  assume the `<img>` exists synchronously right after setting `country`/`language`.
630
- - if `label` is omitted, the accessible name (`alt`) falls back to the **bare uppercase resolved
631
- country code** for `language="en"` that's `"GB"` (the mapped country), not `"EN"` (the language
632
- tag itself). A screen reader will typically spell this out letter-by-letter rather than announce a
633
- country name. Always pass an explicit `label` (e.g. `"France"`) if the flag conveys real
634
- information rather than being purely decorative.
641
+ - if `label` is omitted, the accessible name (`alt`) falls back to a localized region name via
642
+ `Intl.DisplayNames([navigator.language], { type: 'region' })` (e.g. `"United Kingdom"`) instead of
643
+ a bare code for `language="en"` that's derived from `"GB"` (the mapped country), not `"EN"` (the
644
+ language tag itself). Falls back further to the bare uppercase code if `Intl.DisplayNames` throws
645
+ for an unrecognized region or isn't available. You can still pass an explicit `label` (e.g.
646
+ `"France"`) to override the derived name.
635
647
  - an invalid `country` (anything not matching the ISO 3166-1 alpha-2 shape, e.g. containing `../`)
636
648
  is rejected before it ever reaches the peer's `flagUrl()` resolver — treated the same as an
637
649
  unknown/missing flag rather than being passed through. `languageToCountry()`'s region-subtag path
@@ -647,6 +659,13 @@ pnpm add @aceshooting/lyra-flags # required peer — without it, <lyra-flag> r
647
659
  the flags actually requested at runtime (verified with a real Vite build — referencing 2 codes
648
660
  shipped ~28 KB total, not all 249). If you already have a flag's URL at build time, `src` skips
649
661
  the peer-package round trip (and its loading-skeleton flash) entirely.
662
+ - 65 of `@aceshooting/lyra-flags`' 249 flags (any whose design includes a detailed coat of
663
+ arms/seal/emblem, e.g. `es`, `pt`, `sv`) ship a second, pristine full-detail source SVG alongside
664
+ the default icon-optimized one (`flagUrl(code, { variant: 'detailed' })`, or `detailed` on
665
+ `<lyra-flag>`) — the default variant is the one `country`/`language` resolve to unless `detailed`
666
+ is set, and is what almost every consumer wants (an icon-scale rendering, ~65% smaller on average
667
+ for the 65 affected codes, no visible fidelity loss at that scale). `detailed` is a safe no-op for
668
+ the other 184 codes — same file either way.
650
669
 
651
670
  ---
652
671
 
@@ -752,16 +771,27 @@ KPI/stat card — value + unit + label + optional icon/trend/caption.
752
771
  a brand-colored accent edge, orthogonal to the status `variant`; status semantics still win over
753
772
  it — `emphasis` only additionally tints `[part="value"]` brand-colored when `variant` is still
754
773
  `'neutral'`, never overriding an actual `success`/`warning`/`danger` value color
774
+ - `exactValue: string = ''` (attribute `exact-value`) — rendered as a `title` attribute on
775
+ `[part="value"]` for a hover tooltip (e.g. `value="$1.2K" exact-value="$1,204.37"`); also gives
776
+ `[part="value"]` `tabindex="0"` (only when set) so the tooltip is reachable by keyboard focus, not
777
+ just hover
778
+ - `sub: string = ''` — a secondary line distinct from `caption`, e.g. a comparison-period label,
779
+ rendered as `[part="sub"]` between the trend pill and the caption; hidden entirely when unset
780
+ - `prose: boolean = false` (reflected) — CSS-only variant that shrinks/lightens `[part="value"]` and
781
+ hides `[part="unit"]`, for rendering a loading/status message in place of a numeric value
782
+ - `compact: boolean = false` (reflected) — tighter card padding; same convention as `lyra-empty`'s and
783
+ `lyra-widget`'s `compact`
755
784
 
756
785
  **Events:** none.
757
786
 
758
787
  **Slots:** default (leading icon), `caption` (rich caption content — overrides the `caption`
759
788
  attribute when slotted content is provided), `spark` (a sparkline, e.g. `<lyra-sparkline
760
789
  slot="spark">`, or other compact trend visual — `lyra-stat` only reserves the slot and doesn't
761
- render one itself)
790
+ render one itself), `sub` (rich sub-line content — overrides the `sub` attribute when slotted content
791
+ is provided)
762
792
 
763
- **CSS parts:** `base`, `icon`, `label`, `value-row`, `value`, `unit`, `trend`, `spark`, `caption`,
764
- `rows`, `row`, `row-label`, `row-value`
793
+ **CSS parts:** `base`, `icon`, `label`, `value-row`, `value`, `unit`, `trend`, `sub`, `spark`,
794
+ `caption`, `rows`, `row`, `row-label`, `row-value`
765
795
 
766
796
  **Themeable custom properties:** shared tokens only (`--lyra-color-success/-warning/-danger` drive
767
797
  the `variant`-colored value text and up/down trend pill; `--lyra-color-brand` drives `emphasis`'s
@@ -1063,6 +1093,12 @@ position) survives the transition.
1063
1093
  - `collapsed: boolean = false` (reflected)
1064
1094
  - `expandable: boolean = false` (reflected — shows the fullscreen toggle button)
1065
1095
  - `fullscreen: boolean = false` (reflected)
1096
+ - `fullscreenInset: string = ''` (attribute `fullscreen-inset`) — raw CSS `inset` shorthand applied to
1097
+ `[part="base"]` and `[part="backdrop"]` while fullscreen instead of the default
1098
+ `var(--lyra-space-l)` on every side, e.g. `"0 0 0 240px"` to leave a 240px persistent
1099
+ sidebar/toolbar visible during fullscreen
1100
+ - `compact: boolean = false` (reflected) — tighter header/body padding, same convention as
1101
+ `lyra-empty`'s `compact`
1066
1102
 
1067
1103
  **Events:** `lyra-collapse-change` (`detail: boolean`, the new `collapsed` state),
1068
1104
  `lyra-fullscreen-change` (`detail: boolean`, the new `fullscreen` state — also fired when fullscreen
@@ -1095,10 +1131,12 @@ to the panel's own focusable content (`actions` slot → collapse/fullscreen but
1095
1131
  matching visual tab order — resolved shadow-piercingly, so a slotted custom element's real
1096
1132
  focusable target inside its own shadow root is found too) so keyboard focus can't escape to page
1097
1133
  content hidden behind the backdrop. Escape or clicking the backdrop exits fullscreen and returns
1098
- focus to whichever button triggered it.
1134
+ focus to whichever button triggered it. Set `fullscreen-inset` (e.g. `"0 0 0 240px"`) to reserve
1135
+ space for a persistent sidebar/toolbar that should stay visible instead of being covered by the
1136
+ fullscreen panel/backdrop — it overrides the default `var(--lyra-space-l)` inset on every side for
1137
+ both `[part="base"]` and `[part="backdrop"]`. Set `compact` for tighter header/body padding.
1099
1138
 
1100
1139
  **Known gotchas:**
1101
- - no size/density variant — header and body padding are fixed.
1102
1140
  - a reconnect that preserves the same element instance (e.g. a drag-and-drop reparent) restores the
1103
1141
  scroll lock and the Tab-trap `keydown` listener if `fullscreen` was still `true` across the
1104
1142
  move — `disconnectedCallback`/`connectedCallback` fire back-to-back with no update in between, so
@@ -1327,6 +1365,11 @@ click, or Enter/Space on the focused cell, fires `lyra-cell-click`.
1327
1365
  by `date` (whichever pair matches the active `mode`; the other fields are ignored). Draws a
1328
1366
  stroked ring over the matching cell; an annotation with a `label` also gets its own
1329
1367
  `[part="legend-annotation"]` entry in the legend.
1368
+ - `cellText?: (pos: MatrixCellPos | CalendarCellPos, value: number) => string` (attribute: false) —
1369
+ formats the per-cell hover tooltip and keyboard live-region announcement text; receives the cell
1370
+ position (`{ row, col }` in matrix mode, `{ week, weekday }` in calendar mode) and its value.
1371
+ Unset (the default) falls back to the built-in English "Row X, Col Y: value" / "Mon DD: value"
1372
+ template — additive, not breaking.
1330
1373
 
1331
1374
  **Events:** `lyra-cell-click` (fired on click, or Enter/Space on the keyboard-focused cell —
1332
1375
  `detail: { row, col, value }` in matrix mode, `detail: { date, value }` in calendar mode)
@@ -1387,16 +1430,19 @@ color) and `--lyra-space-xs`.
1387
1430
  since `draw()` unconditionally sets an inline `canvas.style.width/height` that wins over it.
1388
1431
  Calendar mode ignores `fit-to-width` entirely — its canvas is always sized from the computed
1389
1432
  `weekCount`.
1390
- - the host itself is unconditionally `role="img"` with a dimensions+range summary `aria-label`
1391
- (calendar mode: a day-count + range summary instead), same as before but `[part="canvas"]`
1392
- inside it is now a real focusable, keyboard-operable, per-cell-interactive control (roving
1393
- arrow-key focus, `[part="live-region"]` announcements, `lyra-cell-click`). `role="img"` is
1394
- documented (ARIA) to flatten its subtree to a single image for some assistive tech, which is in
1395
- tension with a focusable descendant inside it plausible from the code, unverified against real
1396
- AT.
1433
+ - the host is `role="group"` (not `role="img"`) with a dimensions+range summary `aria-label`
1434
+ (calendar mode: a day-count + range summary instead) — `[part="canvas"]` inside it is a real
1435
+ focusable, keyboard-operable, per-cell-interactive control (roving arrow-key focus,
1436
+ `[part="live-region"]` announcements, `lyra-cell-click`), and `role="img"` is documented (ARIA) to
1437
+ flatten its subtree to a single image for some assistive tech, which conflicted with that
1438
+ focusable descendant — fixed, matching `lyra-lite-chart`/`lyra-word-cloud`'s existing `role="group"`
1439
+ pattern.
1397
1440
  - `NaN`/non-finite cell values in matrix mode are correctly treated as no-data now (alongside `-1`),
1398
1441
  and repeated DPR crossings (moving the window across displays with different pixel ratios) no
1399
1442
  longer leak a `MediaQueryList` listener per crossing — both previously-known issues are fixed.
1443
+ - calendar mode's date labels (used by the default `cellText` template and the tooltip/live-region
1444
+ text) now format via the runtime locale (`toLocaleString(undefined, ...)`) instead of a hardcoded
1445
+ `'en'` — fixed.
1400
1446
 
1401
1447
  ---
1402
1448
 
@@ -1416,7 +1462,7 @@ A force-directed node-link diagram with pan/zoom/drag, built on `d3-force`.
1416
1462
  - `linkDistance: number = 100` (attribute `link-distance` — live-reactive, see gotchas)
1417
1463
  - `minZoom: number = 0.1` (attribute `min-zoom`)
1418
1464
  - `maxZoom: number = 8` (attribute `max-zoom`)
1419
- - `seed?: number` (attribute: false) — when set, seeds each node's initial x/y deterministically
1465
+ - `seed?: number` — when set, seeds each node's initial x/y deterministically
1420
1466
  (keyed by node **id**, not array index/order) instead of `forceSimulation()`'s own random start,
1421
1467
  and settles the simulation synchronously instead of animating the settle (same effect
1422
1468
  `prefers-reduced-motion` has, see gotchas)
@@ -1533,6 +1579,11 @@ descendants of the treeitem, matching the WAI-ARIA treeitem pattern's containmen
1533
1579
  - `item: TreeItem` (required, attribute: false)
1534
1580
  - `depth: number = 0`
1535
1581
  - `expanded: boolean = false` (reflected)
1582
+ - `activeId: string | null = null` (attribute: false) — the id of the tree's roving-tabindex-focused
1583
+ item, pushed down from `<lyra-tree>`; normally set internally, not by consumers
1584
+ - `setSize: number = 1`, `posInSet: number = 1` (attribute: false) — this node's `aria-setsize`/
1585
+ `aria-posinset` values among its siblings, pushed down from `<lyra-tree>`; normally set internally,
1586
+ not by consumers
1536
1587
 
1537
1588
  **Methods:** `expand()`, `collapse()` (each a no-op if already in that state, or a leaf), `select()`
1538
1589
  (fires `lyra-node-select`).
@@ -1667,6 +1718,14 @@ respectively; plus shared `--lyra-space-xs`.
1667
1718
  passthrough is deep-merged with `__proto__`/`constructor`/`prototype` keys skipped unconditionally,
1668
1719
  so a JSON-sourced `config` (e.g. parsed from an API response) can't reach up and pollute
1669
1720
  `Object.prototype` through the merge.
1721
+ - lazy-redraw + memoization: an `IntersectionObserver` gates `draw()` — while the host is scrolled
1722
+ off-screen, property changes that would otherwise trigger a Chart.js redraw are skipped (and a
1723
+ single redraw fires once it re-enters the viewport). Independently, a content-signature check
1724
+ (`type`, `labels`, `datasets`, `legend`, `area`, `xLabel`, `yLabel`, `y2Label`, `beginAtZero`,
1725
+ `horizontal`, `stacked`, `config`) skips calling into Chart.js when none of those have actually
1726
+ changed since the last draw (e.g. an unrelated property/state update, or a bare `requestUpdate()`).
1727
+ `refreshTheme()` calls `draw()` directly and is unaffected by either gate — it always redraws, since
1728
+ a theme change isn't reflected in any tracked property.
1670
1729
 
1671
1730
  ---
1672
1731
 
@@ -1691,11 +1750,22 @@ passthrough). Not a subclass of `LyraChart`.
1691
1750
  - `beginAtZero: boolean = true` (attribute `begin-at-zero`)
1692
1751
  - `stacked: boolean = false` — sums each category's bars into one segmented bar instead of grouping
1693
1752
  them side by side; ignored for `type="line"`
1753
+ - `tickFormat?: (value: number) => string` (attribute: false) — formats a y-axis tick value for
1754
+ display (e.g. `(v) => \`$${v.toFixed(2)}\`` for currency, or a duration formatter for `"42s"`).
1755
+ Falls back to the built-in "nice numbers" formatter when unset.
1694
1756
 
1695
1757
  **Events:** `lyra-point-click` — fired when a bar/point is activated (click, or Enter/Space while
1696
1758
  focused). `detail: { datasetIndex: number, index: number, label: string | undefined, value: number
1697
1759
  | null }` — same shape as `lyra-chart`'s `lyra-point-click`.
1698
1760
 
1761
+ **Performance:** rendering is `IntersectionObserver`-gated and content-signature-memoized — `render()`
1762
+ skips recomputing the grid/marks (and reuses the previous `TemplateResult`) while the host is scrolled
1763
+ off-screen, or when none of the content-affecting properties (`type`, `labels`, `datasets`, `legend`,
1764
+ `xLabel`, `yLabel`, `beginAtZero`, `stacked`, or the measured plot size) have changed since the last
1765
+ render. A `tickFormat` identity change alone (with everything else unchanged) does not force a redraw —
1766
+ in practice `tickFormat` is stable across a component's lifetime, and any data change that would make a
1767
+ different `tickFormat` output visible already changes `datasets`/`labels` too.
1768
+
1699
1769
  **Slots:** none.
1700
1770
 
1701
1771
  **CSS parts:** `base`, `grid-line`, `axis-label`, `axis-title`, `bar`, `line`, `point`, `legend`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aceshooting/lyra-ui",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Free, clean-room Lit web components — a companion to Web Awesome.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  "lit": "^3.3.3"
46
46
  },
47
47
  "peerDependencies": {
48
- "@aceshooting/lyra-flags": "^1.1.0",
48
+ "@aceshooting/lyra-flags": "^1.2.0",
49
49
  "@sgratzl/chartjs-chart-boxplot": "^4.4.0",
50
50
  "chart.js": "^4.5.0",
51
51
  "chartjs-plugin-zoom": "^2.2.0",
@@ -85,7 +85,7 @@
85
85
  }
86
86
  },
87
87
  "devDependencies": {
88
- "@aceshooting/lyra-flags": "^1.1.0",
88
+ "@aceshooting/lyra-flags": "^1.2.0",
89
89
  "@custom-elements-manifest/analyzer": "^0.11.0",
90
90
  "@open-wc/testing": "^4.0.0",
91
91
  "@sgratzl/chartjs-chart-boxplot": "^4.4.5",