@aceshooting/lyra-ui 17.0.0 → 18.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 (107) hide show
  1. package/CHANGELOG.md +483 -0
  2. package/README.md +2 -2
  3. package/custom-elements.json +1 -1
  4. package/design-tokens.json +1 -1
  5. package/dist/cli/migration-contract.json +1 -1
  6. package/dist/components/conversation/message-actions/message-actions.class.d.ts +2 -1
  7. package/dist/components/conversation/streaming-text/streaming-text-core.class.d.ts +22 -0
  8. package/dist/components/conversation/streaming-text/streaming-text-core.class.js +1 -0
  9. package/dist/components/conversation/streaming-text/streaming-text.class.d.ts +22 -0
  10. package/dist/components/conversation/streaming-text/streaming-text.class.js +1 -0
  11. package/dist/components/conversation/thread-list/thread-list.class.js +1 -1
  12. package/dist/components/data/table/table.styles.js +1 -1
  13. package/dist/components/forms/combobox/combobox.class.d.ts +12 -2
  14. package/dist/components/forms/combobox/combobox.class.js +2 -2
  15. package/dist/components/forms/combobox/combobox.styles.js +1 -1
  16. package/dist/components/forms/icon-button/icon-button.class.d.ts +18 -9
  17. package/dist/components/forms/select/select.class.d.ts +63 -8
  18. package/dist/components/forms/select/select.class.js +4 -4
  19. package/dist/components/forms/select/select.styles.js +1 -1
  20. package/dist/components/layout/filter-bar/filter-bar.class.d.ts +148 -14
  21. package/dist/components/layout/filter-bar/filter-bar.class.js +12 -4
  22. package/dist/components/layout/filter-bar/filter-bar.styles.js +1 -1
  23. package/dist/components/layout/reorder-list/reorder-list.class.js +1 -1
  24. package/dist/components/layout/virtual-list/virtual-list.class.d.ts +154 -18
  25. package/dist/components/layout/virtual-list/virtual-list.class.js +12 -7
  26. package/dist/components/media/map/map.class.d.ts +269 -14
  27. package/dist/components/media/map/map.class.js +62 -30
  28. package/dist/components/media/map/map.styles.js +1 -1
  29. package/dist/components/utility/copy-button/copy-button.class.d.ts +4 -3
  30. package/dist/custom-elements-jsx.d.ts +1 -1
  31. package/dist/events.d.ts +13 -1
  32. package/dist/internal/package-metadata.d.ts +1 -1
  33. package/dist/internal/package-metadata.js +1 -1
  34. package/dist/internal/tokens.styles.js +1 -1
  35. package/dist/lyra.d.ts +1 -1
  36. package/dist/lyra.js +1 -1
  37. package/dist/styles/tokens-root.css +1 -1
  38. package/dist/svelte.d.ts +1 -1
  39. package/dist/testing/lyra-tag-event-map.js +1 -1
  40. package/dist/translations/ar/retrieval.js +1 -1
  41. package/dist/translations/ar/shared.js +1 -1
  42. package/dist/translations/de/retrieval.js +1 -1
  43. package/dist/translations/de/shared.js +1 -1
  44. package/dist/translations/es/retrieval.js +1 -1
  45. package/dist/translations/es/shared.js +1 -1
  46. package/dist/translations/fa/retrieval.js +1 -1
  47. package/dist/translations/fa/shared.js +1 -1
  48. package/dist/translations/fr/retrieval.js +1 -1
  49. package/dist/translations/fr/shared.js +1 -1
  50. package/dist/translations/he/retrieval.js +1 -1
  51. package/dist/translations/he/shared.js +1 -1
  52. package/dist/translations/it/retrieval.js +1 -1
  53. package/dist/translations/it/shared.js +1 -1
  54. package/dist/translations/ja/retrieval.js +1 -1
  55. package/dist/translations/ja/shared.js +1 -1
  56. package/dist/translations/pt-BR/retrieval.js +1 -1
  57. package/dist/translations/pt-BR/shared.js +1 -1
  58. package/dist/translations/ro/agent-tools.d.ts +1 -0
  59. package/dist/translations/ro/agent-tools.js +1 -0
  60. package/dist/translations/ro/charts.d.ts +1 -0
  61. package/dist/translations/ro/charts.js +1 -0
  62. package/dist/translations/ro/conversation.d.ts +1 -0
  63. package/dist/translations/ro/conversation.js +1 -0
  64. package/dist/translations/ro/data.d.ts +1 -0
  65. package/dist/translations/ro/data.js +1 -0
  66. package/dist/translations/ro/forms.d.ts +1 -0
  67. package/dist/translations/ro/forms.js +1 -0
  68. package/dist/translations/ro/layout.d.ts +1 -0
  69. package/dist/translations/ro/layout.js +1 -0
  70. package/dist/translations/ro/media.d.ts +1 -0
  71. package/dist/translations/ro/media.js +1 -0
  72. package/dist/translations/ro/overlays.d.ts +1 -0
  73. package/dist/translations/ro/overlays.js +1 -0
  74. package/dist/translations/ro/retrieval.d.ts +1 -0
  75. package/dist/translations/ro/retrieval.js +1 -0
  76. package/dist/translations/ro/shared.d.ts +1 -0
  77. package/dist/translations/ro/shared.js +1 -0
  78. package/dist/translations/ro/utility.d.ts +1 -0
  79. package/dist/translations/ro/utility.js +1 -0
  80. package/dist/translations/ro/viewers.d.ts +1 -0
  81. package/dist/translations/ro/viewers.js +5 -0
  82. package/dist/translations/ro.d.ts +1 -0
  83. package/dist/translations/ro.js +1 -0
  84. package/dist/translations/ru/retrieval.js +1 -1
  85. package/dist/translations/ru/shared.js +1 -1
  86. package/dist/translations/zh-CN/retrieval.js +1 -1
  87. package/dist/translations/zh-CN/shared.js +1 -1
  88. package/dist/vue.d.ts +1 -1
  89. package/llms/components/lr-button.md +5 -4
  90. package/llms/components/lr-card.md +2 -1
  91. package/llms/components/lr-combobox.md +11 -0
  92. package/llms/components/lr-filter-bar.md +123 -7
  93. package/llms/components/lr-icon-button.md +17 -8
  94. package/llms/components/lr-map.md +127 -8
  95. package/llms/components/lr-option.md +11 -0
  96. package/llms/components/lr-select.md +45 -3
  97. package/llms/components/lr-streaming-text-core.md +7 -3
  98. package/llms/components/lr-streaming-text.md +7 -2
  99. package/llms/components/lr-virtual-list.md +53 -0
  100. package/llms/shared.md +47 -3
  101. package/llms/tokens.md +7 -4
  102. package/llms-full.txt +465 -36
  103. package/package.json +28 -2
  104. package/registrations.json +1 -1
  105. package/vscode-css-data.json +1 -1
  106. package/vscode-html-data.json +1 -1
  107. package/web-types.json +1 -1
@@ -4,15 +4,27 @@ export type LyraMapLegendPattern='solid'|'diagonal'|'dots'|'crosshatch';
4
4
  /** One immutable, bounded map-legend row. Pattern is required so color is never the sole cue. */
5
5
  export interface LyraMapLegendEntry{readonly color:string;readonly label:string;readonly pattern:LyraMapLegendPattern;
6
6
  /**
7
+ * Category key this row stands for -- the same string a `point.colors` / `point.icons` entry
8
+ * matches against `point.field` / `point.iconField`. Trimmed, bounded to 256 characters and
9
+ * retained in the canonical readback, unlike the `value` on the `icon` record below, which is
10
+ * still dropped. A row that carries one becomes a keyboard-operable visibility toggle under
11
+ * `legendInteractive`; a row without one stays inert. An absent, non-string, empty or
12
+ * whitespace-only key leaves no `value` key at all, so a legend that never used categories
13
+ * reads back exactly as it did before this field existed.
14
+ */
15
+ readonly value?:string;
16
+ /**
7
17
  * Optional glyph painted inside `[part="legend-swatch"]`, in the entry's own color, instead of
8
18
  * the solid color block that would otherwise cover it. Deliberately the record `point.icons`
9
19
  * already carries, so a key can reproduce the symbol its point layer draws rather than
10
20
  * describing it in color alone — hand the legend the very icon object the layer renders.
11
21
  *
12
- * The point layer's `value` category key means nothing to a legend row: it is accepted so a
13
- * pass-through needs no reshaping, and left out of the canonical readback. Validation is the
14
- * point icon's own (path data only, at most 8192 characters, positive `viewBox` dimensions);
15
- * an unusable record is dropped and the row keeps rendering its color swatch.
22
+ * The **icon record's own** `value` is accepted so a pass-through needs no reshaping, and is
23
+ * left out of the canonical readback: a row's category key is the row-level `value` above, and
24
+ * is never derived from the glyph's. Deriving it would silently make a row interactive that the
25
+ * author never marked. Validation is the point icon's own (path data only, at most 8192
26
+ * characters, positive `viewBox` dimensions); an unusable record is dropped and the row keeps
27
+ * rendering its color swatch.
16
28
  *
17
29
  * That per-record 8192-character cap is deliberately the whole bound on path data, with no
18
30
  * aggregate budget of the kind `label` carries across the legend. Two reasons. The admission
@@ -25,7 +37,30 @@ export interface LyraMapLegendEntry{readonly color:string;readonly label:string;
25
37
  * most 8192 characters. A glyph omission is not counted in `legendProjection` either, because
26
38
  * the row it belongs to still renders — only dropped rows are omissions.
27
39
  */
28
- readonly icon?:LyraMapPointIcon|Omit<LyraMapPointIcon,'value'>;}
40
+ readonly icon?:LyraMapPointIcon|Omit<LyraMapPointIcon,'value'>;
41
+ /**
42
+ * Optional section this row belongs to. A key describing two layers at once could previously
43
+ * only be one flat list, with nothing saying which rows belonged to which.
44
+ *
45
+ * **The grouping rule, which is pinned rather than inferred:** CONSECUTIVE entries sharing an
46
+ * identical `group` render as one section -- a visible heading plus a `role="group"` the heading
47
+ * names. An entry with no `group` keeps its DECLARED position: it is never hoisted above or sunk
48
+ * below a section, and a `group` that reappears after an interruption opens a SECOND section
49
+ * rather than reordering rows to merge them. Declaration order is the one thing the legend never
50
+ * rewrites, because the order is itself information about the map.
51
+ *
52
+ * It is caller-supplied DATA, so it renders verbatim and is never passed through the locale
53
+ * catalog. It is trimmed and bounded to 256 characters (ellipsized, since it is rendered prose
54
+ * rather than a matched key); a non-string, empty or whitespace-only value leaves no `group` key
55
+ * at all, so an empty string means "ungrouped" instead of an empty heading, and a legend that
56
+ * never used sections reads back exactly as it did before this field existed.
57
+ *
58
+ * Like the row-level `value`, it is NOT charged to the aggregate label budget: a budget bounds
59
+ * rendered text, and the rendered total here is already finite and stated -- at most one heading
60
+ * per rendered row, so at most 100 of them, each at most 256 characters. A section is also not a
61
+ * row: the 100-row cap and the `legend-limit` summary count rows, never sections.
62
+ */
63
+ readonly group?:string;}
29
64
  /**
30
65
  * One `[value, color]` stop of a continuous legend ramp — deliberately the same shape as
31
66
  * `LyraMapChoroplethLayer['stops']`, so a consumer passes the choropleth's own stops straight
@@ -325,7 +360,27 @@ export interface LyraMapInstance{getCanvas():HTMLCanvasElement;getCenter():{lng:
325
360
  */
326
361
  setMaxBounds?(bounds?:unknown):unknown;}
327
362
  /** A pan-constraining box, `[[west, south], [east, north]]`, in the order maplibre-gl takes. */
328
- export type LyraMapBounds=readonly[readonly[number,number],readonly[number,number]];export declare function buildGeoJsonPropertyDiff(previous:unknown,next:unknown):MapLibreGeoJsonDiff|null;export interface LyraMapEventMap{'lr-map-load':CustomEvent<null>;'lr-map-marker-activate':CustomEvent<LyraMapMarkerActivationDetail>;'lr-map-click':CustomEvent<{readonly lngLat:readonly[number,number];readonly feature:Feature|undefined;
363
+ export type LyraMapBounds=readonly[readonly[number,number],readonly[number,number]];export declare function buildGeoJsonPropertyDiff(previous:unknown,next:unknown):MapLibreGeoJsonDiff|null;
364
+ /**
365
+ * Complete proposed visibility snapshot for one map legend category, mirroring
366
+ * `LyraChartLegendVisibilityChangeDetail`'s shape so a host that already reconciles a chart legend
367
+ * reconciles this one the same way. Frozen, and detached from the component's own state.
368
+ */
369
+ export interface LyraMapLegendToggleDetail{
370
+ /** The activated row's `value` category key, exactly as it was admitted. */
371
+ readonly value:string;
372
+ /** Proposed visibility of `value` after this toggle. */
373
+ readonly visible:boolean;
374
+ /** Complete canonical proposed hidden-category set, in the order it would be committed. */
375
+ readonly hiddenCategories:readonly string[];}
376
+ /**
377
+ * Proposed disclosure state for the legend PANEL, which is a different thing from one category's
378
+ * visibility -- hence its own detail type rather than a reuse of `LyraMapLegendToggleDetail`.
379
+ * Frozen, and detached from the component's own state.
380
+ */
381
+ export interface LyraMapLegendPanelToggleDetail{
382
+ /** Proposed `legendOpen` after this activation. */
383
+ readonly open:boolean;}export interface LyraMapEventMap{'lr-map-load':CustomEvent<null>;'lr-map-marker-activate':CustomEvent<LyraMapMarkerActivationDetail>;'lr-map-legend-toggle':CustomEvent<LyraMapLegendToggleDetail>;'lr-map-legend-panel-toggle':CustomEvent<LyraMapLegendPanelToggleDetail>;'lr-map-click':CustomEvent<{readonly lngLat:readonly[number,number];readonly feature:Feature|undefined;
329
384
  /** Which layer `feature` was hit on, so a click is attributable when both a choropleth and
330
385
  * `dataLayers` are painted. `'cluster'` marks a hit on a clustered entry's aggregate circle,
331
386
  * whose `point_count`/`cluster_id` properties describe the group rather than one feature.
@@ -370,6 +425,25 @@ readonly sourceId:string|undefined;}>;}
370
425
  *
371
426
  * @customElement lr-map
372
427
  * @event lr-map-load - Fired once the underlying maplibregl.Map loads.
428
+ * @event lr-map-legend-toggle - **Cancelable.** Fired once when an interactive legend row is
429
+ * activated by pointer or by Enter/Space, carrying the immutable
430
+ * `detail: { value, visible, hiddenCategories }` -- the activated category key, its proposed
431
+ * visibility, and the complete proposed hidden set in the order it would be committed.
432
+ * `preventDefault()` is a real veto: `hiddenCategories` is not written, the row's `aria-pressed`
433
+ * does not change, the MapLibre paint is untouched, and nothing is announced, which is what lets
434
+ * a host own the set and write it itself. There is deliberately no second confirmation event:
435
+ * the committed state is `hiddenCategories`, which the host already observes, so a paired
436
+ * before/after vocabulary would be permanent public surface nobody asked for. A programmatic
437
+ * `hiddenCategories` assignment reconciles without emitting anything -- this event is a
438
+ * DOM-interaction proposal only.
439
+ * @event lr-map-legend-panel-toggle - **Cancelable.** Fired once when the `legendCollapsible`
440
+ * disclosure is activated by pointer or by Enter/Space, carrying the immutable
441
+ * `detail: { open }` -- the proposed `legendOpen` value. It is the *panel's* disclosure, not a
442
+ * *category's* visibility, so it deliberately does not reuse `lr-map-legend-toggle`.
443
+ * `preventDefault()` is a real veto: `legendOpen` is not written, the rendered rows and the
444
+ * disclosure's `aria-expanded` do not change, which is what lets a host own the open state and
445
+ * write it itself. A programmatic `legendOpen` assignment reconciles without emitting anything,
446
+ * so a controlled host cannot loop.
373
447
  * @event lr-map-marker-activate - Fired once when an accepted declarative marker is activated by
374
448
  * pointer/click or by Enter/Space. The immutable detail carries its normalized `id`, validated
375
449
  * `lngLat`, accepted marker snapshot, and activation `source`.
@@ -384,12 +458,37 @@ readonly sourceId:string|undefined;}>;}
384
458
  * @csspart container - The MapLibre container. Its generated canvas is the actual focusable map
385
459
  * region and receives the host-first accessible name and effective locale.
386
460
  * @slot legend - Custom legend content, rendered inside the legend panel's own layout so it stays
387
- * positioned with the map instead of floating beside it.
461
+ * positioned with the map instead of floating beside it. Slotted content is never made
462
+ * interactive by `legendInteractive`, which only reaches rows projected from `legend`.
463
+ * @slot legend-start - The same extension point at the TOP of the legend panel: it renders ahead
464
+ * of the gradient bar and every projected row, where `legend` renders after them. A panel header
465
+ * -- a title, a source note, a host-built control -- could previously only ever be a footer,
466
+ * because `legend` was the only slot. Content here alone opens the panel, exactly as `legend`
467
+ * content alone does, and it is never made interactive by `legendInteractive`.
388
468
  * @csspart legend - The map legend.
389
469
  * @csspart legend-swatch - A legend color swatch, or the entry's glyph when it carries an `icon`
390
470
  * — in which case the swatch drops its color block and pattern overlay, keeps the `pattern`
391
471
  * border framing the glyph as its non-color cue, carries `data-icon="true"`, and paints the
392
- * glyph itself in the entry color.
472
+ * glyph itself in the entry color. It nests inside `legend-toggle` on an interactive row and
473
+ * stays `aria-hidden`/`inert` there, so it never contributes to the button's accessible name.
474
+ * @csspart legend-toggle - The `button` an interactive legend row renders around its swatch and
475
+ * label when `legendInteractive` is set and the row carries a `value`. Absent entirely when
476
+ * either is missing, so an unset map's legend markup is unchanged.
477
+ * @csspart legend-toggle-hidden - Second token carried alongside `legend-toggle` while that row's
478
+ * category is in `hiddenCategories`. State lives in the part name rather than a separate
479
+ * attribute, so `::part(legend-toggle-hidden)` is a reachable styling hook.
480
+ * @csspart legend-group - The `role="group"` wrapping one consecutive run of legend rows that
481
+ * share a `group`. Absent entirely when no admitted entry carries one, so an ungrouped legend's
482
+ * markup is unchanged.
483
+ * @csspart legend-group-heading - The visible heading naming a `legend-group`. It renders the
484
+ * caller-supplied `group` string verbatim and names the group through `aria-labelledby`.
485
+ * @csspart legend-disclosure - The `button` that collapses and expands the whole legend panel.
486
+ * Rendered only when `legendCollapsible` is set, so an unset map's legend markup is unchanged.
487
+ * It carries the localized panel name as its visible, accessible label plus `aria-expanded`
488
+ * rendered as the literal `"true"`/`"false"`, and it grows to the shared `--lr-icon-button-size`
489
+ * hit-area floor.
490
+ * @csspart legend-disclosure-icon - The decorative chevron inside `legend-disclosure`. It is the
491
+ * wrapping part that rotates (per the shared icon set's contract), including under RTL.
393
492
  * @csspart legend-gradient - The continuous ramp bar rendered from `legendGradient`.
394
493
  * @csspart legend-lo - The low endpoint caption of the `legendGradient` bar (mirrors `lr-heatmap`).
395
494
  * @csspart legend-hi - The high endpoint caption of the `legendGradient` bar (mirrors `lr-heatmap`).
@@ -414,6 +513,12 @@ readonly sourceId:string|undefined;}>;}
414
513
  * @cssprop [--lr-map-choropleth-fill-opacity=0.75] - Fill opacity for choropleth and polygon
415
514
  * `dataLayers` fills. Read from the resolved cascade whenever those layers are applied or painted
416
515
  * after a theme change.
516
+ * @cssprop [--lr-map-hidden-category-opacity=0.15] - Opacity a hidden category's points, point
517
+ * strokes and point icons are muted to in the rendered MapLibre paint. Read from the resolved
518
+ * cascade on every paint, because MapLibre draws to a WebGL canvas the CSS cascade never reaches.
519
+ * @cssprop [--lr-map-legend-hidden-swatch-opacity=0.5] - Opacity of a hidden interactive legend
520
+ * row's decorative swatch. Only the `aria-hidden` swatch dims; the label re-colors through the
521
+ * quiet text token instead, so it keeps AA contrast.
417
522
  * @cssprop [--lr-map-popup-close-button-hover-bg=var(--lr-color-brand-quiet)] - Hover background
418
523
  * of `popup-close-button`.
419
524
  * @cssprop [--lr-map-popup-close-button-hover-color=var(--lr-color-brand)] - Hover foreground of
@@ -422,6 +527,18 @@ readonly sourceId:string|undefined;}>;}
422
527
  * @cssprop [--lr-map-popup-close-button-active-color=var(--lr-color-brand)] - Pressed foreground
423
528
  * of `popup-close-button`.
424
529
  *
530
+ * The legend is read-only unless `legendInteractive` is set, which is opt-in for a reason: an
531
+ * unset map renders exactly the key it rendered before, with no button, no extra attribute and no
532
+ * extra MapLibre paint key. Only a row that carries its own `value` becomes a toggle -- the key is
533
+ * never derived from an `icon` record's `value`, which would silently make a row operable the
534
+ * author never marked. Each toggle is a native `button`, so it is one independent tab stop per row
535
+ * (a 100-row legend contributes 100, exactly as a 100-series `lr-chart` legend does) and it grows
536
+ * to the shared `--lr-icon-button-size` hit-area floor. Activation emits the cancelable
537
+ * `lr-map-legend-toggle`; there is deliberately no confirmation event, because the committed state
538
+ * is `hiddenCategories` and the host already observes it. A hidden category mutes its points,
539
+ * point strokes and point icons through `--lr-map-hidden-category-opacity`; a `kind: 'heatmap'`
540
+ * entry is deliberately out of scope, having no per-category field to mute.
541
+ *
425
542
  * No style or tile provider is selected implicitly. Set `mapStyle` explicitly before connection;
426
543
  * this prevents a bare component from making an undeclared third-party request.
427
544
  * @status stable
@@ -459,7 +576,7 @@ renderWorldCopies?:boolean;
459
576
  maxBounds:LyraMapBounds|null;
460
577
  /** Required MapLibre style URL or peer-neutral style specification. No provider is contacted
461
578
  * unless a consumer assigns this property. */
462
- mapStyle?:Readonly<LyraMapStyleSpecification> |string;private _legend;private _legendProjection;
579
+ mapStyle?:Readonly<LyraMapStyleSpecification> |string;private _legend;private _legendProjection;private _legendGrouped;
463
580
  /** Immutable, bounded entries rendered in the optional map legend. A required pattern keeps
464
581
  * category identity available when authored colors collapse or are unavailable. */
465
582
  get legend():readonly LyraMapLegendEntry[];set legend(value:readonly LyraMapLegendEntry[]);
@@ -471,6 +588,9 @@ get legend():readonly LyraMapLegendEntry[];set legend(value:readonly LyraMapLege
471
588
  * it. `slotchange` still runs afterwards to track content added or removed later.
472
589
  */
473
590
  private hasLegendSlot;
591
+ /** The same presence flag for `slot="legend-start"`, tracked separately so a header alone opens
592
+ * the panel and so the two extension points never stand in for one another. */
593
+ private hasLegendStartSlot;
474
594
  /** Light-DOM probe for slotted legend content, valid before the slot itself has ever rendered. */
475
595
  private probeLegendSlot;private _legendGradient;
476
596
  /**
@@ -500,6 +620,73 @@ legendGradientHiLabel:string|null;
500
620
  /** Counts from the latest bounded legend normalization. `truncated` covers omitted rows or
501
621
  * shortened labels; the returned record is frozen and never aliases caller input. */
502
622
  get legendProjection():LyraMapLegendProjection;
623
+ /**
624
+ * Turns every legend row that carries a `value` into a keyboard-operable visibility toggle;
625
+ * rows without one stay inert. Default `false`, and an unset map renders exactly the read-only
626
+ * key it rendered before this property existed -- no button, no extra attribute, and no extra
627
+ * MapLibre paint key.
628
+ *
629
+ * Each toggle is an independently tabbable native `button`, so Enter and Space are the
630
+ * platform's own activation and no roving tabindex is involved. The consequence is stated
631
+ * rather than hidden: a 100-row interactive legend contributes 100 tab stops, exactly as a
632
+ * 100-series `lr-chart` legend does. Each row also grows to the `--lr-icon-button-size` hit-area
633
+ * floor; the legend panel's own `max-block-size`/`overflow: auto` contains the taller list.
634
+ */
635
+ legendInteractive:boolean;
636
+ /**
637
+ * Renders a disclosure button inside the legend panel that collapses the key down to its header.
638
+ * Default `false`, and an unset map renders exactly the panel it rendered before this property
639
+ * existed -- no button, no `id` minted on the row list, and no `hidden` attribute anywhere.
640
+ *
641
+ * A collapsed panel hides the gradient bar, the rows, the `legend-limit` summary and the
642
+ * trailing `legend` slot; the `legend-start` slot and the disclosure itself stay visible, so a
643
+ * slotted header survives the collapse and the control that would restore the key is never the
644
+ * thing the collapse hides.
645
+ */
646
+ legendCollapsible:boolean;
647
+ /**
648
+ * Whether a `legendCollapsible` panel is expanded. Defaults **open**, so adding only
649
+ * `legendCollapsible` never hides an existing key; it does nothing at all while
650
+ * `legendCollapsible` is unset.
651
+ *
652
+ * It is a `true`-defaulting boolean, so it uses `trueDefaultBooleanConverter` rather than Lit's
653
+ * presence-based boolean converter, which cannot express `legend-open="false"` at all. The
654
+ * reflection follows the same converter: open (the default) reflects as an ABSENT attribute and
655
+ * collapsed reflects as `legend-open="false"`.
656
+ *
657
+ * Controlled public state, so -- exactly like `hiddenCategories` -- it deliberately survives a
658
+ * disconnect and reconnect: the "reset transient open-state in `disconnectedCallback()`" rule
659
+ * covers dropdown/preview/tooltip `@state`, not a documented property a host owns and re-reads.
660
+ * A programmatic assignment reconciles the rendered panel without emitting
661
+ * `lr-map-legend-panel-toggle`, so a controlled host cannot loop.
662
+ */
663
+ legendOpen:boolean;
664
+ /** True only when a collapsible panel is actually collapsed. `legendOpen` alone never hides
665
+ * anything, so an author who sets `legend-open="false"` without `legendCollapsible` -- and
666
+ * therefore renders no control to restore it -- still gets a readable key. */
667
+ private get legendCollapsed();
668
+ /**
669
+ * Flips the whole panel's disclosure from the `legendCollapsible` button.
670
+ *
671
+ * The veto is the absence of a write, not a write that is undone afterwards: a listener that
672
+ * owns the open state can assign its own `legendOpen` without this handler clobbering it.
673
+ */
674
+ private toggleLegendPanel;
675
+ /** The panel disclosure, or nothing at all when the panel cannot collapse. The chevron is
676
+ * decorative: the button's own visible, localized text carries its name, and `aria-expanded`
677
+ * carries the state. */
678
+ private renderLegendDisclosure;private _hiddenCategories;
679
+ /**
680
+ * Complete controlled set of muted category keys, mirroring `lr-chart`'s `hiddenDatasets`.
681
+ * Clone-owned and frozen; non-string, empty, whitespace-only and duplicate entries are dropped,
682
+ * and at most 100 keys are retained. Honoured on the first render and the first MapLibre paint,
683
+ * not only after a user toggle. An empty array deliberately means every category is visible.
684
+ *
685
+ * Controlled public state, so it deliberately survives a disconnect and reconnect: the
686
+ * "reset transient open-state in `disconnectedCallback()`" rule covers dropdown/preview/tooltip
687
+ * `@state`, not a documented property a host owns and re-reads.
688
+ */
689
+ get hiddenCategories():readonly string[];set hiddenCategories(value:readonly string[]);
503
690
  /** Optional GeoJSON choropleth layer and value-to-color configuration. */
504
691
  choropleth?:Readonly<LyraMapChoroplethLayer>;
505
692
  /** Point markers rendered over the map. Explicit IDs are unique-nonempty first-wins. An idless
@@ -530,7 +717,7 @@ label:string;
530
717
  private loading;
531
718
  /** Classified failure rendered as localized ordinary text and announced through the owner
532
719
  * document's assertive sink. */
533
- private failure?;private errorAnnouncementSink?;private loadLibrary;private visible;private intersectionObserver?;private containerEl?;private _map?;private _styleLoaded;private _appliedChoroplethSourceId?;private _appliedFillLayerId?;private _appliedDataLayerIds;
720
+ private failure?;private errorAnnouncementSink?;private legendAnnouncementSink?;private loadLibrary;private visible;private intersectionObserver?;private containerEl?;private _map?;private _styleLoaded;private _appliedChoroplethSourceId?;private _appliedFillLayerId?;private _appliedDataLayerIds;
534
721
  /**
535
722
  * The rendering shape (`'auto'`, a cluster signature, `'heatmap'`) each applied data layer was
536
723
  * built with, keyed identically to `_appliedDataLayerIds`.
@@ -543,7 +730,12 @@ private failure?;private errorAnnouncementSink?;private loadLibrary;private visi
543
730
  private _appliedDataLayerShapes;
544
731
  /** Last GeoJSON applied per resolved source id, so an update can be diffed against it rather
545
732
  * than replacing the whole source. Holds a reference, not a copy -- it is only ever compared. */
546
- private _appliedGeoJson;private _nextDataLayerId;private nextPointIconId;private appliedPointPaint;private appliedPointIcons;private _maplibreModule?;
733
+ private _appliedGeoJson;private _nextDataLayerId;private nextPointIconId;private appliedPointPaint;
734
+ /** Layer ids whose paint currently carries a muting opacity, so the first paint after the last
735
+ * category is un-hidden can restore it -- and a layer that was never muted keeps its paint
736
+ * object free of the key entirely. Keyed by layer id, not source id, because one source's
737
+ * circle and point-icon layers mute independently on different fields. */
738
+ private appliedPointMuting;private appliedPointIcons;private _maplibreModule?;
547
739
  /** True only after WebGL2 has been proved in the current owner-document realm. */
548
740
  private _webglReady;private _markerInstances;private _markerLabels;private _markerPopupIds;private readonly markerActivationDetails;private _configuredPopups;private _nextPopupId;private peerChromeObserver?;private observedPeerContainer?;private mapResizeObserver?;private observedMapContainer?;private _markerColors;private _connectGeneration;
549
741
  /** The underlying runtime `maplibregl.Map`, declared through Lyra's peer-neutral common-method
@@ -596,7 +788,9 @@ private get safeCenter();connectedCallback():void;disconnectedCallback():void;pr
596
788
  * below without risking a double construction.
597
789
  */
598
790
  private tryConstructMap;protected updated(changed:PropertyValues):void;protected willUpdate(changed:PropertyValues):void;
599
- /** Repaints token-derived MapLibre values without touching sources, layers, or map geometry. */
791
+ /** Repaints token-derived and visibility-derived MapLibre values without touching sources,
792
+ * layers, or map geometry -- which is exactly what a theme change and a `hiddenCategories`
793
+ * change each need. */
600
794
  private refreshThemePaint;private applyChoropleth;private choroplethColorExpression;
601
795
  /**
602
796
  * Keeps the choropleth out of every caller-controlled data-layer namespace. Repeatedly prefixing
@@ -630,7 +824,18 @@ private paintDataLayer;
630
824
  /** The pre-existing geometry split: polygons filled, lines/outlines stroked, points circled. */
631
825
  private applyGeometryLayers;
632
826
  /** Paint-only half of `applyGeometryLayers`. See `paintDataLayer` for why the halves are split. */
633
- private paintGeometryLayers;private lineColor;private paintPoints;private pointIconColor;private removePointIcons;private applyPointIcons;private paintPointIcons;
827
+ private paintGeometryLayers;private lineColor;
828
+ /**
829
+ * A `match` expression over `['get', field]` while any admitted category is hidden; a literal
830
+ * `1` on the first paint after the last category is un-hidden; and `undefined` whenever nothing
831
+ * is or was muted on `layerId` -- which is what leaves a `legendInteractive`-unset map
832
+ * byte-identical: the paint key is never written, so MapLibre keeps its own default and the
833
+ * layer's paint object gains no extra property.
834
+ *
835
+ * The flat `label, output` pair form is deliberately the shape `point.colors` already emits two
836
+ * lines above its own `match`, so this file speaks one expression idiom rather than two.
837
+ */
838
+ private mutedPointOpacity;private paintPoints;private pointIconColor;private removePointIcons;private applyPointIcons;private paintPointIcons;
634
839
  /**
635
840
  * `['step', ['get', 'point_count'], …]` over the authored cluster color breaks, or the layer's
636
841
  * own flat color when none were supplied.
@@ -686,4 +891,54 @@ private syncPeerChromeParts;private observePeerChrome;private syncPopupSemantics
686
891
  * holds fewer than two usable stops. Part names mirror `lr-heatmap`'s
687
892
  * `legend-lo`/`legend-hi` so a consumer styling both components learns one vocabulary.
688
893
  */
689
- private renderLegendGradient;render():TemplateResult;}declare global{interface HTMLElementTagNameMap{'lr-map':LyraMap;}}
894
+ /**
895
+ * The swatch-plus-label pair every legend row renders: directly inside the row when the row is
896
+ * inert, and inside the row's toggle button when `legendInteractive` has made it operable. One
897
+ * source of truth, so the two branches can never drift, and an unset map keeps rendering exactly
898
+ * the markup it rendered before the toggle existed.
899
+ */
900
+ private renderLegendRowContent;
901
+ /**
902
+ * Flips one category's visibility from a legend toggle activation.
903
+ *
904
+ * `hiddenCategories` is a key set, so every row carrying the activated key flips together --
905
+ * self-consistent by construction rather than by a per-row visibility flag that two rows
906
+ * describing one category could disagree about.
907
+ */
908
+ private toggleLegendCategory;
909
+ /**
910
+ * The state change belongs in a live region because the thing that changed -- the map, and the
911
+ * legend row's own styling -- is not the focused element, and `aria-pressed` alone only reports
912
+ * the button's new state once focus is already on it.
913
+ */
914
+ private announceLegendVisibility;
915
+ /** Acquired lazily on the first toggle, and re-acquired against a new owner document, so a map
916
+ * that never renders an interactive legend never mounts a live region at all. */
917
+ private syncLegendAnnouncementSink;private releaseLegendAnnouncementSink;
918
+ /**
919
+ * One legend row. Extracted verbatim from the list template so the grouped and ungrouped section
920
+ * paths below render the same node rather than two copies that can drift.
921
+ *
922
+ * `aria-posinset`/`aria-setsize` deliberately stay whole-key values inside a section too.
923
+ * `aria-setsize` already reports the *input* count rather than the rendered one, so a bounded key
924
+ * stays honest; per-section input counts do not exist, because a row dropped by the bound carries
925
+ * no attributable group. A section adds a labelled sub-region; it does not renumber the key.
926
+ */
927
+ private renderLegendRow;
928
+ /**
929
+ * The row list's children: bare rows when no admitted entry carries a `group`, and otherwise one
930
+ * `role="group"` per CONSECUTIVE run sharing a group name, with ungrouped rows left exactly where
931
+ * they were declared. The ungrouped branch is literally the expression this list has always been,
932
+ * so a legend that uses no sections keeps rendering the markup it rendered before they existed.
933
+ *
934
+ * `group` is caller-supplied data: the heading renders it verbatim and never resolves it through
935
+ * the locale catalog.
936
+ *
937
+ * Each section owns its OWN `role="list"` rather than the sections sitting directly inside the
938
+ * outer one. `list` requires `listitem` children, and a `group` is not one -- axe reports both
939
+ * `aria-required-children` on the outer list and `aria-required-parent` on every row inside the
940
+ * group, critical, which is how this shape was caught. So a grouped legend renders one list per
941
+ * run (including each ungrouped run) and the outer element drops its own `role`, while an
942
+ * ungrouped legend keeps the single `role="list"` it has always had.
943
+ */
944
+ private renderLegendRows;private renderLegendGradient;render():TemplateResult;}declare global{interface HTMLElementTagNameMap{'lr-map':LyraMap;}}