@aceshooting/lyra-ui 11.2.0 → 12.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +388 -0
  2. package/README.md +11 -8
  3. package/custom-elements.json +1 -1
  4. package/dist/all.d.ts +1 -0
  5. package/dist/all.js +1 -1
  6. package/dist/components/charts/chart/chart.class.d.ts +13 -1
  7. package/dist/components/data/funnel/funnel.class.d.ts +92 -0
  8. package/dist/components/data/funnel/funnel.class.js +25 -0
  9. package/dist/components/data/funnel/funnel.d.ts +1 -0
  10. package/dist/components/data/funnel/funnel.js +1 -0
  11. package/dist/components/data/funnel/funnel.styles.d.ts +1 -0
  12. package/dist/components/data/funnel/funnel.styles.js +127 -0
  13. package/dist/components/data/heatmap/heatmap.class.d.ts +195 -13
  14. package/dist/components/data/heatmap/heatmap.class.js +30 -22
  15. package/dist/components/data/heatmap/heatmap.styles.js +36 -0
  16. package/dist/components/data/index.d.ts +1 -0
  17. package/dist/components/data/index.js +1 -1
  18. package/dist/components/forms/date-picker/date-input.class.d.ts +23 -0
  19. package/dist/components/forms/date-picker/date-input.class.js +1 -1
  20. package/dist/components/layout/app-rail/app-rail-item.class.d.ts +16 -0
  21. package/dist/components/layout/app-rail/app-rail-item.class.js +4 -4
  22. package/dist/components/layout/filter-bar/filter-bar.class.d.ts +32 -3
  23. package/dist/components/layout/filter-bar/filter-bar.class.js +2 -1
  24. package/dist/components/layout/widget/widget.class.d.ts +16 -0
  25. package/dist/components/layout/widget/widget.class.js +2 -2
  26. package/dist/components/lr-funnel.d.ts +1 -0
  27. package/dist/components/lr-funnel.js +1 -0
  28. package/dist/components/media/flag/flag-peer-bulk-standard.d.ts +25 -0
  29. package/dist/components/media/flag/flag-peer-bulk-standard.js +1 -0
  30. package/dist/components/media/flag/flag.class.d.ts +8 -0
  31. package/dist/components/media/flag/flag.class.js +1 -1
  32. package/dist/components/media/map/map.class.d.ts +196 -15
  33. package/dist/components/media/map/map.class.js +1 -1
  34. package/dist/components/overlays/chip/chip-group.class.d.ts +16 -0
  35. package/dist/components/overlays/chip/chip-group.class.js +10 -3
  36. package/dist/custom-elements-jsx.d.ts +12 -4
  37. package/dist/internal/autoloader-manifest.js +1 -1
  38. package/dist/internal/autoloader-tags.d.ts +1 -1
  39. package/dist/internal/autoloader-tags.js +1 -1
  40. package/dist/internal/lyra-element.d.ts +7 -1
  41. package/dist/internal/lyra-element.js +1 -1
  42. package/dist/internal/package-metadata.d.ts +1 -1
  43. package/dist/internal/package-metadata.js +1 -1
  44. package/dist/internal/root-registration-allowlist.d.ts +1 -1
  45. package/dist/internal/root-registration-allowlist.js +1 -1
  46. package/dist/lyra.d.ts +4 -2
  47. package/dist/lyra.js +1 -1
  48. package/dist/ssr/all.d.ts +1 -0
  49. package/dist/ssr/all.js +1 -1
  50. package/dist/ssr.d.ts +4 -4
  51. package/dist/styles/tokens-root.css +488 -0
  52. package/dist/svelte.d.ts +13 -4
  53. package/dist/vue.d.ts +12 -4
  54. package/llms/components/lr-app-rail-item.md +8 -1
  55. package/llms/components/lr-app-rail.md +6 -0
  56. package/llms/components/lr-chip-group.md +7 -0
  57. package/llms/components/lr-chip.md +7 -0
  58. package/llms/components/lr-date-input.md +19 -1
  59. package/llms/components/lr-date-picker.md +19 -1
  60. package/llms/components/lr-filter-bar.md +50 -1
  61. package/llms/components/lr-flag.md +14 -0
  62. package/llms/components/lr-funnel.md +122 -0
  63. package/llms/components/lr-heatmap.md +51 -7
  64. package/llms/components/lr-map.md +65 -8
  65. package/llms/components/lr-widget.md +7 -1
  66. package/llms/index.md +3 -2
  67. package/llms/peers.md +1 -1
  68. package/llms/shared.md +110 -1
  69. package/llms-full.txt +468 -18
  70. package/llms.txt +1 -1
  71. package/package.json +25 -6
  72. package/vscode-css-data.json +42 -0
  73. package/vscode-html-data.json +96 -17
  74. package/web-types.json +32714 -317
package/CHANGELOG.md CHANGED
@@ -1,5 +1,393 @@
1
1
  # Changelog
2
2
 
3
+ ## 12.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - bd0f05f: **Breaking:** `LyraElement` no longer declares the static `getPropertyDescriptor()`, so that member
8
+ is gone from every element's public surface in `custom-elements.json`.
9
+
10
+ This is the release's only substantive breaking change, and in practice nothing consumer-callable
11
+ was removed: `getPropertyDescriptor()` is Lit's own finalization hook, called *by* `ReactiveElement`
12
+ during `finalize()` and never by application code. It appeared on all 285 tags purely because this
13
+ library overrode it, and the manifest projects an inherited static onto every subclass. Only code
14
+ that subclassed an `lr-*` element and overrode the hook itself is affected — a path Lit has already
15
+ deprecated and states will not be called under standard decorators.
16
+
17
+ The major is nonetheless correct rather than pedantic. By this package's own definition of public
18
+ surface, a public static was removed from every element, and the reachable-declaration set of every
19
+ export shrank as a result. The semver gate reports that honestly, and the alternative — shipping it
20
+ as a minor behind a blanket exception — would have meant weakening the gate to let one change past
21
+ it.
22
+
23
+ `@lit/reactive-element` 2.1.2 deprecates that hook and warns during `finalize()`, so every consumer
24
+ saw an unactionable dev-mode warning on every page load that mounted any `lr-*` element, not
25
+ silenceable without disabling Lit's dev warnings wholesale.
26
+
27
+ The more important half was invisible. That override was what implemented the documented
28
+ clone-owned/bounded/frozen collection contract on 182 enrolled property names across 87 modules
29
+ (`colorSteps`, `legendStops`, `annotations` and their equivalents): it wrapped every reactive setter
30
+ and routed owned values through the snapshot helpers. It worked only because the published dist
31
+ ships experimental decorators, which still call the hook. Lit states plainly that standard
32
+ decorators will not — so a migration, or a consumer build applying them, would have silently
33
+ reverted every one of those properties to storing the caller's live array by reference. No clone, no
34
+ freeze, no error, no warning, and no test would have caught it.
35
+
36
+ The contract now rides a decorator-agnostic seam that re-defines the already-finished prototype
37
+ accessor. Legacy `@property`, standard `accessor`/setter decorators, a `static properties` block and
38
+ hand-written getter/setter pairs all end in a prototype accessor by finalization, so this walks the
39
+ finished accessor rather than the hook Lit refuses to call. It installs from the finalization
40
+ trigger Lit itself documents, and registration strictly precedes every instance — constructing an
41
+ unregistered custom element throws — so no assignment can reach an unwrapped setter.
42
+
43
+ `finalize()` was deliberately not hooked: that would add a static method to the class surface, which
44
+ the component inventory records per component and a pinned-manifest gate grades. The chosen seam
45
+ changes no static surface at all.
46
+
47
+ **No migration is expected.** If you do not override `getPropertyDescriptor()` on an `lr-*`
48
+ subclass, there is nothing to do.
49
+
50
+ ### Minor Changes
51
+
52
+ - 103922d: `<lr-chip-group>` gained `accessibleLabel` (attribute `aria-label`) and now renders
53
+ `role="group"` on `[part='base']` whenever a name is supplied.
54
+
55
+ A chip group is a group, and every peer grouping primitive in this library already said so —
56
+ `<lr-radio-group>` renders `role="radiogroup"`, `<lr-segmented>` the same, each forwarding a host
57
+ `aria-label` inward to the element that owns the role. `<lr-chip-group>` rendered a roleless
58
+ container and read no accessible name at all. Because a host `aria-label` does not cross a shadow
59
+ boundary, a consumer labelling the host named nothing: the chips were announced as unrelated
60
+ toggle buttons with no indication of what set they belonged to.
61
+
62
+ This surfaced from a real multi-select filter row, where the consumer had to hand-write
63
+ `role="group" aria-label="…"` onto the host to get a named group. That workaround is the evidence
64
+ the capability was wanted and was reachable only by reaching around the component.
65
+
66
+ The role is applied only *with* a name, deliberately. An unnamed group role adds verbosity without
67
+ adding information, and applying it unconditionally would change the accessibility tree of every
68
+ decorative chip row already shipped. An explicit unset-regression test pins that.
69
+ - bd0f05f: Completed the date-preset story across the three components that share it.
70
+
71
+ `<lr-date-input>` now mirrors the nested picker's `appliedPreset` as a read-only getter. 11.0.0 added
72
+ `presets` to `<lr-date-picker>`; 11.1.0 then separately forwarded `presets` to `<lr-date-input>` and
73
+ added `appliedPreset` to the picker — but never joined the two halves, so the readback landed on the
74
+ component that does not need it and the component that does could set presets and not read the
75
+ result. `appliedPreset`'s own documentation describes the dashboard time filter ("'Last 7 days' must
76
+ still mean the last 7 days after tomorrow's reload"), and that shape is the compact
77
+ text-field-plus-popover input, not the inline calendar.
78
+
79
+ There was no workaround. The nested picker lives in the input's shadow root with no documented
80
+ readback path: `input`/`change` are deliberately native events and carry no detail, and every
81
+ alternative the docs already reject applied — matching `value` back against the preset list is "the
82
+ mapping table `presets` exists to delete" and is ambiguous (Today and This month coincide on the
83
+ 1st), while reaching for `[part='preset-button'][data-active]` depends on private structure and on
84
+ the popover having been opened at least once.
85
+
86
+ The mirror is the input's own field rather than a shadow-root lookup, so it is correct (`undefined`)
87
+ when the popover has never been opened. It carries both halves of the picker's contract — set before
88
+ `commit()`, so a consumer reading it inside their own `change` handler sees the causing preset, and
89
+ cleared on a hand-pick — plus three clear paths the picker cannot see because typing, clearing and
90
+ resetting never reach it: a typed commit that actually changes the value (deliberately not a no-op
91
+ re-commit, which would otherwise silently drop the preset), `clear()`, and `formResetCallback()`.
92
+
93
+ `<lr-filter-bar>` can now pass `presets` on its `date-range` filter and reports the resolved preset
94
+ on the `lr-input` detail as `appliedPreset`. The bar already composed `<lr-date-input>` and already
95
+ forwarded that control's `min`/`max`, but had no path at all for `presets` — so the quick-range row
96
+ and the component built for the same dashboard shape could not be combined. `type: 'custom'` was a
97
+ poor substitute: hand-rendering the control plus a full adapter to set one property, and forfeiting
98
+ the built-in date-range chip localization the docs themselves flag as non-trivial.
99
+
100
+ `presets` is declared on the `date-range` definition only, not the shared base: a preset names two
101
+ dates and the picker ignores the list outside range mode, so putting it on `'date'` would type-check
102
+ a guaranteed-inert field.
103
+ - bd0f05f: `<lr-heatmap>` gained `sticky-labels` (`'none' | 'rows' | 'cols' | 'both'`, default `'none'`), which
104
+ paints the matrix label bands into their own layers instead of into the scrolling bitmap.
105
+
106
+ Matrix labels shared one canvas with the cells, so a tall grid lost its column header on scroll: a
107
+ 160-row matrix at cell-size 32 is about 5,100px of bitmap, and a header baked into it cannot be
108
+ `position: sticky` on its own. The only workaround was a light-DOM mirror row, which had to follow
109
+ the gutter width and cell size — and before `matrixGeometry` shipped it had to hardcode them, which
110
+ made the workaround mutually exclusive with `row-label-width="auto"`: a consumer got the automatic
111
+ fit or the sticky header, never both. (Scale on why the gutter matters: against the component's own
112
+ 10px label font, 160 country names ellipsized 37 times in the built-in 60px gutter and 3 times in a
113
+ 120px one.)
114
+
115
+ A closed set rather than a boolean, because a boolean cannot express one axis at all and a later
116
+ one-axis need would force either a second property or a breaking type change; and rather than a
117
+ `sticky-row-labels`/`sticky-col-labels` pair, which is two attributes and four states for one
118
+ concept with no single reflected value to select on in CSS. `rows`/`cols` name the axes this
119
+ component already names everywhere else (`rowLabels`, `row-label-width`, `colLabels`,
120
+ `col-label-height`), which `freeze-axis="x|y"` would have clashed with.
121
+
122
+ Default `'none'` reproduces today's single-canvas output exactly, including in calendar mode, and an
123
+ unrecognized value normalizes back to `'none'` and repairs the attribute.
124
+ - bd0f05f: New component `<lr-funnel>`: a conversion funnel — an ordered set of stages, each drawn as a bar
125
+ whose length is that stage's share of the FIRST stage, read top-to-bottom as progressive drop-off.
126
+
127
+ Nothing in the catalogue expressed this. A funnel is not a sorted bar chart: it normalizes to the
128
+ first stage rather than the data maximum, its value axis carries no information worth drawing, and it
129
+ is read as stage-to-stage retention rather than category comparison. Reaching one through
130
+ `lr-bar-chart` meant switching off axes, grid and legend, hand-computing every percentage, and still
131
+ pulling the Chart.js peers for what is a handful of rectangles. `lr-span-waterfall` encodes time
132
+ offset, not share; `lr-flow-canvas` draws a graph, not a quantitative comparison; `lr-stepper` and
133
+ `lr-progress-bar` express position or completion, not per-stage magnitude.
134
+
135
+ It lives in the `data` family beside `lr-heatmap` and `lr-gauge` as an analytics primitive, and pulls
136
+ no peer at all.
137
+
138
+ Each stage carries both its absolute value and its share, because the interesting question is usually
139
+ the percentage but the credibility check is the count. `comparison` draws a second series behind each
140
+ bar, normalized to ITS OWN first stage, so a cohort's funnel *shape* can be read against a baseline
141
+ whose absolute volumes are not comparable — comparing one entity against a many-entity peer group is
142
+ the common case, and per-series normalization is what makes it legible. `dropoff` (on by default)
143
+ renders the consecutive-stage change.
144
+
145
+ The chart is plain HTML — an ordered list of stages with real text and a percentage-width bar — so
146
+ the accessible representation *is* the chart rather than a transcript bolted onto a sighted-only
147
+ drawing.
148
+
149
+ Degenerate cases are defined and tested rather than left to chance: an empty series renders a
150
+ localized empty state, a single stage renders one bar and no drop-off, a zero or negative first stage
151
+ suppresses shares instead of dividing by it, a stage larger than its predecessor (real in funnels
152
+ with re-entry) is not clamped, and a comparison series of a different length is matched by position.
153
+ - bd0f05f: `<lr-map>`'s `dataLayers` gained declarative marker clustering and a heatmap layer kind. Both are
154
+ strictly additive — today's behaviour is the default in each.
155
+
156
+ `cluster?: { radius?, maxZoom?, radiusSteps?, colorSteps?, countFont? }` opts an entry into
157
+ MapLibre's native clustering: the source gains `cluster`/`clusterRadius`/`clusterMaxZoom` and the
158
+ entry emits a cluster circle layer, a count symbol layer, and a circle layer for points that stayed
159
+ unclustered. `markers` creates one `maplibregl.Marker` per entry, which is right for tens of pins and
160
+ wrong for thousands — a consumer rendering up to 5,000 listings in a country-sized viewport got 5,000
161
+ DOM nodes and an unreadable map. `radiusSteps`/`colorSteps` are `['step', …]` breaks on `point_count`
162
+ in the same ascending `[value, output]` vocabulary `choropleth.stops` already uses, including the
163
+ same "the first stop's output is also the base" rule.
164
+
165
+ `kind?: 'auto' | 'heatmap'` plus `heatmap?: { weightField?, weightRange?, stops?, radius?, intensity? }`
166
+ reaches MapLibre's first-class `heatmap` layer type. `dataLayers` emitted exactly three
167
+ geometry-filtered layers — fill, line and circle — so a weighted-point density surface was
168
+ unreachable declaratively even though the peer implements it. The colour ramp reuses the same
169
+ `[value, color]` stop vocabulary `choropleth.stops` and `legendGradient` share.
170
+
171
+ Between them these were the only remaining reason for raw MapLibre in at least one consumer, which
172
+ carried roughly 212 lines behind the `.map` escape hatch — plus a `style.load` listener and
173
+ idempotent remove-then-add, because a basemap swap wipes every layer and `<lr-map>` restored only its
174
+ own. Both new renderings join the component's existing re-application path, so a `mapStyle` swap
175
+ restores them too.
176
+ - bd0f05f: New opt-in stylesheet `@aceshooting/lyra-ui/tokens-root.css` publishes a curated subset of the
177
+ resolved `--lr-*` layer at document scope, so an application's own custom elements can read the
178
+ kit's tokens.
179
+
180
+ `theme.css` ships the `--lr-theme-*` INPUT layer at `:root`, but the resolved OUTPUT layer
181
+ (`--lr-color-*`, `--lr-space-*`, `--lr-radius`, `--lr-shadow-*`, `--lr-font-*`) is declared only
182
+ inside each `lr-*` component's own shadow `:host`. An app's own elements are not descendants of any
183
+ `lr-*` host, so nothing inherits it to them. Consumers measured the consequence in Chromium rather
184
+ than inferring it: at document scope `--lr-color-brand`, `--lr-color-border` and `--lr-focus-ring`
185
+ all resolve to the empty string while `--lr-theme-focus-ring-width` resolves fine. One project found
186
+ 550 `var(--lr-*)` references in its own components reading nothing — 358 with no fallback at all,
187
+ the rest silently running on a literal fallback that never tracked the theme. Neither failure is
188
+ detectable without reading computed styles in a browser, because an undefined custom property is not
189
+ an error.
190
+
191
+ The subset is curated rather than complete, deliberately: `--lr-*` is documented as the internal
192
+ output layer precisely so it can change without a major, and publishing all of it would make several
193
+ hundred names permanent public API. 114 names are in — ambient surfaces/text/borders, the semantic
194
+ colour grid and its flat aliases, the spacing scale, radii, border widths, elevation, font sizes and
195
+ weights, the focus-ring parts, and the base motion pair — each with a stated reason in the file, as
196
+ is each deliberate omission.
197
+
198
+ It is generated from the same canonical token source as everything else, so it cannot drift, and a
199
+ fail-closed validator in the existing `check:design-tokens` gate rejects a curated token whose value
200
+ reaches an internal name the file does not declare — the case that would otherwise ship an empty
201
+ `var()` at `:root`. Ramp references resolve to literals at generation time and stay behind their
202
+ `--lr-theme-*` input, so the file is self-sufficient without `theme.css`, still fully rethemable,
203
+ publishes no ramp names, and computes byte-identical values to what a component reaches through the
204
+ ramp.
205
+
206
+ Opt-in, and layered in `lr-theme` like `theme.css`, so it changes nothing for anyone who does not
207
+ import it and an app's own unlayered rules still win.
208
+ - bd0f05f: `web-types.json` now carries `js.properties`, `js.events` and `slots` alongside its attributes.
209
+
210
+ It previously declared attributes and nothing else: 0 of 284 tags had properties, events or slots,
211
+ while `custom-elements.json` in the same tarball described 1,029 events, 3,102 public fields and 445
212
+ slots. 865 of those fields are `attribute: false` and were therefore invisible to JetBrains
213
+ completion entirely — and they are frequently the primary API rather than an edge case
214
+ (`lr-chart.datasets`, `.labels`, `.config`, `lr-heatmap.legendStops`, `.colorSteps`, `.cellColor`,
215
+ `lr-lite-chart.datasets`).
216
+
217
+ That gap mattered more here than it would for a typical component library: these are Lit components,
218
+ so the idiomatic usage is `.prop=${…}` and `@event=${…}` in a template, not attributes. The shipped
219
+ metadata covered the minority binding style and omitted the majority.
220
+
221
+ The web-types schema the file already declared supports all three directly, and the data was already
222
+ generated for the manifest, so this was a projection gap rather than missing information. It now
223
+ emits every public instance field with its type and default, every declared event with its
224
+ `CustomEvent<…Detail>` handler type, and every slot. Static fields and methods are deliberately
225
+ excluded (a `.formAssociated=` completion would be wrong, and web-types has no IDE-integrated method
226
+ kind).
227
+
228
+ The sibling `vscode-html-data.json` stays attributes-only, which is correct: the VS Code custom-data
229
+ format defines no properties/events/slots concept.
230
+
231
+ ### Patch Changes
232
+
233
+ - 103922d: Documented that `<lr-chart>`'s `description` **replaces** the generated accessible summary rather
234
+ than adding to it.
235
+
236
+ Unset, the component builds an sr-only per-series summary from the actual data; set, it discards
237
+ that summary entirely and substitutes the supplied text. That is the right behaviour for a full
238
+ override, but the property was documented only as "Accessible chart description", which reads as
239
+ additive — and a consumer adding a one-line caveat to five charts would have silently traded away
240
+ the data summary on all five. They caught it by reading the source, and applied it only where the
241
+ trade was actually wanted.
242
+
243
+ No behaviour change; the JSDoc and the family reference now state the trade and point at the better
244
+ tool for a caveat, which is visible text beside the chart rather than a note only screen-reader
245
+ users hear.
246
+ - 2a156eb: Added the missing package-export route for
247
+ `@aceshooting/lyra-ui/components/media/flag/flag-peer-bulk.js`. 11.2.0 led with that module as the
248
+ opt-in bulk peer-registration entry point for `<lr-flag>`, and `llms/components/lr-flag.md` and
249
+ `flag.class.d.ts` both told readers to import it — but it was never listed in `package.json`'s
250
+ `exports`, and an exports map blocks everything it does not list. Following the documentation was a
251
+ hard build error (`"…/flag-peer-bulk.js" is not exported under the conditions […]`), so the
252
+ release's headline `<lr-flag>` feature was unreachable by any consumer.
253
+
254
+ The derivation that exists to prevent exactly this — every `*-loader.ts` / `*-peer.ts` /
255
+ `*-register.ts` / `registry.ts` module must be explicitly classified as public or internal — missed
256
+ it because a *qualified* suffix (`-peer-bulk`) is not the bare suffix (`-peer`). The convention now
257
+ accepts qualified variants; across the whole source tree that widening catches this file and
258
+ nothing else.
259
+
260
+ A second, independent instance surfaced in the same sweep and is fixed too:
261
+ `@aceshooting/lyra-ui/components/data/flow-canvas/flow-types.js` is shown as an import in
262
+ `llms/data.md` and in the generated `llms/components/lr-flow-canvas.md`, and was likewise
263
+ unlisted. (Those types were still reachable through `flow-canvas.class.js`, so this adds the route
264
+ the docs already named rather than any new surface.)
265
+
266
+ Both were promises made in documentation, which no naming convention over the source tree can see.
267
+ So a new release gate, `check:doc-specifiers`, now reads the promises instead: every
268
+ `@aceshooting/lyra-ui/…` specifier a shipped file tells a reader to import must resolve through the
269
+ exports map. It understands prose instructions as well as fenced code examples — the
270
+ `flag-peer-bulk.js` promise was a sentence, not a code block.
271
+ - 8084d04: Added `flag-peer-bulk.js` (and the new `flag-peer-bulk-standard.js`) to `package.json`'s
272
+ `sideEffects` list.
273
+
274
+ These modules exist purely for their import-time side effect: a consumer writes a bare
275
+ `import '…/flag-peer-bulk.js'` and never reads an export, so a bundler honouring `sideEffects` drops
276
+ the module outright unless it is declared. The generator that derives these entries matched the bare
277
+ suffix `-peer.ts` but not the qualified `-peer-bulk.ts` — the same blind spot that left the module
278
+ out of the `exports` map.
279
+
280
+ This half failed more quietly than that one. The missing export route was a hard build error; a
281
+ missing `sideEffects` entry compiles cleanly and then simply does nothing in a production build, so
282
+ `<lr-flag>` would fall back to no resolver with no diagnostic at all.
283
+ - bd0f05f: `<lr-flag>` now distinguishes a peer that is not installed from one that is installed but does not
284
+ carry the capability the chosen entry point needs.
285
+
286
+ Both cases previously produced the same warning — "install it with `pnpm add
287
+ @aceshooting/lyra-flags`" — which is advice a reader in the second case has already followed, and
288
+ which sends them looking for the wrong problem entirely.
289
+
290
+ That case stops being exotic from this release on. `flag-peer-bulk-standard.js` requires
291
+ `createFlagUrlResolver()` on the tier-committed `./standard` subpath, which older peers do not
292
+ export at all, so a consumer who upgrades `@aceshooting/lyra-ui` while pinning
293
+ `@aceshooting/lyra-flags` reaches it by the ordinary route. The peer-range floor moves in the same
294
+ release to make that a resolution warning rather than a silent one, and this makes the runtime
295
+ message match: it now says the package is present, that this is a version mismatch, and where to
296
+ look for the floor it expects.
297
+ - 2a156eb: `<lr-heatmap>`'s `matrixGeometry` now returns the geometry the last matrix-mode draw actually
298
+ painted with, instead of recomputing from current layout on every read.
299
+
300
+ It is documented as "the gutter/cell geometry the last matrix-mode draw actually painted with", and
301
+ 11.2.0's notes claimed it "can never disagree" with the canvas because it reuses the same internal
302
+ getters `drawMatrix()` calls. Reusing those getters is precisely what made it disagree: they read
303
+ *current* layout, not the last paint, so any interval where layout has moved but no draw has
304
+ happened made the getter describe a canvas that does not exist. Two such intervals are routine —
305
+ full redraws pause while the host is outside the viewport (documented behaviour of this component),
306
+ and `rowLabelWidth`/`colLabelHeight` are not redraw-triggering properties at all, so assigning one
307
+ moved the getter *permanently* ahead of the canvas rather than for a transient window.
308
+
309
+ That landed squarely on the use case the property was added for: a light-DOM sticky-header mirror
310
+ for a tall matrix — i.e. exactly the component most likely to be scrolled out of view. A mirror
311
+ synced from the getter while the grid was off-screen lined up with geometry the canvas was not
312
+ using, which is the same misalignment the property exists to eliminate. It also silently disagreed
313
+ with `lr-matrix-geometry-change`, which fires only from the draw path and was always correct.
314
+
315
+ The getter now returns the frozen object the draw stored and the event carried, so the two are
316
+ equal by construction. The returned object is frozen, so a consumer cannot corrupt the component's
317
+ own change detection by mutating it.
318
+ - 2a156eb: Fixed two defects in `<lr-map>`'s `maxBounds`, reported together because the first was the only
319
+ thing hiding the second.
320
+
321
+ `maxBounds` never reached maplibre-gl when set declaratively. It is `attribute: false`, so a
322
+ property binding is the only way to set it, which puts its one and only appearance in `changed` on
323
+ the first update — before the component's asynchronous peer import and WebGL initialization have
324
+ produced a map. The `updated()` guard `changed.has('maxBounds') && this._map` therefore
325
+ short-circuited, and because the property never changed again it was never retried: a documented
326
+ property that read back as set, did nothing, permanently, and warned about none of it. It is now
327
+ applied from the map-ready path as well, so a declaratively-set box reaches the peer; a later
328
+ reassignment still goes through `updated()` as before.
329
+
330
+ The property's guard also could not run in the case it was written for. It applies the bounds and
331
+ then reads the camera back to detect a non-finite zoom — but at the conditions its own warning text
332
+ names (sub-1 fractional zooms in wide containers) maplibre-gl 6.x throws synchronously out of
333
+ `setMaxBounds()` instead, so the readback line was never reached. With no `try`/`catch` the
334
+ exception escaped `updated()` into the consumer's render cycle, degenerating into repeated throws
335
+ from the peer's own matrix math on every later `resize`/`setZoom` and a canvas that never painted
336
+ again. A throw now routes into the same drop-the-constraint-and-restore-the-camera path the
337
+ non-finite-camera branch already used, so the documented worst case — an unconstrained map plus one
338
+ dev-mode warning — is now the real worst case.
339
+ - 2a156eb: The release process now fails when the published upgrade feed lags npm.
340
+
341
+ The documented upgrade workflow tells consumers — and upgrading agents — to fetch
342
+ `https://www.lyra-ui.com/changelog.json` and read every release between their installed version and
343
+ its `latest`. That feed is built from this package's `CHANGELOG.md` by the sibling website and
344
+ deployed separately, after the release, so between `npm publish` and that deploy it advertises the
345
+ *previous* release as current.
346
+
347
+ Consumers reported that window twice, from two different projects, on two consecutive releases: the
348
+ site said 11.0.0 while npm had 11.1.0, then 11.1.0 while npm had 11.2.0. It fails silently and it
349
+ inverts the workflow's own advice — a reader who trusts the feed concludes they are already current
350
+ and never reads the new release. One release skipped that way contained a fix the reader was
351
+ waiting for. Both reporters caught it only by reading the installed tarball's `CHANGELOG.md`
352
+ instead, which is what the workflow tells them they should not have to do.
353
+
354
+ `release-integrity.mjs verify-site-freshness` now checks npm's dist-tag, the published feed's
355
+ `latest`, the presence of the new version in its `releases` array (it went missing entirely once,
356
+ which defeats even a reader who ignores `latest`), and the component catalog's `catalog_version` —
357
+ which rides the same deploy and was caught a release behind at the same time. The release script
358
+ waits on it, so a stale feed is now a loud, actionable release failure rather than something a
359
+ consumer discovers weeks later.
360
+
361
+ No published component surface changes.
362
+ - 8084d04: Restored two public property names that were renamed with no alias, no changelog entry and no
363
+ deprecation record, silently breaking shipped consumers.
364
+
365
+ - `<lr-app-rail-item>`: `active` is back as a deprecated alias for `current`, read alongside it —
366
+ the item is current when either is true, in both property and attribute form.
367
+ - `<lr-widget>`: `activeView` is back as a deprecated alias for `activeViewId`, which it seeds.
368
+
369
+ Both were the members' *original* public names. `active` shipped documented as public API ("add an
370
+ `active` property that reflects `aria-current="page"` onto the item"), and a later release's notes
371
+ still described it as `active` after the rename had already happened. `activeView` never appears in
372
+ `CHANGELOG.md` at all, so its rename was never announced in any form.
373
+
374
+ The breakage was invisible by construction: a Lit `.prop=${…}` binding on a custom element is
375
+ untyped, so `.active=${…}` and `.activeView=${…}` did not error — they became dead expandos. No
376
+ consumer type check, test suite or build step could see it. One consumer's app rail consequently
377
+ had no current-item indicator and a permanent `aria-current="false"` — an accessibility regression
378
+ — and its widgets fell back to their first view, with everything still passing.
379
+
380
+ This is what the house rule about mirrored members already required in general: a rename adds a
381
+ second name, it does not swap one out from under shipped consumers. The compatibility window runs
382
+ long (`removalNotBefore` two majors out) because these aliases are not new API — they are the names
383
+ consumers already wrote.
384
+
385
+ `activeView` seeds rather than being read alongside, because unlike a boolean flag it is a property
386
+ the component itself writes (a view-toggle click, and the fallback when `views` no longer contains
387
+ the active id); a read-alongside alias would undo a later interactive change on the next update.
388
+ - Updated dependencies [bd0f05f]
389
+ - @aceshooting/lyra-flags@2.2.0
390
+
3
391
  ## 11.2.0
4
392
 
5
393
  ### Minor Changes
package/README.md CHANGED
@@ -27,7 +27,7 @@
27
27
  **Lyra UI — the free, independent web-component alternative.** A MIT-licensed [Lit](https://lit.dev)
28
28
  library for accessible forms, dashboards, charts, data visualization, and Conversation & Agent UI.
29
29
  It is a practical open-source alternative to [Shoelace](https://shoelace.style/) and
30
- [Web Awesome](https://webawesome.com/), with 284 custom elements, native custom-element APIs,
30
+ [Web Awesome](https://webawesome.com/), with 285 custom elements, native custom-element APIs,
31
31
  tree-shakeable imports, its own `--lr-*` design tokens, built-in localization and RTL support,
32
32
  and no runtime dependency on either project.
33
33
 
@@ -892,12 +892,14 @@ them — typically in a workspace `.vscode/settings.json` so the whole team pick
892
892
  ```
893
893
 
894
894
  Both settings accept an array, so add these alongside any other custom-data files the workspace
895
- already references. WebStorm/IntelliJ users get the same tag, attribute, and custom-property
896
- completion automatically from the bundled `web-types.json` JetBrains IDEs pick up a dependency's
897
- `web-types.json` with no extra configuration once the package is installed. The selected plain
898
- custom-element schemas do not define structural slot or CSS-part completion fields, so those names
899
- remain available as reference prose in each element's hover description rather than as completion
900
- items.
895
+ already references. WebStorm/IntelliJ users get more from the bundled `web-types.json`, with no
896
+ extra configuration once the package is installed: tag, attribute, JS property (`.prop=${…}`), DOM
897
+ event (`@lr-event=${…}`), slot and custom-property completion. The property and event contributions
898
+ matter most here these are Lit components, so the idiomatic binding style is `.prop=`/`@event=`
899
+ rather than attributes, and 865 public members are declared `attribute: false` and reachable no other
900
+ way. The VS Code custom-data format defines no properties/events/slots concept, so in
901
+ `vscode-html-data.json` those names remain reference prose in each tag's hover description. CSS-part
902
+ names are prose in both files.
901
903
 
902
904
  Build tools can import the published manifest directly through its explicit package export:
903
905
 
@@ -914,7 +916,7 @@ resolved `web-types.json`/`vscode-html-data.json` above instead.
914
916
 
915
917
  ## Components
916
918
 
917
- The catalog below lists all 284 tags in the current Custom Elements Manifest, grouped by
919
+ The catalog below lists all 285 tags in the current Custom Elements Manifest, grouped by
918
920
  capability. The manifest and live docs are the authoritative sources for the complete generated
919
921
  API details.
920
922
 
@@ -995,6 +997,7 @@ API details.
995
997
  | `<lr-time-range>` | — (extra) | Two-handle brush/scrubber over a numeric domain |
996
998
  | `<lr-sequence-playback>` | — (extra) | Play/pause sequence index stepper over `itemCount`, with `currentIndex` and `lr-sequence-step` |
997
999
  | `<lr-heatmap>` | — (extra) | DPR-aware Canvas heatmap with matrix and calendar (`mode="calendar"`) layouts, `fit-to-width` responsive scaling |
1000
+ | `<lr-funnel>` | — (extra) | Dependency-free conversion funnel: each stage a bar sized as its share of the FIRST stage, labelled with both its absolute value and its share, with per-stage drop-off and an optional comparison series normalized to its own first stage; plain HTML, so the accessible representation is the chart itself |
998
1001
  | `<lr-sequence-strip>` | — (extra) | Compact, one-thin-cell-per-item strip visualizing a sequence of categorical states with an optional secondary per-cell marker — pure CSS/flex, no chart.js/SVG/canvas; a named roving `role="list"` whose `role="listitem"` cells are individually inspectable with Arrow/Home/End navigation but deliberately non-activating |
999
1002
  | `<lr-graph>` | — (extra) | Force-directed node-link diagram with pan/zoom/drag, directed/styled relationship links, and rich accessible metadata — needs the optional peer deps `d3-force`, `d3-drag`, `d3-zoom`, `d3-selection` |
1000
1003
  | `<lr-tree>` + `<lr-tree-item>` | `wa-tree` / `wa-tree-item` / `sl-tree` / `sl-tree-item` | Expand/collapse hierarchy with structured icon/label/description/badge rows, optional richer accessible labels, and APG tree keyboard navigation |