@aceshooting/lyra-ui 2.0.0 → 2.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 (224) hide show
  1. package/README.md +87 -14
  2. package/custom-elements.json +11555 -5539
  3. package/dist/components/app-rail/app-rail-item.d.ts +30 -0
  4. package/dist/components/app-rail/app-rail-item.js +68 -0
  5. package/dist/components/app-rail/app-rail-item.styles.d.ts +1 -0
  6. package/dist/components/app-rail/app-rail-item.styles.js +65 -0
  7. package/dist/components/app-rail/app-rail.d.ts +21 -24
  8. package/dist/components/app-rail/app-rail.js +68 -132
  9. package/dist/components/app-rail/app-rail.styles.js +5 -2
  10. package/dist/components/attachment-chip/attachment-chip.d.ts +38 -11
  11. package/dist/components/attachment-chip/attachment-chip.js +73 -29
  12. package/dist/components/attachment-trigger/attachment-trigger.d.ts +13 -0
  13. package/dist/components/attachment-trigger/attachment-trigger.js +13 -1
  14. package/dist/components/attachment-trigger/attachment-trigger.styles.js +28 -6
  15. package/dist/components/chart/bar-chart.js +2 -18
  16. package/dist/components/chart/box-plot.d.ts +25 -1
  17. package/dist/components/chart/box-plot.js +136 -6
  18. package/dist/components/chart/box-plot.styles.js +13 -0
  19. package/dist/components/chart/bubble-chart.js +2 -18
  20. package/dist/components/chart/chart.d.ts +54 -10
  21. package/dist/components/chart/chart.js +182 -39
  22. package/dist/components/chart/doughnut-chart.js +2 -18
  23. package/dist/components/chart/histogram-bin.d.ts +5 -2
  24. package/dist/components/chart/histogram-bin.js +12 -4
  25. package/dist/components/chart/histogram.js +8 -16
  26. package/dist/components/chart/line-chart.js +2 -18
  27. package/dist/components/chart/lite-chart.d.ts +80 -3
  28. package/dist/components/chart/lite-chart.js +250 -53
  29. package/dist/components/chart/pie-chart.js +2 -18
  30. package/dist/components/chart/polar-area-chart.js +2 -18
  31. package/dist/components/chart/radar-chart.js +2 -18
  32. package/dist/components/chart/scatter-chart.js +2 -18
  33. package/dist/components/chat-composer/chat-composer.d.ts +42 -1
  34. package/dist/components/chat-composer/chat-composer.js +84 -3
  35. package/dist/components/chat-composer/chat-composer.styles.js +11 -1
  36. package/dist/components/chat-message/chat-message.d.ts +32 -4
  37. package/dist/components/chat-message/chat-message.js +57 -17
  38. package/dist/components/checkbox/checkbox.d.ts +66 -8
  39. package/dist/components/checkbox/checkbox.js +173 -50
  40. package/dist/components/checkbox/checkbox.styles.js +9 -2
  41. package/dist/components/chip/chip-group.js +8 -2
  42. package/dist/components/chip/chip.js +9 -2
  43. package/dist/components/citation-badge/citation-badge.js +21 -3
  44. package/dist/components/code-block/code-block.d.ts +38 -0
  45. package/dist/components/code-block/code-block.js +72 -7
  46. package/dist/components/code-block/code-loader.d.ts +44 -1
  47. package/dist/components/code-block/code-loader.js +63 -0
  48. package/dist/components/combobox/combobox.d.ts +46 -5
  49. package/dist/components/combobox/combobox.js +175 -35
  50. package/dist/components/combobox/combobox.styles.js +3 -3
  51. package/dist/components/context-meter/context-meter.js +17 -8
  52. package/dist/components/context-meter/context-meter.styles.js +0 -6
  53. package/dist/components/conversation-item/conversation-item.d.ts +13 -16
  54. package/dist/components/conversation-item/conversation-item.js +29 -20
  55. package/dist/components/date-picker/calendar-core.d.ts +24 -0
  56. package/dist/components/date-picker/calendar-core.js +51 -4
  57. package/dist/components/date-picker/date-input.d.ts +77 -10
  58. package/dist/components/date-picker/date-input.js +278 -73
  59. package/dist/components/date-picker/date-picker.d.ts +28 -4
  60. package/dist/components/date-picker/date-picker.js +95 -37
  61. package/dist/components/dialog/confirm.js +3 -6
  62. package/dist/components/dialog/dialog.d.ts +75 -31
  63. package/dist/components/dialog/dialog.js +147 -131
  64. package/dist/components/dialog/dialog.styles.js +46 -2
  65. package/dist/components/dock-panel/dock-panel.d.ts +8 -0
  66. package/dist/components/dock-panel/dock-panel.js +15 -1
  67. package/dist/components/dock-panel/dock-panel.styles.js +15 -1
  68. package/dist/components/document-preview/document-preview.d.ts +15 -7
  69. package/dist/components/document-preview/document-preview.js +29 -13
  70. package/dist/components/empty/empty.d.ts +1 -2
  71. package/dist/components/empty/empty.js +18 -12
  72. package/dist/components/empty/empty.styles.js +0 -3
  73. package/dist/components/export-button/export-button.d.ts +12 -0
  74. package/dist/components/export-button/export-button.js +33 -5
  75. package/dist/components/export-button/export-button.styles.js +5 -1
  76. package/dist/components/file-input/accept.js +2 -0
  77. package/dist/components/file-input/file-input.d.ts +10 -1
  78. package/dist/components/file-input/file-input.js +36 -5
  79. package/dist/components/flag/flag.d.ts +1 -1
  80. package/dist/components/flag/flag.js +15 -1
  81. package/dist/components/flag/flag.styles.js +1 -1
  82. package/dist/components/flag/language-map.d.ts +4 -1
  83. package/dist/components/flag/language-map.js +6 -3
  84. package/dist/components/gauge/gauge.d.ts +10 -1
  85. package/dist/components/gauge/gauge.js +28 -9
  86. package/dist/components/generation-status/generation-status.d.ts +13 -5
  87. package/dist/components/generation-status/generation-status.js +59 -5
  88. package/dist/components/graph/graph.d.ts +37 -3
  89. package/dist/components/graph/graph.js +132 -20
  90. package/dist/components/heatmap/calendar-grid.d.ts +15 -6
  91. package/dist/components/heatmap/calendar-grid.js +17 -6
  92. package/dist/components/heatmap/heatmap-scale.d.ts +5 -1
  93. package/dist/components/heatmap/heatmap-scale.js +8 -2
  94. package/dist/components/heatmap/heatmap.d.ts +166 -25
  95. package/dist/components/heatmap/heatmap.js +372 -89
  96. package/dist/components/json-viewer/json-viewer.d.ts +22 -5
  97. package/dist/components/json-viewer/json-viewer.js +115 -37
  98. package/dist/components/json-viewer/json-viewer.styles.js +2 -1
  99. package/dist/components/kbd/kbd.js +24 -7
  100. package/dist/components/live-region/live-region.d.ts +10 -1
  101. package/dist/components/live-region/live-region.js +42 -6
  102. package/dist/components/map/map.d.ts +24 -1
  103. package/dist/components/map/map.js +89 -24
  104. package/dist/components/markdown/markdown-loader.d.ts +24 -0
  105. package/dist/components/markdown/markdown-loader.js +35 -1
  106. package/dist/components/markdown/markdown.d.ts +46 -8
  107. package/dist/components/markdown/markdown.js +136 -31
  108. package/dist/components/markdown/markdown.styles.js +7 -1
  109. package/dist/components/media-card/media-card.d.ts +25 -17
  110. package/dist/components/media-card/media-card.js +43 -65
  111. package/dist/components/mention-popover/mention-popover.d.ts +4 -1
  112. package/dist/components/mention-popover/mention-popover.js +23 -5
  113. package/dist/components/menu/menu-item.d.ts +32 -3
  114. package/dist/components/menu/menu-item.js +94 -7
  115. package/dist/components/menu/menu-item.styles.js +8 -0
  116. package/dist/components/menu/menu.d.ts +25 -1
  117. package/dist/components/menu/menu.js +99 -3
  118. package/dist/components/menu/menu.styles.js +3 -2
  119. package/dist/components/model-select/model-select.d.ts +48 -3
  120. package/dist/components/model-select/model-select.js +120 -22
  121. package/dist/components/model-select/model-select.styles.js +17 -3
  122. package/dist/components/model-settings-panel/model-settings-panel.d.ts +25 -1
  123. package/dist/components/model-settings-panel/model-settings-panel.js +65 -1
  124. package/dist/components/playback/playback.d.ts +6 -2
  125. package/dist/components/playback/playback.js +72 -29
  126. package/dist/components/playback/playback.styles.js +6 -1
  127. package/dist/components/responsive-panel/responsive-panel.d.ts +29 -16
  128. package/dist/components/responsive-panel/responsive-panel.js +130 -132
  129. package/dist/components/responsive-panel/responsive-panel.styles.js +1 -1
  130. package/dist/components/result-card/result-card.d.ts +8 -2
  131. package/dist/components/result-card/result-card.js +9 -3
  132. package/dist/components/result-card/result-card.styles.js +0 -1
  133. package/dist/components/select/select.d.ts +59 -20
  134. package/dist/components/select/select.js +125 -43
  135. package/dist/components/skeleton/skeleton.d.ts +3 -0
  136. package/dist/components/skeleton/skeleton.js +7 -1
  137. package/dist/components/skeleton/skeleton.styles.js +5 -4
  138. package/dist/components/slider/slider.d.ts +57 -5
  139. package/dist/components/slider/slider.js +195 -80
  140. package/dist/components/source-card/source-card.d.ts +17 -5
  141. package/dist/components/source-card/source-card.js +55 -8
  142. package/dist/components/source-card/source-card.styles.js +1 -1
  143. package/dist/components/source-list/source-list.js +9 -1
  144. package/dist/components/sparkline/sparkline.js +34 -10
  145. package/dist/components/split/split.d.ts +141 -14
  146. package/dist/components/split/split.js +357 -52
  147. package/dist/components/split/split.styles.js +18 -1
  148. package/dist/components/stat/stat.d.ts +10 -4
  149. package/dist/components/stat/stat.js +46 -11
  150. package/dist/components/stream-status/stream-status.d.ts +27 -11
  151. package/dist/components/stream-status/stream-status.js +95 -13
  152. package/dist/components/streaming-text/streaming-text.d.ts +9 -3
  153. package/dist/components/streaming-text/streaming-text.js +25 -10
  154. package/dist/components/streaming-text/streaming-text.styles.js +3 -2
  155. package/dist/components/switch/switch.d.ts +52 -7
  156. package/dist/components/switch/switch.js +111 -40
  157. package/dist/components/switch/switch.styles.js +1 -1
  158. package/dist/components/table/table.d.ts +18 -3
  159. package/dist/components/table/table.js +88 -20
  160. package/dist/components/tabs/tabs.d.ts +23 -0
  161. package/dist/components/tabs/tabs.js +76 -12
  162. package/dist/components/tabs/tabs.styles.js +11 -0
  163. package/dist/components/thinking-panel/thinking-panel.d.ts +3 -1
  164. package/dist/components/thinking-panel/thinking-panel.js +34 -9
  165. package/dist/components/thinking-panel/thinking-panel.styles.js +6 -0
  166. package/dist/components/time-range/time-range.d.ts +59 -2
  167. package/dist/components/time-range/time-range.js +163 -67
  168. package/dist/components/toast/toast-item.d.ts +12 -3
  169. package/dist/components/toast/toast-item.js +90 -53
  170. package/dist/components/toast/toast-item.styles.js +59 -28
  171. package/dist/components/toast/toast.js +17 -5
  172. package/dist/components/toast/toaster.js +10 -1
  173. package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +11 -10
  174. package/dist/components/tool-approval-dialog/tool-approval-dialog.js +50 -124
  175. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +1 -1
  176. package/dist/components/tool-call-chip/tool-call-chip.d.ts +18 -2
  177. package/dist/components/tool-call-chip/tool-call-chip.js +86 -25
  178. package/dist/components/tool-param-form/tool-param-form.d.ts +89 -28
  179. package/dist/components/tool-param-form/tool-param-form.js +350 -106
  180. package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +27 -7
  181. package/dist/components/tool-result-dialog/tool-result-dialog.js +80 -115
  182. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +1 -1
  183. package/dist/components/tool-result-view/registry.d.ts +0 -8
  184. package/dist/components/tool-result-view/registry.js +7 -2
  185. package/dist/components/tool-result-view/tool-result-view.d.ts +6 -3
  186. package/dist/components/tool-result-view/tool-result-view.js +18 -4
  187. package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +11 -11
  188. package/dist/components/tool-select-dialog/tool-select-dialog.js +44 -133
  189. package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +13 -4
  190. package/dist/components/tree/tree-node.d.ts +4 -1
  191. package/dist/components/tree/tree-node.js +4 -1
  192. package/dist/components/tree/tree.d.ts +17 -8
  193. package/dist/components/tree/tree.js +21 -20
  194. package/dist/components/typing-indicator/typing-indicator.d.ts +12 -2
  195. package/dist/components/typing-indicator/typing-indicator.js +16 -4
  196. package/dist/components/typing-indicator/typing-indicator.styles.js +2 -2
  197. package/dist/components/virtual-list/virtual-list.d.ts +56 -19
  198. package/dist/components/virtual-list/virtual-list.js +184 -38
  199. package/dist/components/virtual-list/virtual-list.styles.js +12 -0
  200. package/dist/components/widget/widget.d.ts +5 -4
  201. package/dist/components/widget/widget.js +54 -120
  202. package/dist/components/widget/widget.styles.js +8 -2
  203. package/dist/components/word-cloud/word-cloud-layout.d.ts +7 -0
  204. package/dist/components/word-cloud/word-cloud-layout.js +20 -6
  205. package/dist/components/word-cloud/word-cloud.d.ts +22 -2
  206. package/dist/components/word-cloud/word-cloud.js +45 -6
  207. package/dist/components/word-cloud/word-cloud.styles.js +13 -1
  208. package/dist/internal/anchored-validity.d.ts +1 -0
  209. package/dist/internal/anchored-validity.js +86 -0
  210. package/dist/internal/form-associated.d.ts +7 -0
  211. package/dist/internal/form-associated.js +43 -4
  212. package/dist/internal/numbers.d.ts +12 -0
  213. package/dist/internal/numbers.js +26 -0
  214. package/dist/internal/overlay-manager.d.ts +51 -0
  215. package/dist/internal/overlay-manager.js +523 -0
  216. package/dist/internal/positioner.js +27 -3
  217. package/dist/internal/safe-url.d.ts +12 -0
  218. package/dist/internal/safe-url.js +41 -0
  219. package/dist/internal/tokens.styles.js +17 -11
  220. package/dist/lyra.d.ts +5 -2
  221. package/dist/lyra.js +3 -1
  222. package/llms-full.txt +970 -426
  223. package/llms.txt +5 -4
  224. package/package.json +19 -2
@@ -5,9 +5,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { html, nothing } from 'lit';
8
- import { property, state } from 'lit/decorators.js';
8
+ import { state } from 'lit/decorators.js';
9
9
  import { LyraElement } from '../../internal/lyra-element.js';
10
10
  import { defineElement } from '../../internal/prefix.js';
11
+ import { AnchoredValidityController, VALIDITY_ANCHOR } from '../../internal/anchored-validity.js';
11
12
  import { styles } from './switch.styles.js';
12
13
  /**
13
14
  * `<lyra-switch>` — a boolean toggle-switch form control. Structurally the
@@ -36,13 +37,71 @@ import { styles } from './switch.styles.js';
36
37
  export class LyraSwitch extends LyraElement {
37
38
  static { this.styles = [LyraElement.styles, styles]; }
38
39
  static { this.formAssociated = true; }
40
+ static { this.properties = {
41
+ checked: { type: Boolean, reflect: true, noAccessor: true },
42
+ disabled: { type: Boolean, reflect: true, noAccessor: true },
43
+ name: { reflect: true, noAccessor: true },
44
+ required: { type: Boolean, reflect: true, noAccessor: true },
45
+ value: { noAccessor: true },
46
+ }; }
47
+ /** Whether the control is disabled explicitly or by an ancestor fieldset. */
48
+ get effectiveDisabled() {
49
+ return this.disabled || this._fieldsetDisabled;
50
+ }
51
+ get checked() {
52
+ return this._checked;
53
+ }
54
+ set checked(next) {
55
+ const old = this._checked;
56
+ this._checked = Boolean(next);
57
+ this.syncFormState();
58
+ this.requestUpdate('checked', old);
59
+ }
60
+ get disabled() {
61
+ return this._disabled;
62
+ }
63
+ set disabled(next) {
64
+ const old = this._disabled;
65
+ this._disabled = Boolean(next);
66
+ this.toggleAttribute('disabled', this._disabled);
67
+ this.requestUpdate('disabled', old);
68
+ }
69
+ /** The form submission key, reflected synchronously for native form APIs. */
70
+ get name() {
71
+ return this._name;
72
+ }
73
+ set name(next) {
74
+ const old = this._name;
75
+ this._name = next ?? '';
76
+ if (this._name) {
77
+ this.setAttribute('name', this._name);
78
+ }
79
+ else {
80
+ this.removeAttribute('name');
81
+ }
82
+ this.requestUpdate('name', old);
83
+ }
84
+ get required() {
85
+ return this._required;
86
+ }
87
+ set required(next) {
88
+ const old = this._required;
89
+ this._required = Boolean(next);
90
+ this.toggleAttribute('required', this._required);
91
+ this.updateValidity();
92
+ this.requestUpdate('required', old);
93
+ }
94
+ get value() {
95
+ return this._value;
96
+ }
97
+ set value(next) {
98
+ const old = this._value;
99
+ this._value = next ?? 'on';
100
+ this.syncFormState();
101
+ this.requestUpdate('value', old);
102
+ }
39
103
  constructor() {
40
104
  super();
41
- this.checked = false;
42
- this.disabled = false;
43
- this.required = false;
44
- this.name = '';
45
- this.value = 'on';
46
105
  // Tracks whether the default slot carries any real (non-whitespace)
47
106
  // content, so the label wrapper — and the `gap` next to the track — can
48
107
  // collapse to nothing for an icon-only/aria-label-only switch instead of
@@ -52,10 +111,10 @@ export class LyraSwitch extends LyraElement {
52
111
  // common case here, e.g. `<lyra-switch>Enable notifications</lyra-switch>`)
53
112
  // is a text node, which `assignedElements` would silently ignore.
54
113
  this.hasLabelSlot = false;
55
- // What `form.reset()` restores to — captured once, from whatever the
56
- // `checked` property reads at first connect (i.e. whatever the declarative
57
- // `checked` attribute parsed to, since attribute parsing happens before
58
- // `connectedCallback`). `checked` reflects, so unlike
114
+ // What `form.reset()` restores to — captured once from the declarative
115
+ // `checked` content attribute at first connect. A pre-connect `.checked`
116
+ // property assignment changes live state but not the reset default, matching
117
+ // native `checked`/`defaultChecked` semantics. `checked` reflects, so unlike
59
118
  // `FormAssociated`'s non-reflecting `value` this can't be captured from
60
119
  // `attributeChangedCallback` alone — that would also fire (and wrongly
61
120
  // redefine the default) every time the property setter itself reflects a
@@ -63,11 +122,17 @@ export class LyraSwitch extends LyraElement {
63
122
  // instead mirrors `<lyra-combobox>`'s `_defaultCaptured`/`_defaultSelected`.
64
123
  this._defaultChecked = false;
65
124
  this._defaultCaptured = false;
125
+ this._fieldsetDisabled = false;
126
+ this._name = '';
127
+ this._checked = false;
128
+ this._disabled = false;
129
+ this._required = false;
130
+ this._value = 'on';
66
131
  this.onClick = () => {
67
132
  this.toggle();
68
133
  };
69
134
  this.onKeyDown = (e) => {
70
- if (this.disabled)
135
+ if (this.effectiveDisabled)
71
136
  return;
72
137
  // Space/Enter both activate, matching `<lyra-table>`'s sortable
73
138
  // header/row convention (`table.ts`'s `onHeaderKeyDown`/`onRowKeyDown`)
@@ -83,12 +148,33 @@ export class LyraSwitch extends LyraElement {
83
148
  this.hasLabelSlot = nodes.some((n) => (n.textContent ?? '').trim().length > 0);
84
149
  };
85
150
  this.internals = this.attachInternals();
151
+ this.validityController = new AnchoredValidityController(this, this.internals, () => this[VALIDITY_ANCHOR]());
152
+ this.syncFormState();
153
+ }
154
+ get form() {
155
+ return this.internals.form;
156
+ }
157
+ get labels() {
158
+ return this.internals.labels;
159
+ }
160
+ get validity() {
161
+ return this.internals.validity;
162
+ }
163
+ get validationMessage() {
164
+ return this.internals.validationMessage;
165
+ }
166
+ get willValidate() {
167
+ return this.internals.willValidate;
168
+ }
169
+ /** @internal */
170
+ [VALIDITY_ANCHOR]() {
171
+ return this.renderRoot?.querySelector('[part="base"]') ?? null;
86
172
  }
87
173
  connectedCallback() {
88
174
  super.connectedCallback();
89
175
  if (!this._defaultCaptured) {
90
176
  this._defaultCaptured = true;
91
- this._defaultChecked = this.checked;
177
+ this._defaultChecked = this.hasAttribute('checked');
92
178
  }
93
179
  this.updateValidity();
94
180
  }
@@ -103,25 +189,25 @@ export class LyraSwitch extends LyraElement {
103
189
  }
104
190
  updateValidity() {
105
191
  if (this.required && !this.checked) {
106
- this.internals.setValidity({ valueMissing: true }, 'Please turn this on.');
192
+ this.validityController.setValidity({ valueMissing: true }, 'Please turn this on.');
107
193
  }
108
194
  else {
109
- this.internals.setValidity({});
195
+ this.validityController.setValidity({});
110
196
  }
111
197
  }
112
- updated(changed) {
113
- if (changed.has('checked') || changed.has('value')) {
114
- this.internals.setFormValue(this.checked ? this.value : null);
115
- }
116
- if (changed.has('checked') || changed.has('required')) {
117
- this.updateValidity();
118
- }
198
+ syncFormState() {
199
+ this.internals.setFormValue(this.checked ? this.value : null, this.checked ? 'checked' : 'unchecked');
200
+ this.updateValidity();
119
201
  }
120
202
  formResetCallback() {
121
203
  this.checked = this._defaultChecked;
122
204
  }
205
+ formStateRestoreCallback(state, _mode) {
206
+ this.checked = state === 'checked';
207
+ }
123
208
  formDisabledCallback(disabled) {
124
- this.disabled = disabled;
209
+ this._fieldsetDisabled = disabled;
210
+ this.requestUpdate();
125
211
  }
126
212
  checkValidity() {
127
213
  return this.internals.checkValidity();
@@ -130,7 +216,7 @@ export class LyraSwitch extends LyraElement {
130
216
  return this.internals.reportValidity();
131
217
  }
132
218
  toggle() {
133
- if (this.disabled)
219
+ if (this.effectiveDisabled)
134
220
  return;
135
221
  this.checked = !this.checked;
136
222
  this.emit('lyra-change', { checked: this.checked });
@@ -140,10 +226,10 @@ export class LyraSwitch extends LyraElement {
140
226
  <span
141
227
  part="base"
142
228
  role="switch"
143
- tabindex=${this.disabled ? '-1' : '0'}
229
+ tabindex=${this.effectiveDisabled ? '-1' : '0'}
144
230
  aria-checked=${this.checked ? 'true' : 'false'}
145
231
  aria-required=${this.required ? 'true' : nothing}
146
- aria-disabled=${this.disabled ? 'true' : nothing}
232
+ aria-disabled=${this.effectiveDisabled ? 'true' : nothing}
147
233
  aria-label=${this.getAttribute('aria-label') || nothing}
148
234
  @click=${this.onClick}
149
235
  @keydown=${this.onKeyDown}
@@ -158,21 +244,6 @@ export class LyraSwitch extends LyraElement {
158
244
  `;
159
245
  }
160
246
  }
161
- __decorate([
162
- property({ type: Boolean, reflect: true })
163
- ], LyraSwitch.prototype, "checked", void 0);
164
- __decorate([
165
- property({ type: Boolean, reflect: true })
166
- ], LyraSwitch.prototype, "disabled", void 0);
167
- __decorate([
168
- property({ type: Boolean, reflect: true })
169
- ], LyraSwitch.prototype, "required", void 0);
170
- __decorate([
171
- property()
172
- ], LyraSwitch.prototype, "name", void 0);
173
- __decorate([
174
- property()
175
- ], LyraSwitch.prototype, "value", void 0);
176
247
  __decorate([
177
248
  state()
178
249
  ], LyraSwitch.prototype, "hasLabelSlot", void 0);
@@ -21,7 +21,7 @@ export const styles = css `
21
21
  outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
22
22
  outline-offset: var(--lyra-focus-ring-offset);
23
23
  }
24
- :host([disabled]) [part='base'] {
24
+ :host(:disabled) [part='base'] {
25
25
  cursor: not-allowed;
26
26
  opacity: var(--lyra-opacity-disabled);
27
27
  }
@@ -37,6 +37,9 @@ export interface TableColumn<T> {
37
37
  * Enter/Space still only sort/activate (see `activateColumn()` /
38
38
  * `activateRow()`).
39
39
  *
40
+ * Set `aria-label` on the host to give the `role="grid"` element an
41
+ * accessible name; it's forwarded into the shadow DOM's `<table>`.
42
+ *
40
43
  * `columns[].priority` ('medium' | 'low') hides that column under
41
44
  * `[part='base']`'s `@container` breakpoints; `[part='reveal-columns-button']`
42
45
  * forces them all back into view. Rather than a *static* check of whether any
@@ -56,7 +59,15 @@ export interface TableColumn<T> {
56
59
  * (a `priority` column just became hidden/un-hidden by the `@container`
57
60
  * rules, or `showAllColumns` force-visible mode was toggled while a
58
61
  * `priority` column was hidden). `detail: { hidden: boolean }`.
59
- * @csspart base, table, head, header-cell, row, cell, more-button, sort-icon, reveal-columns-button
62
+ * @csspart base - The root wrapper around the `<table>` and its footer controls.
63
+ * @csspart table - The `<table role="grid">` element.
64
+ * @csspart head - The `<thead>` element.
65
+ * @csspart header-cell - Each `<th>` header cell.
66
+ * @csspart row - Each body `<tr>`.
67
+ * @csspart cell - Each body `<td>`.
68
+ * @csspart more-button - The "load more" control, shown when `hasMore` is true.
69
+ * @csspart sort-icon - The chevron shown in the active sortable column's header cell.
70
+ * @csspart reveal-columns-button - The button that toggles `priority`-hidden columns back into view.
60
71
  */
61
72
  export declare class LyraTable<T = unknown> extends LyraElement {
62
73
  static styles: import("lit").CSSResultGroup[];
@@ -119,9 +130,11 @@ export declare class LyraTable<T = unknown> extends LyraElement {
119
130
  * identity on the next non-empty render, so `updated()` re-observes
120
131
  * whenever this no longer matches the live element. */
121
132
  private observedBase?;
133
+ private readonly observedHeaders;
122
134
  connectedCallback(): void;
123
135
  disconnectedCallback(): void;
124
136
  private observeBase;
137
+ private observeHeaders;
125
138
  /** Recomputes `columnsHidden` from the live DOM (mirrors `visibleHeaders()`'s
126
139
  * own `offsetParent !== null` technique for detecting `@container`-hidden
127
140
  * cells) and dispatches `lyra-columns-hidden-change` only on a real
@@ -130,19 +143,21 @@ export declare class LyraTable<T = unknown> extends LyraElement {
130
143
  * from the `ResizeObserver` callback (covers a container resize with no
131
144
  * Lit-tracked property change at all). */
132
145
  private recomputeColumnsHidden;
146
+ private rehomeFocusedColumn;
133
147
  private keyOf;
134
148
  /** The header cell that currently owns `tabindex="0"`. */
135
149
  private focusedColKey;
136
150
  /** The body row that currently owns `tabindex="0"`. */
137
151
  private focusedRowKey;
138
152
  protected willUpdate(changed: PropertyValues): void;
139
- /** Each sticky column's cumulative left offset — the sum of the *rendered
153
+ /** Each sticky column's cumulative inline-start offset — the sum of the *rendered
140
154
  * width* of every earlier sticky column — so multiple sticky columns
141
155
  * stack left-to-right instead of all pinning to inset-inline-start: 0 and
142
156
  * overlapping. Table columns are intrinsically sized (not fixed-width), so
143
157
  * this can't be computed in CSS alone; it requires measuring the actual
144
158
  * laid-out `offsetWidth` of each earlier sticky column's header cell. */
145
159
  private stickyOffsets;
160
+ private applyStickyOffsets;
146
161
  /** Applies stickyOffsets()'s measured per-column offsets as an inline
147
162
  * `--lyra-table-sticky-offset` custom property on every header cell and
148
163
  * body cell in that column (addressed by the shared `data-col-key`
@@ -158,7 +173,7 @@ export declare class LyraTable<T = unknown> extends LyraElement {
158
173
  * when `hasSticky` is true (opt-in) and simply recomputes on every
159
174
  * update; a future optimization pass could cache column widths instead of
160
175
  * re-querying every time — out of scope for this correctness fix. */
161
- protected updated(): void;
176
+ protected updated(changed: PropertyValues): void;
162
177
  private activateColumn;
163
178
  private activateRow;
164
179
  /** Header cells currently in the tab sequence — excludes columns hidden by
@@ -16,7 +16,7 @@ import '../empty/empty.js';
16
16
  * actions-column button). Clicks/keydowns landing on one of these — or
17
17
  * bubbling up through one — must not be re-interpreted as row/column
18
18
  * activation by the table's own delegated listeners. */
19
- const INTERACTIVE_SELECTOR = 'button, a[href], input, select, textarea, [role="button"], [role="combobox"], [role="listbox"], [role="slider"]';
19
+ const INTERACTIVE_SELECTOR = 'button, a[href], input, select, textarea, summary, audio[controls], video[controls], [contenteditable]:not([contenteditable="false"]), [tabindex]:not([tabindex="-1"]), [role="button"], [role="checkbox"], [role="combobox"], [role="listbox"], [role="menu"], [role="menuitem"], [role="option"], [role="radio"], [role="slider"], [role="spinbutton"], [role="switch"], [role="tab"], [role="textbox"]';
20
20
  /** Encodes a row/column identity key for use as a Map key or a DOM
21
21
  * `data-row-key` attribute value, preserving the distinction between a
22
22
  * numeric key and a string key that happen to stringify the same way
@@ -34,7 +34,8 @@ function encodeKey(key) {
34
34
  function closestInteractive(target, boundary) {
35
35
  let el = target;
36
36
  while (el && el !== boundary) {
37
- if (el.matches(INTERACTIVE_SELECTOR) || el.tagName.includes('-'))
37
+ if ((el.matches(INTERACTIVE_SELECTOR) && !el.matches('[data-row-key], th[data-col-key]')) ||
38
+ el.tagName.includes('-'))
38
39
  return el;
39
40
  el = el.parentElement;
40
41
  }
@@ -60,6 +61,9 @@ function closestInteractive(target, boundary) {
60
61
  * Enter/Space still only sort/activate (see `activateColumn()` /
61
62
  * `activateRow()`).
62
63
  *
64
+ * Set `aria-label` on the host to give the `role="grid"` element an
65
+ * accessible name; it's forwarded into the shadow DOM's `<table>`.
66
+ *
63
67
  * `columns[].priority` ('medium' | 'low') hides that column under
64
68
  * `[part='base']`'s `@container` breakpoints; `[part='reveal-columns-button']`
65
69
  * forces them all back into view. Rather than a *static* check of whether any
@@ -79,7 +83,15 @@ function closestInteractive(target, boundary) {
79
83
  * (a `priority` column just became hidden/un-hidden by the `@container`
80
84
  * rules, or `showAllColumns` force-visible mode was toggled while a
81
85
  * `priority` column was hidden). `detail: { hidden: boolean }`.
82
- * @csspart base, table, head, header-cell, row, cell, more-button, sort-icon, reveal-columns-button
86
+ * @csspart base - The root wrapper around the `<table>` and its footer controls.
87
+ * @csspart table - The `<table role="grid">` element.
88
+ * @csspart head - The `<thead>` element.
89
+ * @csspart header-cell - Each `<th>` header cell.
90
+ * @csspart row - Each body `<tr>`.
91
+ * @csspart cell - Each body `<td>`.
92
+ * @csspart more-button - The "load more" control, shown when `hasMore` is true.
93
+ * @csspart sort-icon - The chevron shown in the active sortable column's header cell.
94
+ * @csspart reveal-columns-button - The button that toggles `priority`-hidden columns back into view.
83
95
  */
84
96
  export class LyraTable extends LyraElement {
85
97
  constructor() {
@@ -121,6 +133,7 @@ export class LyraTable extends LyraElement {
121
133
  this.activeRowKey = null;
122
134
  this.rowsByKey = new Map();
123
135
  this.columnsByKey = new Map();
136
+ this.observedHeaders = new Set();
124
137
  this.toggleColumns = () => {
125
138
  this.showAllColumns = !this.showAllColumns;
126
139
  };
@@ -164,7 +177,10 @@ export class LyraTable extends LyraElement {
164
177
  static { this.styles = [LyraElement.styles, styles]; }
165
178
  connectedCallback() {
166
179
  super.connectedCallback();
167
- this.resizeObserver = new ResizeObserver(() => this.recomputeColumnsHidden());
180
+ this.resizeObserver = new ResizeObserver(() => {
181
+ this.recomputeColumnsHidden();
182
+ this.applyStickyOffsets();
183
+ });
168
184
  // A reconnect re-creates the observer above but the shadow root content
169
185
  // survives across disconnect/reconnect (Lit doesn't tear down the shadow
170
186
  // root) — re-observe [part='base'] here if it already exists from before
@@ -180,6 +196,7 @@ export class LyraTable extends LyraElement {
180
196
  super.disconnectedCallback();
181
197
  this.resizeObserver?.disconnect();
182
198
  this.observedBase = undefined;
199
+ this.observedHeaders.clear();
183
200
  }
184
201
  observeBase(base) {
185
202
  if (this.observedBase === base)
@@ -189,6 +206,23 @@ export class LyraTable extends LyraElement {
189
206
  this.resizeObserver?.observe(base);
190
207
  this.observedBase = base;
191
208
  }
209
+ observeHeaders() {
210
+ const headers = new Set(this.columns.some((column) => column.sticky)
211
+ ? this.renderRoot.querySelectorAll('th[data-col-key]')
212
+ : []);
213
+ for (const header of this.observedHeaders) {
214
+ if (!headers.has(header)) {
215
+ this.resizeObserver?.unobserve(header);
216
+ this.observedHeaders.delete(header);
217
+ }
218
+ }
219
+ for (const header of headers) {
220
+ if (!this.observedHeaders.has(header)) {
221
+ this.observedHeaders.add(header);
222
+ this.resizeObserver?.observe(header);
223
+ }
224
+ }
225
+ }
192
226
  /** Recomputes `columnsHidden` from the live DOM (mirrors `visibleHeaders()`'s
193
227
  * own `offsetParent !== null` technique for detecting `@container`-hidden
194
228
  * cells) and dispatches `lyra-columns-hidden-change` only on a real
@@ -201,20 +235,32 @@ export class LyraTable extends LyraElement {
201
235
  const anyPriorityHidden = hasPriorityColumns &&
202
236
  [...this.renderRoot.querySelectorAll('th[data-priority]')].some((el) => el.offsetParent === null);
203
237
  const next = anyPriorityHidden || (hasPriorityColumns && this.showAllColumns);
238
+ this.rehomeFocusedColumn();
204
239
  if (this.columnsHidden === next)
205
240
  return;
206
241
  this.columnsHidden = next;
207
242
  this.emit('lyra-columns-hidden-change', { hidden: next });
208
243
  }
244
+ rehomeFocusedColumn() {
245
+ const visible = this.visibleHeaders();
246
+ if (visible.length === 0 || this.activeColKey === null)
247
+ return;
248
+ if (!visible.some((header) => header.dataset.colKey === this.activeColKey)) {
249
+ this.activeColKey = visible[0].dataset.colKey ?? null;
250
+ }
251
+ }
209
252
  keyOf(row, index) {
210
253
  return this.rowKey ? this.rowKey(row) : index;
211
254
  }
212
255
  /** The header cell that currently owns `tabindex="0"`. */
213
256
  focusedColKey() {
257
+ const visible = this.visibleHeaders();
258
+ const visibleKeys = new Set(visible.map((el) => el.dataset.colKey).filter((key) => key !== undefined && this.columnsByKey.has(key)));
214
259
  if (this.activeColKey !== null && this.columnsByKey.has(this.activeColKey)) {
215
- return this.activeColKey;
260
+ if (visibleKeys.size === 0 || visibleKeys.has(this.activeColKey))
261
+ return this.activeColKey;
216
262
  }
217
- return this.columns[0]?.key ?? null;
263
+ return visible.find((el) => el.dataset.colKey !== undefined && this.columnsByKey.has(el.dataset.colKey))?.dataset.colKey ?? this.columns[0]?.key ?? null;
218
264
  }
219
265
  /** The body row that currently owns `tabindex="0"`. */
220
266
  focusedRowKey() {
@@ -236,7 +282,7 @@ export class LyraTable extends LyraElement {
236
282
  this.columnsByKey = new Map(this.columns.map((c) => [c.key, c]));
237
283
  }
238
284
  }
239
- /** Each sticky column's cumulative left offset — the sum of the *rendered
285
+ /** Each sticky column's cumulative inline-start offset — the sum of the *rendered
240
286
  * width* of every earlier sticky column — so multiple sticky columns
241
287
  * stack left-to-right instead of all pinning to inset-inline-start: 0 and
242
288
  * overlapping. Table columns are intrinsically sized (not fixed-width), so
@@ -248,12 +294,23 @@ export class LyraTable extends LyraElement {
248
294
  for (const col of this.columns) {
249
295
  if (!col.sticky)
250
296
  continue;
297
+ const headerEl = [...this.renderRoot.querySelectorAll('th[data-col-key]')].find((el) => el.dataset.colKey === col.key);
251
298
  offsets.set(col.key, running);
252
- const headerEl = this.renderRoot.querySelector(`th[data-col-key="${col.key}"]`);
253
299
  running += headerEl?.offsetWidth ?? 0;
254
300
  }
255
301
  return offsets;
256
302
  }
303
+ applyStickyOffsets() {
304
+ if (!this.columns.some((c) => c.sticky))
305
+ return;
306
+ const offsets = this.stickyOffsets();
307
+ this.renderRoot.querySelectorAll('[data-col-key]').forEach((el) => {
308
+ const key = el.dataset.colKey;
309
+ if (key !== undefined && offsets.has(key)) {
310
+ el.style.setProperty('--lyra-table-sticky-offset', `${offsets.get(key)}px`);
311
+ }
312
+ });
313
+ }
257
314
  /** Applies stickyOffsets()'s measured per-column offsets as an inline
258
315
  * `--lyra-table-sticky-offset` custom property on every header cell and
259
316
  * body cell in that column (addressed by the shared `data-col-key`
@@ -269,14 +326,9 @@ export class LyraTable extends LyraElement {
269
326
  * when `hasSticky` is true (opt-in) and simply recomputes on every
270
327
  * update; a future optimization pass could cache column widths instead of
271
328
  * re-querying every time — out of scope for this correctness fix. */
272
- updated() {
273
- if (this.columns.some((c) => c.sticky)) {
274
- for (const [key, offset] of this.stickyOffsets()) {
275
- this.renderRoot
276
- .querySelectorAll(`[data-col-key="${key}"]`)
277
- .forEach((el) => el.style.setProperty('--lyra-table-sticky-offset', `${offset}px`));
278
- }
279
- }
329
+ updated(changed) {
330
+ if (changed.has('columns') || changed.has('rows') || changed.has('rowKey'))
331
+ this.applyStickyOffsets();
280
332
  // Re-observe [part='base'] whenever this update's render() produced a
281
333
  // fresh one (first mount, or a swap to/from the <lyra-empty> template
282
334
  // shape) — observeBase() itself no-ops when it's the same element as
@@ -284,7 +336,16 @@ export class LyraTable extends LyraElement {
284
336
  const base = this.renderRoot.querySelector('[part="base"]');
285
337
  if (base)
286
338
  this.observeBase(base);
287
- this.recomputeColumnsHidden();
339
+ this.observeHeaders();
340
+ // Deferred to a microtask rather than called synchronously here: a real
341
+ // priority-hidden transition mutates the reactive `columnsHidden`
342
+ // property, and doing that from inside this same updated() call stack
343
+ // schedules a second update from within the first update's own lifecycle
344
+ // callback -- Lit's dev-mode "scheduled an update ... after an update
345
+ // completed" warning. Pushing the write out to a microtask lets this
346
+ // update finish first, so the follow-up update is a normal externally
347
+ // triggered one instead.
348
+ queueMicrotask(() => this.recomputeColumnsHidden());
288
349
  }
289
350
  activateColumn(key) {
290
351
  this.activeColKey = key;
@@ -329,14 +390,15 @@ export class LyraTable extends LyraElement {
329
390
  const index = headers.indexOf(th);
330
391
  if (index < 0)
331
392
  return;
393
+ const rtl = getComputedStyle(this).direction === 'rtl';
332
394
  switch (e.key) {
333
395
  case 'ArrowLeft':
334
396
  e.preventDefault();
335
- this.focusHeader(headers[Math.max(0, index - 1)]);
397
+ this.focusHeader(headers[rtl ? Math.min(headers.length - 1, index + 1) : Math.max(0, index - 1)]);
336
398
  return;
337
399
  case 'ArrowRight':
338
400
  e.preventDefault();
339
- this.focusHeader(headers[Math.min(headers.length - 1, index + 1)]);
401
+ this.focusHeader(headers[rtl ? Math.max(0, index - 1) : Math.min(headers.length - 1, index + 1)]);
340
402
  return;
341
403
  case 'Home':
342
404
  e.preventDefault();
@@ -412,7 +474,13 @@ export class LyraTable extends LyraElement {
412
474
  const focusedRow = this.focusedRowKey();
413
475
  return html `
414
476
  <div part="base" ?data-force-visible=${this.showAllColumns}>
415
- <table part="table" role="grid" @click=${this.onTableClick} @keydown=${this.onTableKeyDown}>
477
+ <table
478
+ part="table"
479
+ role="grid"
480
+ aria-label=${this.getAttribute('aria-label') || nothing}
481
+ @click=${this.onTableClick}
482
+ @keydown=${this.onTableKeyDown}
483
+ >
416
484
  <thead part="head">
417
485
  <tr role="row">
418
486
  ${this.columns.map((col) => {
@@ -7,6 +7,22 @@ import { LyraElement } from '../../internal/lyra-element.js';
7
7
  * `slot` name found among the current children — a child with no `label`,
8
8
  * or a name with no matching child, simply never produces a tab.
9
9
  *
10
+ * A tab button's *visible* content can carry a leading icon without ever
11
+ * changing its *accessible name* (which always stays exactly `label`'s
12
+ * text, nothing else): give a tab an extra direct-child sibling of
13
+ * `<lyra-tabs>` carrying `slot="<id>-icon"` (that sibling's own content --
14
+ * an inline SVG, an emoji span, a custom icon element, anything -- is
15
+ * entirely up to the consumer). It's rendered ahead of the label inside
16
+ * that tab's button, wrapped in an `aria-hidden="true"` part so it's
17
+ * excluded from accessible-name computation no matter what it contains. A
18
+ * tab with no matching `<id>-icon` sibling renders no icon wrapper at all,
19
+ * so existing text-only tabs are completely unaffected. (A named slot,
20
+ * rather than a second attribute holding an icon-name lookup, was chosen
21
+ * because this library's `internal/icons.ts` is a small closed set of
22
+ * chrome glyphs for this library's *own* components, not a public
23
+ * name-keyed registry -- a slot lets a consumer supply an arbitrary,
24
+ * domain-specific icon instead of being limited to that internal set.)
25
+ *
10
26
  * Implements the WAI-ARIA APG tabs pattern with automatic activation:
11
27
  * Left/Right (swapped under RTL) move focus *and* selection together,
12
28
  * Home/End jump to the first/last enabled tab, and a roving `tabindex`
@@ -14,10 +30,12 @@ import { LyraElement } from '../../internal/lyra-element.js';
14
30
  *
15
31
  * @customElement lyra-tabs
16
32
  * @slot - Direct children with `slot="<id>" label="<text>"` (and optionally `disabled`); one becomes each tab's panel.
33
+ * @slot <id>-icon - Optional sibling direct child supplying a tab's leading icon content; excluded from the tab button's accessible name.
17
34
  * @event lyra-tabs-change - `detail: { tabId }`, fired when the active tab changes via click or keyboard.
18
35
  * @csspart base - The root wrapper around the tablist and panels.
19
36
  * @csspart tablist - The `role="tablist"` row of tab buttons.
20
37
  * @csspart tab - A single tab button.
38
+ * @csspart tab-icon - The optional leading-icon wrapper inside a tab button; only rendered when that tab has a matching `<id>-icon` sibling.
21
39
  * @csspart panel - A single `role="tabpanel"` wrapper (one per tab, hidden unless active).
22
40
  */
23
41
  export declare class LyraTabs extends LyraElement {
@@ -26,6 +44,8 @@ export declare class LyraTabs extends LyraElement {
26
44
  active: string;
27
45
  private tabs;
28
46
  private baseId;
47
+ private nextOpaqueId;
48
+ private readonly idsBySlot;
29
49
  private mutationObserver?;
30
50
  connectedCallback(): void;
31
51
  disconnectedCallback(): void;
@@ -40,6 +60,9 @@ export declare class LyraTabs extends LyraElement {
40
60
  private onTabListKeyDown;
41
61
  private tabId;
42
62
  private panelId;
63
+ private idsFor;
64
+ /** Derives a tab's optional icon-sibling `slot` name from its own `slotName` -- see the class doc. */
65
+ private iconSlotName;
43
66
  private renderTab;
44
67
  private renderPanel;
45
68
  render(): TemplateResult;