@aceshooting/lyra-ui 1.0.1 → 1.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.
- package/README.md +8 -9
- package/custom-elements.json +12479 -6535
- package/dist/components/chart/chart.d.ts +46 -1
- package/dist/components/chart/chart.js +148 -10
- package/dist/components/chart/chart.stories.d.ts +32 -0
- package/dist/components/chart/chart.stories.js +141 -0
- package/dist/components/chart/chart.styles.js +16 -0
- package/dist/components/chart/histogram.d.ts +2 -0
- package/dist/components/chart/histogram.js +18 -2
- package/dist/components/chart/line-chart.stories.d.ts +17 -0
- package/dist/components/chart/line-chart.stories.js +75 -0
- package/dist/components/chart/lite-chart.d.ts +74 -0
- package/dist/components/chart/lite-chart.js +384 -0
- package/dist/components/chart/lite-chart.stories.d.ts +12 -0
- package/dist/components/chart/lite-chart.stories.js +98 -0
- package/dist/components/chart/lite-chart.styles.d.ts +1 -0
- package/dist/components/chart/lite-chart.styles.js +83 -0
- package/dist/components/combobox/combobox.d.ts +9 -0
- package/dist/components/combobox/combobox.js +75 -12
- package/dist/components/combobox/combobox.stories.d.ts +18 -0
- package/dist/components/combobox/combobox.stories.js +75 -0
- package/dist/components/date-picker/calendar-core.js +13 -2
- package/dist/components/date-picker/date-input.d.ts +9 -1
- package/dist/components/date-picker/date-input.js +55 -7
- package/dist/components/date-picker/date-input.stories.d.ts +5 -0
- package/dist/components/date-picker/date-input.stories.js +36 -0
- package/dist/components/date-picker/date-picker.d.ts +11 -3
- package/dist/components/date-picker/date-picker.js +87 -37
- package/dist/components/date-picker/date-picker.stories.d.ts +4 -0
- package/dist/components/date-picker/date-picker.stories.js +12 -0
- package/dist/components/date-picker/date-picker.styles.js +1 -1
- package/dist/components/empty/empty.d.ts +12 -1
- package/dist/components/empty/empty.js +20 -3
- package/dist/components/empty/empty.stories.d.ts +2 -0
- package/dist/components/empty/empty.stories.js +20 -0
- package/dist/components/empty/empty.styles.js +11 -0
- package/dist/components/export-button/csv.js +6 -2
- package/dist/components/export-button/export-button.d.ts +15 -1
- package/dist/components/export-button/export-button.js +89 -12
- package/dist/components/export-button/export-button.stories.d.ts +1 -0
- package/dist/components/export-button/export-button.stories.js +5 -0
- package/dist/components/export-button/export-button.styles.js +11 -3
- package/dist/components/file-input/accept.d.ts +8 -2
- package/dist/components/file-input/accept.js +9 -3
- package/dist/components/file-input/file-input.d.ts +5 -2
- package/dist/components/file-input/file-input.js +23 -8
- package/dist/components/file-input/file-input.stories.d.ts +2 -0
- package/dist/components/file-input/file-input.stories.js +9 -0
- package/dist/components/flag/flag.d.ts +48 -3
- package/dist/components/flag/flag.js +65 -29
- package/dist/components/flag/flag.styles.js +1 -1
- package/dist/components/flag/language-map.d.ts +11 -0
- package/dist/components/flag/language-map.js +12 -1
- package/dist/components/gauge/gauge.d.ts +2 -0
- package/dist/components/gauge/gauge.js +19 -5
- package/dist/components/gauge/gauge.stories.d.ts +2 -0
- package/dist/components/gauge/gauge.stories.js +6 -0
- package/dist/components/graph/graph-loader.d.ts +28 -0
- package/dist/components/graph/graph-loader.js +44 -0
- package/dist/components/graph/graph.d.ts +41 -15
- package/dist/components/graph/graph.js +146 -71
- package/dist/components/graph/graph.stories.d.ts +3 -0
- package/dist/components/graph/graph.stories.js +38 -0
- package/dist/components/graph/graph.styles.js +6 -1
- package/dist/components/heatmap/calendar-grid.d.ts +7 -0
- package/dist/components/heatmap/calendar-grid.js +27 -10
- package/dist/components/heatmap/heatmap.d.ts +137 -12
- package/dist/components/heatmap/heatmap.js +427 -27
- package/dist/components/heatmap/heatmap.stories.d.ts +17 -0
- package/dist/components/heatmap/heatmap.stories.js +130 -0
- package/dist/components/heatmap/heatmap.styles.js +60 -2
- package/dist/components/map/map.d.ts +17 -1
- package/dist/components/map/map.js +68 -21
- package/dist/components/map/map.stories.d.ts +10 -0
- package/dist/components/map/map.stories.js +107 -12
- package/dist/components/map/map.styles.js +2 -2
- package/dist/components/playback/playback.d.ts +6 -2
- package/dist/components/playback/playback.js +36 -12
- package/dist/components/playback/playback.stories.d.ts +2 -0
- package/dist/components/playback/playback.stories.js +6 -0
- package/dist/components/playback/playback.styles.js +10 -2
- package/dist/components/select/select.d.ts +122 -0
- package/dist/components/select/select.js +516 -0
- package/dist/components/select/select.stories.d.ts +19 -0
- package/dist/components/select/select.stories.js +75 -0
- package/dist/components/select/select.styles.d.ts +1 -0
- package/dist/components/select/select.styles.js +188 -0
- package/dist/components/skeleton/skeleton.js +4 -7
- package/dist/components/sparkline/sparkline.d.ts +1 -1
- package/dist/components/sparkline/sparkline.js +40 -13
- package/dist/components/sparkline/sparkline.stories.d.ts +4 -0
- package/dist/components/sparkline/sparkline.stories.js +22 -0
- package/dist/components/split/split.d.ts +24 -3
- package/dist/components/split/split.js +155 -31
- package/dist/components/split/split.stories.d.ts +2 -0
- package/dist/components/split/split.stories.js +20 -0
- package/dist/components/stat/stat.d.ts +27 -1
- package/dist/components/stat/stat.js +56 -3
- package/dist/components/stat/stat.stories.d.ts +3 -0
- package/dist/components/stat/stat.stories.js +49 -1
- package/dist/components/stat/stat.styles.js +44 -0
- package/dist/components/table/table.d.ts +64 -2
- package/dist/components/table/table.js +213 -17
- package/dist/components/table/table.stories.d.ts +6 -0
- package/dist/components/table/table.stories.js +45 -0
- package/dist/components/table/table.styles.js +51 -4
- package/dist/components/time-range/time-range.d.ts +34 -5
- package/dist/components/time-range/time-range.js +217 -36
- package/dist/components/time-range/time-range.stories.d.ts +2 -0
- package/dist/components/time-range/time-range.stories.js +13 -0
- package/dist/components/time-range/time-range.styles.js +44 -2
- package/dist/components/toast/toast-item.d.ts +14 -2
- package/dist/components/toast/toast-item.js +134 -17
- package/dist/components/toast/toast-item.styles.js +28 -2
- package/dist/components/toast/toast.stories.d.ts +3 -0
- package/dist/components/toast/toast.stories.js +41 -1
- package/dist/components/toast/toast.styles.js +11 -11
- package/dist/components/toast/toaster.d.ts +1 -1
- package/dist/components/toast/toaster.js +13 -6
- package/dist/components/tree/tree-node.d.ts +13 -7
- package/dist/components/tree/tree-node.js +24 -10
- package/dist/components/tree/tree.d.ts +64 -15
- package/dist/components/tree/tree.js +113 -22
- package/dist/components/tree/tree.stories.d.ts +4 -0
- package/dist/components/tree/tree.stories.js +31 -1
- package/dist/components/tree/update-cascade.d.ts +13 -0
- package/dist/components/tree/update-cascade.js +13 -0
- package/dist/components/widget/widget.d.ts +15 -1
- package/dist/components/widget/widget.js +140 -5
- package/dist/components/widget/widget.stories.d.ts +1 -0
- package/dist/components/widget/widget.stories.js +10 -0
- package/dist/components/widget/widget.styles.js +11 -1
- package/dist/components/word-cloud/word-cloud-layout.d.ts +63 -0
- package/dist/components/word-cloud/word-cloud-layout.js +145 -0
- package/dist/components/word-cloud/word-cloud.d.ts +65 -0
- package/dist/components/word-cloud/word-cloud.js +255 -0
- package/dist/components/word-cloud/word-cloud.stories.d.ts +10 -0
- package/dist/components/word-cloud/word-cloud.stories.js +55 -0
- package/dist/components/word-cloud/word-cloud.styles.d.ts +1 -0
- package/dist/components/word-cloud/word-cloud.styles.js +54 -0
- package/dist/internal/a11y.js +2 -1
- package/dist/internal/rtl.d.ts +7 -0
- package/dist/internal/rtl.js +9 -0
- package/dist/lyra.d.ts +9 -1
- package/dist/lyra.js +6 -0
- package/llms-full.txt +892 -276
- package/llms.txt +12 -9
- package/package.json +6 -4
|
@@ -14,8 +14,8 @@ export interface DateRange {
|
|
|
14
14
|
* @customElement lyra-date-picker
|
|
15
15
|
* @event change - The user committed a value.
|
|
16
16
|
* @event input - The value changed during interaction (range: after the first click).
|
|
17
|
-
* @csspart base, month, header, title, previous, next, weekdays, weekday, grid
|
|
18
|
-
* @csspart day, day-today, day-outside, day-selected, day-range-start, day-range-end, day-range-inner
|
|
17
|
+
* @csspart base, month, header, title, previous, next, weekdays, weekday, grid, week
|
|
18
|
+
* @csspart day, day-today, day-outside, day-selected, day-range-start, day-range-end, day-range-inner, day-placeholder
|
|
19
19
|
*/
|
|
20
20
|
export declare class LyraDatePicker extends LyraElement {
|
|
21
21
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -36,6 +36,7 @@ export declare class LyraDatePicker extends LyraElement {
|
|
|
36
36
|
private viewDate;
|
|
37
37
|
private focusedDate;
|
|
38
38
|
private focusPending;
|
|
39
|
+
private suppressViewSync;
|
|
39
40
|
get selection(): DateRange;
|
|
40
41
|
/** Read-only Date view of a single-mode value. */
|
|
41
42
|
get valueAsDate(): Date | null;
|
|
@@ -48,10 +49,17 @@ export declare class LyraDatePicker extends LyraElement {
|
|
|
48
49
|
clear(): void;
|
|
49
50
|
/** Navigate to today and focus it. */
|
|
50
51
|
goToToday(): void;
|
|
51
|
-
/** Navigate the view to a date and focus it
|
|
52
|
+
/** Navigate the view to a date and focus it, clamped to `min`/`max`. */
|
|
52
53
|
goToDate(date: string | Date): void;
|
|
53
54
|
private nav;
|
|
54
55
|
private onGridKey;
|
|
56
|
+
/**
|
|
57
|
+
* The anchor month for a newly-focused date, sliding the view by the
|
|
58
|
+
* minimum amount needed to bring it into view. With `months` > 1, a date
|
|
59
|
+
* that's already visible in a later grid must not discard an earlier grid
|
|
60
|
+
* that's already on-screen.
|
|
61
|
+
*/
|
|
62
|
+
private viewDateForFocus;
|
|
55
63
|
protected updated(): void;
|
|
56
64
|
private renderDay;
|
|
57
65
|
private renderMonth;
|
|
@@ -4,13 +4,13 @@ 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 } 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
12
|
import { styles } from './date-picker.styles.js';
|
|
13
|
-
import { monthMatrix, weekdayLabels, monthTitle, formatISO, parseISO, isSameDay, addMonths, resolveFirstDayOfWeek, } from './calendar-core.js';
|
|
13
|
+
import { monthMatrix, weekdayLabels, monthTitle, formatISO, parseISO, isSameDay, addMonths, clampDate, resolveFirstDayOfWeek, } from './calendar-core.js';
|
|
14
14
|
/**
|
|
15
15
|
* `<lyra-date-picker>` — an inline month-grid calendar for picking a single date
|
|
16
16
|
* or a date range. Mirrors the core `<wa-date-picker>` API under `lyra-`.
|
|
@@ -20,8 +20,8 @@ import { monthMatrix, weekdayLabels, monthTitle, formatISO, parseISO, isSameDay,
|
|
|
20
20
|
* @customElement lyra-date-picker
|
|
21
21
|
* @event change - The user committed a value.
|
|
22
22
|
* @event input - The value changed during interaction (range: after the first click).
|
|
23
|
-
* @csspart base, month, header, title, previous, next, weekdays, weekday, grid
|
|
24
|
-
* @csspart day, day-today, day-outside, day-selected, day-range-start, day-range-end, day-range-inner
|
|
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
|
|
25
25
|
*/
|
|
26
26
|
export class LyraDatePicker extends LyraElement {
|
|
27
27
|
constructor() {
|
|
@@ -43,6 +43,12 @@ export class LyraDatePicker extends LyraElement {
|
|
|
43
43
|
this.viewDate = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
|
|
44
44
|
this.focusedDate = null;
|
|
45
45
|
this.focusPending = false;
|
|
46
|
+
// Set right before `commit()` assigns `value`, so `willUpdate` can tell its
|
|
47
|
+
// own write apart from an external assignment. Internal commits already
|
|
48
|
+
// know the right date is on-screen (it's the cell the user just clicked, or
|
|
49
|
+
// the view the user navigated to), so they must not force the view back to
|
|
50
|
+
// `selection.from`'s month -- only an externally-set `value` should do that.
|
|
51
|
+
this.suppressViewSync = false;
|
|
46
52
|
this.onGridKey = (e) => {
|
|
47
53
|
const current = this.focusedDate ?? this.selection.from ?? new Date();
|
|
48
54
|
let next = null;
|
|
@@ -81,7 +87,7 @@ export class LyraDatePicker extends LyraElement {
|
|
|
81
87
|
}
|
|
82
88
|
e.preventDefault();
|
|
83
89
|
this.focusedDate = next;
|
|
84
|
-
this.viewDate =
|
|
90
|
+
this.viewDate = this.viewDateForFocus(next);
|
|
85
91
|
this.focusPending = true;
|
|
86
92
|
};
|
|
87
93
|
}
|
|
@@ -95,26 +101,26 @@ export class LyraDatePicker extends LyraElement {
|
|
|
95
101
|
return this.mode === 'single' ? this.selection.from : null;
|
|
96
102
|
}
|
|
97
103
|
willUpdate(changed) {
|
|
98
|
-
if (changed.has('value')
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
if (changed.has('value')) {
|
|
105
|
+
const external = !this.suppressViewSync;
|
|
106
|
+
this.suppressViewSync = false;
|
|
107
|
+
if (external && this.value) {
|
|
108
|
+
const from = this.selection.from;
|
|
109
|
+
if (from)
|
|
110
|
+
this.viewDate = new Date(from.getFullYear(), from.getMonth(), 1);
|
|
111
|
+
}
|
|
102
112
|
}
|
|
103
113
|
}
|
|
104
114
|
get fdow() {
|
|
105
115
|
return resolveFirstDayOfWeek(this.firstDayOfWeek, this.locale);
|
|
106
116
|
}
|
|
107
|
-
isDisabled(d) {
|
|
117
|
+
isDisabled(d, min, max, today) {
|
|
108
118
|
if (this.disabled || this.readonly)
|
|
109
119
|
return true;
|
|
110
|
-
const min = parseISO(this.min);
|
|
111
|
-
const max = parseISO(this.max);
|
|
112
120
|
if (min && d < min)
|
|
113
121
|
return true;
|
|
114
122
|
if (max && d > max)
|
|
115
123
|
return true;
|
|
116
|
-
const today = new Date();
|
|
117
|
-
today.setHours(0, 0, 0, 0);
|
|
118
124
|
if (this.disablePast && d < today)
|
|
119
125
|
return true;
|
|
120
126
|
if (this.disableFuture && d > today)
|
|
@@ -122,22 +128,31 @@ export class LyraDatePicker extends LyraElement {
|
|
|
122
128
|
return false;
|
|
123
129
|
}
|
|
124
130
|
commit(from, to, fire) {
|
|
125
|
-
this.
|
|
126
|
-
|
|
127
|
-
? from
|
|
128
|
-
? `${formatISO(from)}/${formatISO(to)}`
|
|
129
|
-
: from
|
|
130
|
-
? formatISO(from)
|
|
131
|
-
: ''
|
|
131
|
+
const next = this.mode === 'range'
|
|
132
|
+
? from && to
|
|
133
|
+
? `${formatISO(from)}/${formatISO(to)}`
|
|
132
134
|
: from
|
|
133
135
|
? formatISO(from)
|
|
134
|
-
: ''
|
|
136
|
+
: ''
|
|
137
|
+
: from
|
|
138
|
+
? formatISO(from)
|
|
139
|
+
: '';
|
|
140
|
+
// Only arm the suppression when `value` is actually about to change --
|
|
141
|
+
// that's the only case `willUpdate` will see `changed.has('value')` and
|
|
142
|
+
// get a chance to consume (and clear) the flag.
|
|
143
|
+
if (next !== this.value)
|
|
144
|
+
this.suppressViewSync = true;
|
|
145
|
+
this.value = next;
|
|
135
146
|
this.emit('input');
|
|
136
147
|
if (fire)
|
|
137
148
|
this.emit('change');
|
|
138
149
|
}
|
|
139
150
|
selectDate(date) {
|
|
140
|
-
|
|
151
|
+
const min = parseISO(this.min);
|
|
152
|
+
const max = parseISO(this.max);
|
|
153
|
+
const today = new Date();
|
|
154
|
+
today.setHours(0, 0, 0, 0);
|
|
155
|
+
if (this.isDisabled(date, min, max, today))
|
|
141
156
|
return;
|
|
142
157
|
this.focusedDate = date;
|
|
143
158
|
if (this.mode === 'range') {
|
|
@@ -165,18 +180,35 @@ export class LyraDatePicker extends LyraElement {
|
|
|
165
180
|
goToToday() {
|
|
166
181
|
this.goToDate(new Date());
|
|
167
182
|
}
|
|
168
|
-
/** Navigate the view to a date and focus it
|
|
183
|
+
/** Navigate the view to a date and focus it, clamped to `min`/`max`. */
|
|
169
184
|
goToDate(date) {
|
|
170
185
|
const d = typeof date === 'string' ? parseISO(date) : date;
|
|
171
186
|
if (!d)
|
|
172
187
|
return;
|
|
173
|
-
|
|
174
|
-
this.
|
|
188
|
+
const clamped = clampDate(d, parseISO(this.min), parseISO(this.max));
|
|
189
|
+
this.viewDate = new Date(clamped.getFullYear(), clamped.getMonth(), 1);
|
|
190
|
+
this.focusedDate = clamped;
|
|
175
191
|
this.focusPending = true;
|
|
176
192
|
}
|
|
177
193
|
nav(delta) {
|
|
178
194
|
this.viewDate = addMonths(this.viewDate, delta);
|
|
179
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* The anchor month for a newly-focused date, sliding the view by the
|
|
198
|
+
* minimum amount needed to bring it into view. With `months` > 1, a date
|
|
199
|
+
* that's already visible in a later grid must not discard an earlier grid
|
|
200
|
+
* that's already on-screen.
|
|
201
|
+
*/
|
|
202
|
+
viewDateForFocus(next) {
|
|
203
|
+
const firstMonth = new Date(this.viewDate.getFullYear(), this.viewDate.getMonth(), 1);
|
|
204
|
+
const nextMonth = new Date(next.getFullYear(), next.getMonth(), 1);
|
|
205
|
+
const lastMonth = addMonths(firstMonth, this.months - 1);
|
|
206
|
+
if (nextMonth < firstMonth)
|
|
207
|
+
return nextMonth;
|
|
208
|
+
if (nextMonth > lastMonth)
|
|
209
|
+
return addMonths(nextMonth, -(this.months - 1));
|
|
210
|
+
return firstMonth;
|
|
211
|
+
}
|
|
180
212
|
updated() {
|
|
181
213
|
if (this.focusPending && this.focusedDate) {
|
|
182
214
|
this.focusPending = false;
|
|
@@ -185,16 +217,24 @@ export class LyraDatePicker extends LyraElement {
|
|
|
185
217
|
cell?.focus();
|
|
186
218
|
}
|
|
187
219
|
}
|
|
188
|
-
renderDay(date, shownMonth) {
|
|
220
|
+
renderDay(date, shownMonth, selection, min, max, today, rowHasVisibleDay) {
|
|
189
221
|
const outside = date.getMonth() !== shownMonth;
|
|
190
222
|
// Outside-month days are empty placeholders by default (matches WA), keeping the
|
|
191
223
|
// 6-row grid aligned without low-contrast faded numbers.
|
|
192
224
|
if (outside && !this.withOutsideDays) {
|
|
193
|
-
|
|
225
|
+
// role="gridcell" stays either way. A trailing week can land entirely
|
|
226
|
+
// outside the shown month (monthMatrix always emits 6 rows of 7), and
|
|
227
|
+
// ARIA's row role requires at least one visible gridcell descendant --
|
|
228
|
+
// so only rows that already have a real, visible day cell may hide
|
|
229
|
+
// their placeholders from the accessibility tree.
|
|
230
|
+
return html `<span
|
|
231
|
+
part="day-placeholder"
|
|
232
|
+
role="gridcell"
|
|
233
|
+
aria-hidden=${rowHasVisibleDay ? 'true' : nothing}
|
|
234
|
+
></span>`;
|
|
194
235
|
}
|
|
195
|
-
const { from, to } =
|
|
196
|
-
const disabled = this.isDisabled(date);
|
|
197
|
-
const today = new Date();
|
|
236
|
+
const { from, to } = selection;
|
|
237
|
+
const disabled = this.isDisabled(date, min, max, today);
|
|
198
238
|
const isToday = isSameDay(date, today);
|
|
199
239
|
const isStart = from && isSameDay(date, from);
|
|
200
240
|
const isEnd = to && isSameDay(date, to);
|
|
@@ -232,12 +272,11 @@ export class LyraDatePicker extends LyraElement {
|
|
|
232
272
|
${date.getDate()}
|
|
233
273
|
</button>`;
|
|
234
274
|
}
|
|
235
|
-
renderMonth(offset) {
|
|
275
|
+
renderMonth(offset, selection, min, max, today, fdow, labels) {
|
|
236
276
|
const base = addMonths(this.viewDate, offset);
|
|
237
277
|
const year = base.getFullYear();
|
|
238
278
|
const month = base.getMonth();
|
|
239
|
-
const matrix = monthMatrix(year, month,
|
|
240
|
-
const labels = weekdayLabels(this.fdow, this.weekdayFormat, this.locale);
|
|
279
|
+
const matrix = monthMatrix(year, month, fdow);
|
|
241
280
|
const isFirst = offset === 0;
|
|
242
281
|
const isLast = offset === this.months - 1;
|
|
243
282
|
return html `<div part="month">
|
|
@@ -256,14 +295,25 @@ export class LyraDatePicker extends LyraElement {
|
|
|
256
295
|
</div>
|
|
257
296
|
<div part="weekdays">${labels.map((l) => html `<span part="weekday">${l}</span>`)}</div>
|
|
258
297
|
<div part="grid" role="grid" @keydown=${this.onGridKey}>
|
|
259
|
-
${matrix.map((week) =>
|
|
298
|
+
${matrix.map((week) => {
|
|
299
|
+
const rowHasVisibleDay = week.some((d) => d.getMonth() === month);
|
|
300
|
+
return html `<div part="week" role="row">${week.map((d) => this.renderDay(d, month, selection, min, max, today, rowHasVisibleDay))}</div>`;
|
|
301
|
+
})}
|
|
260
302
|
</div>
|
|
261
303
|
</div>`;
|
|
262
304
|
}
|
|
263
305
|
render() {
|
|
306
|
+
const selection = this.selection;
|
|
307
|
+
const min = parseISO(this.min);
|
|
308
|
+
const max = parseISO(this.max);
|
|
309
|
+
const today = new Date();
|
|
310
|
+
today.setHours(0, 0, 0, 0);
|
|
311
|
+
const fdow = this.fdow;
|
|
312
|
+
const labels = weekdayLabels(fdow, this.weekdayFormat, this.locale);
|
|
264
313
|
const monthEls = [];
|
|
265
|
-
for (let i = 0; i < this.months; i++)
|
|
266
|
-
monthEls.push(this.renderMonth(i));
|
|
314
|
+
for (let i = 0; i < this.months; i++) {
|
|
315
|
+
monthEls.push(this.renderMonth(i, selection, min, max, today, fdow, labels));
|
|
316
|
+
}
|
|
267
317
|
return html `<div part="base">${monthEls}</div>`;
|
|
268
318
|
}
|
|
269
319
|
}
|
|
@@ -4,3 +4,7 @@ export default meta;
|
|
|
4
4
|
type Story = StoryObj;
|
|
5
5
|
export declare const Single: Story;
|
|
6
6
|
export declare const Range: Story;
|
|
7
|
+
export declare const MinMax: Story;
|
|
8
|
+
export declare const DisablePast: Story;
|
|
9
|
+
export declare const DisableFuture: Story;
|
|
10
|
+
export declare const WithOutsideDays: Story;
|
|
@@ -11,3 +11,15 @@ export const Single = {
|
|
|
11
11
|
export const Range = {
|
|
12
12
|
render: () => html `<lyra-date-picker mode="range" months="2"></lyra-date-picker>`,
|
|
13
13
|
};
|
|
14
|
+
export const MinMax = {
|
|
15
|
+
render: () => html `<lyra-date-picker min="2026-07-10" max="2026-07-20" value="2026-07-15"></lyra-date-picker>`,
|
|
16
|
+
};
|
|
17
|
+
export const DisablePast = {
|
|
18
|
+
render: () => html `<lyra-date-picker disable-past></lyra-date-picker>`,
|
|
19
|
+
};
|
|
20
|
+
export const DisableFuture = {
|
|
21
|
+
render: () => html `<lyra-date-picker disable-future></lyra-date-picker>`,
|
|
22
|
+
};
|
|
23
|
+
export const WithOutsideDays = {
|
|
24
|
+
render: () => html `<lyra-date-picker with-outside-days value="2026-07-15"></lyra-date-picker>`,
|
|
25
|
+
};
|
|
@@ -7,7 +7,11 @@ import { LyraElement } from '../../internal/lyra-element.js';
|
|
|
7
7
|
* @customElement lyra-empty
|
|
8
8
|
* @slot - Custom icon or illustration (defaults to none).
|
|
9
9
|
* @slot actions - Buttons/links shown below the description.
|
|
10
|
-
* @csspart base
|
|
10
|
+
* @csspart base - The outer container.
|
|
11
|
+
* @csspart icon - The wrapper around the default-slotted icon/illustration.
|
|
12
|
+
* @csspart heading - The heading paragraph.
|
|
13
|
+
* @csspart description - The description paragraph.
|
|
14
|
+
* @csspart actions - The wrapper around the `actions`-slotted content.
|
|
11
15
|
*/
|
|
12
16
|
export declare class LyraEmpty extends LyraElement {
|
|
13
17
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -15,6 +19,13 @@ export declare class LyraEmpty extends LyraElement {
|
|
|
15
19
|
heading: string;
|
|
16
20
|
/** Supporting copy, e.g. "Try a different search." */
|
|
17
21
|
description: string;
|
|
22
|
+
/**
|
|
23
|
+
* Compact rendering for use inside a constrained space (e.g. a widget body
|
|
24
|
+
* or table cell) rather than as a full-page state: left-aligned, tighter
|
|
25
|
+
* padding, and a lighter heading weight instead of the centered/spacious
|
|
26
|
+
* default.
|
|
27
|
+
*/
|
|
28
|
+
compact: boolean;
|
|
18
29
|
private hasIcon;
|
|
19
30
|
private hasActions;
|
|
20
31
|
protected willUpdate(): void;
|
|
@@ -16,7 +16,11 @@ import { styles } from './empty.styles.js';
|
|
|
16
16
|
* @customElement lyra-empty
|
|
17
17
|
* @slot - Custom icon or illustration (defaults to none).
|
|
18
18
|
* @slot actions - Buttons/links shown below the description.
|
|
19
|
-
* @csspart base
|
|
19
|
+
* @csspart base - The outer container.
|
|
20
|
+
* @csspart icon - The wrapper around the default-slotted icon/illustration.
|
|
21
|
+
* @csspart heading - The heading paragraph.
|
|
22
|
+
* @csspart description - The description paragraph.
|
|
23
|
+
* @csspart actions - The wrapper around the `actions`-slotted content.
|
|
20
24
|
*/
|
|
21
25
|
export class LyraEmpty extends LyraElement {
|
|
22
26
|
constructor() {
|
|
@@ -25,6 +29,13 @@ export class LyraEmpty extends LyraElement {
|
|
|
25
29
|
this.heading = '';
|
|
26
30
|
/** Supporting copy, e.g. "Try a different search." */
|
|
27
31
|
this.description = '';
|
|
32
|
+
/**
|
|
33
|
+
* Compact rendering for use inside a constrained space (e.g. a widget body
|
|
34
|
+
* or table cell) rather than as a full-page state: left-aligned, tighter
|
|
35
|
+
* padding, and a lighter heading weight instead of the centered/spacious
|
|
36
|
+
* default.
|
|
37
|
+
*/
|
|
38
|
+
this.compact = false;
|
|
28
39
|
// `[part='icon']:empty` never matches because the part always contains a
|
|
29
40
|
// `<slot>` element (CSS `:empty` only ignores text/comment nodes). Track
|
|
30
41
|
// real slot assignment in JS instead and key the CSS off these instead.
|
|
@@ -44,7 +55,10 @@ export class LyraEmpty extends LyraElement {
|
|
|
44
55
|
// `firstUpdated` (after the update completes) would schedule a second,
|
|
45
56
|
// wasted update (Lit's dev-mode "change-in-update" warning).
|
|
46
57
|
if (!this.hasUpdated) {
|
|
47
|
-
|
|
58
|
+
// An explicit `slot=""` still assigns to the default slot per the HTML
|
|
59
|
+
// slot algorithm, so check the attribute's value rather than its mere
|
|
60
|
+
// presence.
|
|
61
|
+
this.hasIcon = Array.from(this.children).some((el) => !el.getAttribute('slot'));
|
|
48
62
|
this.hasActions = Array.from(this.children).some((el) => el.getAttribute('slot') === 'actions');
|
|
49
63
|
}
|
|
50
64
|
}
|
|
@@ -64,7 +78,7 @@ export class LyraEmpty extends LyraElement {
|
|
|
64
78
|
}
|
|
65
79
|
render() {
|
|
66
80
|
return html `
|
|
67
|
-
<div part="base">
|
|
81
|
+
<div part="base" role="status" aria-live="polite">
|
|
68
82
|
<div part="icon" ?hidden=${!this.hasIcon}><slot @slotchange=${this.onIconSlotChange}></slot></div>
|
|
69
83
|
<p part="heading">${this.heading}</p>
|
|
70
84
|
<p part="description">${this.description}</p>
|
|
@@ -81,6 +95,9 @@ __decorate([
|
|
|
81
95
|
__decorate([
|
|
82
96
|
property()
|
|
83
97
|
], LyraEmpty.prototype, "description", void 0);
|
|
98
|
+
__decorate([
|
|
99
|
+
property({ type: Boolean, reflect: true })
|
|
100
|
+
], LyraEmpty.prototype, "compact", void 0);
|
|
84
101
|
__decorate([
|
|
85
102
|
state()
|
|
86
103
|
], LyraEmpty.prototype, "hasIcon", void 0);
|
|
@@ -12,3 +12,23 @@ export const Default = {
|
|
|
12
12
|
</lyra-empty>
|
|
13
13
|
`,
|
|
14
14
|
};
|
|
15
|
+
export const WithIcon = {
|
|
16
|
+
render: () => html `
|
|
17
|
+
<lyra-empty heading="No results" description="Try a different search.">
|
|
18
|
+
<svg slot="" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
19
|
+
<circle cx="11" cy="11" r="7" stroke-width="2"></circle>
|
|
20
|
+
<path d="M21 21l-4.35-4.35" stroke-width="2" stroke-linecap="round"></path>
|
|
21
|
+
</svg>
|
|
22
|
+
<span slot="actions"><button>Reset</button></span>
|
|
23
|
+
</lyra-empty>
|
|
24
|
+
`,
|
|
25
|
+
};
|
|
26
|
+
export const Compact = {
|
|
27
|
+
render: () => html `
|
|
28
|
+
<div style="max-width: 16rem; border: 1px solid var(--lyra-color-border);">
|
|
29
|
+
<lyra-empty compact heading="No results" description="Try a different search.">
|
|
30
|
+
<span slot="actions"><button>Reset</button></span>
|
|
31
|
+
</lyra-empty>
|
|
32
|
+
</div>
|
|
33
|
+
`,
|
|
34
|
+
};
|
|
@@ -13,6 +13,11 @@ export const styles = css `
|
|
|
13
13
|
color: var(--lyra-color-text-quiet);
|
|
14
14
|
inline-size: 100%;
|
|
15
15
|
}
|
|
16
|
+
:host([compact]) [part='base'] {
|
|
17
|
+
align-items: flex-start;
|
|
18
|
+
text-align: start;
|
|
19
|
+
padding: var(--lyra-space-xs);
|
|
20
|
+
}
|
|
16
21
|
[part='icon'] {
|
|
17
22
|
font-size: 2rem;
|
|
18
23
|
line-height: 1;
|
|
@@ -26,6 +31,12 @@ export const styles = css `
|
|
|
26
31
|
color: var(--lyra-color-text);
|
|
27
32
|
margin: 0;
|
|
28
33
|
}
|
|
34
|
+
[part='heading']:empty {
|
|
35
|
+
display: none;
|
|
36
|
+
}
|
|
37
|
+
:host([compact]) [part='heading'] {
|
|
38
|
+
font-weight: 400;
|
|
39
|
+
}
|
|
29
40
|
[part='description'] {
|
|
30
41
|
font-size: 0.875rem;
|
|
31
42
|
margin: 0;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// A bare leading '-' is not itself formula syntax (only '=', and context-dependent '+'/'@',
|
|
2
|
+
// reliably trigger spreadsheet formula evaluation) — guarding it forces text rendering on
|
|
3
|
+
// ordinary negative numbers/currency. Per OWASP CSV-injection guidance, '-' is intentionally
|
|
4
|
+
// excluded here.
|
|
5
|
+
const UNSAFE_LEADING = /^[=+@\t\r]/;
|
|
6
|
+
const NEEDS_QUOTING = /[",\r\n]/;
|
|
3
7
|
/** Escapes a CSV field: quotes as needed, guards against formula injection. */
|
|
4
8
|
export function escapeCsvField(value) {
|
|
5
9
|
let s = value == null ? '' : String(value);
|
|
@@ -11,7 +11,9 @@ export type ExportFormat = 'csv' | 'json';
|
|
|
11
11
|
* @event lyra-export - `detail: { format }`, cancelable — call `preventDefault()`
|
|
12
12
|
* to substitute the built-in client-side download with a server-generated one.
|
|
13
13
|
* @event lyra-export-complete - Fired after a non-cancelled download completes.
|
|
14
|
-
* @csspart trigger
|
|
14
|
+
* @csspart trigger - The button that triggers the export (or opens the format menu).
|
|
15
|
+
* @csspart menu - The format-choice menu, shown when more than one format is configured.
|
|
16
|
+
* @csspart menu-item - A single format option inside the menu.
|
|
15
17
|
*/
|
|
16
18
|
export declare class LyraExportButton extends LyraElement {
|
|
17
19
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -22,14 +24,26 @@ export declare class LyraExportButton extends LyraElement {
|
|
|
22
24
|
disabled: boolean;
|
|
23
25
|
label: string;
|
|
24
26
|
open: boolean;
|
|
27
|
+
private triggerEl?;
|
|
28
|
+
private menuEl?;
|
|
29
|
+
private readonly menuId;
|
|
25
30
|
private cleanup?;
|
|
31
|
+
/** Which menu item to focus the next time `open` flips true; reset after use. */
|
|
32
|
+
private pendingMenuFocusIndex;
|
|
26
33
|
disconnectedCallback(): void;
|
|
27
34
|
private onDocPointer;
|
|
28
35
|
private openMenu;
|
|
29
36
|
private closeMenu;
|
|
37
|
+
private menuItemEls;
|
|
38
|
+
/** Focuses the menu item at `index` (clamped), if the menu is already open and rendered. */
|
|
39
|
+
private focusMenuItem;
|
|
40
|
+
/** Opens the menu (if closed) and focuses `index`, or moves focus there directly if already open. */
|
|
41
|
+
private focusMenuItemOnOpen;
|
|
30
42
|
private onKeyDown;
|
|
31
43
|
protected firstUpdated(): void;
|
|
32
44
|
protected updated(changed: PropertyValues): void;
|
|
45
|
+
/** Applies the same `columns` allow-list CSV exports use, so JSON can't leak fields CSV hides. */
|
|
46
|
+
private rowsForExport;
|
|
33
47
|
private doExport;
|
|
34
48
|
private onTriggerClick;
|
|
35
49
|
render(): TemplateResult;
|