@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
@@ -4,13 +4,26 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { html, nothing } from 'lit';
7
+ import { html, nothing, } from 'lit';
8
8
  import { property, state } from 'lit/decorators.js';
9
9
  import { LyraElement } from '../../internal/lyra-element.js';
10
10
  import { defineElement } from '../../internal/prefix.js';
11
11
  import { chevronIcon } from '../../internal/icons.js';
12
+ import { nextId } from '../../internal/a11y.js';
12
13
  import { styles } from './date-picker.styles.js';
13
- import { monthMatrix, weekdayLabels, monthTitle, formatISO, parseISO, isSameDay, addMonths, clampDate, resolveFirstDayOfWeek, } from './calendar-core.js';
14
+ import { monthMatrix, weekdayLabels, monthTitle, formatISO, parseISO, isSameDay, addMonths, addMonthsClampingDay, clampDate, dateTimeFormat, normalizeCalendarMode, normalizeCalendarMonths, normalizeWeekdayFormat, resolveFirstDayOfWeek, } from './calendar-core.js';
15
+ const modeConverter = {
16
+ fromAttribute: normalizeCalendarMode,
17
+ toAttribute: normalizeCalendarMode,
18
+ };
19
+ const monthsConverter = {
20
+ fromAttribute: normalizeCalendarMonths,
21
+ toAttribute: normalizeCalendarMonths,
22
+ };
23
+ const weekdayFormatConverter = {
24
+ fromAttribute: normalizeWeekdayFormat,
25
+ toAttribute: normalizeWeekdayFormat,
26
+ };
14
27
  /**
15
28
  * `<lyra-date-picker>` — an inline month-grid calendar for picking a single date
16
29
  * or a date range. Mirrors the core `<wa-date-picker>` API under `lyra-`.
@@ -20,8 +33,24 @@ import { monthMatrix, weekdayLabels, monthTitle, formatISO, parseISO, isSameDay,
20
33
  * @customElement lyra-date-picker
21
34
  * @event change - The user committed a value.
22
35
  * @event input - The value changed during interaction (range: after the first click).
23
- * @csspart base, month, header, title, previous, next, weekdays, weekday, grid, week
24
- * @csspart day, day-today, day-outside, day-selected, day-range-start, day-range-end, day-range-inner, day-placeholder
36
+ * @csspart base - The date-picker wrapper.
37
+ * @csspart month - A visible month wrapper.
38
+ * @csspart header - The month header.
39
+ * @csspart title - The month title.
40
+ * @csspart previous - The previous-month button.
41
+ * @csspart next - The next-month button.
42
+ * @csspart weekdays - The weekday header row.
43
+ * @csspart weekday - A weekday label.
44
+ * @csspart grid - A month date grid.
45
+ * @csspart week - A calendar week row.
46
+ * @csspart day - A calendar day button.
47
+ * @csspart day-today - A day representing today.
48
+ * @csspart day-outside - A day outside the active month.
49
+ * @csspart day-selected - A selected day.
50
+ * @csspart day-range-start - The start of a selected range.
51
+ * @csspart day-range-end - The end of a selected range.
52
+ * @csspart day-range-inner - An interior day in a selected range.
53
+ * @csspart day-placeholder - A non-day grid placeholder.
25
54
  */
26
55
  export class LyraDatePicker extends LyraElement {
27
56
  constructor() {
@@ -40,9 +69,17 @@ export class LyraDatePicker extends LyraElement {
40
69
  this.disablePast = false;
41
70
  this.disableFuture = false;
42
71
  this.withOutsideDays = false;
72
+ /** Accessible label for the previous-month button. Override for a non-English `locale`. */
73
+ this.previousLabel = 'Previous month';
74
+ /** Accessible label for the next-month button. Override for a non-English `locale`. */
75
+ this.nextLabel = 'Next month';
43
76
  this.viewDate = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
44
77
  this.focusedDate = null;
45
78
  this.focusPending = false;
79
+ // Stable per-instance ids for each visible month's title, referenced by
80
+ // that month's grid via aria-labelledby -- `months` only ever renders 1 or
81
+ // 2 months, so two ids always suffice regardless of which is in use.
82
+ this.titleIds = [nextId('date-picker-title'), nextId('date-picker-title')];
46
83
  // Set right before `commit()` assigns `value`, so `willUpdate` can tell its
47
84
  // own write apart from an external assignment. Internal commits already
48
85
  // know the right date is on-screen (it's the cell the user just clicked, or
@@ -88,10 +125,10 @@ export class LyraDatePicker extends LyraElement {
88
125
  next = firstEnabledFrom(step(current, 7), 1);
89
126
  break;
90
127
  case 'PageUp':
91
- next = firstEnabledFrom(new Date(current.getFullYear(), current.getMonth() - 1, current.getDate()), 1);
128
+ next = firstEnabledFrom(addMonthsClampingDay(current, -1), 1);
92
129
  break;
93
130
  case 'PageDown':
94
- next = firstEnabledFrom(new Date(current.getFullYear(), current.getMonth() + 1, current.getDate()), 1);
131
+ next = firstEnabledFrom(addMonthsClampingDay(current, 1), 1);
95
132
  break;
96
133
  case 'Home':
97
134
  next = firstEnabledFrom(new Date(current.getFullYear(), current.getMonth(), 1), 1);
@@ -116,13 +153,22 @@ export class LyraDatePicker extends LyraElement {
116
153
  };
117
154
  }
118
155
  static { this.styles = [LyraElement.styles, styles]; }
156
+ get effectiveMode() {
157
+ return normalizeCalendarMode(this.mode);
158
+ }
159
+ get visibleMonths() {
160
+ return normalizeCalendarMonths(this.months);
161
+ }
162
+ get effectiveWeekdayFormat() {
163
+ return normalizeWeekdayFormat(this.weekdayFormat);
164
+ }
119
165
  get selection() {
120
166
  const parts = this.value.split('/');
121
167
  return { from: parseISO(parts[0] ?? ''), to: parseISO(parts[1] ?? '') };
122
168
  }
123
169
  /** Read-only Date view of a single-mode value. */
124
170
  get valueAsDate() {
125
- return this.mode === 'single' ? this.selection.from : null;
171
+ return this.effectiveMode === 'single' ? this.selection.from : null;
126
172
  }
127
173
  willUpdate(changed) {
128
174
  if (changed.has('value')) {
@@ -159,7 +205,7 @@ export class LyraDatePicker extends LyraElement {
159
205
  * min/max window). */
160
206
  firstEnabledDate(min, max, today) {
161
207
  let d = new Date(this.viewDate.getFullYear(), this.viewDate.getMonth(), 1);
162
- const lastVisibleMonth = addMonths(d, this.months - 1);
208
+ const lastVisibleMonth = addMonths(d, this.visibleMonths - 1);
163
209
  const boundEnd = new Date(lastVisibleMonth.getFullYear(), lastVisibleMonth.getMonth() + 1, 0);
164
210
  for (let i = 0; i < 732 && d <= boundEnd; i++) {
165
211
  if (!this.isDisabled(d, min, max, today))
@@ -169,7 +215,7 @@ export class LyraDatePicker extends LyraElement {
169
215
  return null;
170
216
  }
171
217
  commit(from, to, fire) {
172
- const next = this.mode === 'range'
218
+ const next = this.effectiveMode === 'range'
173
219
  ? from && to
174
220
  ? `${formatISO(from)}/${formatISO(to)}`
175
221
  : from
@@ -196,7 +242,7 @@ export class LyraDatePicker extends LyraElement {
196
242
  if (this.isDisabled(date, min, max, today))
197
243
  return;
198
244
  this.focusedDate = date;
199
- if (this.mode === 'range') {
245
+ if (this.effectiveMode === 'range') {
200
246
  const { from, to } = this.selection;
201
247
  if (!from || (from && to)) {
202
248
  this.commit(date, null, false);
@@ -224,9 +270,9 @@ export class LyraDatePicker extends LyraElement {
224
270
  /** Navigate the view to a date and focus it, clamped to `min`/`max`. */
225
271
  goToDate(date) {
226
272
  const d = typeof date === 'string' ? parseISO(date) : date;
227
- if (!d)
273
+ if (!d || !Number.isFinite(d.getTime()))
228
274
  return;
229
- const clamped = clampDate(d, parseISO(this.min), parseISO(this.max));
275
+ const clamped = clampDate(new Date(d.getTime()), parseISO(this.min), parseISO(this.max));
230
276
  this.viewDate = new Date(clamped.getFullYear(), clamped.getMonth(), 1);
231
277
  this.focusedDate = clamped;
232
278
  this.focusPending = true;
@@ -243,11 +289,11 @@ export class LyraDatePicker extends LyraElement {
243
289
  viewDateForFocus(next) {
244
290
  const firstMonth = new Date(this.viewDate.getFullYear(), this.viewDate.getMonth(), 1);
245
291
  const nextMonth = new Date(next.getFullYear(), next.getMonth(), 1);
246
- const lastMonth = addMonths(firstMonth, this.months - 1);
292
+ const lastMonth = addMonths(firstMonth, this.visibleMonths - 1);
247
293
  if (nextMonth < firstMonth)
248
294
  return nextMonth;
249
295
  if (nextMonth > lastMonth)
250
- return addMonths(nextMonth, -(this.months - 1));
296
+ return addMonths(nextMonth, -(this.visibleMonths - 1));
251
297
  return firstMonth;
252
298
  }
253
299
  updated() {
@@ -258,7 +304,7 @@ export class LyraDatePicker extends LyraElement {
258
304
  cell?.focus();
259
305
  }
260
306
  }
261
- renderDay(date, shownMonth, selection, min, max, today, rowHasVisibleDay, fallbackFocusDate) {
307
+ renderDay(date, shownMonth, selection, min, max, today, rowHasVisibleDay, fallbackFocusDate, dayLabelFmt) {
262
308
  const outside = date.getMonth() !== shownMonth;
263
309
  // Outside-month days are empty placeholders by default (matches WA), keeping the
264
310
  // 6-row grid aligned without low-contrast faded numbers.
@@ -279,8 +325,8 @@ export class LyraDatePicker extends LyraElement {
279
325
  const isToday = isSameDay(date, today);
280
326
  const isStart = from && isSameDay(date, from);
281
327
  const isEnd = to && isSameDay(date, to);
282
- const selected = this.mode === 'single' ? isStart : isStart || isEnd;
283
- const inRange = this.mode === 'range' && from && to && date > from && date < to;
328
+ const selected = this.effectiveMode === 'single' ? isStart : isStart || isEnd;
329
+ const inRange = this.effectiveMode === 'range' && from && to && date > from && date < to;
284
330
  // Falls back to the first *enabled* day across the visible month(s) (see
285
331
  // firstEnabledDate()) when there's neither a focusedDate nor a selection,
286
332
  // so the grid always has exactly one tabbable cell -- otherwise every
@@ -301,7 +347,7 @@ export class LyraDatePicker extends LyraElement {
301
347
  parts.push('day-today');
302
348
  if (selected)
303
349
  parts.push('day-selected');
304
- if (isStart && this.mode === 'range')
350
+ if (isStart && this.effectiveMode === 'range')
305
351
  parts.push('day-range-start');
306
352
  if (isEnd)
307
353
  parts.push('day-range-end');
@@ -312,12 +358,7 @@ export class LyraDatePicker extends LyraElement {
312
358
  role="gridcell"
313
359
  data-date=${formatISO(date)}
314
360
  aria-selected=${selected ? 'true' : 'false'}
315
- aria-label=${date.toLocaleDateString(this.locale || undefined, {
316
- weekday: 'long',
317
- year: 'numeric',
318
- month: 'long',
319
- day: 'numeric',
320
- })}
361
+ aria-label=${dayLabelFmt.format(date)}
321
362
  tabindex=${focused ? '0' : '-1'}
322
363
  ?disabled=${disabled}
323
364
  @click=${() => this.selectDate(date)}
@@ -325,32 +366,33 @@ export class LyraDatePicker extends LyraElement {
325
366
  ${date.getDate()}
326
367
  </button>`;
327
368
  }
328
- renderMonth(offset, selection, min, max, today, fdow, labels, fallbackFocusDate) {
369
+ renderMonth(offset, selection, min, max, today, fdow, labels, fallbackFocusDate, dayLabelFmt) {
329
370
  const base = addMonths(this.viewDate, offset);
330
371
  const year = base.getFullYear();
331
372
  const month = base.getMonth();
332
373
  const matrix = monthMatrix(year, month, fdow);
333
374
  const isFirst = offset === 0;
334
- const isLast = offset === this.months - 1;
375
+ const isLast = offset === this.visibleMonths - 1;
376
+ const titleId = this.titleIds[offset];
335
377
  return html `<div part="month">
336
378
  <div part="header">
337
379
  ${isFirst
338
380
  ? html `<button
339
381
  part="previous"
340
382
  type="button"
341
- aria-label="Previous month"
383
+ aria-label=${this.previousLabel}
342
384
  ?disabled=${this.disabled || this.readonly}
343
385
  @click=${() => this.nav(-1)}
344
386
  >
345
387
  ${chevronIcon()}
346
388
  </button>`
347
389
  : html `<span></span>`}
348
- <div part="title">${monthTitle(year, month, this.locale)}</div>
390
+ <div part="title" id=${titleId}>${monthTitle(year, month, this.locale)}</div>
349
391
  ${isLast
350
392
  ? html `<button
351
393
  part="next"
352
394
  type="button"
353
- aria-label="Next month"
395
+ aria-label=${this.nextLabel}
354
396
  ?disabled=${this.disabled || this.readonly}
355
397
  @click=${() => this.nav(1)}
356
398
  >
@@ -359,10 +401,10 @@ export class LyraDatePicker extends LyraElement {
359
401
  : html `<span></span>`}
360
402
  </div>
361
403
  <div part="weekdays">${labels.map((l) => html `<span part="weekday">${l}</span>`)}</div>
362
- <div part="grid" role="grid" @keydown=${this.onGridKey}>
404
+ <div part="grid" role="grid" aria-labelledby=${titleId} @keydown=${this.onGridKey}>
363
405
  ${matrix.map((week) => {
364
406
  const rowHasVisibleDay = week.some((d) => d.getMonth() === month);
365
- return html `<div part="week" role="row">${week.map((d) => this.renderDay(d, month, selection, min, max, today, rowHasVisibleDay, fallbackFocusDate))}</div>`;
407
+ return html `<div part="week" role="row">${week.map((d) => this.renderDay(d, month, selection, min, max, today, rowHasVisibleDay, fallbackFocusDate, dayLabelFmt))}</div>`;
366
408
  })}
367
409
  </div>
368
410
  </div>`;
@@ -374,14 +416,24 @@ export class LyraDatePicker extends LyraElement {
374
416
  const today = new Date();
375
417
  today.setHours(0, 0, 0, 0);
376
418
  const fdow = this.fdow;
377
- const labels = weekdayLabels(fdow, this.weekdayFormat, this.locale);
419
+ const labels = weekdayLabels(fdow, this.effectiveWeekdayFormat, this.locale);
420
+ // Hoisted once per render and reused across every day cell, rather than
421
+ // each cell constructing its own Intl.DateTimeFormat via
422
+ // toLocaleDateString() -- mirrors how the weekday-header and month-title
423
+ // labels already share a single formatter instead of one per cell.
424
+ const dayLabelFmt = dateTimeFormat(this.locale, {
425
+ weekday: 'long',
426
+ year: 'numeric',
427
+ month: 'long',
428
+ day: 'numeric',
429
+ });
378
430
  // Only bother scanning for a fallback focus day when it's actually
379
431
  // needed: there's no point walking the visible days if a focusedDate or
380
432
  // an existing selection already determines the sole tabbable cell.
381
433
  const fallbackFocusDate = this.focusedDate || selection.from ? null : this.firstEnabledDate(min, max, today);
382
434
  const monthEls = [];
383
- for (let i = 0; i < this.months; i++) {
384
- monthEls.push(this.renderMonth(i, selection, min, max, today, fdow, labels, fallbackFocusDate));
435
+ for (let i = 0; i < this.visibleMonths; i++) {
436
+ monthEls.push(this.renderMonth(i, selection, min, max, today, fdow, labels, fallbackFocusDate, dayLabelFmt));
385
437
  }
386
438
  return html `<div part="base">${monthEls}</div>`;
387
439
  }
@@ -390,7 +442,7 @@ __decorate([
390
442
  property()
391
443
  ], LyraDatePicker.prototype, "value", void 0);
392
444
  __decorate([
393
- property()
445
+ property({ converter: modeConverter })
394
446
  ], LyraDatePicker.prototype, "mode", void 0);
395
447
  __decorate([
396
448
  property()
@@ -405,7 +457,7 @@ __decorate([
405
457
  property({ type: Boolean, reflect: true })
406
458
  ], LyraDatePicker.prototype, "readonly", void 0);
407
459
  __decorate([
408
- property({ type: Number })
460
+ property({ converter: monthsConverter })
409
461
  ], LyraDatePicker.prototype, "months", void 0);
410
462
  __decorate([
411
463
  property()
@@ -414,7 +466,7 @@ __decorate([
414
466
  property({ attribute: 'first-day-of-week' })
415
467
  ], LyraDatePicker.prototype, "firstDayOfWeek", void 0);
416
468
  __decorate([
417
- property({ attribute: 'weekday-format' })
469
+ property({ attribute: 'weekday-format', converter: weekdayFormatConverter })
418
470
  ], LyraDatePicker.prototype, "weekdayFormat", void 0);
419
471
  __decorate([
420
472
  property({ type: Boolean, attribute: 'disable-past' })
@@ -425,6 +477,12 @@ __decorate([
425
477
  __decorate([
426
478
  property({ type: Boolean, attribute: 'with-outside-days' })
427
479
  ], LyraDatePicker.prototype, "withOutsideDays", void 0);
480
+ __decorate([
481
+ property({ attribute: 'previous-label' })
482
+ ], LyraDatePicker.prototype, "previousLabel", void 0);
483
+ __decorate([
484
+ property({ attribute: 'next-label' })
485
+ ], LyraDatePicker.prototype, "nextLabel", void 0);
428
486
  __decorate([
429
487
  state()
430
488
  ], LyraDatePicker.prototype, "viewDate", void 0);
@@ -2,17 +2,14 @@ import './dialog.js';
2
2
  // Plain inline-styled <button>s, not a shared lyra-button component -- none
3
3
  // exists in this library yet. Every value below is still a --lyra-* token
4
4
  // reference, never a raw literal, same requirement as a component's own
5
- // styles.ts. --lyra-color-on-brand is documented (tokens.styles.ts) as the
6
- // text color for *brand*-fill content specifically, but it's white in both
7
- // light and dark themes and reads fine over the danger fill too, so the
8
- // confirm button reuses it rather than introducing a redundant --lyra-color-
9
- // on-danger token for one call site.
5
+ // styles.ts. Each filled tone uses its matching on-color token so standalone
6
+ // light/dark fallbacks and a consumer's Web Awesome theme stay paired.
10
7
  const BUTTON_BASE_STYLE = 'font: inherit; font-size: 0.875rem; padding: var(--lyra-space-xs) var(--lyra-space-m); ' +
11
8
  'border-radius: var(--lyra-radius); cursor: pointer; border: 1px solid var(--lyra-color-border);';
12
9
  const CANCEL_STYLE = 'background: var(--lyra-color-surface); color: var(--lyra-color-text);';
13
10
  const CONFIRM_TONE_STYLE = {
14
11
  neutral: 'background: var(--lyra-color-brand); color: var(--lyra-color-on-brand); border-color: var(--lyra-color-brand);',
15
- danger: 'background: var(--lyra-color-danger); color: var(--lyra-color-on-brand); border-color: var(--lyra-color-danger);',
12
+ danger: 'background: var(--lyra-color-danger); color: var(--lyra-color-on-danger); border-color: var(--lyra-color-danger);',
16
13
  };
17
14
  function createButton(label, style, onClick) {
18
15
  const button = document.createElement('button');
@@ -3,45 +3,77 @@ import { LyraElement } from '../../internal/lyra-element.js';
3
3
  /**
4
4
  * Reason a dialog was dismissed, forwarded as the `lyra-dialog-close` event
5
5
  * detail. `'escape'` and `'backdrop'` are emitted by the dialog's own built-in
6
- * dismiss triggers; any other string is whatever a caller passes to
7
- * `close()` (e.g. a consumer's own footer close button, or confirm.ts's
8
- * `'confirm'`/`'cancel'`).
6
+ * dismiss triggers; `'close-button'` by the built-in header close button
7
+ * (rendered when `closable` is set); `'unmount'` is emitted when the dialog is
8
+ * removed from the DOM while still open by something other than its own
9
+ * `close()` (e.g. a consumer's own cleanup code, or a parent re-render that
10
+ * drops it); any other string is whatever a caller passes to `close()` (e.g. a
11
+ * consumer's own footer close button, or confirm.ts's `'confirm'`/`'cancel'`).
9
12
  */
10
- export type DialogCloseReason = 'escape' | 'backdrop' | 'api' | string;
13
+ export type DialogCloseReason = 'escape' | 'backdrop' | 'close-button' | 'api' | 'unmount' | string;
11
14
  /**
12
15
  * `<lyra-dialog>` — a general-purpose modal/overlay. `role="dialog"`,
13
16
  * focus-trapped while open, dismissible via Escape or a backdrop click, and
14
- * scroll-locks the document for as long as it's open. Chrome stays minimal
15
- * no built-in title bar or close button; a consumer supplies a heading and
16
- * any close affordance itself via the default/`footer` slots.
17
+ * scroll-locks the document for as long as it's open. Chrome stays minimal by
18
+ * default — no built-in title bar or close button; a consumer supplies a
19
+ * heading and any close affordance itself via the default/`footer` slots.
20
+ * `heading`/`closable` are an opt-in convenience for the common case where
21
+ * hand-building that chrome isn't worth it (see below).
17
22
  *
18
- * Accessible name: if a heading element (`h1`–`h6` or `[role="heading"]`) is
19
- * a *direct child* (not inside `slot="footer"`), its text content becomes
20
- * `aria-label` on the panel. Otherwise, when `label` is set, an invisible
21
- * (`.sr-only`, exposed as the `label` part) element carrying that text is
22
- * rendered inside the panel and `aria-labelledby` points at it instead.
23
- * Either way `label` itself never renders visible chrome — a slotted heading
24
- * is what a sighted user sees; `::part(label)` can be restyled to make the
25
- * sr-only text visible too, if a consumer wants that instead of slotting a
26
- * heading.
23
+ * Accessible name / visible header, in priority order:
24
+ * 1. If a heading element (`h1`–`h6` or `[role="heading"]`) is a *direct
25
+ * child* (not inside `slot="footer"`), its text content becomes
26
+ * `aria-label` on the panel unchanged, and takes priority over `heading`
27
+ * below so an existing consumer that already slots its own heading keeps
28
+ * rendering it exactly as before.
29
+ * 2. Otherwise, when `heading` is set, a visible header row (`part="header"`)
30
+ * renders containing that text (`part="heading"`), which becomes the
31
+ * `aria-labelledby` target.
32
+ * 3. Otherwise, when `label` is set, an invisible (`.sr-only`, exposed as the
33
+ * `label` part) element carrying that text is rendered inside the panel
34
+ * and `aria-labelledby` points at it instead.
35
+ * Only one of cases 2/3 ever renders at a time, so exactly one element ever
36
+ * claims `aria-labelledby`. `label` itself never renders visible chrome on
37
+ * its own — `::part(label)` can be restyled to make the sr-only text visible,
38
+ * or `heading` can be set instead, if a consumer wants visible chrome without
39
+ * slotting a real heading element.
27
40
  *
28
- * The heading case deliberately uses `aria-label` (a copied string) rather
29
- * than `aria-labelledby` pointing at the heading's `id`: the heading is
41
+ * The slotted-heading case deliberately uses `aria-label` (a copied string)
42
+ * rather than `aria-labelledby` pointing at the heading's `id`: the heading is
30
43
  * *light-DOM* content while `[part="panel"]` lives in this element's
31
44
  * *shadow* tree, and an ID-reference attribute can't resolve across that
32
45
  * boundary (verified against axe's `aria-dialog-name` rule) — unlike the
33
- * `label`-prop case above, where the sr-only element is rendered inside the
34
- * same shadow root it labels, so `aria-labelledby` there is safe.
46
+ * `heading`/`label`-prop cases above, where the target element is rendered
47
+ * inside the same shadow root it labels, so `aria-labelledby` there is safe.
48
+ *
49
+ * `closable` renders a close (X) button in the header row (creating one, with
50
+ * no heading text, if `heading` is unset) that closes the dialog via the same
51
+ * `close()` path as Escape/backdrop-dismiss, with reason `'close-button'`.
52
+ *
53
+ * Stacking: opening one `<lyra-dialog>` while another is already open (e.g. a
54
+ * `confirm()` launched from within an already-open dialog) is supported --
55
+ * Escape and the Tab focus trap only ever act on the topmost open dialog, so
56
+ * dialogs beneath it stay open and untouched until the one on top closes.
35
57
  *
36
58
  * @customElement lyra-dialog
37
59
  * @slot - The dialog body.
38
60
  * @slot footer - Action buttons, rendered in a bottom row.
39
61
  * @event lyra-dialog-close - `detail: DialogCloseReason`. Fired whenever the
40
- * dialog is dismissed via Escape, a backdrop click, or a `close()` call.
62
+ * dialog is dismissed via Escape, a backdrop click, the built-in close
63
+ * button (`closable`), a `close()` call, or (with reason `'unmount'`)
64
+ * removal from the DOM by anything else while still open.
41
65
  * @csspart backdrop - The full-viewport scrim behind the panel.
42
- * @csspart panel - The dialog panel itself (`role="dialog"` while open).
66
+ * @csspart panel - The dialog panel itself (`role="dialog"` while open). Its
67
+ * max-inline-size is controlled by the `--lyra-dialog-max-width` custom
68
+ * property (default `32rem`).
69
+ * @csspart header - The header row, rendered when `heading` is set (and no
70
+ * heading is slotted) and/or `closable` is `true`.
71
+ * @csspart heading - The visible `heading`-text element inside `header`,
72
+ * rendered only when `heading` is set and no heading is slotted.
73
+ * @csspart close-button - The built-in close button, rendered inside `header`
74
+ * only when `closable` is `true`.
43
75
  * @csspart label - The invisible `label`-text element used for
44
- * `aria-labelledby` when no heading is slotted.
76
+ * `aria-labelledby` when no heading is slotted and `heading` is unset.
45
77
  * @csspart body - The wrapper around the default slot.
46
78
  * @csspart footer - The wrapper around the `footer` slot.
47
79
  */
@@ -51,11 +83,22 @@ export declare class LyraDialog extends LyraElement {
51
83
  open: boolean;
52
84
  /** Accessible name used when no heading is slotted — see the class doc for the full fallback order. */
53
85
  label: string;
86
+ /** Visible header text, rendered when no heading element is slotted into
87
+ * the default slot — see the class doc for the full fallback order. Has
88
+ * no effect (renders nothing) if a light-DOM heading is slotted; that case
89
+ * keeps working completely unchanged whether or not `heading` is set. */
90
+ heading?: string;
91
+ /** Renders a built-in close (X) button in the header row (creating one,
92
+ * with no heading text, if `heading` is unset), wired to the same
93
+ * `close()` path Escape/backdrop-dismiss already use, with reason
94
+ * `'close-button'`. */
95
+ closable: boolean;
54
96
  private hasFooterSlot;
55
97
  private headingText?;
56
98
  private releaseScrollLock?;
57
- private lastTrigger?;
99
+ private overlay?;
58
100
  private readonly srLabelId;
101
+ private readonly headingId;
59
102
  protected willUpdate(changed: PropertyValues): void;
60
103
  protected updated(changed: PropertyValues): void;
61
104
  connectedCallback(): void;
@@ -66,16 +109,17 @@ export declare class LyraDialog extends LyraElement {
66
109
  /**
67
110
  * Close the dialog and return focus to whatever had it before the dialog
68
111
  * opened. `reason` is forwarded as the `lyra-dialog-close` detail --
69
- * built-in triggers pass `'escape'`/`'backdrop'`; a consumer's own close
70
- * affordance (e.g. a footer Cancel button) should call this directly with
71
- * its own reason string, so every dismissal path funnels through the same
72
- * event instead of the consumer having to also toggle `open` itself.
112
+ * built-in triggers pass `'escape'`/`'backdrop'`/`'close-button'`; a
113
+ * consumer's own close affordance (e.g. a footer Cancel button) should
114
+ * call this directly with its own reason string, so every dismissal path
115
+ * funnels through the same event instead of the consumer having to also
116
+ * toggle `open` itself.
73
117
  */
74
118
  close(reason?: DialogCloseReason): void;
75
119
  private onBackdropClick;
76
- private onDocKeyDown;
77
- private getFocusableElements;
78
- private getActiveElement;
120
+ private onCloseButtonClick;
121
+ private activateOverlay;
122
+ private deactivateOverlay;
79
123
  render(): TemplateResult;
80
124
  }
81
125
  declare global {