@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.
Files changed (117) hide show
  1. package/README.md +77 -6
  2. package/custom-elements.json +12015 -0
  3. package/dist/components/chart/bar-chart.d.ts +14 -0
  4. package/dist/components/chart/bar-chart.js +14 -0
  5. package/dist/components/chart/box-plot.d.ts +46 -0
  6. package/dist/components/chart/box-plot.js +145 -0
  7. package/dist/components/chart/box-plot.styles.d.ts +1 -0
  8. package/dist/components/chart/box-plot.styles.js +22 -0
  9. package/dist/components/chart/bubble-chart.d.ts +19 -0
  10. package/dist/components/chart/bubble-chart.js +18 -0
  11. package/dist/components/chart/chart-loader.d.ts +8 -0
  12. package/dist/components/chart/chart-loader.js +26 -0
  13. package/dist/components/chart/chart.d.ts +91 -0
  14. package/dist/components/chart/chart.js +275 -0
  15. package/dist/components/chart/chart.styles.d.ts +1 -0
  16. package/dist/components/chart/chart.styles.js +33 -0
  17. package/dist/components/chart/doughnut-chart.d.ts +15 -0
  18. package/dist/components/chart/doughnut-chart.js +14 -0
  19. package/dist/components/chart/histogram-bin.d.ts +6 -0
  20. package/dist/components/chart/histogram-bin.js +19 -0
  21. package/dist/components/chart/histogram.d.ts +20 -0
  22. package/dist/components/chart/histogram.js +70 -0
  23. package/dist/components/chart/histogram.styles.d.ts +1 -0
  24. package/dist/components/chart/histogram.styles.js +1 -0
  25. package/dist/components/chart/line-chart.d.ts +14 -0
  26. package/dist/components/chart/line-chart.js +14 -0
  27. package/dist/components/chart/pie-chart.d.ts +16 -0
  28. package/dist/components/chart/pie-chart.js +15 -0
  29. package/dist/components/chart/polar-area-chart.d.ts +15 -0
  30. package/dist/components/chart/polar-area-chart.js +14 -0
  31. package/dist/components/chart/radar-chart.d.ts +15 -0
  32. package/dist/components/chart/radar-chart.js +14 -0
  33. package/dist/components/chart/scatter-chart.d.ts +15 -0
  34. package/dist/components/chart/scatter-chart.js +15 -0
  35. package/dist/components/combobox/combobox.d.ts +16 -0
  36. package/dist/components/combobox/combobox.js +113 -6
  37. package/dist/components/combobox/combobox.styles.js +68 -7
  38. package/dist/components/combobox/option.d.ts +2 -2
  39. package/dist/components/combobox/option.js +11 -7
  40. package/dist/components/date-picker/date-input.d.ts +12 -1
  41. package/dist/components/date-picker/date-input.js +68 -6
  42. package/dist/components/date-picker/date-input.styles.js +58 -6
  43. package/dist/components/date-picker/date-picker.js +5 -2
  44. package/dist/components/date-picker/date-picker.styles.js +9 -2
  45. package/dist/components/empty/empty.d.ts +1 -0
  46. package/dist/components/empty/empty.js +14 -2
  47. package/dist/components/export-button/csv.d.ts +10 -0
  48. package/dist/components/export-button/csv.js +28 -0
  49. package/dist/components/export-button/export-button.d.ts +41 -0
  50. package/dist/components/export-button/export-button.js +151 -0
  51. package/dist/components/export-button/export-button.styles.d.ts +1 -0
  52. package/dist/components/export-button/export-button.styles.js +79 -0
  53. package/dist/components/file-input/accept.d.ts +14 -0
  54. package/dist/components/file-input/accept.js +30 -0
  55. package/dist/components/file-input/file-input.d.ts +47 -0
  56. package/dist/components/file-input/file-input.js +182 -0
  57. package/dist/components/file-input/file-input.styles.d.ts +1 -0
  58. package/dist/components/file-input/file-input.styles.js +44 -0
  59. package/dist/components/flag/flag.d.ts +4 -0
  60. package/dist/components/flag/flag.js +24 -1
  61. package/dist/components/flag/flag.styles.js +1 -1
  62. package/dist/components/gauge/gauge.d.ts +29 -0
  63. package/dist/components/gauge/gauge.js +133 -0
  64. package/dist/components/gauge/gauge.styles.d.ts +1 -0
  65. package/dist/components/gauge/gauge.styles.js +60 -0
  66. package/dist/components/graph/graph.d.ts +68 -0
  67. package/dist/components/graph/graph.js +276 -0
  68. package/dist/components/graph/graph.styles.d.ts +1 -0
  69. package/dist/components/graph/graph.styles.js +34 -0
  70. package/dist/components/heatmap/heatmap-scale.d.ts +8 -0
  71. package/dist/components/heatmap/heatmap-scale.js +17 -0
  72. package/dist/components/heatmap/heatmap.d.ts +66 -0
  73. package/dist/components/heatmap/heatmap.js +252 -0
  74. package/dist/components/heatmap/heatmap.styles.d.ts +1 -0
  75. package/dist/components/heatmap/heatmap.styles.js +39 -0
  76. package/dist/components/map/map-loader.d.ts +8 -0
  77. package/dist/components/map/map-loader.js +17 -0
  78. package/dist/components/map/map.d.ts +49 -0
  79. package/dist/components/map/map.js +189 -0
  80. package/dist/components/map/map.styles.d.ts +1 -0
  81. package/dist/components/map/map.styles.js +48 -0
  82. package/dist/components/playback/playback.d.ts +51 -0
  83. package/dist/components/playback/playback.js +146 -0
  84. package/dist/components/playback/playback.styles.d.ts +1 -0
  85. package/dist/components/playback/playback.styles.js +40 -0
  86. package/dist/components/split/split.d.ts +41 -0
  87. package/dist/components/split/split.js +171 -0
  88. package/dist/components/split/split.styles.d.ts +1 -0
  89. package/dist/components/split/split.styles.js +51 -0
  90. package/dist/components/stat/stat.d.ts +9 -0
  91. package/dist/components/stat/stat.js +52 -7
  92. package/dist/components/stat/stat.styles.js +15 -5
  93. package/dist/components/table/table.d.ts +18 -6
  94. package/dist/components/table/table.js +76 -24
  95. package/dist/components/table/table.styles.js +32 -0
  96. package/dist/components/time-range/time-range.d.ts +40 -0
  97. package/dist/components/time-range/time-range.js +219 -0
  98. package/dist/components/time-range/time-range.styles.d.ts +1 -0
  99. package/dist/components/time-range/time-range.styles.js +78 -0
  100. package/dist/components/toast/toast-item.js +10 -2
  101. package/dist/components/toast/toast-item.styles.js +13 -4
  102. package/dist/components/toast/toast.styles.js +0 -1
  103. package/dist/components/tree/tree-node.d.ts +50 -0
  104. package/dist/components/tree/tree-node.js +196 -0
  105. package/dist/components/tree/tree.d.ts +65 -0
  106. package/dist/components/tree/tree.js +227 -0
  107. package/dist/components/tree/tree.styles.d.ts +1 -0
  108. package/dist/components/tree/tree.styles.js +13 -0
  109. package/dist/internal/form-associated.js +49 -1
  110. package/dist/internal/icons.d.ts +11 -0
  111. package/dist/internal/icons.js +64 -0
  112. package/dist/internal/tokens.styles.js +41 -1
  113. package/dist/lyra.d.ts +67 -0
  114. package/dist/lyra.js +55 -0
  115. package/llms-full.txt +1425 -0
  116. package/llms.txt +47 -0
  117. package/package.json +53 -4
@@ -0,0 +1,39 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ /* Sequential ramp endpoints for the data-driven cell colors (canvas can't
6
+ consume var() directly, so heatmap.ts resolves these via
7
+ getComputedStyle and interpolates between them). Componentspecific
8
+ business color per Global Constraints — exposed so hosts can retheme
9
+ the ramp without raw hex leaking into the public API. */
10
+ --lyra-heatmap-scale-lo: #cde2fb;
11
+ --lyra-heatmap-scale-hi: #0969da;
12
+ }
13
+ [part='base'] {
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: var(--lyra-space-xs);
17
+ }
18
+ canvas {
19
+ display: block;
20
+ inline-size: 100%;
21
+ }
22
+ [part='legend'] {
23
+ display: flex;
24
+ align-items: center;
25
+ gap: var(--lyra-space-xs);
26
+ font-size: 0.75rem;
27
+ color: var(--lyra-color-text-quiet);
28
+ }
29
+ [part='legend'] .bar {
30
+ inline-size: 6rem;
31
+ block-size: 0.5rem;
32
+ border-radius: 2px;
33
+ background: linear-gradient(
34
+ to right,
35
+ var(--lyra-heatmap-scale-lo),
36
+ var(--lyra-heatmap-scale-hi)
37
+ );
38
+ }
39
+ `;
@@ -0,0 +1,8 @@
1
+ import type * as MaplibreModule from 'maplibre-gl';
2
+ /**
3
+ * Lazily loads the optional peer dependency `maplibre-gl` once per page.
4
+ * Resolves to `null` (with a one-time warning) if it isn't installed —
5
+ * mirrors `<lyra-flag>`'s peer-dependency pattern. Consumers must separately
6
+ * import `maplibre-gl/dist/maplibre-gl.css` once they install the peer.
7
+ */
8
+ export declare function loadMaplibre(): Promise<typeof MaplibreModule | null>;
@@ -0,0 +1,17 @@
1
+ let maplibre;
2
+ /**
3
+ * Lazily loads the optional peer dependency `maplibre-gl` once per page.
4
+ * Resolves to `null` (with a one-time warning) if it isn't installed —
5
+ * mirrors `<lyra-flag>`'s peer-dependency pattern. Consumers must separately
6
+ * import `maplibre-gl/dist/maplibre-gl.css` once they install the peer.
7
+ */
8
+ export function loadMaplibre() {
9
+ if (!maplibre) {
10
+ maplibre = import('maplibre-gl').catch(() => {
11
+ console.warn('<lyra-map> needs the optional peer dependency `maplibre-gl` — install it with ' +
12
+ '`pnpm add maplibre-gl` and import `maplibre-gl/dist/maplibre-gl.css` once in your app.');
13
+ return null;
14
+ });
15
+ }
16
+ return maplibre;
17
+ }
@@ -0,0 +1,49 @@
1
+ import { type TemplateResult, type PropertyValues } from 'lit';
2
+ import type { Map as MaplibreMap, StyleSpecification } from 'maplibre-gl';
3
+ import { LyraElement } from '../../internal/lyra-element.js';
4
+ import '../skeleton/skeleton.js';
5
+ export interface LegendEntry {
6
+ color: string;
7
+ label: string;
8
+ }
9
+ export interface ChoroplethLayer {
10
+ sourceId: string;
11
+ geojson: GeoJSON.FeatureCollection;
12
+ field: string;
13
+ stops: [number, string][];
14
+ }
15
+ /**
16
+ * `<lyra-map>` — a maplibre-gl wrapper with a declarative legend and
17
+ * choropleth GeoJSON layer, plus a raw `map` escape hatch. Requires the
18
+ * optional peer dep `maplibre-gl` (consumers also import its CSS once).
19
+ *
20
+ * @customElement lyra-map
21
+ * @event lyra-map-load - Fired once the underlying maplibregl.Map loads.
22
+ * @event lyra-map-click - `detail: { lngLat, feature? }`.
23
+ * @csspart base, container, legend, legend-swatch
24
+ */
25
+ export declare class LyraMap extends LyraElement {
26
+ static styles: import("lit").CSSResultGroup[];
27
+ center: [number, number];
28
+ zoom: number;
29
+ mapStyle: StyleSpecification | string;
30
+ legend: LegendEntry[];
31
+ choropleth?: ChoroplethLayer;
32
+ /** True until the lazy-loaded `maplibre-gl` peer dependency has settled (success or failure). */
33
+ private loading;
34
+ private containerEl?;
35
+ private _map?;
36
+ private _styleLoaded;
37
+ /** The raw `maplibregl.Map` instance — escape hatch for anything this wrapper doesn't expose. */
38
+ get map(): MaplibreMap | undefined;
39
+ connectedCallback(): void;
40
+ disconnectedCallback(): void;
41
+ protected updated(changed: PropertyValues): void;
42
+ private applyChoropleth;
43
+ render(): TemplateResult;
44
+ }
45
+ declare global {
46
+ interface HTMLElementTagNameMap {
47
+ 'lyra-map': LyraMap;
48
+ }
49
+ }
@@ -0,0 +1,189 @@
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
+ /// <reference types="geojson" />
8
+ import { html, nothing } from 'lit';
9
+ import { property, query, state } from 'lit/decorators.js';
10
+ import { LyraElement } from '../../internal/lyra-element.js';
11
+ import { defineElement } from '../../internal/prefix.js';
12
+ import { loadMaplibre } from './map-loader.js';
13
+ import { styles } from './map.styles.js';
14
+ import '../skeleton/skeleton.js';
15
+ const DEFAULT_STYLE = {
16
+ version: 8,
17
+ sources: {
18
+ 'lyra-osm': {
19
+ type: 'raster',
20
+ tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
21
+ tileSize: 256,
22
+ attribution: '© OpenStreetMap contributors',
23
+ },
24
+ },
25
+ layers: [{ id: 'lyra-osm', type: 'raster', source: 'lyra-osm' }],
26
+ };
27
+ /**
28
+ * `<lyra-map>` — a maplibre-gl wrapper with a declarative legend and
29
+ * choropleth GeoJSON layer, plus a raw `map` escape hatch. Requires the
30
+ * optional peer dep `maplibre-gl` (consumers also import its CSS once).
31
+ *
32
+ * @customElement lyra-map
33
+ * @event lyra-map-load - Fired once the underlying maplibregl.Map loads.
34
+ * @event lyra-map-click - `detail: { lngLat, feature? }`.
35
+ * @csspart base, container, legend, legend-swatch
36
+ */
37
+ export class LyraMap extends LyraElement {
38
+ constructor() {
39
+ super(...arguments);
40
+ this.center = [0, 0];
41
+ this.zoom = 2;
42
+ this.mapStyle = DEFAULT_STYLE;
43
+ this.legend = [];
44
+ /** True until the lazy-loaded `maplibre-gl` peer dependency has settled (success or failure). */
45
+ this.loading = true;
46
+ // Tracks whether the style has fired its initial 'load' (i.e. addSource/
47
+ // addLayer/setPaintProperty are now safe to call), rather than re-querying
48
+ // `this._map.isStyleLoaded()`: that also reflects in-flight *tile* loading
49
+ // for every source, so it flips back to `false` as soon as the choropleth's
50
+ // own GeoJSON source is added — which would wrongly block subsequent
51
+ // choropleth updates from ever re-running.
52
+ this._styleLoaded = false;
53
+ }
54
+ static { this.styles = [LyraElement.styles, styles]; }
55
+ /** The raw `maplibregl.Map` instance — escape hatch for anything this wrapper doesn't expose. */
56
+ get map() {
57
+ return this._map;
58
+ }
59
+ connectedCallback() {
60
+ super.connectedCallback();
61
+ void loadMaplibre().then(async (mod) => {
62
+ this.loading = false;
63
+ if (!mod)
64
+ return;
65
+ // `[part="container"]` only exists once `loading` flips to `false` and
66
+ // Lit re-renders — wait for that render to land before querying it.
67
+ await this.updateComplete;
68
+ // The element may have been removed from the DOM while the async
69
+ // loadMaplibre()/updateComplete window was in flight — don't spin up
70
+ // a maplibre Map (WebGL context + event listeners) for a detached
71
+ // instance (disconnectedCallback's cleanup already ran).
72
+ if (!this.containerEl || !this.isConnected)
73
+ return;
74
+ this._map = new mod.Map({
75
+ container: this.containerEl,
76
+ style: this.mapStyle,
77
+ center: this.center,
78
+ zoom: this.zoom,
79
+ });
80
+ this._map.on('load', () => {
81
+ this._styleLoaded = true;
82
+ this.applyChoropleth();
83
+ this.emit('lyra-map-load');
84
+ });
85
+ this._map.on('click', (e) => {
86
+ // Guard on the fill layer actually existing, not just `this.choropleth` being
87
+ // set: applyChoropleth() only adds it once the style has finished loading, so
88
+ // a click landing in that window (choropleth set before the map's own 'load')
89
+ // would otherwise query a layer id maplibre-gl doesn't know about yet.
90
+ const fillLayerId = this.choropleth ? `${this.choropleth.sourceId}-fill` : undefined;
91
+ const features = fillLayerId && this._map.getLayer(fillLayerId)
92
+ ? this._map.queryRenderedFeatures(e.point, { layers: [fillLayerId] })
93
+ : [];
94
+ this.emit('lyra-map-click', {
95
+ lngLat: [e.lngLat.lng, e.lngLat.lat],
96
+ feature: features[0],
97
+ });
98
+ });
99
+ });
100
+ }
101
+ disconnectedCallback() {
102
+ super.disconnectedCallback();
103
+ this._map?.remove();
104
+ this._map = undefined;
105
+ this._styleLoaded = false;
106
+ }
107
+ updated(changed) {
108
+ if (this.loading)
109
+ this.setAttribute('aria-busy', 'true');
110
+ else
111
+ this.removeAttribute('aria-busy');
112
+ if (changed.has('choropleth') && this._styleLoaded)
113
+ this.applyChoropleth();
114
+ if (changed.has('center') && this._map)
115
+ this._map.setCenter(this.center);
116
+ if (changed.has('zoom') && this._map)
117
+ this._map.setZoom(this.zoom);
118
+ }
119
+ applyChoropleth() {
120
+ if (!this.choropleth || !this._map)
121
+ return;
122
+ const { sourceId, geojson, field, stops } = this.choropleth;
123
+ const fillLayerId = `${sourceId}-fill`;
124
+ const colorExpr = ['interpolate', ['linear'], ['get', field]];
125
+ for (const [value, color] of stops)
126
+ colorExpr.push(value, color);
127
+ const existingSource = this._map.getSource(sourceId);
128
+ if (existingSource) {
129
+ // Re-apply both the data and the color expression: `field`/`stops` may have
130
+ // changed even though `sourceId` didn't (e.g. switching which metric colors
131
+ // the same GeoJSON), so the paint property must be refreshed too.
132
+ existingSource.setData(geojson);
133
+ this._map.setPaintProperty(fillLayerId, 'fill-color', colorExpr);
134
+ }
135
+ else {
136
+ this._map.addSource(sourceId, { type: 'geojson', data: geojson, promoteId: 'id' });
137
+ this._map.addLayer({
138
+ id: fillLayerId,
139
+ type: 'fill',
140
+ source: sourceId,
141
+ paint: { 'fill-color': colorExpr, 'fill-opacity': 0.75 },
142
+ });
143
+ }
144
+ }
145
+ render() {
146
+ // Lit's own whitespace/comment marker nodes around the `${...}` binding mean
147
+ // `[part="legend"]` is never truly `:empty` in CSS even with zero entries, so
148
+ // the panel is omitted from the template entirely when `legend` is empty
149
+ // (same `nothing` pattern `stat.ts` uses to omit its optional trend section)
150
+ // rather than relying on a CSS `:empty` selector that can never match.
151
+ return html `
152
+ <div part="base">
153
+ ${this.loading
154
+ ? html `<lyra-skeleton variant="rect"></lyra-skeleton>`
155
+ : html `<div part="container"></div>`}
156
+ ${this.legend.length
157
+ ? html `<div part="legend">
158
+ ${this.legend.map((entry) => html `<div class="legend-row">
159
+ <span part="legend-swatch" style=${`background:${entry.color}`}></span>
160
+ <span>${entry.label}</span>
161
+ </div>`)}
162
+ </div>`
163
+ : nothing}
164
+ </div>
165
+ `;
166
+ }
167
+ }
168
+ __decorate([
169
+ property({ type: Array })
170
+ ], LyraMap.prototype, "center", void 0);
171
+ __decorate([
172
+ property({ type: Number })
173
+ ], LyraMap.prototype, "zoom", void 0);
174
+ __decorate([
175
+ property({ attribute: false })
176
+ ], LyraMap.prototype, "mapStyle", void 0);
177
+ __decorate([
178
+ property({ attribute: false })
179
+ ], LyraMap.prototype, "legend", void 0);
180
+ __decorate([
181
+ property({ attribute: false })
182
+ ], LyraMap.prototype, "choropleth", void 0);
183
+ __decorate([
184
+ state()
185
+ ], LyraMap.prototype, "loading", void 0);
186
+ __decorate([
187
+ query('[part="container"]')
188
+ ], LyraMap.prototype, "containerEl", void 0);
189
+ defineElement('map', LyraMap);
@@ -0,0 +1 @@
1
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,48 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ position: relative;
6
+ inline-size: 100%;
7
+ block-size: 24rem;
8
+ }
9
+ [part='base'] {
10
+ position: relative;
11
+ inline-size: 100%;
12
+ block-size: 100%;
13
+ }
14
+ lyra-skeleton {
15
+ --lyra-skeleton-w: 100%;
16
+ --lyra-skeleton-h: 100%;
17
+ }
18
+ [part='container'] {
19
+ position: absolute;
20
+ inset: 0;
21
+ }
22
+ [part='legend'] {
23
+ position: absolute;
24
+ inset-block-end: var(--lyra-space-s);
25
+ inset-inline-start: var(--lyra-space-s);
26
+ z-index: 1;
27
+ display: flex;
28
+ flex-direction: column;
29
+ gap: 0.2rem;
30
+ padding: var(--lyra-space-xs) var(--lyra-space-s);
31
+ background: var(--lyra-color-surface);
32
+ border: 1px solid var(--lyra-color-border);
33
+ border-radius: var(--lyra-radius);
34
+ box-shadow: var(--lyra-shadow);
35
+ font-size: 0.75rem;
36
+ }
37
+ .legend-row {
38
+ display: flex;
39
+ align-items: center;
40
+ gap: 0.35rem;
41
+ }
42
+ [part='legend-swatch'] {
43
+ inline-size: 0.75rem;
44
+ block-size: 0.75rem;
45
+ border-radius: 2px;
46
+ flex: 0 0 auto;
47
+ }
48
+ `;
@@ -0,0 +1,51 @@
1
+ import { type TemplateResult, type PropertyValues } from 'lit';
2
+ import { LyraElement } from '../../internal/lyra-element.js';
3
+ /**
4
+ * `<lyra-playback>` — steps an index through `[0, length)` on a fixed
5
+ * interval (play/pause), like the manual play-timers duplicated across
6
+ * per-repo time-series dashboards.
7
+ *
8
+ * @customElement lyra-playback
9
+ * @event lyra-play
10
+ * @event lyra-pause
11
+ * @event lyra-step - `detail: { index }`, fired on every tick and manual step.
12
+ * @csspart base, play-button, slider
13
+ */
14
+ export declare class LyraPlayback extends LyraElement {
15
+ static styles: import("lit").CSSResultGroup[];
16
+ length: number;
17
+ index: number;
18
+ intervalMs: number;
19
+ playing: boolean;
20
+ loop: boolean;
21
+ /**
22
+ * Re-declared as a Lit reactive property (shadowing the inherited plain
23
+ * `HTMLElement.hidden` IDL property) so that setting `el.hidden = true` —
24
+ * or the `hidden` attribute — actually enters Lit's change-tracking system
25
+ * and the `willUpdate` auto-pause guard below can see it via `changed`.
26
+ * `reflect: true` preserves the native attribute-reflection behavior.
27
+ */
28
+ hidden: boolean;
29
+ private timer?;
30
+ disconnectedCallback(): void;
31
+ protected willUpdate(changed: PropertyValues): void;
32
+ /** Start playback; no-op if there's nothing to advance through. */
33
+ play(): void;
34
+ /** Stop playback. */
35
+ pause(): void;
36
+ toggle(): void;
37
+ private tick;
38
+ private setIndex;
39
+ /** Advance one step without starting playback. */
40
+ next(): void;
41
+ /** Go back one step without starting playback. */
42
+ previous(): void;
43
+ /** Jump to an explicit index, pausing playback. */
44
+ goTo(index: number): void;
45
+ render(): TemplateResult;
46
+ }
47
+ declare global {
48
+ interface HTMLElementTagNameMap {
49
+ 'lyra-playback': LyraPlayback;
50
+ }
51
+ }
@@ -0,0 +1,146 @@
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 } from 'lit/decorators.js';
9
+ import { LyraElement } from '../../internal/lyra-element.js';
10
+ import { defineElement } from '../../internal/prefix.js';
11
+ import { playIcon, pauseIcon } from '../../internal/icons.js';
12
+ import { styles } from './playback.styles.js';
13
+ /**
14
+ * `<lyra-playback>` — steps an index through `[0, length)` on a fixed
15
+ * interval (play/pause), like the manual play-timers duplicated across
16
+ * per-repo time-series dashboards.
17
+ *
18
+ * @customElement lyra-playback
19
+ * @event lyra-play
20
+ * @event lyra-pause
21
+ * @event lyra-step - `detail: { index }`, fired on every tick and manual step.
22
+ * @csspart base, play-button, slider
23
+ */
24
+ export class LyraPlayback extends LyraElement {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.length = 0;
28
+ this.index = 0;
29
+ this.intervalMs = 900;
30
+ this.playing = false;
31
+ this.loop = true;
32
+ /**
33
+ * Re-declared as a Lit reactive property (shadowing the inherited plain
34
+ * `HTMLElement.hidden` IDL property) so that setting `el.hidden = true` —
35
+ * or the `hidden` attribute — actually enters Lit's change-tracking system
36
+ * and the `willUpdate` auto-pause guard below can see it via `changed`.
37
+ * `reflect: true` preserves the native attribute-reflection behavior.
38
+ */
39
+ this.hidden = false;
40
+ }
41
+ static { this.styles = [LyraElement.styles, styles]; }
42
+ disconnectedCallback() {
43
+ super.disconnectedCallback();
44
+ this.pause();
45
+ }
46
+ willUpdate(changed) {
47
+ if (changed.has('hidden') && this.hidden)
48
+ this.pause();
49
+ }
50
+ /** Start playback; no-op if there's nothing to advance through. */
51
+ play() {
52
+ if (this.playing || this.length <= 1)
53
+ return;
54
+ this.playing = true;
55
+ this.emit('lyra-play');
56
+ this.timer = window.setInterval(() => this.tick(), this.intervalMs);
57
+ }
58
+ /** Stop playback. */
59
+ pause() {
60
+ if (!this.playing)
61
+ return;
62
+ window.clearInterval(this.timer);
63
+ this.timer = undefined;
64
+ this.playing = false;
65
+ this.emit('lyra-pause');
66
+ }
67
+ toggle() {
68
+ this.playing ? this.pause() : this.play();
69
+ }
70
+ tick() {
71
+ const next = this.index + 1;
72
+ if (next >= this.length) {
73
+ if (this.loop)
74
+ this.setIndex(0);
75
+ else {
76
+ this.setIndex(this.length - 1);
77
+ this.pause();
78
+ }
79
+ }
80
+ else {
81
+ this.setIndex(next);
82
+ }
83
+ }
84
+ setIndex(i) {
85
+ this.index = i;
86
+ this.emit('lyra-step', { index: this.index });
87
+ }
88
+ /** Advance one step without starting playback. */
89
+ next() {
90
+ if (this.index + 1 < this.length)
91
+ this.setIndex(this.index + 1);
92
+ }
93
+ /** Go back one step without starting playback. */
94
+ previous() {
95
+ if (this.index > 0)
96
+ this.setIndex(this.index - 1);
97
+ }
98
+ /** Jump to an explicit index, pausing playback. */
99
+ goTo(index) {
100
+ this.pause();
101
+ this.setIndex(Math.min(this.length - 1, Math.max(0, index)));
102
+ }
103
+ render() {
104
+ return html `
105
+ <div part="base">
106
+ <button
107
+ part="play-button"
108
+ type="button"
109
+ aria-label=${this.playing ? 'Pause' : 'Play'}
110
+ ?disabled=${this.length <= 1}
111
+ @click=${() => this.toggle()}
112
+ >
113
+ ${this.playing ? pauseIcon() : playIcon()}
114
+ </button>
115
+ <input
116
+ part="slider"
117
+ type="range"
118
+ min="0"
119
+ max=${Math.max(0, this.length - 1)}
120
+ .value=${String(this.index)}
121
+ aria-label="Playback position"
122
+ @input=${(e) => this.goTo(Number(e.target.value))}
123
+ />
124
+ </div>
125
+ `;
126
+ }
127
+ }
128
+ __decorate([
129
+ property({ type: Number })
130
+ ], LyraPlayback.prototype, "length", void 0);
131
+ __decorate([
132
+ property({ type: Number })
133
+ ], LyraPlayback.prototype, "index", void 0);
134
+ __decorate([
135
+ property({ type: Number, attribute: 'interval-ms' })
136
+ ], LyraPlayback.prototype, "intervalMs", void 0);
137
+ __decorate([
138
+ property({ type: Boolean, reflect: true })
139
+ ], LyraPlayback.prototype, "playing", void 0);
140
+ __decorate([
141
+ property({ type: Boolean })
142
+ ], LyraPlayback.prototype, "loop", void 0);
143
+ __decorate([
144
+ property({ type: Boolean, reflect: true })
145
+ ], LyraPlayback.prototype, "hidden", void 0);
146
+ defineElement('playback', LyraPlayback);
@@ -0,0 +1 @@
1
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,40 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ gap: var(--lyra-space-s);
7
+ }
8
+ [part='base'] {
9
+ display: flex;
10
+ align-items: center;
11
+ gap: var(--lyra-space-s);
12
+ }
13
+ [part='play-button'] {
14
+ inline-size: 2rem;
15
+ block-size: 2rem;
16
+ border-radius: 50%;
17
+ border: 1px solid var(--lyra-color-border);
18
+ background: var(--lyra-color-surface);
19
+ color: var(--lyra-color-text);
20
+ cursor: pointer;
21
+ display: inline-flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ font-size: 0.875rem;
25
+ }
26
+ [part='play-button']:hover {
27
+ border-color: var(--lyra-color-brand);
28
+ }
29
+ [part='play-button']:disabled {
30
+ opacity: var(--lyra-opacity-disabled);
31
+ cursor: not-allowed;
32
+ }
33
+ [part='play-button']:focus-visible {
34
+ outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
35
+ outline-offset: var(--lyra-focus-ring-offset);
36
+ }
37
+ [part='slider'] {
38
+ accent-color: var(--lyra-color-brand);
39
+ }
40
+ `;
@@ -0,0 +1,41 @@
1
+ import { type TemplateResult, type PropertyValues } from 'lit';
2
+ import { LyraElement } from '../../internal/lyra-element.js';
3
+ /**
4
+ * `<lyra-split>` — resizable panels for dashboard layouts. Direct light-DOM
5
+ * children are the panels; a divider is auto-inserted between each pair.
6
+ *
7
+ * @customElement lyra-split
8
+ * @event lyra-resize - `detail: { sizes }`, fired on every drag step/release
9
+ * and every keyboard step.
10
+ * @csspart base, divider
11
+ */
12
+ export declare class LyraSplit extends LyraElement {
13
+ static styles: import("lit").CSSResultGroup[];
14
+ sizes: number[];
15
+ min: number;
16
+ orientation: 'horizontal' | 'vertical';
17
+ storageKey?: string;
18
+ private panelCount;
19
+ private dragIndex;
20
+ private dragStartPos;
21
+ private dragStartSizes;
22
+ connectedCallback(): void;
23
+ disconnectedCallback(): void;
24
+ private get storageFullKey();
25
+ private loadPersisted;
26
+ private persist;
27
+ private ensureSizes;
28
+ private clampPair;
29
+ private applyDelta;
30
+ private onPointerDown;
31
+ private onPointerMove;
32
+ private onPointerUp;
33
+ private onDividerKeyDown;
34
+ protected updated(changed: PropertyValues): void;
35
+ render(): TemplateResult;
36
+ }
37
+ declare global {
38
+ interface HTMLElementTagNameMap {
39
+ 'lyra-split': LyraSplit;
40
+ }
41
+ }