@aceshooting/lyra-ui 1.1.0 → 1.2.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 +1 -1
- package/custom-elements.json +9289 -8457
- package/dist/components/chart/chart.d.ts +11 -0
- package/dist/components/chart/chart.js +54 -2
- package/dist/components/chart/lite-chart.d.ts +9 -0
- package/dist/components/chart/lite-chart.js +41 -1
- package/dist/components/chart/lite-chart.stories.d.ts +2 -0
- package/dist/components/chart/lite-chart.stories.js +16 -0
- package/dist/components/combobox/combobox.js +1 -1
- package/dist/components/flag/flag.d.ts +26 -5
- package/dist/components/flag/flag.js +44 -3
- package/dist/components/flag/flag.stories.d.ts +1 -0
- package/dist/components/flag/flag.stories.js +14 -0
- package/dist/components/heatmap/heatmap.d.ts +15 -3
- package/dist/components/heatmap/heatmap.js +24 -7
- package/dist/components/heatmap/heatmap.stories.d.ts +5 -0
- package/dist/components/heatmap/heatmap.stories.js +25 -0
- package/dist/components/select/select.d.ts +3 -0
- package/dist/components/select/select.js +6 -42
- package/dist/components/select/select.stories.d.ts +2 -0
- package/dist/components/select/select.stories.js +16 -0
- package/dist/components/select/select.styles.js +26 -2
- package/dist/components/stat/stat.d.ts +16 -0
- package/dist/components/stat/stat.js +41 -1
- package/dist/components/stat/stat.stories.d.ts +1 -0
- package/dist/components/stat/stat.stories.js +17 -0
- package/dist/components/stat/stat.styles.js +20 -0
- package/dist/components/widget/widget.d.ts +10 -0
- package/dist/components/widget/widget.js +24 -1
- package/dist/components/widget/widget.stories.d.ts +2 -0
- package/dist/components/widget/widget.stories.js +33 -0
- package/dist/components/widget/widget.styles.js +9 -2
- package/dist/components/word-cloud/word-cloud.styles.js +1 -0
- package/llms-full.txt +90 -20
- package/package.json +3 -3
|
@@ -14,47 +14,6 @@ import { chevronIcon } from '../../internal/icons.js';
|
|
|
14
14
|
import { styles } from './select.styles.js';
|
|
15
15
|
import { LyraOption } from '../combobox/option.js';
|
|
16
16
|
import '../combobox/option.js';
|
|
17
|
-
/**
|
|
18
|
-
* `<lyra-select>` — a plain closed-list dropdown: a direct `<lyra-*>`
|
|
19
|
-
* counterpart to `<wa-select>`/`<wa-option>`. Trigger is a button (not a text
|
|
20
|
-
* input) -- click/Enter/Space/ArrowDown opens it, there's no typing-to-filter.
|
|
21
|
-
* A printable keypress instead jumps (or, while closed, directly selects) the
|
|
22
|
-
* next option whose label starts with what's been typed, like a native
|
|
23
|
-
* `<select>`'s type-ahead.
|
|
24
|
-
*
|
|
25
|
-
* Options are `<lyra-option value>` children, the same element `<lyra-combobox>`
|
|
26
|
-
* uses. Unlike `lyra-combobox` this is single-select only, with no filter/
|
|
27
|
-
* source/with-clear/max-options-visible/empty-text/max-render/multiple surface
|
|
28
|
-
* -- see `<lyra-combobox>` for the filterable/multi-select case.
|
|
29
|
-
*
|
|
30
|
-
* Reuses `lyra-combobox`'s popup positioning (`internal/positioner.js`) and
|
|
31
|
-
* click-outside/Escape/Home/End/Arrow-key listbox navigation patterns,
|
|
32
|
-
* adapted to a trigger button that keeps DOM focus throughout (the listbox's
|
|
33
|
-
* "active" row is conveyed via `aria-activedescendant`, never actual focus),
|
|
34
|
-
* matching the WAI-ARIA "select-only combobox" pattern.
|
|
35
|
-
*
|
|
36
|
-
* @customElement lyra-select
|
|
37
|
-
* @slot - `<lyra-option>` elements.
|
|
38
|
-
* @slot label - Custom label content.
|
|
39
|
-
* @slot hint - Custom hint content.
|
|
40
|
-
* @slot error - Custom error content.
|
|
41
|
-
* @event change - The selection changed.
|
|
42
|
-
* @event input - Fired alongside `change` on every selection change (native
|
|
43
|
-
* `<select>` doesn't meaningfully distinguish the two either).
|
|
44
|
-
* @event lyra-show - The listbox opened.
|
|
45
|
-
* @event lyra-hide - The listbox closed.
|
|
46
|
-
* @csspart form-control - The outer wrapper around label, trigger, listbox, error and hint.
|
|
47
|
-
* @csspart form-control-label - The `<label>` element.
|
|
48
|
-
* @csspart trigger - The trigger button (positioning anchor).
|
|
49
|
-
* @csspart listbox - The options popover.
|
|
50
|
-
* @csspart option - An option row.
|
|
51
|
-
* @csspart option-dot - An option row's leading status dot (when `dot-color` is set).
|
|
52
|
-
* @csspart option-label - An option row's label/sub wrapper.
|
|
53
|
-
* @csspart option-sub - An option row's secondary line (when `sub` is set).
|
|
54
|
-
* @csspart expand-icon - The dropdown indicator.
|
|
55
|
-
* @csspart error - The error message.
|
|
56
|
-
* @csspart hint - The hint message.
|
|
57
|
-
*/
|
|
58
17
|
export class LyraSelect extends LyraElement {
|
|
59
18
|
static { this.formAssociated = true; }
|
|
60
19
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
@@ -71,6 +30,8 @@ export class LyraSelect extends LyraElement {
|
|
|
71
30
|
this.hint = '';
|
|
72
31
|
this.errorText = '';
|
|
73
32
|
this.open = false;
|
|
33
|
+
/** Visual size — same `xs`–`xl` scale as `lyra-toast-item`'s `size`. */
|
|
34
|
+
this.size = 'm';
|
|
74
35
|
this.activeIndex = -1;
|
|
75
36
|
this.options = [];
|
|
76
37
|
// Set on the trigger button's first `blur`; gates the `data-invalid`
|
|
@@ -438,7 +399,7 @@ export class LyraSelect extends LyraElement {
|
|
|
438
399
|
aria-expanded=${this.open ? 'true' : 'false'}
|
|
439
400
|
aria-controls=${this.listId}
|
|
440
401
|
aria-activedescendant=${activeId}
|
|
441
|
-
aria-label=${this.label || this.placeholder || 'Select'}
|
|
402
|
+
aria-label=${this.getAttribute('aria-label') || this.label || this.placeholder || 'Select'}
|
|
442
403
|
aria-required=${this.required ? 'true' : 'false'}
|
|
443
404
|
aria-invalid=${this.touched && !this.internals.validity.valid ? 'true' : 'false'}
|
|
444
405
|
?disabled=${this.disabled}
|
|
@@ -495,6 +456,9 @@ __decorate([
|
|
|
495
456
|
__decorate([
|
|
496
457
|
property({ type: Boolean, reflect: true })
|
|
497
458
|
], LyraSelect.prototype, "open", void 0);
|
|
459
|
+
__decorate([
|
|
460
|
+
property({ reflect: true })
|
|
461
|
+
], LyraSelect.prototype, "size", void 0);
|
|
498
462
|
__decorate([
|
|
499
463
|
state()
|
|
500
464
|
], LyraSelect.prototype, "activeIndex", void 0);
|
|
@@ -11,6 +11,8 @@ export declare const PreSelectedValue: Story;
|
|
|
11
11
|
* rich-row support as `<lyra-combobox>`.
|
|
12
12
|
*/
|
|
13
13
|
export declare const RichRows: Story;
|
|
14
|
+
/** `size` spans the same `xs`–`xl` scale as `lyra-toast-item`, default `m`. */
|
|
15
|
+
export declare const Sizes: Story;
|
|
14
16
|
export declare const Disabled: Story;
|
|
15
17
|
/**
|
|
16
18
|
* `required` blocks form submission while empty; `error-text` renders a
|
|
@@ -46,6 +46,22 @@ export const RichRows = {
|
|
|
46
46
|
</lyra-select>
|
|
47
47
|
`,
|
|
48
48
|
};
|
|
49
|
+
/** `size` spans the same `xs`–`xl` scale as `lyra-toast-item`, default `m`. */
|
|
50
|
+
export const Sizes = {
|
|
51
|
+
render: () => {
|
|
52
|
+
const sizes = ['xs', 's', 'm', 'l', 'xl'];
|
|
53
|
+
return html `
|
|
54
|
+
<div style="display: flex; flex-direction: column; gap: 1rem; max-width: 20rem">
|
|
55
|
+
${sizes.map((size) => html `
|
|
56
|
+
<lyra-select size=${size} placeholder=${`Size "${size}"`}>
|
|
57
|
+
<lyra-option value="a">Apple</lyra-option>
|
|
58
|
+
<lyra-option value="b">Banana</lyra-option>
|
|
59
|
+
</lyra-select>
|
|
60
|
+
`)}
|
|
61
|
+
</div>
|
|
62
|
+
`;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
49
65
|
export const Disabled = {
|
|
50
66
|
render: () => html `
|
|
51
67
|
<lyra-select label="Disabled" disabled placeholder="Can't touch this" style="max-width: 20rem">
|
|
@@ -2,6 +2,29 @@ import { css } from 'lit';
|
|
|
2
2
|
export const styles = css `
|
|
3
3
|
:host {
|
|
4
4
|
display: block;
|
|
5
|
+
--lyra-select-trigger-padding: var(--lyra-space-xs) var(--lyra-space-s);
|
|
6
|
+
--lyra-select-trigger-min-height: 2.5rem;
|
|
7
|
+
--lyra-select-font-size: 1rem;
|
|
8
|
+
}
|
|
9
|
+
:host([size='xs']) {
|
|
10
|
+
--lyra-select-trigger-padding: 0.125rem var(--lyra-space-xs);
|
|
11
|
+
--lyra-select-trigger-min-height: 1.5rem;
|
|
12
|
+
--lyra-select-font-size: 0.75rem;
|
|
13
|
+
}
|
|
14
|
+
:host([size='s']) {
|
|
15
|
+
--lyra-select-trigger-padding: var(--lyra-space-xs) var(--lyra-space-xs);
|
|
16
|
+
--lyra-select-trigger-min-height: 1.875rem;
|
|
17
|
+
--lyra-select-font-size: 0.8125rem;
|
|
18
|
+
}
|
|
19
|
+
:host([size='l']) {
|
|
20
|
+
--lyra-select-trigger-padding: var(--lyra-space-s) var(--lyra-space-m);
|
|
21
|
+
--lyra-select-trigger-min-height: 3rem;
|
|
22
|
+
--lyra-select-font-size: 1.125rem;
|
|
23
|
+
}
|
|
24
|
+
:host([size='xl']) {
|
|
25
|
+
--lyra-select-trigger-padding: var(--lyra-space-m) var(--lyra-space-l);
|
|
26
|
+
--lyra-select-trigger-min-height: 3.5rem;
|
|
27
|
+
--lyra-select-font-size: 1.25rem;
|
|
5
28
|
}
|
|
6
29
|
[part='form-control-label'] {
|
|
7
30
|
display: block;
|
|
@@ -30,13 +53,14 @@ export const styles = css `
|
|
|
30
53
|
justify-content: space-between;
|
|
31
54
|
gap: var(--lyra-space-xs);
|
|
32
55
|
inline-size: 100%;
|
|
33
|
-
min-block-size:
|
|
34
|
-
padding: var(--lyra-
|
|
56
|
+
min-block-size: var(--lyra-select-trigger-min-height);
|
|
57
|
+
padding: var(--lyra-select-trigger-padding);
|
|
35
58
|
border: 1px solid var(--lyra-color-border);
|
|
36
59
|
border-radius: var(--lyra-radius);
|
|
37
60
|
background: var(--lyra-color-surface);
|
|
38
61
|
color: inherit;
|
|
39
62
|
font: inherit;
|
|
63
|
+
font-size: var(--lyra-select-font-size);
|
|
40
64
|
text-align: start;
|
|
41
65
|
cursor: pointer;
|
|
42
66
|
}
|
|
@@ -15,6 +15,7 @@ export interface StatRow {
|
|
|
15
15
|
* @slot caption - Rich caption content (overrides the `caption` attribute).
|
|
16
16
|
* @slot spark - A sparkline (e.g. `<lyra-sparkline>`) or other compact trend
|
|
17
17
|
* visual. `lyra-stat` only reserves the slot; it doesn't render one itself.
|
|
18
|
+
* @slot sub - Rich sub-line content (overrides the `sub` attribute).
|
|
18
19
|
* @csspart base - The component's root wrapper.
|
|
19
20
|
* @csspart icon - Container for the leading icon slot.
|
|
20
21
|
* @csspart label - The label text.
|
|
@@ -22,6 +23,7 @@ export interface StatRow {
|
|
|
22
23
|
* @csspart value - The value text.
|
|
23
24
|
* @csspart unit - The unit text.
|
|
24
25
|
* @csspart trend - The trend pill.
|
|
26
|
+
* @csspart sub - Container for the `sub` attribute/slot.
|
|
25
27
|
* @csspart spark - Container for the `spark` slot.
|
|
26
28
|
* @csspart caption - Container for the caption attribute/slot.
|
|
27
29
|
* @csspart rows - Container for the `rows` breakdown list.
|
|
@@ -46,13 +48,27 @@ export declare class LyraStat extends LyraElement {
|
|
|
46
48
|
* the status `variant`; see the `[part='value']` selector below for how
|
|
47
49
|
* the two combine. */
|
|
48
50
|
emphasis: boolean;
|
|
51
|
+
/** Exact value shown as a hover/focus tooltip on the headline `value` (e.g. `value="$1.2K"
|
|
52
|
+
* exact-value="$1,204.37"`). Also makes `[part='value']` keyboard-focusable so the tooltip is
|
|
53
|
+
* reachable without a pointer. */
|
|
54
|
+
exactValue: string;
|
|
55
|
+
/** A secondary line distinct from `caption` (e.g. a comparison-period label), rendered between the
|
|
56
|
+
* trend pill and the caption. */
|
|
57
|
+
sub: string;
|
|
58
|
+
/** Renders `value` as smaller/lighter prose (e.g. a loading/status message) instead of the bold
|
|
59
|
+
* numeric headline style, and hides `unit`. */
|
|
60
|
+
prose: boolean;
|
|
61
|
+
/** Tighter padding for constrained spaces — same convention as `lyra-empty`'s `compact`. */
|
|
62
|
+
compact: boolean;
|
|
49
63
|
private hasIcon;
|
|
50
64
|
private hasCaptionSlot;
|
|
51
65
|
private hasSparkSlot;
|
|
66
|
+
private hasSubSlot;
|
|
52
67
|
protected willUpdate(): void;
|
|
53
68
|
private onIconSlotChange;
|
|
54
69
|
private onCaptionSlotChange;
|
|
55
70
|
private onSparkSlotChange;
|
|
71
|
+
private onSubSlotChange;
|
|
56
72
|
render(): TemplateResult;
|
|
57
73
|
}
|
|
58
74
|
declare global {
|
|
@@ -20,6 +20,7 @@ import { styles } from './stat.styles.js';
|
|
|
20
20
|
* @slot caption - Rich caption content (overrides the `caption` attribute).
|
|
21
21
|
* @slot spark - A sparkline (e.g. `<lyra-sparkline>`) or other compact trend
|
|
22
22
|
* visual. `lyra-stat` only reserves the slot; it doesn't render one itself.
|
|
23
|
+
* @slot sub - Rich sub-line content (overrides the `sub` attribute).
|
|
23
24
|
* @csspart base - The component's root wrapper.
|
|
24
25
|
* @csspart icon - Container for the leading icon slot.
|
|
25
26
|
* @csspart label - The label text.
|
|
@@ -27,6 +28,7 @@ import { styles } from './stat.styles.js';
|
|
|
27
28
|
* @csspart value - The value text.
|
|
28
29
|
* @csspart unit - The unit text.
|
|
29
30
|
* @csspart trend - The trend pill.
|
|
31
|
+
* @csspart sub - Container for the `sub` attribute/slot.
|
|
30
32
|
* @csspart spark - Container for the `spark` slot.
|
|
31
33
|
* @csspart caption - Container for the caption attribute/slot.
|
|
32
34
|
* @csspart rows - Container for the `rows` breakdown list.
|
|
@@ -52,12 +54,25 @@ export class LyraStat extends LyraElement {
|
|
|
52
54
|
* the status `variant`; see the `[part='value']` selector below for how
|
|
53
55
|
* the two combine. */
|
|
54
56
|
this.emphasis = false;
|
|
57
|
+
/** Exact value shown as a hover/focus tooltip on the headline `value` (e.g. `value="$1.2K"
|
|
58
|
+
* exact-value="$1,204.37"`). Also makes `[part='value']` keyboard-focusable so the tooltip is
|
|
59
|
+
* reachable without a pointer. */
|
|
60
|
+
this.exactValue = '';
|
|
61
|
+
/** A secondary line distinct from `caption` (e.g. a comparison-period label), rendered between the
|
|
62
|
+
* trend pill and the caption. */
|
|
63
|
+
this.sub = '';
|
|
64
|
+
/** Renders `value` as smaller/lighter prose (e.g. a loading/status message) instead of the bold
|
|
65
|
+
* numeric headline style, and hides `unit`. */
|
|
66
|
+
this.prose = false;
|
|
67
|
+
/** Tighter padding for constrained spaces — same convention as `lyra-empty`'s `compact`. */
|
|
68
|
+
this.compact = false;
|
|
55
69
|
// Same fix `lyra-empty` already established: `[part]:empty` never matches
|
|
56
70
|
// because the part always contains a literal `<slot>` child. Track real
|
|
57
71
|
// slot assignment in JS instead.
|
|
58
72
|
this.hasIcon = false;
|
|
59
73
|
this.hasCaptionSlot = false;
|
|
60
74
|
this.hasSparkSlot = false;
|
|
75
|
+
this.hasSubSlot = false;
|
|
61
76
|
this.onIconSlotChange = (e) => {
|
|
62
77
|
this.hasIcon = e.target.assignedElements({ flatten: true }).length > 0;
|
|
63
78
|
};
|
|
@@ -67,6 +82,9 @@ export class LyraStat extends LyraElement {
|
|
|
67
82
|
this.onSparkSlotChange = (e) => {
|
|
68
83
|
this.hasSparkSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
69
84
|
};
|
|
85
|
+
this.onSubSlotChange = (e) => {
|
|
86
|
+
this.hasSubSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
87
|
+
};
|
|
70
88
|
}
|
|
71
89
|
static { this.styles = [LyraElement.styles, styles, srOnly]; }
|
|
72
90
|
willUpdate() {
|
|
@@ -74,6 +92,7 @@ export class LyraStat extends LyraElement {
|
|
|
74
92
|
this.hasIcon = Array.from(this.children).some((el) => !el.hasAttribute('slot'));
|
|
75
93
|
this.hasCaptionSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'caption');
|
|
76
94
|
this.hasSparkSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'spark');
|
|
95
|
+
this.hasSubSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'sub');
|
|
77
96
|
}
|
|
78
97
|
}
|
|
79
98
|
render() {
|
|
@@ -86,6 +105,7 @@ export class LyraStat extends LyraElement {
|
|
|
86
105
|
// [part='trend'].
|
|
87
106
|
const arrow = rawDirection === 'flat' ? '–' : chevronIcon();
|
|
88
107
|
const hasCaption = this.hasCaptionSlot || this.caption.length > 0;
|
|
108
|
+
const hasSub = this.hasSubSlot || this.sub.length > 0;
|
|
89
109
|
// The visible pill only ever shows the icon rotation + color to convey
|
|
90
110
|
// direction and good/bad polarity; both are invisible to screen readers,
|
|
91
111
|
// so mirror them into a plain-language sr-only announcement.
|
|
@@ -99,7 +119,9 @@ export class LyraStat extends LyraElement {
|
|
|
99
119
|
></span>
|
|
100
120
|
<span part="label">${this.label}</span>
|
|
101
121
|
<div part="value-row">
|
|
102
|
-
<span part="value"
|
|
122
|
+
<span part="value" title=${this.exactValue || nothing} tabindex=${this.exactValue ? '0' : nothing}
|
|
123
|
+
>${this.value}</span
|
|
124
|
+
>
|
|
103
125
|
<span part="unit">${this.unit}</span>
|
|
104
126
|
</div>
|
|
105
127
|
${hasTrend
|
|
@@ -112,6 +134,9 @@ export class LyraStat extends LyraElement {
|
|
|
112
134
|
<span class="sr-only">${trendAnnouncement}</span>
|
|
113
135
|
</span>`
|
|
114
136
|
: nothing}
|
|
137
|
+
<div part="sub" ?hidden=${!hasSub}>
|
|
138
|
+
${this.sub}<slot name="sub" @slotchange=${this.onSubSlotChange}></slot>
|
|
139
|
+
</div>
|
|
115
140
|
<div part="spark" ?hidden=${!this.hasSparkSlot}>
|
|
116
141
|
<slot name="spark" @slotchange=${this.onSparkSlotChange}></slot>
|
|
117
142
|
</div>
|
|
@@ -157,6 +182,18 @@ __decorate([
|
|
|
157
182
|
__decorate([
|
|
158
183
|
property({ type: Boolean, reflect: true })
|
|
159
184
|
], LyraStat.prototype, "emphasis", void 0);
|
|
185
|
+
__decorate([
|
|
186
|
+
property({ attribute: 'exact-value' })
|
|
187
|
+
], LyraStat.prototype, "exactValue", void 0);
|
|
188
|
+
__decorate([
|
|
189
|
+
property()
|
|
190
|
+
], LyraStat.prototype, "sub", void 0);
|
|
191
|
+
__decorate([
|
|
192
|
+
property({ type: Boolean, reflect: true })
|
|
193
|
+
], LyraStat.prototype, "prose", void 0);
|
|
194
|
+
__decorate([
|
|
195
|
+
property({ type: Boolean, reflect: true })
|
|
196
|
+
], LyraStat.prototype, "compact", void 0);
|
|
160
197
|
__decorate([
|
|
161
198
|
state()
|
|
162
199
|
], LyraStat.prototype, "hasIcon", void 0);
|
|
@@ -166,4 +203,7 @@ __decorate([
|
|
|
166
203
|
__decorate([
|
|
167
204
|
state()
|
|
168
205
|
], LyraStat.prototype, "hasSparkSlot", void 0);
|
|
206
|
+
__decorate([
|
|
207
|
+
state()
|
|
208
|
+
], LyraStat.prototype, "hasSubSlot", void 0);
|
|
169
209
|
defineElement('stat', LyraStat);
|
|
@@ -62,3 +62,20 @@ export const Emphasis = {
|
|
|
62
62
|
</div>
|
|
63
63
|
`,
|
|
64
64
|
};
|
|
65
|
+
export const ExactValueSubProseCompact = {
|
|
66
|
+
render: () => html `
|
|
67
|
+
<div class="flex flex-wrap gap-4">
|
|
68
|
+
<lyra-stat
|
|
69
|
+
label="Revenue"
|
|
70
|
+
value="$1.2K"
|
|
71
|
+
exact-value="$1,204.37"
|
|
72
|
+
sub="vs. last week"
|
|
73
|
+
caption="Updated 2h ago"
|
|
74
|
+
trend="3.2"
|
|
75
|
+
variant="success"
|
|
76
|
+
></lyra-stat>
|
|
77
|
+
<lyra-stat label="Status" prose value="Waiting for the next sync…"></lyra-stat>
|
|
78
|
+
<lyra-stat label="Sessions" value="9,204" sub="+312 today" compact></lyra-stat>
|
|
79
|
+
</div>
|
|
80
|
+
`,
|
|
81
|
+
};
|
|
@@ -84,6 +84,13 @@ export const styles = css `
|
|
|
84
84
|
[part='spark'][hidden] {
|
|
85
85
|
display: none;
|
|
86
86
|
}
|
|
87
|
+
[part='sub'] {
|
|
88
|
+
font-size: 0.8125rem;
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
}
|
|
91
|
+
[part='sub'][hidden] {
|
|
92
|
+
display: none;
|
|
93
|
+
}
|
|
87
94
|
[part='caption'] {
|
|
88
95
|
font-size: 0.8125rem;
|
|
89
96
|
color: var(--lyra-color-text-quiet);
|
|
@@ -127,4 +134,17 @@ export const styles = css `
|
|
|
127
134
|
:host([emphasis][variant='neutral']) [part='value'] {
|
|
128
135
|
color: var(--lyra-color-brand);
|
|
129
136
|
}
|
|
137
|
+
:host([prose]) [part='value'] {
|
|
138
|
+
font-size: 0.9375rem;
|
|
139
|
+
font-weight: 400;
|
|
140
|
+
font-family: inherit;
|
|
141
|
+
color: var(--lyra-color-text-quiet);
|
|
142
|
+
}
|
|
143
|
+
:host([prose]) [part='unit'] {
|
|
144
|
+
display: none;
|
|
145
|
+
}
|
|
146
|
+
:host([compact]) [part='base'] {
|
|
147
|
+
padding: var(--lyra-space-s);
|
|
148
|
+
gap: 0.125rem;
|
|
149
|
+
}
|
|
130
150
|
`;
|
|
@@ -21,6 +21,10 @@ import { LyraElement } from '../../internal/lyra-element.js';
|
|
|
21
21
|
* @csspart fullscreen-button - The fullscreen toggle button.
|
|
22
22
|
* @csspart body - The wrapper around the default slot (the panel body).
|
|
23
23
|
* @csspart backdrop - The fullscreen scrim behind the panel.
|
|
24
|
+
*
|
|
25
|
+
* `fullscreen-inset` overrides the default `var(--lyra-space-l)` inset applied to `[part="base"]`
|
|
26
|
+
* and `[part="backdrop"]` while fullscreen (e.g. `"0 0 0 240px"` to leave a persistent sidebar
|
|
27
|
+
* visible). `compact` tightens header/body padding — same convention as `lyra-empty`'s `compact`.
|
|
24
28
|
*/
|
|
25
29
|
export declare class LyraWidget extends LyraElement {
|
|
26
30
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -30,6 +34,12 @@ export declare class LyraWidget extends LyraElement {
|
|
|
30
34
|
collapsed: boolean;
|
|
31
35
|
expandable: boolean;
|
|
32
36
|
fullscreen: boolean;
|
|
37
|
+
/** Raw CSS `inset` shorthand applied to the fullscreen panel and backdrop instead of the default
|
|
38
|
+
* `var(--lyra-space-l)` on every side — e.g. `"0 0 0 240px"` to leave a 240px persistent sidebar
|
|
39
|
+
* visible while fullscreen. */
|
|
40
|
+
fullscreenInset: string;
|
|
41
|
+
/** Tighter header/body padding for constrained spaces. */
|
|
42
|
+
compact: boolean;
|
|
33
43
|
private hasActionsSlot;
|
|
34
44
|
private releaseScrollLock?;
|
|
35
45
|
private lastTrigger?;
|
|
@@ -69,6 +69,10 @@ function isRendered(el) {
|
|
|
69
69
|
* @csspart fullscreen-button - The fullscreen toggle button.
|
|
70
70
|
* @csspart body - The wrapper around the default slot (the panel body).
|
|
71
71
|
* @csspart backdrop - The fullscreen scrim behind the panel.
|
|
72
|
+
*
|
|
73
|
+
* `fullscreen-inset` overrides the default `var(--lyra-space-l)` inset applied to `[part="base"]`
|
|
74
|
+
* and `[part="backdrop"]` while fullscreen (e.g. `"0 0 0 240px"` to leave a persistent sidebar
|
|
75
|
+
* visible). `compact` tightens header/body padding — same convention as `lyra-empty`'s `compact`.
|
|
72
76
|
*/
|
|
73
77
|
export class LyraWidget extends LyraElement {
|
|
74
78
|
constructor() {
|
|
@@ -79,6 +83,12 @@ export class LyraWidget extends LyraElement {
|
|
|
79
83
|
this.collapsed = false;
|
|
80
84
|
this.expandable = false;
|
|
81
85
|
this.fullscreen = false;
|
|
86
|
+
/** Raw CSS `inset` shorthand applied to the fullscreen panel and backdrop instead of the default
|
|
87
|
+
* `var(--lyra-space-l)` on every side — e.g. `"0 0 0 240px"` to leave a 240px persistent sidebar
|
|
88
|
+
* visible while fullscreen. */
|
|
89
|
+
this.fullscreenInset = '';
|
|
90
|
+
/** Tighter header/body padding for constrained spaces. */
|
|
91
|
+
this.compact = false;
|
|
82
92
|
this.hasActionsSlot = false;
|
|
83
93
|
this.bodyId = nextId('widget-body');
|
|
84
94
|
this.onActionsSlotChange = (e) => {
|
|
@@ -221,13 +231,20 @@ export class LyraWidget extends LyraElement {
|
|
|
221
231
|
const hasLabel = this.label.length > 0;
|
|
222
232
|
const hasSublabel = this.sublabel.length > 0;
|
|
223
233
|
return html `
|
|
224
|
-
${this.fullscreen
|
|
234
|
+
${this.fullscreen
|
|
235
|
+
? html `<div
|
|
236
|
+
part="backdrop"
|
|
237
|
+
style=${this.fullscreenInset ? `--lyra-widget-fullscreen-inset:${this.fullscreenInset}` : nothing}
|
|
238
|
+
@click=${this.onBackdropClick}
|
|
239
|
+
></div>`
|
|
240
|
+
: nothing}
|
|
225
241
|
<div
|
|
226
242
|
part="base"
|
|
227
243
|
role=${this.fullscreen ? 'dialog' : nothing}
|
|
228
244
|
aria-modal=${this.fullscreen ? 'true' : nothing}
|
|
229
245
|
aria-label=${this.fullscreen ? (hasLabel ? this.label : 'Fullscreen panel') : nothing}
|
|
230
246
|
tabindex=${this.fullscreen ? '-1' : nothing}
|
|
247
|
+
style=${this.fullscreenInset ? `--lyra-widget-fullscreen-inset:${this.fullscreenInset}` : nothing}
|
|
231
248
|
>
|
|
232
249
|
<div part="header">
|
|
233
250
|
<div part="title">
|
|
@@ -288,6 +305,12 @@ __decorate([
|
|
|
288
305
|
__decorate([
|
|
289
306
|
property({ type: Boolean, reflect: true })
|
|
290
307
|
], LyraWidget.prototype, "fullscreen", void 0);
|
|
308
|
+
__decorate([
|
|
309
|
+
property({ attribute: 'fullscreen-inset' })
|
|
310
|
+
], LyraWidget.prototype, "fullscreenInset", void 0);
|
|
311
|
+
__decorate([
|
|
312
|
+
property({ type: Boolean, reflect: true })
|
|
313
|
+
], LyraWidget.prototype, "compact", void 0);
|
|
291
314
|
__decorate([
|
|
292
315
|
state()
|
|
293
316
|
], LyraWidget.prototype, "hasActionsSlot", void 0);
|
|
@@ -39,3 +39,36 @@ export const FullscreenInitially = {
|
|
|
39
39
|
</lyra-widget>
|
|
40
40
|
`,
|
|
41
41
|
};
|
|
42
|
+
export const FullscreenWithSidebarInset = {
|
|
43
|
+
render: () => html `
|
|
44
|
+
<div style="position: relative;">
|
|
45
|
+
<div
|
|
46
|
+
style="position: fixed; inset: 0 auto 0 0; inline-size: 240px; background: #1e293b; color: #fff; padding: 1rem; z-index: 1001;"
|
|
47
|
+
>
|
|
48
|
+
Persistent sidebar (stays visible above the widget's fullscreen panel)
|
|
49
|
+
</div>
|
|
50
|
+
<lyra-widget
|
|
51
|
+
label="Load profile"
|
|
52
|
+
sublabel="Last 7 days"
|
|
53
|
+
expandable
|
|
54
|
+
fullscreen
|
|
55
|
+
fullscreen-inset="0 0 0 240px"
|
|
56
|
+
style="max-width: 28rem;"
|
|
57
|
+
>
|
|
58
|
+
<div style="padding: 1rem;">
|
|
59
|
+
<p style="margin: 0;">
|
|
60
|
+
Fullscreen with <code>fullscreen-inset="0 0 0 240px"</code> — the panel and backdrop leave
|
|
61
|
+
room for the 240px sidebar instead of covering it.
|
|
62
|
+
</p>
|
|
63
|
+
</div>
|
|
64
|
+
</lyra-widget>
|
|
65
|
+
</div>
|
|
66
|
+
`,
|
|
67
|
+
};
|
|
68
|
+
export const Compact = {
|
|
69
|
+
render: () => html `
|
|
70
|
+
<lyra-widget label="Alerts" sublabel="3 active" compact collapsible expandable style="max-width: 28rem;">
|
|
71
|
+
<div style="padding: 0.5rem;">Tighter header/body padding for constrained spaces.</div>
|
|
72
|
+
</lyra-widget>
|
|
73
|
+
`,
|
|
74
|
+
};
|
|
@@ -6,6 +6,7 @@ export const styles = css `
|
|
|
6
6
|
without a raw literal leaking into the public API (no shared
|
|
7
7
|
--wa-*-overlay token exists in the design system to resolve through). */
|
|
8
8
|
--lyra-widget-overlay-color: rgb(0 0 0 / 0.5);
|
|
9
|
+
--lyra-widget-fullscreen-inset: var(--lyra-space-l);
|
|
9
10
|
}
|
|
10
11
|
[part='base'] {
|
|
11
12
|
display: flex;
|
|
@@ -77,13 +78,13 @@ export const styles = css `
|
|
|
77
78
|
}
|
|
78
79
|
[part='backdrop'] {
|
|
79
80
|
position: fixed;
|
|
80
|
-
inset: 0;
|
|
81
|
+
inset: var(--lyra-widget-fullscreen-inset, 0);
|
|
81
82
|
background: var(--lyra-widget-overlay-color);
|
|
82
83
|
z-index: 999;
|
|
83
84
|
}
|
|
84
85
|
:host([fullscreen]) [part='base'] {
|
|
85
86
|
position: fixed;
|
|
86
|
-
inset: var(--lyra-
|
|
87
|
+
inset: var(--lyra-widget-fullscreen-inset);
|
|
87
88
|
z-index: 1000;
|
|
88
89
|
box-shadow: var(--lyra-shadow);
|
|
89
90
|
}
|
|
@@ -91,6 +92,12 @@ export const styles = css `
|
|
|
91
92
|
overflow: auto;
|
|
92
93
|
block-size: 100%;
|
|
93
94
|
}
|
|
95
|
+
:host([compact]) [part='header'] {
|
|
96
|
+
padding: var(--lyra-space-xs) var(--lyra-space-s);
|
|
97
|
+
}
|
|
98
|
+
:host([compact]) [part='body'] {
|
|
99
|
+
padding: var(--lyra-space-s);
|
|
100
|
+
}
|
|
94
101
|
@media (prefers-reduced-motion: reduce) {
|
|
95
102
|
[part='collapse-button'],
|
|
96
103
|
[part='fullscreen-button'] {
|