@aceshooting/lyra-ui 0.1.1 → 0.1.3
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 +77 -6
- package/custom-elements.json +12015 -0
- package/dist/components/chart/bar-chart.d.ts +14 -0
- package/dist/components/chart/bar-chart.js +14 -0
- package/dist/components/chart/box-plot.d.ts +46 -0
- package/dist/components/chart/box-plot.js +145 -0
- package/dist/components/chart/box-plot.styles.d.ts +1 -0
- package/dist/components/chart/box-plot.styles.js +22 -0
- package/dist/components/chart/bubble-chart.d.ts +19 -0
- package/dist/components/chart/bubble-chart.js +18 -0
- package/dist/components/chart/chart-loader.d.ts +8 -0
- package/dist/components/chart/chart-loader.js +26 -0
- package/dist/components/chart/chart.d.ts +91 -0
- package/dist/components/chart/chart.js +275 -0
- package/dist/components/chart/chart.styles.d.ts +1 -0
- package/dist/components/chart/chart.styles.js +33 -0
- package/dist/components/chart/doughnut-chart.d.ts +15 -0
- package/dist/components/chart/doughnut-chart.js +14 -0
- package/dist/components/chart/histogram-bin.d.ts +6 -0
- package/dist/components/chart/histogram-bin.js +19 -0
- package/dist/components/chart/histogram.d.ts +20 -0
- package/dist/components/chart/histogram.js +70 -0
- package/dist/components/chart/histogram.styles.d.ts +1 -0
- package/dist/components/chart/histogram.styles.js +1 -0
- package/dist/components/chart/line-chart.d.ts +14 -0
- package/dist/components/chart/line-chart.js +14 -0
- package/dist/components/chart/pie-chart.d.ts +16 -0
- package/dist/components/chart/pie-chart.js +15 -0
- package/dist/components/chart/polar-area-chart.d.ts +15 -0
- package/dist/components/chart/polar-area-chart.js +14 -0
- package/dist/components/chart/radar-chart.d.ts +15 -0
- package/dist/components/chart/radar-chart.js +14 -0
- package/dist/components/chart/scatter-chart.d.ts +15 -0
- package/dist/components/chart/scatter-chart.js +15 -0
- package/dist/components/combobox/combobox.d.ts +16 -0
- package/dist/components/combobox/combobox.js +113 -6
- package/dist/components/combobox/combobox.styles.js +68 -7
- package/dist/components/combobox/option.d.ts +2 -2
- package/dist/components/combobox/option.js +11 -7
- package/dist/components/date-picker/date-input.d.ts +12 -1
- package/dist/components/date-picker/date-input.js +68 -6
- package/dist/components/date-picker/date-input.styles.js +58 -6
- package/dist/components/date-picker/date-picker.js +5 -2
- package/dist/components/date-picker/date-picker.styles.js +9 -2
- package/dist/components/empty/empty.d.ts +1 -0
- package/dist/components/empty/empty.js +14 -2
- package/dist/components/export-button/csv.d.ts +10 -0
- package/dist/components/export-button/csv.js +28 -0
- package/dist/components/export-button/export-button.d.ts +41 -0
- package/dist/components/export-button/export-button.js +151 -0
- package/dist/components/export-button/export-button.styles.d.ts +1 -0
- package/dist/components/export-button/export-button.styles.js +79 -0
- package/dist/components/file-input/accept.d.ts +14 -0
- package/dist/components/file-input/accept.js +30 -0
- package/dist/components/file-input/file-input.d.ts +47 -0
- package/dist/components/file-input/file-input.js +182 -0
- package/dist/components/file-input/file-input.styles.d.ts +1 -0
- package/dist/components/file-input/file-input.styles.js +44 -0
- package/dist/components/flag/flag.d.ts +4 -0
- package/dist/components/flag/flag.js +24 -1
- package/dist/components/flag/flag.styles.js +1 -1
- package/dist/components/gauge/gauge.d.ts +29 -0
- package/dist/components/gauge/gauge.js +133 -0
- package/dist/components/gauge/gauge.styles.d.ts +1 -0
- package/dist/components/gauge/gauge.styles.js +60 -0
- package/dist/components/graph/graph.d.ts +68 -0
- package/dist/components/graph/graph.js +276 -0
- package/dist/components/graph/graph.styles.d.ts +1 -0
- package/dist/components/graph/graph.styles.js +34 -0
- package/dist/components/heatmap/heatmap-scale.d.ts +8 -0
- package/dist/components/heatmap/heatmap-scale.js +17 -0
- package/dist/components/heatmap/heatmap.d.ts +66 -0
- package/dist/components/heatmap/heatmap.js +252 -0
- package/dist/components/heatmap/heatmap.styles.d.ts +1 -0
- package/dist/components/heatmap/heatmap.styles.js +39 -0
- package/dist/components/map/map-loader.d.ts +8 -0
- package/dist/components/map/map-loader.js +17 -0
- package/dist/components/map/map.d.ts +49 -0
- package/dist/components/map/map.js +189 -0
- package/dist/components/map/map.styles.d.ts +1 -0
- package/dist/components/map/map.styles.js +48 -0
- package/dist/components/playback/playback.d.ts +51 -0
- package/dist/components/playback/playback.js +146 -0
- package/dist/components/playback/playback.styles.d.ts +1 -0
- package/dist/components/playback/playback.styles.js +40 -0
- package/dist/components/split/split.d.ts +41 -0
- package/dist/components/split/split.js +171 -0
- package/dist/components/split/split.styles.d.ts +1 -0
- package/dist/components/split/split.styles.js +51 -0
- package/dist/components/stat/stat.d.ts +9 -0
- package/dist/components/stat/stat.js +52 -7
- package/dist/components/stat/stat.styles.js +15 -5
- package/dist/components/table/table.d.ts +18 -6
- package/dist/components/table/table.js +76 -24
- package/dist/components/table/table.styles.js +32 -0
- package/dist/components/time-range/time-range.d.ts +40 -0
- package/dist/components/time-range/time-range.js +219 -0
- package/dist/components/time-range/time-range.styles.d.ts +1 -0
- package/dist/components/time-range/time-range.styles.js +78 -0
- package/dist/components/toast/toast-item.js +10 -2
- package/dist/components/toast/toast-item.styles.js +13 -4
- package/dist/components/toast/toast.styles.js +0 -1
- package/dist/components/tree/tree-node.d.ts +50 -0
- package/dist/components/tree/tree-node.js +196 -0
- package/dist/components/tree/tree.d.ts +65 -0
- package/dist/components/tree/tree.js +227 -0
- package/dist/components/tree/tree.styles.d.ts +1 -0
- package/dist/components/tree/tree.styles.js +13 -0
- package/dist/internal/form-associated.js +49 -1
- package/dist/internal/icons.d.ts +11 -0
- package/dist/internal/icons.js +64 -0
- package/dist/internal/tokens.styles.js +41 -1
- package/dist/lyra.d.ts +67 -0
- package/dist/lyra.js +55 -0
- package/llms-full.txt +1425 -0
- package/llms.txt +47 -0
- package/package.json +53 -4
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
2
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
|
+
import './tree-node.js';
|
|
4
|
+
export interface TreeItem {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
children?: TreeItem[];
|
|
8
|
+
badge?: string | number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `<lyra-tree>` — an expand/collapse hierarchy for graph/document navigation.
|
|
12
|
+
*
|
|
13
|
+
* Implements the WAI-ARIA treeitem keyboard pattern: a single roving
|
|
14
|
+
* `tabindex` (tracked here as `activeId`, pushed down to every
|
|
15
|
+
* `<lyra-tree-node>` — including nested ones, recursively) and
|
|
16
|
+
* ArrowUp/Down/Right/Left/Home/End/Enter/Space handled by one delegated
|
|
17
|
+
* `keydown` listener. Native `KeyboardEvent`s are `composed: true` and
|
|
18
|
+
* bubble across shadow-DOM boundaries, so a press inside a deeply-nested
|
|
19
|
+
* `<lyra-tree-node>`'s own shadow root still reaches this listener.
|
|
20
|
+
*
|
|
21
|
+
* @customElement lyra-tree
|
|
22
|
+
* @event lyra-node-toggle - `detail: { id, expanded }`, re-emitted from a child `<lyra-tree-node>`.
|
|
23
|
+
* @event lyra-node-select - `detail: { id }`, re-emitted from a child `<lyra-tree-node>`.
|
|
24
|
+
* @csspart base
|
|
25
|
+
* @slot - `<lyra-tree-node>` elements (top-level tree items).
|
|
26
|
+
*/
|
|
27
|
+
export declare class LyraTree extends LyraElement {
|
|
28
|
+
static styles: import("lit").CSSResultGroup[];
|
|
29
|
+
data: TreeItem[];
|
|
30
|
+
private activeId;
|
|
31
|
+
private get nodeElements();
|
|
32
|
+
private childrenOf;
|
|
33
|
+
/** Every currently *visible* (ancestor-expanded) node, top-to-bottom. */
|
|
34
|
+
private visibleNodeElements;
|
|
35
|
+
private findItem;
|
|
36
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
37
|
+
protected updated(changed: PropertyValues): void;
|
|
38
|
+
/** Unchanged from the existing implementation — by-id reconciliation of top-level items. */
|
|
39
|
+
private syncNodes;
|
|
40
|
+
private focusNode;
|
|
41
|
+
/**
|
|
42
|
+
* `updated()` only pushes the new `activeId` to *top-level* nodes; a
|
|
43
|
+
* nested node only receives it once its ancestor chain's own renders
|
|
44
|
+
* cascade it down (one more pending update per depth level). Cascade
|
|
45
|
+
* `updateComplete` itself to match: awaiting `<lyra-tree>`'s (or any
|
|
46
|
+
* `<lyra-tree-node>`'s — see the matching override there) `updateComplete`
|
|
47
|
+
* now transitively waits for every visible descendant node's own update,
|
|
48
|
+
* not just this element's. Without this, `focusNode()`'s `.focus()` call
|
|
49
|
+
* can run while a nested target is still mid-cascade (no `tabindex`
|
|
50
|
+
* attribute committed yet), and `.focus()` on an element with no
|
|
51
|
+
* `tabindex` attribute at all is a silent no-op.
|
|
52
|
+
*/
|
|
53
|
+
protected getUpdateComplete(): Promise<boolean>;
|
|
54
|
+
private onTreeKeyDown;
|
|
55
|
+
/** Expand every node in the tree, recursively. (unchanged) */
|
|
56
|
+
expandAll(): void;
|
|
57
|
+
/** Collapse every node in the tree. (unchanged) */
|
|
58
|
+
collapseAll(): void;
|
|
59
|
+
render(): TemplateResult;
|
|
60
|
+
}
|
|
61
|
+
declare global {
|
|
62
|
+
interface HTMLElementTagNameMap {
|
|
63
|
+
'lyra-tree': LyraTree;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { html } from 'lit';
|
|
8
|
+
import { property, state } from 'lit/decorators.js';
|
|
9
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
10
|
+
import { defineElement } from '../../internal/prefix.js';
|
|
11
|
+
import { styles } from './tree.styles.js';
|
|
12
|
+
import './tree-node.js';
|
|
13
|
+
/**
|
|
14
|
+
* `<lyra-tree>` — an expand/collapse hierarchy for graph/document navigation.
|
|
15
|
+
*
|
|
16
|
+
* Implements the WAI-ARIA treeitem keyboard pattern: a single roving
|
|
17
|
+
* `tabindex` (tracked here as `activeId`, pushed down to every
|
|
18
|
+
* `<lyra-tree-node>` — including nested ones, recursively) and
|
|
19
|
+
* ArrowUp/Down/Right/Left/Home/End/Enter/Space handled by one delegated
|
|
20
|
+
* `keydown` listener. Native `KeyboardEvent`s are `composed: true` and
|
|
21
|
+
* bubble across shadow-DOM boundaries, so a press inside a deeply-nested
|
|
22
|
+
* `<lyra-tree-node>`'s own shadow root still reaches this listener.
|
|
23
|
+
*
|
|
24
|
+
* @customElement lyra-tree
|
|
25
|
+
* @event lyra-node-toggle - `detail: { id, expanded }`, re-emitted from a child `<lyra-tree-node>`.
|
|
26
|
+
* @event lyra-node-select - `detail: { id }`, re-emitted from a child `<lyra-tree-node>`.
|
|
27
|
+
* @csspart base
|
|
28
|
+
* @slot - `<lyra-tree-node>` elements (top-level tree items).
|
|
29
|
+
*/
|
|
30
|
+
export class LyraTree extends LyraElement {
|
|
31
|
+
constructor() {
|
|
32
|
+
super(...arguments);
|
|
33
|
+
this.data = [];
|
|
34
|
+
this.activeId = null;
|
|
35
|
+
this.onTreeKeyDown = (e) => {
|
|
36
|
+
const visible = this.visibleNodeElements();
|
|
37
|
+
if (visible.length === 0)
|
|
38
|
+
return;
|
|
39
|
+
const currentIndex = visible.findIndex((n) => n.item.id === this.activeId);
|
|
40
|
+
const current = currentIndex >= 0 ? visible[currentIndex] : visible[0];
|
|
41
|
+
switch (e.key) {
|
|
42
|
+
case 'ArrowDown':
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
this.focusNode(visible[Math.min(visible.length - 1, currentIndex + 1)]);
|
|
45
|
+
break;
|
|
46
|
+
case 'ArrowUp':
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
this.focusNode(visible[Math.max(0, currentIndex - 1)]);
|
|
49
|
+
break;
|
|
50
|
+
case 'Home':
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
this.focusNode(visible[0]);
|
|
53
|
+
break;
|
|
54
|
+
case 'End':
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
this.focusNode(visible[visible.length - 1]);
|
|
57
|
+
break;
|
|
58
|
+
case 'ArrowRight':
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
if (!current.hasChildren)
|
|
61
|
+
break;
|
|
62
|
+
if (!current.expanded) {
|
|
63
|
+
current.expand(); // focus stays put; a 2nd ArrowRight steps into the first child
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const child = visible[currentIndex + 1];
|
|
67
|
+
if (child && child.depth > current.depth)
|
|
68
|
+
this.focusNode(child);
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
case 'ArrowLeft':
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
if (current.hasChildren && current.expanded) {
|
|
74
|
+
current.collapse();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
for (let i = currentIndex - 1; i >= 0; i--) {
|
|
78
|
+
if (visible[i].depth < current.depth) {
|
|
79
|
+
this.focusNode(visible[i]);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
case 'Enter':
|
|
86
|
+
case ' ':
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
current.select();
|
|
89
|
+
break;
|
|
90
|
+
default:
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
static { this.styles = [LyraElement.styles, styles]; }
|
|
96
|
+
get nodeElements() {
|
|
97
|
+
return [...this.querySelectorAll('lyra-tree-node')];
|
|
98
|
+
}
|
|
99
|
+
childrenOf(node) {
|
|
100
|
+
return [...(node.shadowRoot?.querySelectorAll('lyra-tree-node') ?? [])];
|
|
101
|
+
}
|
|
102
|
+
/** Every currently *visible* (ancestor-expanded) node, top-to-bottom. */
|
|
103
|
+
visibleNodeElements() {
|
|
104
|
+
const acc = [];
|
|
105
|
+
const walk = (nodes) => {
|
|
106
|
+
for (const n of nodes) {
|
|
107
|
+
acc.push(n);
|
|
108
|
+
if (n.expanded)
|
|
109
|
+
walk(this.childrenOf(n));
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
walk(this.nodeElements);
|
|
113
|
+
return acc;
|
|
114
|
+
}
|
|
115
|
+
findItem(items, id) {
|
|
116
|
+
for (const item of items) {
|
|
117
|
+
if (item.id === id)
|
|
118
|
+
return item;
|
|
119
|
+
const nested = item.children && this.findItem(item.children, id);
|
|
120
|
+
if (nested)
|
|
121
|
+
return nested;
|
|
122
|
+
}
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
willUpdate(changed) {
|
|
126
|
+
if (changed.has('data')) {
|
|
127
|
+
this.syncNodes();
|
|
128
|
+
if (!this.activeId || !this.findItem(this.data, this.activeId)) {
|
|
129
|
+
this.activeId = this.data[0]?.id ?? null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
updated(changed) {
|
|
134
|
+
if (changed.has('activeId') || changed.has('data')) {
|
|
135
|
+
const count = this.data.length;
|
|
136
|
+
this.nodeElements.forEach((node, i) => {
|
|
137
|
+
node.activeId = this.activeId;
|
|
138
|
+
node.setSize = count;
|
|
139
|
+
node.posInSet = i + 1;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Unchanged from the existing implementation — by-id reconciliation of top-level items. */
|
|
144
|
+
syncNodes() {
|
|
145
|
+
const existingById = new Map();
|
|
146
|
+
for (const node of this.nodeElements) {
|
|
147
|
+
if (node.item)
|
|
148
|
+
existingById.set(node.item.id, node);
|
|
149
|
+
}
|
|
150
|
+
const seen = new Set();
|
|
151
|
+
let previousSibling = null;
|
|
152
|
+
for (const item of this.data) {
|
|
153
|
+
const reused = !seen.has(item.id) ? existingById.get(item.id) : undefined;
|
|
154
|
+
const node = reused ?? document.createElement('lyra-tree-node');
|
|
155
|
+
node.item = item;
|
|
156
|
+
node.depth = 0;
|
|
157
|
+
seen.add(item.id);
|
|
158
|
+
const targetPosition = previousSibling
|
|
159
|
+
? previousSibling.nextElementSibling
|
|
160
|
+
: this.firstElementChild;
|
|
161
|
+
if (targetPosition !== node)
|
|
162
|
+
this.insertBefore(node, targetPosition);
|
|
163
|
+
previousSibling = node;
|
|
164
|
+
}
|
|
165
|
+
for (const [id, node] of existingById) {
|
|
166
|
+
if (!seen.has(id))
|
|
167
|
+
node.remove();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
focusNode(node) {
|
|
171
|
+
if (!node)
|
|
172
|
+
return;
|
|
173
|
+
this.activeId = node.item.id;
|
|
174
|
+
node.focus();
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* `updated()` only pushes the new `activeId` to *top-level* nodes; a
|
|
178
|
+
* nested node only receives it once its ancestor chain's own renders
|
|
179
|
+
* cascade it down (one more pending update per depth level). Cascade
|
|
180
|
+
* `updateComplete` itself to match: awaiting `<lyra-tree>`'s (or any
|
|
181
|
+
* `<lyra-tree-node>`'s — see the matching override there) `updateComplete`
|
|
182
|
+
* now transitively waits for every visible descendant node's own update,
|
|
183
|
+
* not just this element's. Without this, `focusNode()`'s `.focus()` call
|
|
184
|
+
* can run while a nested target is still mid-cascade (no `tabindex`
|
|
185
|
+
* attribute committed yet), and `.focus()` on an element with no
|
|
186
|
+
* `tabindex` attribute at all is a silent no-op.
|
|
187
|
+
*/
|
|
188
|
+
async getUpdateComplete() {
|
|
189
|
+
const result = await super.getUpdateComplete();
|
|
190
|
+
await Promise.all(this.nodeElements.map((n) => n.updateComplete));
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
/** Expand every node in the tree, recursively. (unchanged) */
|
|
194
|
+
expandAll() {
|
|
195
|
+
const setAll = (nodes) => {
|
|
196
|
+
for (const n of nodes) {
|
|
197
|
+
n.expanded = true;
|
|
198
|
+
void n.updateComplete.then(() => setAll(this.childrenOf(n)));
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
setAll(this.nodeElements);
|
|
202
|
+
}
|
|
203
|
+
/** Collapse every node in the tree. (unchanged) */
|
|
204
|
+
collapseAll() {
|
|
205
|
+
const setAll = (nodes) => {
|
|
206
|
+
for (const n of nodes) {
|
|
207
|
+
setAll(this.childrenOf(n));
|
|
208
|
+
n.expanded = false;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
setAll(this.nodeElements);
|
|
212
|
+
}
|
|
213
|
+
render() {
|
|
214
|
+
return html `
|
|
215
|
+
<div part="base" role="tree" @keydown=${this.onTreeKeyDown}>
|
|
216
|
+
<slot></slot>
|
|
217
|
+
</div>
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
__decorate([
|
|
222
|
+
property({ attribute: false })
|
|
223
|
+
], LyraTree.prototype, "data", void 0);
|
|
224
|
+
__decorate([
|
|
225
|
+
state()
|
|
226
|
+
], LyraTree.prototype, "activeId", void 0);
|
|
227
|
+
defineElement('tree', LyraTree);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import("lit").CSSResult;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
export const styles = css `
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
}
|
|
6
|
+
[part='base'] {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
/* Fallback for a deeply-indented node whose row still overflows despite
|
|
10
|
+
the [part=label] truncation + padding-inline-start cap in tree-node.ts. */
|
|
11
|
+
overflow-x: auto;
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
@@ -24,6 +24,16 @@ export function FormAssociated(Base) {
|
|
|
24
24
|
this.disabled = false;
|
|
25
25
|
this.required = false;
|
|
26
26
|
this._value = '';
|
|
27
|
+
// What native `defaultValue`/`form.reset()` restores to. Mirrors the
|
|
28
|
+
// `value` *content attribute* only (see `attributeChangedCallback`
|
|
29
|
+
// below) — exactly like native `<input>`: setting the `.value` IDL
|
|
30
|
+
// property (whether from a user typing, a picker commit, or a
|
|
31
|
+
// consumer's own script) never touches `defaultValue`, only
|
|
32
|
+
// `setAttribute('value', ...)`/declarative markup does. Using the
|
|
33
|
+
// property setter itself to capture "whichever assignment happens
|
|
34
|
+
// first" would wrongly let a user's first-ever edit become permanent
|
|
35
|
+
// (a required field could never be reset back to blank again).
|
|
36
|
+
this._defaultValue = '';
|
|
27
37
|
this.internals = this.attachInternals();
|
|
28
38
|
}
|
|
29
39
|
get value() {
|
|
@@ -33,12 +43,36 @@ export function FormAssociated(Base) {
|
|
|
33
43
|
const old = this._value;
|
|
34
44
|
this._value = next ?? '';
|
|
35
45
|
this.internals.setFormValue(this._value);
|
|
46
|
+
this.updateValidity();
|
|
36
47
|
this.requestUpdate('value', old);
|
|
37
48
|
}
|
|
49
|
+
attributeChangedCallback(name, old, value) {
|
|
50
|
+
super.attributeChangedCallback(name, old, value);
|
|
51
|
+
if (name === 'value') {
|
|
52
|
+
// Runs after the base class has already applied the attribute to
|
|
53
|
+
// the `value` property (via the setter above), so `_value` here
|
|
54
|
+
// reflects the newly-parsed/assigned attribute value.
|
|
55
|
+
this._defaultValue = this._value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
38
58
|
/** Programmatically set the submitted value (alias kept for clarity). */
|
|
39
59
|
setFormValue(next) {
|
|
40
60
|
this.value = next;
|
|
41
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Recomputes `ElementInternals`'s validity state. Without this,
|
|
64
|
+
* `internals` defaults to permanently "valid" and `required` never
|
|
65
|
+
* blocks form submission — the single highest-leverage correctness gap
|
|
66
|
+
* the 2026-07-10 cross-repo audit found (forms-core §internal/, High).
|
|
67
|
+
*/
|
|
68
|
+
updateValidity() {
|
|
69
|
+
if (this.required && this._value === '') {
|
|
70
|
+
this.internals.setValidity({ valueMissing: true }, 'Please fill out this field.');
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.internals.setValidity({});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
42
76
|
checkValidity() {
|
|
43
77
|
return this.internals.checkValidity();
|
|
44
78
|
}
|
|
@@ -46,11 +80,25 @@ export function FormAssociated(Base) {
|
|
|
46
80
|
return this.internals.reportValidity();
|
|
47
81
|
}
|
|
48
82
|
formResetCallback() {
|
|
49
|
-
|
|
83
|
+
// Restore the constructed default value (native `defaultValue`
|
|
84
|
+
// semantics) — previously this unconditionally blanked the field.
|
|
85
|
+
this.value = this._defaultValue;
|
|
50
86
|
}
|
|
51
87
|
formDisabledCallback(disabled) {
|
|
52
88
|
this.disabled = disabled;
|
|
53
89
|
}
|
|
90
|
+
connectedCallback() {
|
|
91
|
+
super.connectedCallback();
|
|
92
|
+
// `required` may already be set from an attribute by the time this
|
|
93
|
+
// runs; reflect validity from the start, not only after the first
|
|
94
|
+
// `value` write.
|
|
95
|
+
this.updateValidity();
|
|
96
|
+
}
|
|
97
|
+
updated(changed) {
|
|
98
|
+
super.updated(changed);
|
|
99
|
+
if (changed.has('required'))
|
|
100
|
+
this.updateValidity();
|
|
101
|
+
}
|
|
54
102
|
}
|
|
55
103
|
return FormAssociatedElement;
|
|
56
104
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type SVGTemplateResult } from 'lit';
|
|
2
|
+
/** A single right-pointing chevron. Rotate the wrapping element for other directions. */
|
|
3
|
+
export declare function chevronIcon(): SVGTemplateResult;
|
|
4
|
+
/** An "x" close/clear glyph. */
|
|
5
|
+
export declare function closeIcon(): SVGTemplateResult;
|
|
6
|
+
/** A right-pointing play triangle. */
|
|
7
|
+
export declare function playIcon(): SVGTemplateResult;
|
|
8
|
+
/** Two vertical pause bars. */
|
|
9
|
+
export declare function pauseIcon(): SVGTemplateResult;
|
|
10
|
+
/** A calendar/date glyph, for date-input's open-calendar toggle. */
|
|
11
|
+
export declare function calendarIcon(): SVGTemplateResult;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { svg } from 'lit';
|
|
2
|
+
/**
|
|
3
|
+
* Shared inline-SVG icon set. Every component in this library previously
|
|
4
|
+
* rendered functional icons (chevrons, close buttons, play/pause, the
|
|
5
|
+
* date-input calendar toggle) as literal Unicode/HTML-entity/emoji text
|
|
6
|
+
* glyphs — font-dependent, non-recolorable beyond plain text color, and
|
|
7
|
+
* inconsistent in weight/size across the OS/browser font stack a host page
|
|
8
|
+
* happens to ship (2026-07-10 design review). These replace all of them.
|
|
9
|
+
*
|
|
10
|
+
* Every icon shares one 24x24 viewBox and one stroke-width so the whole set
|
|
11
|
+
* reads as one visual language; each renders at `1em` so it inherits the
|
|
12
|
+
* caller's own font-size instead of imposing a fixed pixel size. None bakes
|
|
13
|
+
* in a direction/rotation — callers needing "up"/"left"/"open" etc. rotate
|
|
14
|
+
* the *wrapping part element* via CSS `transform: rotate(...)`, not the svg.
|
|
15
|
+
*/
|
|
16
|
+
const STROKE_WIDTH = '1.75';
|
|
17
|
+
const VIEW_BOX = '0 0 24 24';
|
|
18
|
+
function icon(paths) {
|
|
19
|
+
return svg `
|
|
20
|
+
<svg
|
|
21
|
+
width="1em"
|
|
22
|
+
height="1em"
|
|
23
|
+
viewBox=${VIEW_BOX}
|
|
24
|
+
fill="none"
|
|
25
|
+
stroke="currentColor"
|
|
26
|
+
stroke-width=${STROKE_WIDTH}
|
|
27
|
+
stroke-linecap="round"
|
|
28
|
+
stroke-linejoin="round"
|
|
29
|
+
aria-hidden="true"
|
|
30
|
+
focusable="false"
|
|
31
|
+
>${paths}</svg>
|
|
32
|
+
`;
|
|
33
|
+
}
|
|
34
|
+
/** A single right-pointing chevron. Rotate the wrapping element for other directions. */
|
|
35
|
+
export function chevronIcon() {
|
|
36
|
+
return icon(svg `<polyline points="9 6 15 12 9 18"></polyline>`);
|
|
37
|
+
}
|
|
38
|
+
/** An "x" close/clear glyph. */
|
|
39
|
+
export function closeIcon() {
|
|
40
|
+
return icon(svg `
|
|
41
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
42
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
43
|
+
`);
|
|
44
|
+
}
|
|
45
|
+
/** A right-pointing play triangle. */
|
|
46
|
+
export function playIcon() {
|
|
47
|
+
return icon(svg `<polygon points="6 4 20 12 6 20 6 4"></polygon>`);
|
|
48
|
+
}
|
|
49
|
+
/** Two vertical pause bars. */
|
|
50
|
+
export function pauseIcon() {
|
|
51
|
+
return icon(svg `
|
|
52
|
+
<rect x="6" y="4" width="4" height="16" rx="1"></rect>
|
|
53
|
+
<rect x="14" y="4" width="4" height="16" rx="1"></rect>
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
/** A calendar/date glyph, for date-input's open-calendar toggle. */
|
|
57
|
+
export function calendarIcon() {
|
|
58
|
+
return icon(svg `
|
|
59
|
+
<rect x="3" y="5" width="18" height="16" rx="2"></rect>
|
|
60
|
+
<line x1="16" y1="3" x2="16" y2="7"></line>
|
|
61
|
+
<line x1="8" y1="3" x2="8" y2="7"></line>
|
|
62
|
+
<line x1="3" y1="10" x2="21" y2="10"></line>
|
|
63
|
+
`);
|
|
64
|
+
}
|
|
@@ -6,7 +6,7 @@ export const tokens = css `
|
|
|
6
6
|
--lyra-color-surface: var(--wa-color-surface-default, #fff);
|
|
7
7
|
--lyra-color-text: var(--wa-color-text-normal, #1a1a1a);
|
|
8
8
|
--lyra-color-text-quiet: var(--wa-color-text-quiet, #6b7280);
|
|
9
|
-
--lyra-color-border: var(--wa-color-neutral-fill-normal, #
|
|
9
|
+
--lyra-color-border: var(--wa-color-neutral-fill-normal, #8a8a90);
|
|
10
10
|
--lyra-color-brand: var(--wa-color-brand-fill-loud, #0969da);
|
|
11
11
|
--lyra-color-brand-quiet: var(--wa-color-brand-fill-quiet, #ddf4ff);
|
|
12
12
|
--lyra-color-success: var(--wa-color-success-fill-loud, #1a7f37);
|
|
@@ -20,10 +20,50 @@ export const tokens = css `
|
|
|
20
20
|
--lyra-shadow: var(--wa-shadow-m, 0 2px 8px rgb(0 0 0 / 0.15));
|
|
21
21
|
--lyra-font: var(--wa-font-family-body, system-ui, sans-serif);
|
|
22
22
|
|
|
23
|
+
/* Motion — every component that animates (popovers, gauge fill, toast)
|
|
24
|
+
reads from these two instead of hand-rolling its own duration/easing,
|
|
25
|
+
so the library has one consistent rhythm (2026-07-10 design review). */
|
|
26
|
+
--lyra-transition-fast: var(--wa-transition-fast, 120ms ease-out);
|
|
27
|
+
--lyra-transition-base: var(--wa-transition-normal, 180ms ease-out);
|
|
28
|
+
|
|
29
|
+
/* Disabled state — one opacity value for every disabled control,
|
|
30
|
+
replacing three previously-independent hardcoded values (0.5/0.4/0.35). */
|
|
31
|
+
--lyra-opacity-disabled: var(--wa-opacity-disabled, 0.5);
|
|
32
|
+
|
|
33
|
+
/* Focus ring — every :focus-visible rule in the library should reference
|
|
34
|
+
these three instead of hardcoding its own width/color/offset. */
|
|
35
|
+
--lyra-focus-ring-width: 2px;
|
|
36
|
+
--lyra-focus-ring-color: var(--lyra-color-brand);
|
|
37
|
+
--lyra-focus-ring-offset: 2px;
|
|
38
|
+
|
|
39
|
+
/* Minimum tappable box for an icon-only button (close/dismiss/nav
|
|
40
|
+
controls). Visual icon size is unaffected; components pad out to this
|
|
41
|
+
via min-inline-size/min-block-size, not by growing the glyph itself. */
|
|
42
|
+
--lyra-icon-button-size: 2.5rem;
|
|
43
|
+
|
|
23
44
|
font-family: var(--lyra-font);
|
|
24
45
|
color: var(--lyra-color-text);
|
|
25
46
|
box-sizing: border-box;
|
|
26
47
|
}
|
|
48
|
+
|
|
49
|
+
/* Standalone (no Web Awesome theme) dark-mode fallback. A real --wa-* value
|
|
50
|
+
from a consumer's theme always wins — this only changes what a bare
|
|
51
|
+
lyra-ui component renders when dropped, unstyled, onto a dark host page
|
|
52
|
+
(2026-07-10 design review: previously zero dark-mode adaptation existed
|
|
53
|
+
in the pure-fallback case). */
|
|
54
|
+
@media (prefers-color-scheme: dark) {
|
|
55
|
+
:host {
|
|
56
|
+
--lyra-color-surface: var(--wa-color-surface-default, #1a1a1a);
|
|
57
|
+
--lyra-color-text: var(--wa-color-text-normal, #f2f2f2);
|
|
58
|
+
--lyra-color-text-quiet: var(--wa-color-text-quiet, #9aa1ac);
|
|
59
|
+
--lyra-color-border: var(--wa-color-neutral-fill-normal, #4a4a52);
|
|
60
|
+
--lyra-color-brand: var(--wa-color-brand-fill-loud, #4d9fef);
|
|
61
|
+
--lyra-color-brand-quiet: var(--wa-color-brand-fill-quiet, #163650);
|
|
62
|
+
--lyra-color-success: var(--wa-color-success-fill-loud, #3fb950);
|
|
63
|
+
--lyra-color-warning: var(--wa-color-warning-fill-loud, #d29922);
|
|
64
|
+
--lyra-color-danger: var(--wa-color-danger-fill-loud, #f85149);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
27
67
|
:host([hidden]) {
|
|
28
68
|
display: none !important;
|
|
29
69
|
}
|
package/dist/lyra.d.ts
CHANGED
|
@@ -6,6 +6,32 @@ import './components/combobox/option.js';
|
|
|
6
6
|
import './components/date-picker/date-picker.js';
|
|
7
7
|
import './components/date-picker/date-input.js';
|
|
8
8
|
import './components/flag/flag.js';
|
|
9
|
+
import './components/empty/empty.js';
|
|
10
|
+
import './components/skeleton/skeleton.js';
|
|
11
|
+
import './components/stat/stat.js';
|
|
12
|
+
import './components/table/table.js';
|
|
13
|
+
import './components/gauge/gauge.js';
|
|
14
|
+
import './components/export-button/export-button.js';
|
|
15
|
+
import './components/split/split.js';
|
|
16
|
+
import './components/time-range/time-range.js';
|
|
17
|
+
import './components/playback/playback.js';
|
|
18
|
+
import './components/heatmap/heatmap.js';
|
|
19
|
+
import './components/graph/graph.js';
|
|
20
|
+
import './components/tree/tree.js';
|
|
21
|
+
import './components/tree/tree-node.js';
|
|
22
|
+
import './components/chart/chart.js';
|
|
23
|
+
import './components/chart/bar-chart.js';
|
|
24
|
+
import './components/chart/line-chart.js';
|
|
25
|
+
import './components/chart/pie-chart.js';
|
|
26
|
+
import './components/chart/doughnut-chart.js';
|
|
27
|
+
import './components/chart/scatter-chart.js';
|
|
28
|
+
import './components/chart/bubble-chart.js';
|
|
29
|
+
import './components/chart/radar-chart.js';
|
|
30
|
+
import './components/chart/polar-area-chart.js';
|
|
31
|
+
import './components/chart/box-plot.js';
|
|
32
|
+
import './components/chart/histogram.js';
|
|
33
|
+
import './components/map/map.js';
|
|
34
|
+
import './components/file-input/file-input.js';
|
|
9
35
|
export { LyraSparkline } from './components/sparkline/sparkline.js';
|
|
10
36
|
export { LyraToast } from './components/toast/toast.js';
|
|
11
37
|
export type { ToastPlacement, ToastCreateOptions } from './components/toast/toast.js';
|
|
@@ -21,6 +47,47 @@ export type { DateRange } from './components/date-picker/date-picker.js';
|
|
|
21
47
|
export { LyraDateInput } from './components/date-picker/date-input.js';
|
|
22
48
|
export { LyraFlag } from './components/flag/flag.js';
|
|
23
49
|
export { LANGUAGE_TO_COUNTRY, languageToCountry } from './components/flag/language-map.js';
|
|
50
|
+
export { LyraEmpty } from './components/empty/empty.js';
|
|
51
|
+
export { LyraSkeleton } from './components/skeleton/skeleton.js';
|
|
52
|
+
export type { SkeletonVariant, SkeletonEffect } from './components/skeleton/skeleton.js';
|
|
53
|
+
export { LyraStat } from './components/stat/stat.js';
|
|
54
|
+
export type { StatVariant } from './components/stat/stat.js';
|
|
55
|
+
export { LyraTable } from './components/table/table.js';
|
|
56
|
+
export type { TableColumn } from './components/table/table.js';
|
|
57
|
+
export { LyraGauge } from './components/gauge/gauge.js';
|
|
58
|
+
export type { GaugeType } from './components/gauge/gauge.js';
|
|
59
|
+
export { LyraExportButton } from './components/export-button/export-button.js';
|
|
60
|
+
export type { ExportFormat } from './components/export-button/export-button.js';
|
|
61
|
+
export { escapeCsvField, buildCsv, downloadBlob } from './components/export-button/csv.js';
|
|
62
|
+
export type { CsvColumn } from './components/export-button/csv.js';
|
|
63
|
+
export { LyraSplit } from './components/split/split.js';
|
|
64
|
+
export { LyraTimeRange } from './components/time-range/time-range.js';
|
|
65
|
+
export { LyraPlayback } from './components/playback/playback.js';
|
|
66
|
+
export { LyraHeatmap } from './components/heatmap/heatmap.js';
|
|
67
|
+
export { linearAlpha, sqrtStep } from './components/heatmap/heatmap-scale.js';
|
|
68
|
+
export { LyraGraph } from './components/graph/graph.js';
|
|
69
|
+
export type { GraphNode, GraphLink } from './components/graph/graph.js';
|
|
70
|
+
export { LyraTree } from './components/tree/tree.js';
|
|
71
|
+
export type { TreeItem } from './components/tree/tree.js';
|
|
72
|
+
export { LyraTreeNode } from './components/tree/tree-node.js';
|
|
73
|
+
export { LyraChart } from './components/chart/chart.js';
|
|
74
|
+
export type { Series, LyraChartType } from './components/chart/chart.js';
|
|
75
|
+
export { LyraBarChart } from './components/chart/bar-chart.js';
|
|
76
|
+
export { LyraLineChart } from './components/chart/line-chart.js';
|
|
77
|
+
export { LyraPieChart } from './components/chart/pie-chart.js';
|
|
78
|
+
export { LyraDoughnutChart } from './components/chart/doughnut-chart.js';
|
|
79
|
+
export { LyraScatterChart } from './components/chart/scatter-chart.js';
|
|
80
|
+
export { LyraBubbleChart } from './components/chart/bubble-chart.js';
|
|
81
|
+
export { LyraRadarChart } from './components/chart/radar-chart.js';
|
|
82
|
+
export { LyraPolarAreaChart } from './components/chart/polar-area-chart.js';
|
|
83
|
+
export { LyraBoxPlot } from './components/chart/box-plot.js';
|
|
84
|
+
export type { BoxPlotSeries, BoxPlotPoint } from './components/chart/box-plot.js';
|
|
85
|
+
export { LyraHistogram } from './components/chart/histogram.js';
|
|
86
|
+
export { binValues } from './components/chart/histogram-bin.js';
|
|
87
|
+
export type { HistogramBucket } from './components/chart/histogram-bin.js';
|
|
88
|
+
export { LyraMap } from './components/map/map.js';
|
|
89
|
+
export type { LegendEntry, ChoroplethLayer } from './components/map/map.js';
|
|
90
|
+
export { LyraFileInput } from './components/file-input/file-input.js';
|
|
24
91
|
export { LyraElement } from './internal/lyra-element.js';
|
|
25
92
|
export { FormAssociated } from './internal/form-associated.js';
|
|
26
93
|
export { LYRA_PREFIX, tag, defineElement } from './internal/prefix.js';
|