@aceshooting/lyra-ui 12.0.0 → 12.1.1

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 (174) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/custom-elements.json +1 -1
  3. package/dist/autoloader.js +1 -1
  4. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.d.ts +0 -1
  5. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.js +1 -1
  6. package/dist/components/charts/chart/histogram-bin.d.ts +0 -1
  7. package/dist/components/charts/chart/histogram-bin.js +1 -1
  8. package/dist/components/charts/chart/lite-chart.class.d.ts +22 -9
  9. package/dist/components/charts/chart/lite-chart.class.js +6 -6
  10. package/dist/components/conversation/code-block/code-block-shared.d.ts +4 -54
  11. package/dist/components/conversation/code-block/code-block-shared.js +1 -1
  12. package/dist/components/conversation/code-block/shiki-types.d.ts +2 -1
  13. package/dist/components/conversation/generation-metrics/generation-metrics.class.js +1 -1
  14. package/dist/components/conversation/model-select/model-select.class.d.ts +0 -3
  15. package/dist/components/conversation/model-select/model-select.class.js +1 -1
  16. package/dist/components/conversation/selection-toolbar/selection-toolbar.class.js +1 -1
  17. package/dist/components/conversation/voice-picker/voice-picker.class.d.ts +0 -1
  18. package/dist/components/conversation/voice-picker/voice-picker.class.js +1 -1
  19. package/dist/components/data/data-grid/data-grid.class.js +1 -1
  20. package/dist/components/data/graph-query-builder/graph-query-builder.class.d.ts +0 -1
  21. package/dist/components/data/graph-query-builder/graph-query-builder.class.js +1 -1
  22. package/dist/components/data/heatmap/heatmap.class.d.ts +4 -1
  23. package/dist/components/data/heatmap/heatmap.class.js +2 -2
  24. package/dist/components/data/table/table.class.d.ts +18 -4
  25. package/dist/components/data/table/table.class.js +2 -2
  26. package/dist/components/data/table/table.styles.js +2 -1
  27. package/dist/components/data/timeline/timeline-cluster.d.ts +1 -0
  28. package/dist/components/data/timeline/timeline-cluster.js +1 -0
  29. package/dist/components/data/timeline/timeline-item.class.d.ts +17 -2
  30. package/dist/components/data/timeline/timeline-item.class.js +13 -2
  31. package/dist/components/data/timeline/timeline-item.styles.js +65 -0
  32. package/dist/components/data/timeline/timeline.class.d.ts +83 -27
  33. package/dist/components/data/timeline/timeline.class.js +3 -3
  34. package/dist/components/data/timeline/timeline.d.ts +1 -0
  35. package/dist/components/data/timeline/timeline.js +1 -1
  36. package/dist/components/data/timeline/timeline.styles.js +14 -0
  37. package/dist/components/forms/button/button.class.js +1 -1
  38. package/dist/components/forms/checkbox/checkbox.class.d.ts +0 -1
  39. package/dist/components/forms/checkbox/checkbox.class.js +1 -1
  40. package/dist/components/forms/checkbox-group/checkbox-group.class.d.ts +0 -1
  41. package/dist/components/forms/checkbox-group/checkbox-group.class.js +1 -1
  42. package/dist/components/forms/code-editor/code-editor.class.js +1 -1
  43. package/dist/components/forms/color-picker/color-picker.class.js +1 -1
  44. package/dist/components/forms/combobox/combobox.class.d.ts +7 -1
  45. package/dist/components/forms/combobox/combobox.class.js +3 -2
  46. package/dist/components/forms/combobox/combobox.styles.js +1 -1
  47. package/dist/components/forms/date-picker/date-input.class.js +1 -1
  48. package/dist/components/forms/emoji-picker/emoji-data-loader.d.ts +0 -1
  49. package/dist/components/forms/input/native-time-input.class.js +1 -1
  50. package/dist/components/forms/input/time-input-shared.d.ts +2 -1
  51. package/dist/components/forms/input/time-input.class.js +1 -1
  52. package/dist/components/forms/locale-picker/locale-picker.class.d.ts +0 -1
  53. package/dist/components/forms/locale-picker/locale-picker.class.js +1 -1
  54. package/dist/components/forms/radio/radio-button.styles.d.ts +0 -1
  55. package/dist/components/forms/radio/radio-button.styles.js +1 -1
  56. package/dist/components/forms/radio/radio-group.class.d.ts +0 -1
  57. package/dist/components/forms/radio/radio-group.class.js +1 -1
  58. package/dist/components/forms/radio/radio.class.d.ts +0 -1
  59. package/dist/components/forms/radio/radio.class.js +1 -1
  60. package/dist/components/forms/rubric-form/rubric-form.class.d.ts +0 -1
  61. package/dist/components/forms/rubric-form/rubric-form.class.js +1 -1
  62. package/dist/components/forms/select/select.class.d.ts +0 -1
  63. package/dist/components/forms/select/select.class.js +1 -1
  64. package/dist/components/forms/slider/slider.class.d.ts +0 -1
  65. package/dist/components/forms/slider/slider.class.js +1 -1
  66. package/dist/components/forms/switch/switch.class.d.ts +0 -1
  67. package/dist/components/forms/switch/switch.class.js +1 -1
  68. package/dist/components/forms/time-range/time-range.class.d.ts +0 -1
  69. package/dist/components/forms/time-range/time-range.class.js +1 -1
  70. package/dist/components/forms/token-input/token-input.class.d.ts +0 -1
  71. package/dist/components/forms/token-input/token-input.class.js +1 -1
  72. package/dist/components/layout/dashboard-grid/layout-internal.d.ts +0 -1
  73. package/dist/components/layout/dashboard-grid/layout-internal.js +1 -1
  74. package/dist/components/layout/details/accordion-owner.d.ts +1 -1
  75. package/dist/components/layout/filter-bar/filter-bar.class.js +1 -1
  76. package/dist/components/layout/menu/menu-item.class.js +1 -1
  77. package/dist/components/layout/virtual-list/virtual-list.class.js +1 -1
  78. package/dist/components/media/av-player/av-metadata.d.ts +0 -2
  79. package/dist/components/media/av-player/av-metadata.js +1 -1
  80. package/dist/components/media/file-input/file-input.class.d.ts +0 -1
  81. package/dist/components/media/file-input/file-input.class.js +1 -1
  82. package/dist/components/media/map/map-loader.d.ts +4 -1
  83. package/dist/components/media/map/map.class.d.ts +50 -12
  84. package/dist/components/media/map/map.class.js +2 -2
  85. package/dist/components/overlays/overlay/popover.class.d.ts +7 -1
  86. package/dist/components/overlays/overlay/popover.class.js +1 -1
  87. package/dist/components/overlays/overlay/tooltip.class.d.ts +1 -0
  88. package/dist/components/overlays/overlay/tooltip.class.js +1 -1
  89. package/dist/components/overlays/progress/progress-shared.d.ts +0 -2
  90. package/dist/components/overlays/progress/progress-shared.js +1 -1
  91. package/dist/components/overlays/rating/rating.class.js +1 -1
  92. package/dist/components/retrieval/graph/graph-canvas.d.ts +10 -9
  93. package/dist/components/retrieval/mind-map/mind-map-layout.d.ts +0 -4
  94. package/dist/components/retrieval/mind-map/mind-map-layout.js +1 -1
  95. package/dist/components/utility/format/format-options.d.ts +0 -2
  96. package/dist/components/utility/format/format-options.js +1 -1
  97. package/dist/components/utility/icon/icon-resource.d.ts +0 -2
  98. package/dist/components/utility/icon/icon-resource.js +1 -1
  99. package/dist/components/viewers/archive-viewer/zip-resource-guard.d.ts +2 -1
  100. package/dist/components/viewers/docx-viewer/docx-resource-guard.d.ts +0 -3
  101. package/dist/components/viewers/docx-viewer/docx-resource-guard.js +1 -1
  102. package/dist/components/viewers/ebook-viewer/ebook-loader.d.ts +2 -1
  103. package/dist/components/viewers/ebook-viewer/epub-resource-guard.d.ts +0 -3
  104. package/dist/components/viewers/ebook-viewer/epub-resource-guard.js +1 -1
  105. package/dist/components/viewers/pdf-viewer/pdf-loader.d.ts +2 -2
  106. package/dist/components/viewers/pdf-viewer/pdf-viewer.class.js +2 -2
  107. package/dist/components/viewers/pptx-viewer/pptx-resource-guard.d.ts +0 -2
  108. package/dist/components/viewers/pptx-viewer/pptx-resource-guard.js +1 -1
  109. package/dist/components/viewers/spreadsheet-viewer/xlsx-resource-guard.d.ts +0 -5
  110. package/dist/components/viewers/spreadsheet-viewer/xlsx-resource-guard.js +1 -1
  111. package/dist/custom-elements-jsx.d.ts +4 -4
  112. package/dist/events.d.ts +15 -0
  113. package/dist/internal/accessibility-visibility.d.ts +1 -1
  114. package/dist/internal/anchor-target.d.ts +1 -3
  115. package/dist/internal/anchor-target.js +2 -2
  116. package/dist/internal/anchored-overlay-runtime.d.ts +7 -0
  117. package/dist/internal/anchored-overlay-runtime.js +1 -0
  118. package/dist/internal/announcement-text.d.ts +1 -1
  119. package/dist/internal/ansi.d.ts +0 -4
  120. package/dist/internal/ansi.js +1 -1
  121. package/dist/internal/aria-ownership.d.ts +2 -1
  122. package/dist/internal/default-strings.generated.d.ts +1 -0
  123. package/dist/internal/default-strings.generated.js +1 -1
  124. package/dist/internal/focus-navigation.d.ts +3 -2
  125. package/dist/internal/form-associated.d.ts +0 -1
  126. package/dist/internal/form-associated.js +1 -1
  127. package/dist/internal/form-control-labels.d.ts +0 -3
  128. package/dist/internal/form-control-labels.js +1 -1
  129. package/dist/internal/localization-runtime.js +1 -1
  130. package/dist/internal/localization-types.d.ts +1 -1
  131. package/dist/internal/localization.js +1 -1
  132. package/dist/internal/lyra-element.d.ts +0 -13
  133. package/dist/internal/lyra-element.js +1 -1
  134. package/dist/internal/nonmodal-overlay-manager.d.ts +9 -0
  135. package/dist/internal/nonmodal-overlay-manager.js +1 -0
  136. package/dist/internal/overlay-manager.d.ts +4 -20
  137. package/dist/internal/overlay-manager.js +1 -1
  138. package/dist/internal/overlay-stack.d.ts +66 -0
  139. package/dist/internal/overlay-stack.js +1 -0
  140. package/dist/internal/package-metadata.d.ts +1 -1
  141. package/dist/internal/package-metadata.js +1 -1
  142. package/dist/internal/positioner.js +1 -1
  143. package/dist/internal/text-quote.d.ts +1 -1
  144. package/dist/lyra.d.ts +2 -3
  145. package/dist/svelte.d.ts +4 -4
  146. package/dist/translations/ar.js +1 -1
  147. package/dist/translations/de.js +1 -1
  148. package/dist/translations/es.js +1 -1
  149. package/dist/translations/fa.js +1 -1
  150. package/dist/translations/fr.js +1 -1
  151. package/dist/translations/he.js +1 -1
  152. package/dist/translations/ja.js +1 -1
  153. package/dist/translations/pt-BR.js +1 -1
  154. package/dist/translations/ru.js +1 -1
  155. package/dist/translations/zh-CN.js +1 -1
  156. package/dist/utilities/localization.js +1 -1
  157. package/dist/vue.d.ts +4 -4
  158. package/llms/components/lr-combobox.md +42 -0
  159. package/llms/components/lr-date-input.md +1 -1
  160. package/llms/components/lr-date-picker.md +1 -1
  161. package/llms/components/lr-filter-bar.md +2 -2
  162. package/llms/components/lr-heatmap.md +4 -1
  163. package/llms/components/lr-lite-chart.md +20 -8
  164. package/llms/components/lr-map.md +52 -22
  165. package/llms/components/lr-option.md +42 -0
  166. package/llms/components/lr-popover.md +39 -0
  167. package/llms/components/lr-table.md +7 -3
  168. package/llms/components/lr-timeline-item.md +49 -24
  169. package/llms/components/lr-timeline.md +49 -24
  170. package/llms-full.txt +224 -60
  171. package/package.json +3 -4
  172. package/vscode-css-data.json +21 -0
  173. package/vscode-html-data.json +12 -6
  174. package/web-types.json +47 -16
@@ -16,7 +16,8 @@ import{css}from"lit";const styles=css`
16
16
  contain-intrinsic-inline-size: var(--lr-size-20rem);
17
17
  }
18
18
 
19
- :host([scroll-mode='page']) [part='base'] {
19
+ :host([scroll-mode='page']) [part='base'],
20
+ :host([scroll-mode='auto']) [part='base']:not([data-scroll-overflow]) {
20
21
  overflow: visible;
21
22
  max-block-size: none;
22
23
  }
@@ -0,0 +1 @@
1
+ const SET_TIMELINE_CLUSTER_PRESENTATION=Symbol.for("@aceshooting/lyra-ui/timeline/cluster-presentation/v1"),OBSERVE_TIMELINE_ITEM_TIMESTAMP=Symbol.for("@aceshooting/lyra-ui/timeline/timestamp-observer/v1");function isTimelineClusterItemContract(value){const candidate=value;return typeof candidate[SET_TIMELINE_CLUSTER_PRESENTATION]=="function"&&typeof candidate[OBSERVE_TIMELINE_ITEM_TIMESTAMP]=="function"}export{OBSERVE_TIMELINE_ITEM_TIMESTAMP,SET_TIMELINE_CLUSTER_PRESENTATION,isTimelineClusterItemContract};
@@ -21,8 +21,12 @@ import type { LyraVariant } from '../../../internal/variants.js';
21
21
  * `::slotted(:last-child)` rule (see that component's stylesheet) — no JS coordination between the
22
22
  * two components is needed anywhere in this mechanism.
23
23
  *
24
- * A pure display row: no events, no keyboard interaction, and no selection/expansion state of its
25
- * own — a deliberate scope decision, not an oversight. An earlier "interactive row" design (mirroring
24
+ * A pure display row by default: no events, no keyboard interaction, and no selection/expansion
25
+ * state of its own — a deliberate scope decision, not an oversight. When a parent timeline opts
26
+ * into collision clustering, the first item in each author-ordered group temporarily represents
27
+ * that group with a native count button in this item's list position; activation still belongs to
28
+ * the parent timeline and emits its `lr-cluster-activate` event. An earlier "interactive row"
29
+ * design (mirroring
26
30
  * `<lr-conversation-item>`'s clickable `role="button"` row) was considered and dropped: this
27
31
  * component's `title` and `description` are slots that routinely contain focusable content of their
28
32
  * own (a link, a button) — wrapping them in an ancestor `role="button"` would trip axe's
@@ -63,6 +67,9 @@ import type { LyraVariant } from '../../../internal/variants.js';
63
67
  * fallback. Hidden entirely when there's nothing to show.
64
68
  * @csspart description - Wrapper around the `description` slot. Hidden entirely when the slot is
65
69
  * empty.
70
+ * @csspart cluster - The native count-marker button rendered while this item represents a parent
71
+ * timeline collision cluster; retains the shared 40px minimum action surface.
72
+ * @csspart cluster-count - The painted count pill inside a representative cluster button.
66
73
  * @cssprop [--lr-timeline-marker-size=var(--lr-size-1-25rem)] - Diameter of the marker circle
67
74
  * (both inline-size and block-size, so the default dot stays circular). Inherits from theme
68
75
  * ancestors.
@@ -79,6 +86,11 @@ import type { LyraVariant } from '../../../internal/variants.js';
79
86
  * @cssprop [--lr-timeline-active-ring-color=var(--lr-timeline-marker-color)] - Static outline color
80
87
  * for the current/in-progress marker. The outline remains visible when reduced motion disables
81
88
  * the optional pulse animation.
89
+ * @cssprop [--lr-timeline-cluster-size=var(--lr-size-2rem)] - Minimum inline and block size of the
90
+ * painted cluster count pill. Its containing button retains the shared 40px minimum action
91
+ * surface.
92
+ * @cssprop [--lr-timeline-cluster-bg=var(--lr-color-brand)] - Cluster count pill background.
93
+ * @cssprop [--lr-timeline-cluster-color=var(--lr-color-on-brand)] - Cluster count pill foreground.
82
94
  * @status stable
83
95
  * @since 4.0.0
84
96
  */
@@ -110,6 +122,9 @@ export declare class LyraTimelineItem extends LyraElement {
110
122
  private hasIconSlot;
111
123
  private hasTimestampSlot;
112
124
  private hasDescriptionSlot;
125
+ private clusterPresentation?;
126
+ private readonly timestampObservers;
127
+ private timestampObserversReady;
113
128
  connectedCallback(): void;
114
129
  protected willUpdate(changed: PropertyValues): void;
115
130
  protected updated(changed: PropertyValues): void;
@@ -1,4 +1,15 @@
1
- var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import{styles}from"./timeline-item.styles.js";import{getDateTimeFormat}from"../../../internal/intl-cache.js";const timelineItemVariantConverter={fromAttribute(value){return normalizeTimelineItemVariant(value)},toAttribute(value){return value==="neutral"?null:value}},normalizeTimelineItemVariant=value=>value==="brand"||value==="success"||value==="warning"||value==="danger"?value:"neutral";class LyraTimelineItem extends LyraElement{constructor(){super(...arguments),this.sync=!1,this._variant="neutral",this.active=!1,this.hasIconSlot=!1,this.hasTimestampSlot=!1,this.hasDescriptionSlot=!1,this.onIconSlotChange=()=>{const markerIconSlot=this.renderRoot.querySelector('slot[name="marker-icon"]');this.hasIconSlot=!!markerIconSlot?.assignedElements({flatten:!0}).length},this.onTimestampSlotChange=e=>{this.hasTimestampSlot=e.target.assignedElements({flatten:!0}).length>0},this.onDescriptionSlotChange=e=>{this.hasDescriptionSlot=e.target.assignedElements({flatten:!0}).length>0}}static{this.styles=[LyraElement.styles,styles]}get variant(){return this._variant}set variant(value){const normalized=normalizeTimelineItemVariant(value),previous=this._variant;if(previous===normalized){value!==normalized&&this.requestUpdate("variant",previous);return}this._variant=normalized,this.requestUpdate("variant",previous)}connectedCallback(){super.connectedCallback(),this.setAttribute("role","listitem")}willUpdate(changed){super.willUpdate(changed),this.setAttribute("aria-current",String(this.active))}updated(changed){if(super.updated(changed),changed.has("variant")){const reflected=timelineItemVariantConverter.toAttribute(this.variant);reflected===null?this.removeAttribute("variant"):this.getAttribute("variant")!==reflected&&this.setAttribute("variant",reflected)}}get normalizedTimestamp(){if(this.timestamp===void 0)return;const date=this.timestamp instanceof Date?this.timestamp:new Date(this.timestamp);return Number.isNaN(date.getTime())?void 0:date}render(){const ts=this.normalizedTimestamp,showTimestampFallback=!this.hasTimestampSlot&&ts!==void 0,showTimestamp=this.hasTimestampSlot||ts!==void 0,absolute=ts?getDateTimeFormat(this.effectiveLocale||void 0,{dateStyle:"long",timeStyle:"short"}).format(ts):"";return html`
1
+ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import{styles}from"./timeline-item.styles.js";import{getDateTimeFormat}from"../../../internal/intl-cache.js";import{OBSERVE_TIMELINE_ITEM_TIMESTAMP,SET_TIMELINE_CLUSTER_PRESENTATION}from"./timeline-cluster.js";const timelineItemVariantConverter={fromAttribute(value){return normalizeTimelineItemVariant(value)},toAttribute(value){return value==="neutral"?null:value}},normalizeTimelineItemVariant=value=>value==="brand"||value==="success"||value==="warning"||value==="danger"?value:"neutral";class LyraTimelineItem extends LyraElement{constructor(){super(...arguments),this.sync=!1,this._variant="neutral",this.active=!1,this.hasIconSlot=!1,this.hasTimestampSlot=!1,this.hasDescriptionSlot=!1,this.timestampObservers=new Set,this.timestampObserversReady=!1,this.onIconSlotChange=()=>{const markerIconSlot=this.renderRoot.querySelector('slot[name="marker-icon"]');this.hasIconSlot=!!markerIconSlot?.assignedElements({flatten:!0}).length},this.onTimestampSlotChange=e=>{this.hasTimestampSlot=e.target.assignedElements({flatten:!0}).length>0},this.onDescriptionSlotChange=e=>{this.hasDescriptionSlot=e.target.assignedElements({flatten:!0}).length>0}}static{this.styles=[LyraElement.styles,styles]}get variant(){return this._variant}set variant(value){const normalized=normalizeTimelineItemVariant(value),previous=this._variant;if(previous===normalized){value!==normalized&&this.requestUpdate("variant",previous);return}this._variant=normalized,this.requestUpdate("variant",previous)}[SET_TIMELINE_CLUSTER_PRESENTATION](presentation){const current=this.clusterPresentation;current===presentation||current!==void 0&&presentation!==void 0&&current.accessibleLabel===presentation.accessibleLabel&&current.countText===presentation.countText&&current.activate===presentation.activate||(this.clusterPresentation=presentation)}[OBSERVE_TIMELINE_ITEM_TIMESTAMP](observer,observe){observe?this.timestampObservers.add(observer):this.timestampObservers.delete(observer)}connectedCallback(){super.connectedCallback(),this.setAttribute("role","listitem")}willUpdate(changed){super.willUpdate(changed),this.clusterPresentation?this.removeAttribute("aria-current"):this.setAttribute("aria-current",String(this.active))}updated(changed){if(super.updated(changed),changed.has("variant")){const reflected=timelineItemVariantConverter.toAttribute(this.variant);reflected===null?this.removeAttribute("variant"):this.getAttribute("variant")!==reflected&&this.setAttribute("variant",reflected)}this.timestampObserversReady&&changed.has("timestamp")&&this.scheduleAfterUpdate(()=>{for(const observer of[...this.timestampObservers])observer()},"timeline-item-timestamp-observers"),this.timestampObserversReady=!0}get normalizedTimestamp(){if(this.timestamp===void 0)return;const date=this.timestamp instanceof Date?this.timestamp:new Date(this.timestamp);return Number.isNaN(date.getTime())?void 0:date}render(){if(this.clusterPresentation)return html`
2
+ <button
3
+ part="cluster"
4
+ type="button"
5
+ aria-label=${this.clusterPresentation.accessibleLabel}
6
+ @click=${this.clusterPresentation.activate}
7
+ >
8
+ <span part="cluster-count" aria-hidden="true"
9
+ >${this.clusterPresentation.countText}</span
10
+ >
11
+ </button>
12
+ `;const ts=this.normalizedTimestamp,showTimestampFallback=!this.hasTimestampSlot&&ts!==void 0,showTimestamp=this.hasTimestampSlot||ts!==void 0,absolute=ts?getDateTimeFormat(this.effectiveLocale||void 0,{dateStyle:"long",timeStyle:"short"}).format(ts):"";return html`
2
13
  <div part="base">
3
14
  <div part="track">
4
15
  <span
@@ -37,4 +48,4 @@ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3
37
48
  </span>
38
49
  </div>
39
50
  </div>
40
- `}}__decorate([property({attribute:!1})],LyraTimelineItem.prototype,"timestamp",void 0),__decorate([property({type:Boolean})],LyraTimelineItem.prototype,"sync",void 0),__decorate([property({reflect:!0,converter:timelineItemVariantConverter})],LyraTimelineItem.prototype,"variant",null),__decorate([property({type:Boolean,reflect:!0})],LyraTimelineItem.prototype,"active",void 0),__decorate([state()],LyraTimelineItem.prototype,"hasIconSlot",void 0),__decorate([state()],LyraTimelineItem.prototype,"hasTimestampSlot",void 0),__decorate([state()],LyraTimelineItem.prototype,"hasDescriptionSlot",void 0);export{LyraTimelineItem};
51
+ `}}__decorate([property({attribute:!1})],LyraTimelineItem.prototype,"timestamp",void 0),__decorate([property({type:Boolean})],LyraTimelineItem.prototype,"sync",void 0),__decorate([property({reflect:!0,converter:timelineItemVariantConverter})],LyraTimelineItem.prototype,"variant",null),__decorate([property({type:Boolean,reflect:!0})],LyraTimelineItem.prototype,"active",void 0),__decorate([state()],LyraTimelineItem.prototype,"hasIconSlot",void 0),__decorate([state()],LyraTimelineItem.prototype,"hasTimestampSlot",void 0),__decorate([state()],LyraTimelineItem.prototype,"hasDescriptionSlot",void 0),__decorate([state()],LyraTimelineItem.prototype,"clusterPresentation",void 0);export{LyraTimelineItem};
@@ -128,4 +128,69 @@ import{css}from"lit";const styles=css`
128
128
  [part='description'][hidden] {
129
129
  display: none;
130
130
  }
131
+
132
+ [part='cluster'] {
133
+ display: inline-flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ box-sizing: border-box;
137
+ min-inline-size: var(--lr-icon-button-size);
138
+ min-block-size: var(--lr-icon-button-size);
139
+ margin: 0;
140
+ padding: 0;
141
+ border: 0;
142
+ background: transparent;
143
+ color: inherit;
144
+ font: inherit;
145
+ cursor: pointer;
146
+ -webkit-tap-highlight-color: transparent;
147
+ }
148
+ [part='cluster-count'] {
149
+ display: inline-flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ box-sizing: border-box;
153
+ min-inline-size: var(--lr-timeline-cluster-size, var(--lr-size-2rem));
154
+ min-block-size: var(--lr-timeline-cluster-size, var(--lr-size-2rem));
155
+ padding-inline: var(--lr-space-xs);
156
+ border-radius: var(--lr-radius-pill);
157
+ background: var(--lr-timeline-cluster-bg, var(--lr-color-brand));
158
+ color: var(--lr-timeline-cluster-color, var(--lr-color-on-brand));
159
+ font-size: var(--lr-font-size-sm);
160
+ font-weight: var(--lr-font-weight-semibold);
161
+ line-height: var(--lr-line-height-snug);
162
+ }
163
+ [part='cluster']:hover [part='cluster-count'] {
164
+ background: color-mix(
165
+ in oklab,
166
+ var(--lr-timeline-cluster-bg, var(--lr-color-brand)),
167
+ var(--lr-color-mix-partner) var(--lr-color-mix-hover)
168
+ );
169
+ }
170
+ [part='cluster']:active [part='cluster-count'] {
171
+ background: color-mix(
172
+ in oklab,
173
+ var(--lr-timeline-cluster-bg, var(--lr-color-brand)),
174
+ var(--lr-color-mix-partner) var(--lr-color-mix-active)
175
+ );
176
+ }
177
+ [part='cluster']:focus-visible {
178
+ outline: var(--lr-focus-ring-width) solid var(--lr-focus-ring-color);
179
+ outline-offset: var(--lr-focus-ring-offset);
180
+ }
181
+
182
+ @media (forced-colors: active) {
183
+ [part='cluster-count'] {
184
+ border: var(--lr-border-width-medium) solid ButtonText;
185
+ background: ButtonFace;
186
+ color: ButtonText;
187
+ forced-color-adjust: auto;
188
+ }
189
+ [part='cluster']:hover [part='cluster-count'] {
190
+ border-color: Highlight;
191
+ }
192
+ [part='cluster']:focus-visible {
193
+ outline-color: Highlight;
194
+ }
195
+ }
131
196
  `;export{styles};
@@ -1,30 +1,46 @@
1
1
  import { type PropertyValues, type TemplateResult } from 'lit';
2
2
  import { LyraElement } from '../../../internal/lyra-element.js';
3
3
  import type { LyraOrientation } from '../../../internal/shared-unions.js';
4
+ import type { LyraTimelineItem } from './timeline-item.class.js';
4
5
  /** How a timeline distributes its items along the main axis. */
5
6
  export type LyraTimelineScale = 'flow' | 'time';
6
7
  /** How `scale="time"` handles items that land on (nearly) the same position. */
7
- export type LyraTimelineCollision = 'overlap' | 'stack';
8
+ export type LyraTimelineCollision = 'overlap' | 'stack' | 'cluster';
9
+ export interface LyraTimelineClusterActivateDetail {
10
+ /** The clustered `<lr-timeline-item>` elements, as a frozen snapshot in document order. */
11
+ readonly items: readonly LyraTimelineItem[];
12
+ }
13
+ export interface LyraTimelineEventMap {
14
+ 'lr-cluster-activate': CustomEvent<LyraTimelineClusterActivateDetail>;
15
+ }
8
16
  /**
9
17
  * `<lr-timeline>` — an ordered, connected sequence of past-event rows (an audit trail, an agent
10
18
  * action history, a changelog) composed from `<lr-timeline-item>` light-DOM children, joined by a
11
19
  * continuous connecting rail. First-party invention: no Web Awesome/Shoelace counterpart exists, so
12
20
  * this follows the library's own established conventions rather than mirroring an upstream API.
13
21
  *
14
- * A pure, read-only, declarative display component — same zero-event shape as `<lr-badge>`/
15
- * `<lr-avatar>`/`<lr-skeleton>`. It never mutates its own children and fires no events; a
16
- * consumer who needs to react to item count changes already owns the mutation (they're the one
17
- * adding/removing `<lr-timeline-item>` children) and can listen to the native `slotchange` event
18
- * directly if truly needed.
22
+ * A read-only declarative display by default — same zero-interaction shape as `<lr-badge>`/
23
+ * `<lr-avatar>`/`<lr-skeleton>`. The opt-in `scale="time" collision="cluster"` presentation is the
24
+ * one exception: overlapping events collapse behind a native count button and activation emits
25
+ * their exact element identities so the consumer can open its own popover, dialog, or detail
26
+ * view. The component does not select, expand, reorder, or mutate the content of those items.
19
27
  *
20
- * No keyboard navigation, roving-tabindex, or selection model of any kind a deliberate scope
21
- * decision, not an oversight. A timeline is a passive record display, not a navigable widget; see
22
- * `<lr-timeline-item>`'s class doc for the full reasoning behind dropping an earlier
23
- * "interactive row" design. Not a form-associated control — no value to submit, no label/hint/error
24
- * chrome.
28
+ * No roving-tabindex or per-event selection model is introduced. Timeline items remain passive;
29
+ * each cluster marker is an independent native `<button>` in the normal Tab sequence, so pointer,
30
+ * Enter, and Space activation require no custom keyboard model. Not a form-associated control —
31
+ * no value to submit, no label/hint/error chrome.
32
+ *
33
+ * The first member in document order represents a cluster: its ordinary shadow row is temporarily
34
+ * replaced by the count action while the remaining members are hidden. This preserves the author's
35
+ * list and Tab order instead of appending visually positioned controls after the slot. The action
36
+ * exposes `cluster` and `cluster-count` parts on that representative `<lr-timeline-item>`.
25
37
  *
26
38
  * @customElement lr-timeline
27
39
  * @slot - `<lr-timeline-item>` children, in display order.
40
+ * @event lr-cluster-activate - A `collision="cluster"` count marker was activated by pointer,
41
+ * Enter, or Space. `detail: { items }` contains a fresh frozen snapshot of the member
42
+ * `<lr-timeline-item>` elements in document order. Non-cancelable notification; the timeline has
43
+ * no built-in expansion or selection action to veto.
28
44
  * @csspart base - The root wrapper. `role="list"` lives here directly (a timeline isn't a navigation
29
45
  * landmark, so it doesn't need a two-layer `base`+`list` split). Flex container: `flex-direction:
30
46
  * column` in `vertical` orientation (the default), `flex-direction: row` (with `overflow-x: auto`,
@@ -38,6 +54,10 @@ export type LyraTimelineCollision = 'overlap' | 'stack';
38
54
  * stacked by `collision="stack"`. Each collision lane is indented one step further, so a wider
39
55
  * marker can claim more room without the lanes overlapping again. Ignored unless both
40
56
  * `scale="time"` and `collision="stack"` are set.
57
+ * @cssprop [--lr-timeline-cluster-size=var(--lr-size-2rem)] - Minimum inline and block size of the
58
+ * painted count pill. Its containing button retains the shared 40px minimum action surface.
59
+ * @cssprop [--lr-timeline-cluster-bg=var(--lr-color-brand)] - Cluster count pill background.
60
+ * @cssprop [--lr-timeline-cluster-color=var(--lr-color-on-brand)] - Cluster count pill foreground.
41
61
  * @cssprop [--lr-timeline-time-extent=var(--lr-size-20rem)] - Distance the `scale="time"` axis
42
62
  * distributes items along: `block-size` when vertical, `inline-size` when horizontal. Time-scaled
43
63
  * items are absolutely positioned, and a percentage offset against an auto-sized track resolves
@@ -48,7 +68,11 @@ export type LyraTimelineCollision = 'overlap' | 'stack';
48
68
  * @status stable
49
69
  * @since 4.0.0
50
70
  */
51
- export declare class LyraTimeline extends LyraElement {
71
+ export declare class LyraTimeline extends LyraElement<LyraTimelineEventMap> {
72
+ protected static readonly immutableEventDetails: readonly string[];
73
+ protected static readonly identityEventDetailProperties: Readonly<{
74
+ 'lr-cluster-activate': readonly string[];
75
+ }>;
52
76
  static styles: import("lit").CSSResultGroup[];
53
77
  /** `'vertical'` (the default) lays items out in a column, the primary/most-common use case — an
54
78
  * audit trail or agent history reads top-to-bottom. `'horizontal'` lays them out in a row.
@@ -67,9 +91,8 @@ export declare class LyraTimeline extends LyraElement {
67
91
  *
68
92
  * `'time'` needs a definite extent to distribute along, which comes from
69
93
  * `--lr-timeline-time-extent` (default `20rem` block-size when vertical, inline-size when
70
- * horizontal). Items are absolutely positioned within it, so two events sharing a date overlap
71
- * rather than being fanned into lanes; a dense dataset needing lane assignment, brushing, or
72
- * per-event selection is a different component than this deliberately passive one.
94
+ * horizontal). Items are absolutely positioned within it. The `collision` property controls
95
+ * whether nearby items overlap, fan into lanes, or collapse behind an activatable count marker.
73
96
  *
74
97
  * An item with no `timestamp` this component can parse (including one whose timestamp comes only
75
98
  * from the `timestamp` slot, which carries no machine-readable instant) keeps document order and
@@ -83,13 +106,13 @@ export declare class LyraTimeline extends LyraElement {
83
106
  *
84
107
  * `'overlap'` (the default, and the only previous behavior) leaves them stacked on top of one
85
108
  * another. `'stack'` offsets each colliding item along the **cross** axis instead, so a dense
86
- * chronology stays readable with ~1,800 events over ~330 years, same-period collisions are the
87
- * common case rather than the exception. Ignored unless `scale="time"`.
88
- *
89
- * There is deliberately no `'cluster'` mode. Collapsing coincident items into one marker with a
90
- * count that expands on interaction needs a selection model and click events, and this component
91
- * is documented as passive with neither; adding them here would change what `lr-timeline` is
92
- * rather than extend it.
109
+ * chronology with many same-period events stays readable. `'cluster'` represents each group of
110
+ * overlapping items with one author-ordered member's count marker. Its collision window grows
111
+ * from the ordinary 1.5%
112
+ * floor to the rendered count button's footprint on the currently allocated axis, preventing
113
+ * interactive markers from overlapping after an allocation or themed-size change. Activating it
114
+ * emits `lr-cluster-activate` with the member elements but does not select or expand them. Ignored
115
+ * unless `scale="time"`.
93
116
  */
94
117
  private _collision;
95
118
  get collision(): LyraTimelineCollision;
@@ -107,6 +130,14 @@ export declare class LyraTimeline extends LyraElement {
107
130
  * `aria-label` stays empty. */
108
131
  accessibleLabel?: string;
109
132
  private slottedCount;
133
+ private collisionClusters;
134
+ private readonly managedClusterHiddenItems;
135
+ private readonly managedClusterRepresentatives;
136
+ private readonly clusterActivations;
137
+ private readonly timestampObservedItems;
138
+ private clusterMeasurementFrame?;
139
+ private clusterMeasurementView?;
140
+ private focusRepairGeneration;
110
141
  /** Gates the horizontal [part='base'] edge fade on the strip genuinely overflowing, with
111
142
  * one-sided/RTL-aware logical-edge state -- see --lr-scroll-fade-size and timeline.styles.ts.
112
143
  * Harmless in the vertical default, where the strip never scrolls inline and the attribute
@@ -115,14 +146,19 @@ export declare class LyraTimeline extends LyraElement {
115
146
  * below -- an item's own intrinsic content (a longer title, an icon loading in) can grow
116
147
  * scrollWidth without [part='base']'s own border box changing at all. */
117
148
  private scrollOverflow;
149
+ connectedCallback(): void;
150
+ disconnectedCallback(): void;
118
151
  protected willUpdate(changed: PropertyValues): void;
119
152
  protected updated(changed: PropertyValues): void;
120
153
  private countTimelineItems;
121
154
  firstUpdated(changed: PropertyValues): void;
122
- /** Read-only, live-updated count of the currently-slotted `<lr-timeline-item>` children — handy
123
- * for building a `"{count} events"` header without hand-counting DOM children. */
155
+ /** Read-only, live-updated count of default-slot `<lr-timeline-item>` assignments, including
156
+ * flattened forwarding slots — handy for building a `"{count} events"` header without
157
+ * hand-counting DOM children. */
124
158
  get itemCount(): number;
125
159
  private onSlotChange;
160
+ private onTimelineItemTimestampChange;
161
+ private syncTimestampObservers;
126
162
  /** The slotted `<lr-timeline-item>` children, in document order. */
127
163
  private timelineItems;
128
164
  /** The axis bounds: an explicitly pinned pair when both ends are finite and ordered, otherwise
@@ -134,9 +170,8 @@ export declare class LyraTimeline extends LyraElement {
134
170
  * timeline.styles.ts's `scale="time"` rules.
135
171
  *
136
172
  * Deliberately a style write on the light-DOM child rather than a wrapper element per item: the
137
- * component's whole contract is that it never mutates its children's content or structure, and a
138
- * custom property is the one mutation that stays invisible to the consumer's own DOM shape. The
139
- * property is removed again in `'flow'`, so toggling back leaves no residue.
173
+ * component never mutates its children's content or structure. The private position properties
174
+ * and cluster visibility marker are presentation-only and are removed when their modes end.
140
175
  */
141
176
  private applyTimeScale;
142
177
  /**
@@ -149,6 +184,27 @@ export declare class LyraTimeline extends LyraElement {
149
184
  * clears every lane rather than leaving stale offsets on some children.
150
185
  */
151
186
  private applyCollisionLanes;
187
+ /** Groups sorted offsets into bounded collision windows. Each window is anchored at its first
188
+ * item rather than chained transitively through every adjacent neighbour, so a large uniformly
189
+ * dense history becomes a sequence of useful count markers instead of one axis-wide group. */
190
+ private buildCollisionClusters;
191
+ /** The minimum fraction shared with stack mode, widened when the rendered native actions need
192
+ * more of the allocated axis to avoid overlapping hit targets. Re-evaluated after every cluster
193
+ * render and by the existing owner-realm ResizeObserver attached to the base and actions. */
194
+ private clusterCollisionThreshold;
195
+ /** Coalesces ResizeObserver-driven membership writes into the next owner-realm frame. Updating
196
+ * observed cluster actions synchronously inside their observer callback would create a resize
197
+ * notification loop whenever a larger count changes the action's footprint. */
198
+ private scheduleClusterMeasurement;
199
+ private cancelClusterMeasurement;
200
+ private sameClusters;
201
+ private captureClusterFocusRepair;
202
+ private scheduleClusterFocusRepair;
203
+ private applyCollisionClusters;
204
+ private syncClusterPresentations;
205
+ private restoreClusterPresentation;
206
+ private restoreClusterVisibility;
207
+ private activateCluster;
152
208
  render(): TemplateResult;
153
209
  }
154
210
  declare global {
@@ -1,5 +1,5 @@
1
- var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html}from"lit";import{property,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import{tag}from"../../../internal/prefix.js";import{observeScrollOverflow}from"../../../internal/scroll-overflow.js";import{styles}from"./timeline.styles.js";import{LYRA_DEFAULT_timeline}from"../../../internal/default-strings.generated.js";const normalizeTimelineOrientation=value=>value==="horizontal"?"horizontal":"vertical",normalizeTimelineScale=value=>value==="time"?"time":"flow",normalizeTimelineCollision=value=>value==="stack"?"stack":"overlap",TIMELINE_COLLISION_THRESHOLD=.015;function itemEpochMs(element){const raw=element.timestamp;if(raw==null)return null;const ms=(raw instanceof Date?raw:typeof raw=="number"?new Date(raw):new Date(String(raw))).getTime();return Number.isFinite(ms)?ms:null}class LyraTimeline extends LyraElement{constructor(){super(...arguments),this._orientation="vertical",this._scale="flow",this._collision="overlap",this.slottedCount=0,this.scrollOverflow=observeScrollOverflow(this,()=>this.renderRoot.querySelector("[part='base']")),this.onSlotChange=e=>{this.slottedCount=this.countTimelineItems(e.target),this.applyTimeScale()}}static{this.defaultStrings={...super.defaultStrings,timeline:LYRA_DEFAULT_timeline}}static{this.styles=[LyraElement.styles,styles]}get orientation(){return this._orientation}set orientation(value){const normalized=normalizeTimelineOrientation(value),previous=this._orientation;if(previous===normalized){value!==normalized&&this.requestUpdate("orientation",previous);return}this._orientation=normalized,this.requestUpdate("orientation",previous)}get scale(){return this._scale}set scale(value){const normalized=normalizeTimelineScale(value),previous=this._scale;if(previous===normalized){value!==normalized&&this.requestUpdate("scale",previous);return}this._scale=normalized,this.requestUpdate("scale",previous)}get collision(){return this._collision}set collision(value){const normalized=normalizeTimelineCollision(value),previous=this._collision;if(previous===normalized){value!==normalized&&this.requestUpdate("collision",previous);return}this._collision=normalized,this.requestUpdate("collision",previous)}willUpdate(changed){super.willUpdate(changed),this.hasUpdated||(this.slottedCount=Array.from(this.children).filter(element=>!element.getAttribute("slot")&&element.localName===tag("timeline-item")).length)}updated(changed){super.updated(changed),this.scrollOverflow.observeExtra(this.timelineItems()),changed.has("orientation")&&this.getAttribute("orientation")!==this.orientation&&this.setAttribute("orientation",this.orientation),(changed.has("scale")||changed.has("collision")||changed.has("rangeStart")||changed.has("rangeEnd"))&&this.applyTimeScale()}countTimelineItems(slot){return slot.assignedElements({flatten:!0}).filter(element=>element.localName===tag("timeline-item")).length}firstUpdated(changed){super.firstUpdated(changed);const slot=this.shadowRoot.querySelector("slot");this.slottedCount=this.countTimelineItems(slot),this.applyTimeScale()}get itemCount(){return this.slottedCount}timelineItems(){const slot=this.shadowRoot?.querySelector("slot");return slot?slot.assignedElements({flatten:!0}).filter(element=>element.localName===tag("timeline-item")):[]}timeRange(stamps){const pinnedStart=this.rangeStart==null?null:itemEpochMs({timestamp:this.rangeStart}),pinnedEnd=this.rangeEnd==null?null:itemEpochMs({timestamp:this.rangeEnd});if(pinnedStart!==null&&pinnedEnd!==null&&pinnedEnd>pinnedStart)return[pinnedStart,pinnedEnd];const finite=stamps.filter(value=>value!==null);if(finite.length<2)return null;const lo=Math.min(...finite),hi=Math.max(...finite);return hi>lo?[lo,hi]:null}applyTimeScale(){const items=this.timelineItems();if(this.scale!=="time"){for(const item of items)item.style.removeProperty("--_lr-timeline-item-offset"),item.style.removeProperty("--_lr-timeline-item-lane");return}const stamps=items.map(item=>itemEpochMs(item)),range=this.timeRange(stamps),lastIndex=Math.max(1,items.length-1),offsets=new Array(items.length).fill(0);items.forEach((item,index)=>{const stamp=stamps[index]??null,ratio=range&&stamp!==null?(stamp-range[0])/(range[1]-range[0]):index/lastIndex,clamped=Math.min(1,Math.max(0,ratio));offsets[index]=clamped,item.style.setProperty("--_lr-timeline-item-offset",`${clamped*100}%`)}),this.applyCollisionLanes(items,offsets)}applyCollisionLanes(items,offsets){if(this.collision!=="stack"){for(const item of items)item.style.removeProperty("--_lr-timeline-item-lane");return}const order=items.map((_,index)=>index).sort((a,b)=>(offsets[a]??0)-(offsets[b]??0)),laneTails=[],lanes=new Array(items.length).fill(0);for(const index of order){const offset=offsets[index]??0;let lane=laneTails.findIndex(tail=>offset-tail>=TIMELINE_COLLISION_THRESHOLD);lane===-1&&(lane=laneTails.length),laneTails[lane]=offset,lanes[index]=lane}items.forEach((item,index)=>{item.style.setProperty("--_lr-timeline-item-lane",String(lanes[index]??0))})}render(){return html`
2
- <div part="base" role="list" aria-label=${this.accessibleLabel==null?this.localize("timeline"):this.accessibleLabel}>
1
+ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html}from"lit";import{property,state}from"lit/decorators.js";import{applyComposedFocusRepair,captureComposedFocusRepair,collectComposedFocusTargets}from"../../../internal/focus-navigation.js";import{getNumberFormat}from"../../../internal/intl-cache.js";import{LyraElement}from"../../../internal/lyra-element.js";import{tag}from"../../../internal/prefix.js";import{observeScrollOverflow}from"../../../internal/scroll-overflow.js";import{OBSERVE_TIMELINE_ITEM_TIMESTAMP,SET_TIMELINE_CLUSTER_PRESENTATION,isTimelineClusterItemContract}from"./timeline-cluster.js";import{styles}from"./timeline.styles.js";import{LYRA_DEFAULT_timeline,LYRA_DEFAULT_timelineClusterCount}from"../../../internal/default-strings.generated.js";const normalizeTimelineOrientation=value=>value==="horizontal"?"horizontal":"vertical",normalizeTimelineScale=value=>value==="time"?"time":"flow",normalizeTimelineCollision=value=>value==="stack"||value==="cluster"?value:"overlap",EMPTY_TIMELINE_CLUSTERS=Object.freeze([]),CLUSTER_HIDDEN_ATTRIBUTE="data-lr-timeline-cluster-hidden",TIMELINE_COLLISION_THRESHOLD=.015;function timelineEpochMs(raw){if(raw==null)return null;const ms=(raw instanceof Date?raw:typeof raw=="number"?new Date(raw):new Date(String(raw))).getTime();return Number.isFinite(ms)?ms:null}function itemEpochMs(element){return timelineEpochMs(element.timestamp)}class LyraTimeline extends LyraElement{constructor(){super(...arguments),this._orientation="vertical",this._scale="flow",this._collision="overlap",this.slottedCount=0,this.collisionClusters=EMPTY_TIMELINE_CLUSTERS,this.managedClusterHiddenItems=new Set,this.managedClusterRepresentatives=new Set,this.clusterActivations=new Map,this.timestampObservedItems=new Set,this.focusRepairGeneration=0,this.scrollOverflow=observeScrollOverflow(this,()=>this.renderRoot.querySelector('[part="base"]'),()=>{this.scale==="time"&&this.collision==="cluster"&&this.scheduleClusterMeasurement()}),this.onSlotChange=e=>{this.updateBrowserDerivedState(()=>{this.slottedCount=this.countTimelineItems(e.target),this.applyTimeScale()})},this.onTimelineItemTimestampChange=()=>{this.isConnected&&this.scheduleAfterUpdate(()=>this.applyTimeScale(),"timeline-item-timestamps")}}static{this.defaultStrings={...super.defaultStrings,timeline:LYRA_DEFAULT_timeline,timelineClusterCount:LYRA_DEFAULT_timelineClusterCount}}static{this.immutableEventDetails=Object.freeze(["lr-cluster-activate"])}static{this.identityEventDetailProperties=Object.freeze({"lr-cluster-activate":Object.freeze(["items"])})}static{this.styles=[LyraElement.styles,styles]}get orientation(){return this._orientation}set orientation(value){const normalized=normalizeTimelineOrientation(value),previous=this._orientation;if(previous===normalized){value!==normalized&&this.requestUpdate("orientation",previous);return}this._orientation=normalized,this.requestUpdate("orientation",previous)}get scale(){return this._scale}set scale(value){const normalized=normalizeTimelineScale(value),previous=this._scale;if(previous===normalized){value!==normalized&&this.requestUpdate("scale",previous);return}this._scale=normalized,this.requestUpdate("scale",previous)}get collision(){return this._collision}set collision(value){const normalized=normalizeTimelineCollision(value),previous=this._collision;if(previous===normalized){value!==normalized&&this.requestUpdate("collision",previous);return}this._collision=normalized,this.requestUpdate("collision",previous)}connectedCallback(){super.connectedCallback(),this.hasUpdated&&this.scheduleAfterUpdate(()=>this.applyTimeScale(),"timeline-clusters")}disconnectedCallback(){this.cancelClusterMeasurement(),this.focusRepairGeneration+=1,this.restoreClusterPresentation(),this.restoreClusterVisibility(),this.syncTimestampObservers([]),this.collisionClusters.length>0&&(this.collisionClusters=EMPTY_TIMELINE_CLUSTERS),super.disconnectedCallback()}willUpdate(changed){super.willUpdate(changed),this.hasUpdated||(this.slottedCount=Array.from(this.children).filter(element=>!element.getAttribute("slot")&&element.localName===tag("timeline-item")).length),this.hasUpdated?(changed.has("scale")||changed.has("collision")||changed.has("rangeStart")||changed.has("rangeEnd"))&&this.applyTimeScale():this.seedFirstRenderState(()=>this.applyTimeScale())}updated(changed){super.updated(changed),this.scrollOverflow.observeExtra(this.timelineItems()),changed.has("orientation")&&this.getAttribute("orientation")!==this.orientation&&this.setAttribute("orientation",this.orientation),(changed.has("collisionClusters")||changed.has("orientation"))&&this.collisionClusters.length>0&&this.scheduleAfterUpdate(()=>this.applyTimeScale(),"timeline-cluster-measurement"),this.collisionClusters.length>0&&this.syncClusterPresentations(this.collisionClusters)}countTimelineItems(slot){return slot.assignedElements({flatten:!0}).filter(element=>element.localName===tag("timeline-item")).length}firstUpdated(changed){super.firstUpdated(changed),this.scheduleAfterUpdate(()=>this.updateBrowserDerivedState(()=>{const slot=this.shadowRoot.querySelector("slot");this.slottedCount=this.countTimelineItems(slot),this.applyTimeScale()}),"timeline-first-slot-reconciliation")}get itemCount(){return this.slottedCount}syncTimestampObservers(items){const current=new Set(items);for(const item of this.timestampObservedItems)current.has(item)||(isTimelineClusterItemContract(item)&&item[OBSERVE_TIMELINE_ITEM_TIMESTAMP](this.onTimelineItemTimestampChange,!1),this.timestampObservedItems.delete(item));for(const item of current)this.timestampObservedItems.has(item)||isTimelineClusterItemContract(item)&&(item[OBSERVE_TIMELINE_ITEM_TIMESTAMP](this.onTimelineItemTimestampChange,!0),this.timestampObservedItems.add(item))}timelineItems(){const slot=this.shadowRoot?.querySelector("slot");return(slot?slot.assignedElements({flatten:!0}):Array.from(this.children).filter(element=>!element.getAttribute("slot"))).filter(element=>element.localName===tag("timeline-item"))}timeRange(stamps){const pinnedStart=timelineEpochMs(this.rangeStart),pinnedEnd=timelineEpochMs(this.rangeEnd);if(pinnedStart!==null&&pinnedEnd!==null&&pinnedEnd>pinnedStart)return[pinnedStart,pinnedEnd];const finite=stamps.filter(value=>value!==null);if(finite.length<2)return null;const lo=Math.min(...finite),hi=Math.max(...finite);return hi>lo?[lo,hi]:null}applyTimeScale(){const items=this.timelineItems();if(this.syncTimestampObservers(items),this.scale!=="time"){for(const item of items)item.style.removeProperty("--_lr-timeline-item-offset"),item.style.removeProperty("--_lr-timeline-item-lane");this.applyCollisionClusters([]);return}const stamps=items.map(item=>itemEpochMs(item)),range=this.timeRange(stamps),lastIndex=Math.max(1,items.length-1),offsets=new Array(items.length).fill(0);items.forEach((item,index)=>{const stamp=stamps[index]??null,ratio=range&&stamp!==null?(stamp-range[0])/(range[1]-range[0]):this.collision==="cluster"&&stamp!==null?0:index/lastIndex,clamped=Math.min(1,Math.max(0,ratio));offsets[index]=clamped,item.style.setProperty("--_lr-timeline-item-offset",`${clamped*100}%`)}),this.applyCollisionLanes(items,offsets),this.applyCollisionClusters(this.collision==="cluster"?this.buildCollisionClusters(items,offsets,this.clusterCollisionThreshold()):[])}applyCollisionLanes(items,offsets){if(this.collision!=="stack"){for(const item of items)item.style.removeProperty("--_lr-timeline-item-lane");return}const order=items.map((_,index)=>index).sort((a,b)=>(offsets[a]??0)-(offsets[b]??0)),laneTails=[],lanes=new Array(items.length).fill(0);for(const index of order){const offset=offsets[index]??0;let lane=laneTails.findIndex(tail=>offset-tail>=TIMELINE_COLLISION_THRESHOLD);lane===-1&&(lane=laneTails.length),laneTails[lane]=offset,lanes[index]=lane}items.forEach((item,index)=>{item.style.setProperty("--_lr-timeline-item-lane",String(lanes[index]??0))})}buildCollisionClusters(items,offsets,threshold){const order=items.map((_,index)=>index).sort((a,b)=>(offsets[a]??0)-(offsets[b]??0)||a-b),clusters=[];let window=[],windowStart=0;const flush=()=>{if(window.length<2){window=[];return}const memberIndexes=[...window].sort((a,b)=>a-b);clusters.push({offset:windowStart,items:memberIndexes.map(index=>items[index])}),window=[]};for(const index of order){const offset=offsets[index]??0;window.length>0&&offset-windowStart>=threshold&&flush(),window.length===0&&(windowStart=offset),window.push(index)}return flush(),clusters}clusterCollisionThreshold(){const base=this.renderRoot.querySelector('[part="base"]');if(!base)return TIMELINE_COLLISION_THRESHOLD;const axisExtent=this.orientation==="horizontal"?base.clientWidth:base.clientHeight;if(!Number.isFinite(axisExtent)||axisExtent<=0)return TIMELINE_COLLISION_THRESHOLD;let markerExtent=0;for(const item of this.managedClusterRepresentatives){const marker=item.shadowRoot?.querySelector('[part="cluster"]');if(!marker)continue;const rect=marker.getBoundingClientRect();markerExtent=Math.max(markerExtent,this.orientation==="horizontal"?rect.width:rect.height)}return!Number.isFinite(markerExtent)||markerExtent<=0?TIMELINE_COLLISION_THRESHOLD:Math.max(TIMELINE_COLLISION_THRESHOLD,markerExtent/axisExtent)}scheduleClusterMeasurement(){const view=this.ownerDocument.defaultView;view&&(this.clusterMeasurementFrame!==void 0&&this.clusterMeasurementView===view||(this.cancelClusterMeasurement(),this.clusterMeasurementView=view,this.clusterMeasurementFrame=view.requestAnimationFrame(()=>{this.clusterMeasurementFrame=void 0,this.clusterMeasurementView=void 0,this.isConnected&&this.ownerDocument.defaultView===view&&this.scale==="time"&&this.collision==="cluster"&&this.applyTimeScale()})))}cancelClusterMeasurement(){this.clusterMeasurementFrame!==void 0&&this.clusterMeasurementView&&this.clusterMeasurementView.cancelAnimationFrame(this.clusterMeasurementFrame),this.clusterMeasurementFrame=void 0,this.clusterMeasurementView=void 0}sameClusters(left,right){return left.length===right.length&&left.every((cluster,index)=>cluster.offset===right[index]?.offset&&cluster.items.length===right[index]?.items.length&&cluster.items.every((item,itemIndex)=>item===right[index]?.items[itemIndex]))}captureClusterFocusRepair(clusters){const active=this.ownerDocument.activeElement;if(!active)return;const focusedItem=this.timelineItems().find(item=>item===active||item.contains(active)||!!item.shadowRoot?.activeElement);if(!focusedItem)return;const wasRepresentative=this.managedClusterRepresentatives.has(focusedItem),nextCluster=clusters.find(cluster=>cluster.items.includes(focusedItem)),nextRepresentative=nextCluster?.items[0],mode=nextCluster?"cluster":"item";if(mode==="cluster"&&wasRepresentative&&nextRepresentative===focusedItem||mode==="item"&&!wasRepresentative)return;const base=this.renderRoot.querySelector('[part="base"]'),snapshot=captureComposedFocusRepair(focusedItem,base);if(snapshot)return{item:mode==="cluster"?nextRepresentative:focusedItem,mode,snapshot}}scheduleClusterFocusRepair(repair){const generation=++this.focusRepairGeneration;repair&&repair.item.updateComplete.then(()=>{if(generation!==this.focusRepairGeneration||!this.isConnected)return;const base=this.renderRoot.querySelector('[part="base"]'),target=repair.mode==="cluster"?repair.item.shadowRoot?.querySelector('[part="cluster"]')??null:collectComposedFocusTargets(repair.item).elements[0]??base;applyComposedFocusRepair(repair.snapshot,target)})}applyCollisionClusters(clusters){const frozen=Object.freeze(clusters.map(cluster=>Object.freeze({offset:cluster.offset,items:Object.freeze([...cluster.items])}))),changed=!this.sameClusters(this.collisionClusters,frozen),focusRepair=changed?this.captureClusterFocusRepair(frozen):void 0,representatives=new Set(frozen.map(cluster=>cluster.items[0])),hiddenItems=new Set(frozen.flatMap(cluster=>cluster.items.filter(item=>!representatives.has(item))));for(const item of this.managedClusterHiddenItems){if(hiddenItems.has(item)){item.hasAttribute(CLUSTER_HIDDEN_ATTRIBUTE)||item.setAttribute(CLUSTER_HIDDEN_ATTRIBUTE,"");continue}item.getAttribute(CLUSTER_HIDDEN_ATTRIBUTE)===""&&item.removeAttribute(CLUSTER_HIDDEN_ATTRIBUTE),this.managedClusterHiddenItems.delete(item)}for(const item of hiddenItems)this.managedClusterHiddenItems.has(item)||item.hasAttribute(CLUSTER_HIDDEN_ATTRIBUTE)||(item.setAttribute(CLUSTER_HIDDEN_ATTRIBUTE,""),this.managedClusterHiddenItems.add(item));if(changed){this.restoreClusterPresentation();for(const cluster of frozen){const representative=cluster.items[0];this.clusterActivations.set(representative,()=>this.activateCluster(cluster.items)),this.managedClusterRepresentatives.add(representative)}this.collisionClusters=frozen,this.syncClusterPresentations(frozen),this.scheduleClusterFocusRepair(focusRepair)}for(const cluster of frozen)cluster.items[0].style.setProperty("--_lr-timeline-item-offset",`${cluster.offset*100}%`)}syncClusterPresentations(clusters){for(const cluster of clusters){const representative=cluster.items[0],activate=this.clusterActivations.get(representative);if(!activate)continue;const countText=getNumberFormat(this.effectiveLocale).format(cluster.items.length);isTimelineClusterItemContract(representative)&&representative[SET_TIMELINE_CLUSTER_PRESENTATION]({accessibleLabel:this.localize("timelineClusterCount",void 0,{count:countText}),countText,activate})}}restoreClusterPresentation(){for(const item of this.managedClusterRepresentatives)isTimelineClusterItemContract(item)&&item[SET_TIMELINE_CLUSTER_PRESENTATION](void 0);this.managedClusterRepresentatives.clear(),this.clusterActivations.clear()}restoreClusterVisibility(){for(const item of this.managedClusterHiddenItems)item.getAttribute(CLUSTER_HIDDEN_ATTRIBUTE)===""&&item.removeAttribute(CLUSTER_HIDDEN_ATTRIBUTE);this.managedClusterHiddenItems.clear()}activateCluster(items){const snapshot=this.ownerDocument.defaultView?.Array.from(items)??[...items];this.emit("lr-cluster-activate",Object.freeze({items:Object.freeze(snapshot)}))}render(){return html`
2
+ <div part="base" role="list" tabindex="-1" aria-label=${this.accessibleLabel==null?this.localize("timeline"):this.accessibleLabel}>
3
3
  <slot @slotchange=${this.onSlotChange}></slot>
4
4
  </div>
5
- `}}__decorate([property({reflect:!0})],LyraTimeline.prototype,"orientation",null),__decorate([property({reflect:!0})],LyraTimeline.prototype,"scale",null),__decorate([property({reflect:!0})],LyraTimeline.prototype,"collision",null),__decorate([property({attribute:!1})],LyraTimeline.prototype,"rangeStart",void 0),__decorate([property({attribute:!1})],LyraTimeline.prototype,"rangeEnd",void 0),__decorate([property({attribute:"aria-label"})],LyraTimeline.prototype,"accessibleLabel",void 0),__decorate([state()],LyraTimeline.prototype,"slottedCount",void 0);export{LyraTimeline};
5
+ `}}__decorate([property({reflect:!0})],LyraTimeline.prototype,"orientation",null),__decorate([property({reflect:!0})],LyraTimeline.prototype,"scale",null),__decorate([property({reflect:!0})],LyraTimeline.prototype,"collision",null),__decorate([property({attribute:!1})],LyraTimeline.prototype,"rangeStart",void 0),__decorate([property({attribute:!1})],LyraTimeline.prototype,"rangeEnd",void 0),__decorate([property({attribute:"aria-label"})],LyraTimeline.prototype,"accessibleLabel",void 0),__decorate([state()],LyraTimeline.prototype,"slottedCount",void 0),__decorate([state()],LyraTimeline.prototype,"collisionClusters",void 0);export{LyraTimeline};
@@ -1 +1,2 @@
1
1
  export * from './timeline.class.js';
2
+ import './timeline-item.js';
@@ -1 +1 @@
1
- export*from"./timeline.class.js";import{LyraTimeline}from"./timeline.class.js";import{defineElement}from"../../../internal/prefix.js";defineElement("timeline",LyraTimeline);
1
+ export*from"./timeline.class.js";import{LyraTimeline}from"./timeline.class.js";import{defineElement}from"../../../internal/prefix.js";import"./timeline-item.js";defineElement("timeline",LyraTimeline);
@@ -54,6 +54,20 @@ import{css}from"lit";const styles=css`
54
54
  inset-inline-start: var(--_lr-timeline-item-offset, 0%);
55
55
  inline-size: auto;
56
56
  }
57
+
58
+ :host([scale='time'][collision='cluster'])
59
+ ::slotted([data-lr-timeline-cluster-hidden]) {
60
+ display: none !important;
61
+ }
62
+
63
+ :host([scale='time'][collision='cluster'][orientation='horizontal'])
64
+ [part='base'] {
65
+ min-block-size: max(
66
+ var(--lr-icon-button-size),
67
+ var(--lr-timeline-cluster-size, var(--lr-size-2rem))
68
+ );
69
+ }
70
+
57
71
  :host([orientation='horizontal']) [part='base'] {
58
72
  flex-direction: row;
59
73
  overflow-x: auto;
@@ -1,4 +1,4 @@
1
- var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,query,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import{chevronIcon,spinnerIcon}from"../../../internal/icons.js";import{safeDownloadHref,safeLinkHref}from"../../../internal/safe-url.js";import{syncAriaControlsElements,syncAriaDescribedByElements}from"../../../internal/aria-controls.js";import{sizes}from"../../../internal/sizes.styles.js";import{variants}from"../../../internal/variants.styles.js";import{styles}from"./button.styles.js";import{relayNativeEvent}from"../../../internal/native-event-relay.js";import{installInvalidEventAlias}from"../../../internal/invalid-event-alias.js";import{attachInternalsSafely,getFormOwner,installCustomErrorProperty,setFormOwner}from"../../../internal/form-associated.js";import{AnchoredValidityController,VALIDITY_ANCHOR}from"../../../internal/anchored-validity.js";import{setCustomState}from"../../../internal/custom-states.js";import{EXTERNAL_LABEL_ACTIVATION}from"../../../internal/form-control-labels.js";import{omittedEmptyStringConverter}from"../../../internal/converters.js";import{currentValidityValidator}from"../form-validator.js";import{LYRA_DEFAULT_fieldRequired}from"../../../internal/default-strings.generated.js";class LyraButton extends LyraElement{static{this.defaultStrings={...super.defaultStrings,fieldRequired:LYRA_DEFAULT_fieldRequired}}static get validators(){return[currentValidityValidator("required","disabled","loading","href","value")]}static{this.styles=[LyraElement.styles,sizes,variants,styles]}static{this.formAssociated=!0}static{this.properties={disabled:{type:Boolean,reflect:!0,noAccessor:!0},name:{reflect:!0,noAccessor:!0,converter:omittedEmptyStringConverter},customError:{attribute:"custom-error",reflect:!0,noAccessor:!0}}}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),this.requestUpdate("disabled",old),this.updateValidity()}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}get effectiveDisabled(){return this._disabled||this._fieldsetDisabled}get form(){return getFormOwner(this.internals)}set form(owner){setFormOwner(this,owner)}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}constructor(){super(),this._fieldsetDisabled=!1,this._disabled=!1,this._name="",this._value="",this._required=!1,this._variant="neutral",this.hasSyncedDescribedByElements=!1,this.customValidityMessage="",this.reflectingCustomError=!1,this.accessibleLabel=null,this.triggerHasPopup=null,this.triggerExpanded=null,this.triggerControls=null,this.triggerDescribedBy=null,this.appearance="accent",this.size="m",this.pill=!1,this.circle=!1,this.outline=!1,this.withCaret=!1,this.withStart=!1,this.withEnd=!1,this.type="button",this.formNoValidate=!1,this.loading=!1,this.hasStartSlot=!1,this.hasEndSlot=!1,this.isIconButton=!1,this.onClick=event=>{if(this.type!=="submit"&&this.type!=="reset")return;const ownerWindow=this.ownerDocument.defaultView;let settled=!1;const finish=()=>{settled||(settled=!0,ownerWindow?.removeEventListener("click",finishAtWindow),!(event.defaultPrevented||this.effectiveDisabled||this.loading)&&this.runClickDefaultAction())},finishAtWindow=candidate=>{candidate===event&&finish()};ownerWindow?.addEventListener("click",finishAtWindow),queueMicrotask(finish)},this.onFocus=event=>{relayNativeEvent(this,event)},this.onBlur=event=>{relayNativeEvent(this,event)},this.onStartSlotChange=()=>{this.syncAdornmentSlots()},this.onEndSlotChange=()=>{this.syncAdornmentSlots()},this.onDefaultSlotChange=()=>{this.isIconButton=this.hasIconOnlyDefaultContent(),this.syncButtonStates()},installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init)),this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),installCustomErrorProperty(this,()=>this.customValidityMessage),this.updateValidity(),this.syncButtonStates()}get variant(){return this._variant}set variant(next){next==="primary"?this._variant="brand":next==="default"||next==="text"?this._variant="neutral":this._variant=next,next==="text"&&(this.appearance="plain")}get caret(){return this.withCaret}set caret(next){this.withCaret=!!next}get value(){return this._value}set value(next){this._value=next??"",this.updateValidity()}get required(){return this._required}set required(next){this._required=!!next,this.updateValidity()}get resolvedRel(){const authored=(this.rel??"").split(/\s+/).filter(token=>token!==""&&token.toLowerCase()!=="opener"),tokens=new Set(authored);return this.target&&(tokens.add("noopener"),tokens.add("noreferrer")),tokens.size>0?[...tokens].join(" "):void 0}click(){this.effectiveDisabled||this.loading||this.baseEl?.click()}focus(options){!this.effectiveDisabled&&!this.loading&&this.baseEl?.focus(options)}blur(){this.baseEl?.blur()}[VALIDITY_ANCHOR](){return this.baseEl??null}[EXTERNAL_LABEL_ACTIVATION](){return"activate"}checkValidity(){return this.internals.checkValidity()}reportValidity(){return this.internals.reportValidity()}setCustomValidity(message){const old=this.customValidityMessage||null,next=message??"";if(this.customValidityMessage=next,this.validityController.setCustomValidity(this.isValidationBarred?"":next),!this.reflectingCustomError){this.reflectingCustomError=!0;try{next?this.setAttribute("custom-error",next):this.removeAttribute("custom-error")}finally{this.reflectingCustomError=!1}}this.requestUpdate("customError",old)}resetValidity(){this.customValidityMessage="",this.validityController.setCustomValidity(""),this.updateValidity()}formStateRestoreCallback(state2,reason){this.value=typeof state2=="string"?state2:""}runClickDefaultAction(){if(this.type==="submit"){const form=this.getForm();if(!form)return;this.hasSubmitterOverrides?this.submitAsNamedSubmitter(form):form.requestSubmit()}else this.type==="reset"&&this.getForm()?.reset()}get hasSubmitterOverrides(){return!!(this.name||this.value||this.formNoValidate)||this.formAction!==void 0||this.formEnctype!==void 0||this.formMethod!==void 0||this.formTarget!==void 0}submitAsNamedSubmitter(form){const submitter=this.ownerDocument.createElement("button");submitter.type="submit",submitter.hidden=!0,submitter.tabIndex=-1,this.name&&(submitter.name=this.name,submitter.value=this.value),this.formAction!==void 0&&submitter.setAttribute("formaction",this.formAction),this.formEnctype!==void 0&&submitter.setAttribute("formenctype",this.formEnctype),this.formMethod!==void 0&&submitter.setAttribute("formmethod",this.formMethod),this.formNoValidate&&(submitter.formNoValidate=!0),this.formTarget!==void 0&&submitter.setAttribute("formtarget",this.formTarget),this.parentElement&&this.closest("form")===form?this.insertAdjacentElement("afterend",submitter):form.append(submitter);try{form.requestSubmit(submitter)}finally{submitter.remove()}}formDisabledCallback(disabled){this._fieldsetDisabled=disabled,this.updateValidity(),this.syncButtonStates(),this.requestUpdate()}connectedCallback(){super.connectedCallback(),this.updateValidity(),this.syncButtonStates()}willUpdate(changed){super.willUpdate(changed),this.hasUpdated||(this.syncAdornmentSlots(),this.isIconButton=this.hasIconOnlyDefaultContent())}syncAdornmentSlots(){const collection=this.children,children=collection?Array.from(collection):[];this.hasStartSlot=children.some(element=>{const slot=element.getAttribute("slot");return slot==="start"||slot==="prefix"}),this.hasEndSlot=children.some(element=>{const slot=element.getAttribute("slot");return slot==="end"||slot==="suffix"})}hasIconOnlyDefaultContent(){const childElements=this.children,elements=(childElements?Array.from(childElements):[]).filter(element=>!element.getAttribute("slot"));if(elements.length!==1)return!1;const childNodes=this.childNodes;return(childNodes?Array.from(childNodes):[]).filter(node=>node.nodeType===3).map(node=>node.textContent??"").join("").trim()===""&&(elements[0]?.textContent??"").trim()===""}updated(changed){super.updated(changed),syncAriaControlsElements(this,this.baseEl,this.triggerControls),this.syncDescribedByElements(),this.updateValidity(),this.syncButtonStates()}updateValidity(){if(this.validityController){if(this.isValidationBarred){this.validityController.setCustomValidity(""),this.validityController.setValidity({});return}this.required&&!this.value?this.validityController.setValidity({valueMissing:!0},this.localize("fieldRequired")):this.validityController.setValidity({}),this.validityController.setCustomValidity(this.customValidityMessage)}}get isValidationBarred(){return this.effectiveDisabled||this.loading||this.baseEl?.localName==="a"}syncButtonStates(){this.internals&&(setCustomState(this.internals,"disabled",this.effectiveDisabled||this.loading),setCustomState(this.internals,"icon-button",this.isIconButton),setCustomState(this.internals,"link",this.baseEl?.localName==="a"),setCustomState(this.internals,"loading",this.loading))}syncDescribedByElements(){!this.triggerDescribedBy&&!this.hasSyncedDescribedByElements||(this.hasSyncedDescribedByElements=syncAriaDescribedByElements(this,this.baseEl,this.triggerDescribedBy))}render(){const content=html`
1
+ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,query,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import{chevronIcon,spinnerIcon}from"../../../internal/icons.js";import{safeDownloadHref,safeLinkHref}from"../../../internal/safe-url.js";import{syncAriaControlsElements,syncAriaDescribedByElements}from"../../../internal/aria-controls.js";import{sizes}from"../../../internal/sizes.styles.js";import{variants}from"../../../internal/variants.styles.js";import{styles}from"./button.styles.js";import{relayNativeEvent}from"../../../internal/native-event-relay.js";import{installInvalidEventAlias}from"../../../internal/invalid-event-alias.js";import{attachInternalsSafely,getFormOwner,installCustomErrorProperty,setFormOwner}from"../../../internal/form-associated.js";import{AnchoredValidityController,VALIDITY_ANCHOR}from"../../../internal/anchored-validity.js";import{setCustomState}from"../../../internal/custom-states.js";import{EXTERNAL_LABEL_ACTIVATION,installFormControlLabelSupport}from"../../../internal/form-control-labels.js";installFormControlLabelSupport();import{omittedEmptyStringConverter}from"../../../internal/converters.js";import{currentValidityValidator}from"../form-validator.js";import{LYRA_DEFAULT_fieldRequired}from"../../../internal/default-strings.generated.js";class LyraButton extends LyraElement{static{this.defaultStrings={...super.defaultStrings,fieldRequired:LYRA_DEFAULT_fieldRequired}}static get validators(){return[currentValidityValidator("required","disabled","loading","href","value")]}static{this.styles=[LyraElement.styles,sizes,variants,styles]}static{this.formAssociated=!0}static{this.properties={disabled:{type:Boolean,reflect:!0,noAccessor:!0},name:{reflect:!0,noAccessor:!0,converter:omittedEmptyStringConverter},customError:{attribute:"custom-error",reflect:!0,noAccessor:!0}}}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),this.requestUpdate("disabled",old),this.updateValidity()}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}get effectiveDisabled(){return this._disabled||this._fieldsetDisabled}get form(){return getFormOwner(this.internals)}set form(owner){setFormOwner(this,owner)}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}constructor(){super(),this._fieldsetDisabled=!1,this._disabled=!1,this._name="",this._value="",this._required=!1,this._variant="neutral",this.hasSyncedDescribedByElements=!1,this.customValidityMessage="",this.reflectingCustomError=!1,this.accessibleLabel=null,this.triggerHasPopup=null,this.triggerExpanded=null,this.triggerControls=null,this.triggerDescribedBy=null,this.appearance="accent",this.size="m",this.pill=!1,this.circle=!1,this.outline=!1,this.withCaret=!1,this.withStart=!1,this.withEnd=!1,this.type="button",this.formNoValidate=!1,this.loading=!1,this.hasStartSlot=!1,this.hasEndSlot=!1,this.isIconButton=!1,this.onClick=event=>{if(this.type!=="submit"&&this.type!=="reset")return;const ownerWindow=this.ownerDocument.defaultView;let settled=!1;const finish=()=>{settled||(settled=!0,ownerWindow?.removeEventListener("click",finishAtWindow),!(event.defaultPrevented||this.effectiveDisabled||this.loading)&&this.runClickDefaultAction())},finishAtWindow=candidate=>{candidate===event&&finish()};ownerWindow?.addEventListener("click",finishAtWindow),queueMicrotask(finish)},this.onFocus=event=>{relayNativeEvent(this,event)},this.onBlur=event=>{relayNativeEvent(this,event)},this.onStartSlotChange=()=>{this.syncAdornmentSlots()},this.onEndSlotChange=()=>{this.syncAdornmentSlots()},this.onDefaultSlotChange=()=>{this.isIconButton=this.hasIconOnlyDefaultContent(),this.syncButtonStates()},installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init)),this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),installCustomErrorProperty(this,()=>this.customValidityMessage),this.updateValidity(),this.syncButtonStates()}get variant(){return this._variant}set variant(next){next==="primary"?this._variant="brand":next==="default"||next==="text"?this._variant="neutral":this._variant=next,next==="text"&&(this.appearance="plain")}get caret(){return this.withCaret}set caret(next){this.withCaret=!!next}get value(){return this._value}set value(next){this._value=next??"",this.updateValidity()}get required(){return this._required}set required(next){this._required=!!next,this.updateValidity()}get resolvedRel(){const authored=(this.rel??"").split(/\s+/).filter(token=>token!==""&&token.toLowerCase()!=="opener"),tokens=new Set(authored);return this.target&&(tokens.add("noopener"),tokens.add("noreferrer")),tokens.size>0?[...tokens].join(" "):void 0}click(){this.effectiveDisabled||this.loading||this.baseEl?.click()}focus(options){!this.effectiveDisabled&&!this.loading&&this.baseEl?.focus(options)}blur(){this.baseEl?.blur()}[VALIDITY_ANCHOR](){return this.baseEl??null}[EXTERNAL_LABEL_ACTIVATION](){return"activate"}checkValidity(){return this.internals.checkValidity()}reportValidity(){return this.internals.reportValidity()}setCustomValidity(message){const old=this.customValidityMessage||null,next=message??"";if(this.customValidityMessage=next,this.validityController.setCustomValidity(this.isValidationBarred?"":next),!this.reflectingCustomError){this.reflectingCustomError=!0;try{next?this.setAttribute("custom-error",next):this.removeAttribute("custom-error")}finally{this.reflectingCustomError=!1}}this.requestUpdate("customError",old)}resetValidity(){this.customValidityMessage="",this.validityController.setCustomValidity(""),this.updateValidity()}formStateRestoreCallback(state2,reason){this.value=typeof state2=="string"?state2:""}runClickDefaultAction(){if(this.type==="submit"){const form=this.getForm();if(!form)return;this.hasSubmitterOverrides?this.submitAsNamedSubmitter(form):form.requestSubmit()}else this.type==="reset"&&this.getForm()?.reset()}get hasSubmitterOverrides(){return!!(this.name||this.value||this.formNoValidate)||this.formAction!==void 0||this.formEnctype!==void 0||this.formMethod!==void 0||this.formTarget!==void 0}submitAsNamedSubmitter(form){const submitter=this.ownerDocument.createElement("button");submitter.type="submit",submitter.hidden=!0,submitter.tabIndex=-1,this.name&&(submitter.name=this.name,submitter.value=this.value),this.formAction!==void 0&&submitter.setAttribute("formaction",this.formAction),this.formEnctype!==void 0&&submitter.setAttribute("formenctype",this.formEnctype),this.formMethod!==void 0&&submitter.setAttribute("formmethod",this.formMethod),this.formNoValidate&&(submitter.formNoValidate=!0),this.formTarget!==void 0&&submitter.setAttribute("formtarget",this.formTarget),this.parentElement&&this.closest("form")===form?this.insertAdjacentElement("afterend",submitter):form.append(submitter);try{form.requestSubmit(submitter)}finally{submitter.remove()}}formDisabledCallback(disabled){this._fieldsetDisabled=disabled,this.updateValidity(),this.syncButtonStates(),this.requestUpdate()}connectedCallback(){super.connectedCallback(),this.updateValidity(),this.syncButtonStates()}willUpdate(changed){super.willUpdate(changed),this.hasUpdated||(this.syncAdornmentSlots(),this.isIconButton=this.hasIconOnlyDefaultContent())}syncAdornmentSlots(){const collection=this.children,children=collection?Array.from(collection):[];this.hasStartSlot=children.some(element=>{const slot=element.getAttribute("slot");return slot==="start"||slot==="prefix"}),this.hasEndSlot=children.some(element=>{const slot=element.getAttribute("slot");return slot==="end"||slot==="suffix"})}hasIconOnlyDefaultContent(){const childElements=this.children,elements=(childElements?Array.from(childElements):[]).filter(element=>!element.getAttribute("slot"));if(elements.length!==1)return!1;const childNodes=this.childNodes;return(childNodes?Array.from(childNodes):[]).filter(node=>node.nodeType===3).map(node=>node.textContent??"").join("").trim()===""&&(elements[0]?.textContent??"").trim()===""}updated(changed){super.updated(changed),syncAriaControlsElements(this,this.baseEl,this.triggerControls),this.syncDescribedByElements(),this.updateValidity(),this.syncButtonStates()}updateValidity(){if(this.validityController){if(this.isValidationBarred){this.validityController.setCustomValidity(""),this.validityController.setValidity({});return}this.required&&!this.value?this.validityController.setValidity({valueMissing:!0},this.localize("fieldRequired")):this.validityController.setValidity({}),this.validityController.setCustomValidity(this.customValidityMessage)}}get isValidationBarred(){return this.effectiveDisabled||this.loading||this.baseEl?.localName==="a"}syncButtonStates(){this.internals&&(setCustomState(this.internals,"disabled",this.effectiveDisabled||this.loading),setCustomState(this.internals,"icon-button",this.isIconButton),setCustomState(this.internals,"link",this.baseEl?.localName==="a"),setCustomState(this.internals,"loading",this.loading))}syncDescribedByElements(){!this.triggerDescribedBy&&!this.hasSyncedDescribedByElements||(this.hasSyncedDescribedByElements=syncAriaDescribedByElements(this,this.baseEl,this.triggerDescribedBy))}render(){const content=html`
2
2
  <span
3
3
  part="start prefix"
4
4
  ?hidden=${!(this.hasStartSlot||this.withStart)}
@@ -1,6 +1,5 @@
1
1
  import { type TemplateResult, type PropertyValues } from 'lit';
2
2
  import { LyraElement } from '../../../internal/lyra-element.js';
3
- import '../../../internal/form-control-labels.js';
4
3
  import type { LyraSize } from '../../../internal/variants.js';
5
4
  import { type FormOwnerValue } from '../../../internal/form-associated.js';
6
5
  import { type LyraFormValidator } from '../form-validator.js';
@@ -1,4 +1,4 @@
1
- var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,svg,nothing}from"lit";import{property,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import"../../../internal/form-control-labels.js";import{AnchoredValidityController,VALIDITY_ANCHOR}from"../../../internal/anchored-validity.js";import{setCustomState,syncValidityStates}from"../../../internal/custom-states.js";import{syncAriaDescribedByElements}from"../../../internal/aria-controls.js";import{sizes}from"../../../internal/sizes.styles.js";import{styles}from"./checkbox.styles.js";import{dispatchNativeEvent,relayNativeEvent}from"../../../internal/native-event-relay.js";import{installInvalidEventAlias}from"../../../internal/invalid-event-alias.js";import{omittedEmptyStringConverter}from"../../../internal/converters.js";import{hasRealContent}from"../../../internal/a11y.js";import{isActionableElement}from"../../../internal/focus-navigation.js";import{attachInternalsSafely,getFormOwner,installCustomErrorProperty,isBarredFromValidation,setFormOwner}from"../../../internal/form-associated.js";import{currentValidityValidator}from"../form-validator.js";import{LYRA_DEFAULT_checkboxRequired,LYRA_DEFAULT_fieldRequired}from"../../../internal/default-strings.generated.js";const GLYPH_VIEW_BOX="0 0 24 24",GLYPH_STROKE_WIDTH="1.75";function checkmarkGlyph(){return svg`
1
+ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,svg,nothing}from"lit";import{property,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import{installFormControlLabelSupport}from"../../../internal/form-control-labels.js";installFormControlLabelSupport();import{AnchoredValidityController,VALIDITY_ANCHOR}from"../../../internal/anchored-validity.js";import{setCustomState,syncValidityStates}from"../../../internal/custom-states.js";import{syncAriaDescribedByElements}from"../../../internal/aria-controls.js";import{sizes}from"../../../internal/sizes.styles.js";import{styles}from"./checkbox.styles.js";import{dispatchNativeEvent,relayNativeEvent}from"../../../internal/native-event-relay.js";import{installInvalidEventAlias}from"../../../internal/invalid-event-alias.js";import{omittedEmptyStringConverter}from"../../../internal/converters.js";import{hasRealContent}from"../../../internal/a11y.js";import{isActionableElement}from"../../../internal/focus-navigation.js";import{attachInternalsSafely,getFormOwner,installCustomErrorProperty,isBarredFromValidation,setFormOwner}from"../../../internal/form-associated.js";import{currentValidityValidator}from"../form-validator.js";import{LYRA_DEFAULT_checkboxRequired,LYRA_DEFAULT_fieldRequired}from"../../../internal/default-strings.generated.js";const GLYPH_VIEW_BOX="0 0 24 24",GLYPH_STROKE_WIDTH="1.75";function checkmarkGlyph(){return svg`
2
2
  <svg
3
3
  part="checkmark checked-icon"
4
4
  width="1em"
@@ -1,6 +1,5 @@
1
1
  import { type PropertyValues, type TemplateResult } from 'lit';
2
2
  import { LyraElement } from '../../../internal/lyra-element.js';
3
- import '../../../internal/form-control-labels.js';
4
3
  import type { LyraSize } from '../../../internal/variants.js';
5
4
  import { type FormOwnerValue } from '../../../internal/form-associated.js';
6
5
  export interface LyraCheckboxGroupEventMap {