@aceshooting/lyra-ui 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -9
- package/custom-elements.json +10463 -4519
- package/dist/components/chart/chart.d.ts +46 -1
- package/dist/components/chart/chart.js +148 -10
- package/dist/components/chart/chart.stories.d.ts +32 -0
- package/dist/components/chart/chart.stories.js +141 -0
- package/dist/components/chart/chart.styles.js +16 -0
- package/dist/components/chart/histogram.d.ts +2 -0
- package/dist/components/chart/histogram.js +18 -2
- package/dist/components/chart/line-chart.stories.d.ts +17 -0
- package/dist/components/chart/line-chart.stories.js +75 -0
- package/dist/components/chart/lite-chart.d.ts +74 -0
- package/dist/components/chart/lite-chart.js +384 -0
- package/dist/components/chart/lite-chart.stories.d.ts +12 -0
- package/dist/components/chart/lite-chart.stories.js +98 -0
- package/dist/components/chart/lite-chart.styles.d.ts +1 -0
- package/dist/components/chart/lite-chart.styles.js +83 -0
- package/dist/components/combobox/combobox.d.ts +9 -0
- package/dist/components/combobox/combobox.js +75 -12
- package/dist/components/combobox/combobox.stories.d.ts +18 -0
- package/dist/components/combobox/combobox.stories.js +75 -0
- package/dist/components/date-picker/calendar-core.js +13 -2
- package/dist/components/date-picker/date-input.d.ts +9 -1
- package/dist/components/date-picker/date-input.js +55 -7
- package/dist/components/date-picker/date-input.stories.d.ts +5 -0
- package/dist/components/date-picker/date-input.stories.js +36 -0
- package/dist/components/date-picker/date-picker.d.ts +11 -3
- package/dist/components/date-picker/date-picker.js +87 -37
- package/dist/components/date-picker/date-picker.stories.d.ts +4 -0
- package/dist/components/date-picker/date-picker.stories.js +12 -0
- package/dist/components/date-picker/date-picker.styles.js +1 -1
- package/dist/components/empty/empty.d.ts +12 -1
- package/dist/components/empty/empty.js +20 -3
- package/dist/components/empty/empty.stories.d.ts +2 -0
- package/dist/components/empty/empty.stories.js +20 -0
- package/dist/components/empty/empty.styles.js +11 -0
- package/dist/components/export-button/csv.js +6 -2
- package/dist/components/export-button/export-button.d.ts +15 -1
- package/dist/components/export-button/export-button.js +89 -12
- package/dist/components/export-button/export-button.stories.d.ts +1 -0
- package/dist/components/export-button/export-button.stories.js +5 -0
- package/dist/components/export-button/export-button.styles.js +11 -3
- package/dist/components/file-input/accept.d.ts +8 -2
- package/dist/components/file-input/accept.js +9 -3
- package/dist/components/file-input/file-input.d.ts +5 -2
- package/dist/components/file-input/file-input.js +23 -8
- package/dist/components/file-input/file-input.stories.d.ts +2 -0
- package/dist/components/file-input/file-input.stories.js +9 -0
- package/dist/components/flag/flag.d.ts +48 -3
- package/dist/components/flag/flag.js +65 -29
- package/dist/components/flag/flag.styles.js +1 -1
- package/dist/components/flag/language-map.d.ts +11 -0
- package/dist/components/flag/language-map.js +12 -1
- package/dist/components/gauge/gauge.d.ts +2 -0
- package/dist/components/gauge/gauge.js +19 -5
- package/dist/components/gauge/gauge.stories.d.ts +2 -0
- package/dist/components/gauge/gauge.stories.js +6 -0
- package/dist/components/graph/graph-loader.d.ts +28 -0
- package/dist/components/graph/graph-loader.js +44 -0
- package/dist/components/graph/graph.d.ts +41 -15
- package/dist/components/graph/graph.js +146 -71
- package/dist/components/graph/graph.stories.d.ts +3 -0
- package/dist/components/graph/graph.stories.js +38 -0
- package/dist/components/graph/graph.styles.js +6 -1
- package/dist/components/heatmap/calendar-grid.d.ts +7 -0
- package/dist/components/heatmap/calendar-grid.js +27 -10
- package/dist/components/heatmap/heatmap.d.ts +137 -12
- package/dist/components/heatmap/heatmap.js +427 -27
- package/dist/components/heatmap/heatmap.stories.d.ts +17 -0
- package/dist/components/heatmap/heatmap.stories.js +130 -0
- package/dist/components/heatmap/heatmap.styles.js +60 -2
- package/dist/components/map/map.d.ts +17 -1
- package/dist/components/map/map.js +68 -21
- package/dist/components/map/map.stories.d.ts +10 -0
- package/dist/components/map/map.stories.js +107 -12
- package/dist/components/map/map.styles.js +2 -2
- package/dist/components/playback/playback.d.ts +6 -2
- package/dist/components/playback/playback.js +36 -12
- package/dist/components/playback/playback.stories.d.ts +2 -0
- package/dist/components/playback/playback.stories.js +6 -0
- package/dist/components/playback/playback.styles.js +10 -2
- package/dist/components/select/select.d.ts +122 -0
- package/dist/components/select/select.js +516 -0
- package/dist/components/select/select.stories.d.ts +19 -0
- package/dist/components/select/select.stories.js +75 -0
- package/dist/components/select/select.styles.d.ts +1 -0
- package/dist/components/select/select.styles.js +188 -0
- package/dist/components/skeleton/skeleton.js +4 -7
- package/dist/components/sparkline/sparkline.d.ts +1 -1
- package/dist/components/sparkline/sparkline.js +40 -13
- package/dist/components/sparkline/sparkline.stories.d.ts +4 -0
- package/dist/components/sparkline/sparkline.stories.js +22 -0
- package/dist/components/split/split.d.ts +24 -3
- package/dist/components/split/split.js +155 -31
- package/dist/components/split/split.stories.d.ts +2 -0
- package/dist/components/split/split.stories.js +20 -0
- package/dist/components/stat/stat.d.ts +27 -1
- package/dist/components/stat/stat.js +56 -3
- package/dist/components/stat/stat.stories.d.ts +3 -0
- package/dist/components/stat/stat.stories.js +49 -1
- package/dist/components/stat/stat.styles.js +44 -0
- package/dist/components/table/table.d.ts +64 -2
- package/dist/components/table/table.js +213 -17
- package/dist/components/table/table.stories.d.ts +6 -0
- package/dist/components/table/table.stories.js +45 -0
- package/dist/components/table/table.styles.js +51 -4
- package/dist/components/time-range/time-range.d.ts +34 -5
- package/dist/components/time-range/time-range.js +217 -36
- package/dist/components/time-range/time-range.stories.d.ts +2 -0
- package/dist/components/time-range/time-range.stories.js +13 -0
- package/dist/components/time-range/time-range.styles.js +44 -2
- package/dist/components/toast/toast-item.d.ts +14 -2
- package/dist/components/toast/toast-item.js +134 -17
- package/dist/components/toast/toast-item.styles.js +28 -2
- package/dist/components/toast/toast.stories.d.ts +3 -0
- package/dist/components/toast/toast.stories.js +41 -1
- package/dist/components/toast/toast.styles.js +11 -11
- package/dist/components/toast/toaster.d.ts +1 -1
- package/dist/components/toast/toaster.js +13 -6
- package/dist/components/tree/tree-node.d.ts +13 -7
- package/dist/components/tree/tree-node.js +24 -10
- package/dist/components/tree/tree.d.ts +64 -15
- package/dist/components/tree/tree.js +113 -22
- package/dist/components/tree/tree.stories.d.ts +4 -0
- package/dist/components/tree/tree.stories.js +31 -1
- package/dist/components/tree/update-cascade.d.ts +13 -0
- package/dist/components/tree/update-cascade.js +13 -0
- package/dist/components/widget/widget.d.ts +15 -1
- package/dist/components/widget/widget.js +140 -5
- package/dist/components/widget/widget.stories.d.ts +1 -0
- package/dist/components/widget/widget.stories.js +10 -0
- package/dist/components/widget/widget.styles.js +11 -1
- package/dist/components/word-cloud/word-cloud-layout.d.ts +63 -0
- package/dist/components/word-cloud/word-cloud-layout.js +145 -0
- package/dist/components/word-cloud/word-cloud.d.ts +65 -0
- package/dist/components/word-cloud/word-cloud.js +255 -0
- package/dist/components/word-cloud/word-cloud.stories.d.ts +10 -0
- package/dist/components/word-cloud/word-cloud.stories.js +55 -0
- package/dist/components/word-cloud/word-cloud.styles.d.ts +1 -0
- package/dist/components/word-cloud/word-cloud.styles.js +54 -0
- package/dist/internal/a11y.js +2 -1
- package/dist/internal/rtl.d.ts +7 -0
- package/dist/internal/rtl.js +9 -0
- package/dist/lyra.d.ts +9 -1
- package/dist/lyra.js +6 -0
- package/llms-full.txt +892 -276
- package/llms.txt +12 -9
- package/package.json +6 -4
|
@@ -6,6 +6,15 @@ export interface TableColumn<T> {
|
|
|
6
6
|
label: string;
|
|
7
7
|
sortable?: boolean;
|
|
8
8
|
align?: 'start' | 'end';
|
|
9
|
+
/** Responsive priority — `undefined` (the default) means "always visible".
|
|
10
|
+
* `'low'` columns hide first (narrowest container), `'medium'` next, as
|
|
11
|
+
* `[part='base']`'s container-query width shrinks; both can be forced back
|
|
12
|
+
* on via `[part='reveal-columns-button']`. */
|
|
13
|
+
priority?: 'medium' | 'low';
|
|
14
|
+
/** Pins this column's header/cell to the inline-start edge with
|
|
15
|
+
* `position: sticky` so it stays visible while the table scrolls
|
|
16
|
+
* horizontally. */
|
|
17
|
+
sticky?: boolean;
|
|
9
18
|
cell: (row: T) => unknown;
|
|
10
19
|
}
|
|
11
20
|
/**
|
|
@@ -14,13 +23,31 @@ export interface TableColumn<T> {
|
|
|
14
23
|
* Header/row activation is delegated: one `click` and one `keydown`
|
|
15
24
|
* listener on `<table>` resolve the target via `closest('[data-col-key]'
|
|
16
25
|
* | '[data-row-key]')` and a key→object lookup map, instead of allocating
|
|
17
|
-
* fresh per-column/per-row closures on every render.
|
|
26
|
+
* fresh per-column/per-row closures on every render. Both listeners guard
|
|
27
|
+
* against nested interactive `cell()` content first (see
|
|
28
|
+
* `INTERACTIVE_SELECTOR`) so a button/link/input inside a cell owns its own
|
|
29
|
+
* activation instead of triggering `lyra-row-click`.
|
|
30
|
+
*
|
|
31
|
+
* Keyboard focus follows a roving-tabindex pattern (one `tabindex="0"` stop
|
|
32
|
+
* among the header cells, one among the body rows — see `focusedColKey()` /
|
|
33
|
+
* `focusedRowKey()`), matching this repo's other `role="grid"`/composite
|
|
34
|
+
* widgets. Left/Right/Home/End move within the header row; Up/Down/Home/End
|
|
35
|
+
* move within the body; Down from the header enters the body's roving stop,
|
|
36
|
+
* and Up from the body's first row returns to the header's roving stop.
|
|
37
|
+
* Enter/Space still only sort/activate (see `activateColumn()` /
|
|
38
|
+
* `activateRow()`).
|
|
39
|
+
*
|
|
40
|
+
* `columns[].priority` ('medium' | 'low') hides that column under
|
|
41
|
+
* `[part='base']`'s `@container` breakpoints; `[part='reveal-columns-button']`
|
|
42
|
+
* (rendered whenever any column has a priority) forces them all back into
|
|
43
|
+
* view. `columns[].sticky` pins a column's header/cells to the inline-start
|
|
44
|
+
* edge while the table scrolls horizontally.
|
|
18
45
|
*
|
|
19
46
|
* @customElement lyra-table
|
|
20
47
|
* @event lyra-sort - A sortable header was activated. `detail: { key }`.
|
|
21
48
|
* @event lyra-row-click - A row was activated. `detail: { row }`.
|
|
22
49
|
* @event lyra-load-more - The "load more" control was activated.
|
|
23
|
-
* @csspart base, table, head, header-cell, row, cell, more-button, sort-icon
|
|
50
|
+
* @csspart base, table, head, header-cell, row, cell, more-button, sort-icon, reveal-columns-button
|
|
24
51
|
*/
|
|
25
52
|
export declare class LyraTable<T = unknown> extends LyraElement {
|
|
26
53
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -28,6 +55,13 @@ export declare class LyraTable<T = unknown> extends LyraElement {
|
|
|
28
55
|
rows: T[];
|
|
29
56
|
sortKey: string;
|
|
30
57
|
sortDir: 'asc' | 'desc';
|
|
58
|
+
/** Derives each row's stable identity for `repeat()`'s DOM-reconciliation
|
|
59
|
+
* key and the delegated click/keydown row lookup (`rowsByKey`,
|
|
60
|
+
* `data-row-key`). When omitted, `keyOf()` falls back to the row's index
|
|
61
|
+
* in `rows`, which is only a safe identity while `rows` never reorders —
|
|
62
|
+
* provide `rowKey` whenever `rows` can be sorted, filtered, or otherwise
|
|
63
|
+
* re-ordered across renders, or row identity (selection, focus, click
|
|
64
|
+
* targets) can silently attach to the wrong row. */
|
|
31
65
|
rowKey?: (row: T) => string | number;
|
|
32
66
|
selectedKey: string | number | null;
|
|
33
67
|
hasMore: boolean;
|
|
@@ -36,14 +70,42 @@ export declare class LyraTable<T = unknown> extends LyraElement {
|
|
|
36
70
|
emptyDescription: string;
|
|
37
71
|
noColumnsHeading: string;
|
|
38
72
|
noColumnsDescription: string;
|
|
73
|
+
revealColumnsLabel: string;
|
|
74
|
+
hideColumnsLabel: string;
|
|
75
|
+
/** Forces `priority`-hidden columns back into view, overriding the
|
|
76
|
+
* `@container` hide rules in table.styles.ts. Toggled by
|
|
77
|
+
* `[part='reveal-columns-button']`. */
|
|
78
|
+
private showAllColumns;
|
|
79
|
+
/** Roving-tabindex position among header cells; `null` until a header is
|
|
80
|
+
* clicked/navigated to, at which point `focusedColKey()` falls back to
|
|
81
|
+
* the first column. */
|
|
82
|
+
private activeColKey;
|
|
83
|
+
/** Roving-tabindex position among body rows; `null` until a row is
|
|
84
|
+
* clicked/navigated to, at which point `focusedRowKey()` falls back to
|
|
85
|
+
* `selectedKey` (if it matches a row) or the first row. */
|
|
86
|
+
private activeRowKey;
|
|
39
87
|
private rowsByKey;
|
|
40
88
|
private columnsByKey;
|
|
41
89
|
private keyOf;
|
|
90
|
+
/** The header cell that currently owns `tabindex="0"`. */
|
|
91
|
+
private focusedColKey;
|
|
92
|
+
/** The body row that currently owns `tabindex="0"`. */
|
|
93
|
+
private focusedRowKey;
|
|
42
94
|
protected willUpdate(changed: PropertyValues): void;
|
|
43
95
|
private activateColumn;
|
|
44
96
|
private activateRow;
|
|
97
|
+
/** Header cells currently in the tab sequence — excludes columns hidden by
|
|
98
|
+
* a `priority`-driven `@container` rule (table.styles.ts), so Left/Right/
|
|
99
|
+
* Home/End never strand the roving tab stop on a `display: none` cell
|
|
100
|
+
* that `.focus()` would silently no-op on. */
|
|
101
|
+
private visibleHeaders;
|
|
102
|
+
private focusHeader;
|
|
103
|
+
private focusRow;
|
|
104
|
+
private toggleColumns;
|
|
45
105
|
private onTableClick;
|
|
46
106
|
private onTableKeyDown;
|
|
107
|
+
private onHeaderKeyDown;
|
|
108
|
+
private onRowKeyDown;
|
|
47
109
|
render(): TemplateResult;
|
|
48
110
|
}
|
|
49
111
|
declare global {
|
|
@@ -5,26 +5,49 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html, nothing } from 'lit';
|
|
8
|
-
import { property } from 'lit/decorators.js';
|
|
8
|
+
import { property, state } from 'lit/decorators.js';
|
|
9
9
|
import { repeat } from 'lit/directives/repeat.js';
|
|
10
10
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
11
11
|
import { defineElement } from '../../internal/prefix.js';
|
|
12
12
|
import { styles } from './table.styles.js';
|
|
13
13
|
import { chevronIcon } from '../../internal/icons.js';
|
|
14
14
|
import '../empty/empty.js';
|
|
15
|
+
/** Interactive elements a nested `cell()` template may render (e.g. an
|
|
16
|
+
* actions-column button). Clicks/keydowns landing on one of these — or
|
|
17
|
+
* bubbling up through one — must not be re-interpreted as row/column
|
|
18
|
+
* activation by the table's own delegated listeners. */
|
|
19
|
+
const INTERACTIVE_SELECTOR = 'button, a[href], input, select, textarea, [role="button"]';
|
|
15
20
|
/**
|
|
16
21
|
* `<lyra-table>` — a presentational, sort/select-aware data table.
|
|
17
22
|
*
|
|
18
23
|
* Header/row activation is delegated: one `click` and one `keydown`
|
|
19
24
|
* listener on `<table>` resolve the target via `closest('[data-col-key]'
|
|
20
25
|
* | '[data-row-key]')` and a key→object lookup map, instead of allocating
|
|
21
|
-
* fresh per-column/per-row closures on every render.
|
|
26
|
+
* fresh per-column/per-row closures on every render. Both listeners guard
|
|
27
|
+
* against nested interactive `cell()` content first (see
|
|
28
|
+
* `INTERACTIVE_SELECTOR`) so a button/link/input inside a cell owns its own
|
|
29
|
+
* activation instead of triggering `lyra-row-click`.
|
|
30
|
+
*
|
|
31
|
+
* Keyboard focus follows a roving-tabindex pattern (one `tabindex="0"` stop
|
|
32
|
+
* among the header cells, one among the body rows — see `focusedColKey()` /
|
|
33
|
+
* `focusedRowKey()`), matching this repo's other `role="grid"`/composite
|
|
34
|
+
* widgets. Left/Right/Home/End move within the header row; Up/Down/Home/End
|
|
35
|
+
* move within the body; Down from the header enters the body's roving stop,
|
|
36
|
+
* and Up from the body's first row returns to the header's roving stop.
|
|
37
|
+
* Enter/Space still only sort/activate (see `activateColumn()` /
|
|
38
|
+
* `activateRow()`).
|
|
39
|
+
*
|
|
40
|
+
* `columns[].priority` ('medium' | 'low') hides that column under
|
|
41
|
+
* `[part='base']`'s `@container` breakpoints; `[part='reveal-columns-button']`
|
|
42
|
+
* (rendered whenever any column has a priority) forces them all back into
|
|
43
|
+
* view. `columns[].sticky` pins a column's header/cells to the inline-start
|
|
44
|
+
* edge while the table scrolls horizontally.
|
|
22
45
|
*
|
|
23
46
|
* @customElement lyra-table
|
|
24
47
|
* @event lyra-sort - A sortable header was activated. `detail: { key }`.
|
|
25
48
|
* @event lyra-row-click - A row was activated. `detail: { row }`.
|
|
26
49
|
* @event lyra-load-more - The "load more" control was activated.
|
|
27
|
-
* @csspart base, table, head, header-cell, row, cell, more-button, sort-icon
|
|
50
|
+
* @csspart base, table, head, header-cell, row, cell, more-button, sort-icon, reveal-columns-button
|
|
28
51
|
*/
|
|
29
52
|
export class LyraTable extends LyraElement {
|
|
30
53
|
constructor() {
|
|
@@ -40,10 +63,32 @@ export class LyraTable extends LyraElement {
|
|
|
40
63
|
this.emptyDescription = '';
|
|
41
64
|
this.noColumnsHeading = 'No columns configured';
|
|
42
65
|
this.noColumnsDescription = '';
|
|
66
|
+
this.revealColumnsLabel = 'Show all columns';
|
|
67
|
+
this.hideColumnsLabel = 'Show fewer columns';
|
|
68
|
+
/** Forces `priority`-hidden columns back into view, overriding the
|
|
69
|
+
* `@container` hide rules in table.styles.ts. Toggled by
|
|
70
|
+
* `[part='reveal-columns-button']`. */
|
|
71
|
+
this.showAllColumns = false;
|
|
72
|
+
/** Roving-tabindex position among header cells; `null` until a header is
|
|
73
|
+
* clicked/navigated to, at which point `focusedColKey()` falls back to
|
|
74
|
+
* the first column. */
|
|
75
|
+
this.activeColKey = null;
|
|
76
|
+
/** Roving-tabindex position among body rows; `null` until a row is
|
|
77
|
+
* clicked/navigated to, at which point `focusedRowKey()` falls back to
|
|
78
|
+
* `selectedKey` (if it matches a row) or the first row. */
|
|
79
|
+
this.activeRowKey = null;
|
|
43
80
|
this.rowsByKey = new Map();
|
|
44
81
|
this.columnsByKey = new Map();
|
|
82
|
+
this.toggleColumns = () => {
|
|
83
|
+
this.showAllColumns = !this.showAllColumns;
|
|
84
|
+
};
|
|
45
85
|
this.onTableClick = (e) => {
|
|
46
86
|
const target = e.target;
|
|
87
|
+
// A cell()-rendered button/link/input etc. owns its own click — don't let
|
|
88
|
+
// the delegated row/column resolution below re-interpret it as row or
|
|
89
|
+
// header activation.
|
|
90
|
+
if (target.closest(INTERACTIVE_SELECTOR))
|
|
91
|
+
return;
|
|
47
92
|
const th = target.closest('[data-col-key]');
|
|
48
93
|
if (th)
|
|
49
94
|
return this.activateColumn(th.dataset.colKey);
|
|
@@ -52,25 +97,43 @@ export class LyraTable extends LyraElement {
|
|
|
52
97
|
this.activateRow(tr.dataset.rowKey);
|
|
53
98
|
};
|
|
54
99
|
this.onTableKeyDown = (e) => {
|
|
55
|
-
if (e.key !== 'Enter' && e.key !== ' ')
|
|
56
|
-
return;
|
|
57
100
|
const target = e.target;
|
|
101
|
+
// Same guard as onTableClick — also skips the table's own
|
|
102
|
+
// preventDefault(), so a focused nested control keeps its native/own
|
|
103
|
+
// Enter or Space activation instead of having it swallowed.
|
|
104
|
+
if (target.closest(INTERACTIVE_SELECTOR))
|
|
105
|
+
return;
|
|
58
106
|
const th = target.closest('[data-col-key]');
|
|
59
|
-
if (th)
|
|
60
|
-
|
|
61
|
-
return this.activateColumn(th.dataset.colKey);
|
|
62
|
-
}
|
|
107
|
+
if (th)
|
|
108
|
+
return this.onHeaderKeyDown(e, th);
|
|
63
109
|
const tr = target.closest('[data-row-key]');
|
|
64
|
-
if (tr)
|
|
65
|
-
|
|
66
|
-
this.activateRow(tr.dataset.rowKey);
|
|
67
|
-
}
|
|
110
|
+
if (tr)
|
|
111
|
+
this.onRowKeyDown(e, tr);
|
|
68
112
|
};
|
|
69
113
|
}
|
|
70
114
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
71
115
|
keyOf(row, index) {
|
|
72
116
|
return this.rowKey ? this.rowKey(row) : index;
|
|
73
117
|
}
|
|
118
|
+
/** The header cell that currently owns `tabindex="0"`. */
|
|
119
|
+
focusedColKey() {
|
|
120
|
+
if (this.activeColKey !== null && this.columnsByKey.has(this.activeColKey)) {
|
|
121
|
+
return this.activeColKey;
|
|
122
|
+
}
|
|
123
|
+
return this.columns[0]?.key ?? null;
|
|
124
|
+
}
|
|
125
|
+
/** The body row that currently owns `tabindex="0"`. */
|
|
126
|
+
focusedRowKey() {
|
|
127
|
+
if (this.activeRowKey !== null && this.rowsByKey.has(this.activeRowKey)) {
|
|
128
|
+
return this.activeRowKey;
|
|
129
|
+
}
|
|
130
|
+
if (this.selectedKey !== null) {
|
|
131
|
+
const selected = String(this.selectedKey);
|
|
132
|
+
if (this.rowsByKey.has(selected))
|
|
133
|
+
return selected;
|
|
134
|
+
}
|
|
135
|
+
return this.rows.length > 0 ? String(this.keyOf(this.rows[0], 0)) : null;
|
|
136
|
+
}
|
|
74
137
|
willUpdate(changed) {
|
|
75
138
|
if (changed.has('rows') || changed.has('rowKey')) {
|
|
76
139
|
this.rowsByKey = new Map(this.rows.map((row, i) => [String(this.keyOf(row, i)), row]));
|
|
@@ -80,15 +143,112 @@ export class LyraTable extends LyraElement {
|
|
|
80
143
|
}
|
|
81
144
|
}
|
|
82
145
|
activateColumn(key) {
|
|
146
|
+
this.activeColKey = key;
|
|
83
147
|
const col = this.columnsByKey.get(key);
|
|
84
148
|
if (col?.sortable)
|
|
85
149
|
this.emit('lyra-sort', { key: col.key });
|
|
86
150
|
}
|
|
87
151
|
activateRow(key) {
|
|
152
|
+
this.activeRowKey = key;
|
|
88
153
|
const row = this.rowsByKey.get(key);
|
|
89
154
|
if (row !== undefined)
|
|
90
155
|
this.emit('lyra-row-click', { row });
|
|
91
156
|
}
|
|
157
|
+
/** Header cells currently in the tab sequence — excludes columns hidden by
|
|
158
|
+
* a `priority`-driven `@container` rule (table.styles.ts), so Left/Right/
|
|
159
|
+
* Home/End never strand the roving tab stop on a `display: none` cell
|
|
160
|
+
* that `.focus()` would silently no-op on. */
|
|
161
|
+
visibleHeaders() {
|
|
162
|
+
return [...this.renderRoot.querySelectorAll('[data-col-key]')].filter((el) => el.offsetParent !== null);
|
|
163
|
+
}
|
|
164
|
+
focusHeader(el) {
|
|
165
|
+
if (!el?.dataset.colKey)
|
|
166
|
+
return;
|
|
167
|
+
this.activeColKey = el.dataset.colKey;
|
|
168
|
+
el.focus();
|
|
169
|
+
}
|
|
170
|
+
focusRow(el) {
|
|
171
|
+
if (!el?.dataset.rowKey)
|
|
172
|
+
return;
|
|
173
|
+
this.activeRowKey = el.dataset.rowKey;
|
|
174
|
+
el.focus();
|
|
175
|
+
}
|
|
176
|
+
onHeaderKeyDown(e, th) {
|
|
177
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
this.activateColumn(th.dataset.colKey);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const headers = this.visibleHeaders();
|
|
183
|
+
const index = headers.indexOf(th);
|
|
184
|
+
if (index < 0)
|
|
185
|
+
return;
|
|
186
|
+
switch (e.key) {
|
|
187
|
+
case 'ArrowLeft':
|
|
188
|
+
e.preventDefault();
|
|
189
|
+
this.focusHeader(headers[Math.max(0, index - 1)]);
|
|
190
|
+
return;
|
|
191
|
+
case 'ArrowRight':
|
|
192
|
+
e.preventDefault();
|
|
193
|
+
this.focusHeader(headers[Math.min(headers.length - 1, index + 1)]);
|
|
194
|
+
return;
|
|
195
|
+
case 'Home':
|
|
196
|
+
e.preventDefault();
|
|
197
|
+
this.focusHeader(headers[0]);
|
|
198
|
+
return;
|
|
199
|
+
case 'End':
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
this.focusHeader(headers[headers.length - 1]);
|
|
202
|
+
return;
|
|
203
|
+
case 'ArrowDown': {
|
|
204
|
+
e.preventDefault();
|
|
205
|
+
const rows = [...this.renderRoot.querySelectorAll('[data-row-key]')];
|
|
206
|
+
const key = this.focusedRowKey();
|
|
207
|
+
this.focusRow(rows.find((r) => r.dataset.rowKey === key) ?? rows[0] ?? null);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
default:
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
onRowKeyDown(e, tr) {
|
|
215
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
216
|
+
e.preventDefault();
|
|
217
|
+
this.activateRow(tr.dataset.rowKey);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const bodyRows = [...this.renderRoot.querySelectorAll('[data-row-key]')];
|
|
221
|
+
const index = bodyRows.indexOf(tr);
|
|
222
|
+
if (index < 0)
|
|
223
|
+
return;
|
|
224
|
+
switch (e.key) {
|
|
225
|
+
case 'ArrowDown':
|
|
226
|
+
e.preventDefault();
|
|
227
|
+
this.focusRow(bodyRows[Math.min(bodyRows.length - 1, index + 1)]);
|
|
228
|
+
return;
|
|
229
|
+
case 'ArrowUp':
|
|
230
|
+
e.preventDefault();
|
|
231
|
+
if (index === 0) {
|
|
232
|
+
const headers = this.visibleHeaders();
|
|
233
|
+
const key = this.focusedColKey();
|
|
234
|
+
this.focusHeader(headers.find((h) => h.dataset.colKey === key) ?? headers[0] ?? null);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
this.focusRow(bodyRows[index - 1]);
|
|
238
|
+
}
|
|
239
|
+
return;
|
|
240
|
+
case 'Home':
|
|
241
|
+
e.preventDefault();
|
|
242
|
+
this.focusRow(bodyRows[0]);
|
|
243
|
+
return;
|
|
244
|
+
case 'End':
|
|
245
|
+
e.preventDefault();
|
|
246
|
+
this.focusRow(bodyRows[bodyRows.length - 1]);
|
|
247
|
+
return;
|
|
248
|
+
default:
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
92
252
|
render() {
|
|
93
253
|
if (this.columns.length === 0) {
|
|
94
254
|
return html `<lyra-empty
|
|
@@ -102,8 +262,11 @@ export class LyraTable extends LyraElement {
|
|
|
102
262
|
description=${this.emptyDescription}
|
|
103
263
|
></lyra-empty>`;
|
|
104
264
|
}
|
|
265
|
+
const hasPriorityColumns = this.columns.some((col) => col.priority);
|
|
266
|
+
const focusedCol = this.focusedColKey();
|
|
267
|
+
const focusedRow = this.focusedRowKey();
|
|
105
268
|
return html `
|
|
106
|
-
<div part="base">
|
|
269
|
+
<div part="base" ?data-force-visible=${this.showAllColumns}>
|
|
107
270
|
<table part="table" role="grid" @click=${this.onTableClick} @keydown=${this.onTableKeyDown}>
|
|
108
271
|
<thead part="head">
|
|
109
272
|
<tr role="row">
|
|
@@ -116,9 +279,11 @@ export class LyraTable extends LyraElement {
|
|
|
116
279
|
scope="col"
|
|
117
280
|
data-col-key=${col.key}
|
|
118
281
|
data-align=${col.align ?? 'start'}
|
|
282
|
+
data-priority=${col.priority ?? nothing}
|
|
283
|
+
?data-sticky=${col.sticky}
|
|
119
284
|
?data-sortable=${col.sortable}
|
|
120
285
|
aria-sort=${col.sortable ? ariaSort : nothing}
|
|
121
|
-
tabindex=${col.
|
|
286
|
+
tabindex=${col.key === focusedCol ? '0' : '-1'}
|
|
122
287
|
>
|
|
123
288
|
${col.label}
|
|
124
289
|
${active
|
|
@@ -139,15 +304,31 @@ export class LyraTable extends LyraElement {
|
|
|
139
304
|
role="row"
|
|
140
305
|
data-row-key=${String(key)}
|
|
141
306
|
aria-selected=${selected ? 'true' : 'false'}
|
|
142
|
-
tabindex
|
|
307
|
+
tabindex=${String(key) === focusedRow ? '0' : '-1'}
|
|
143
308
|
>
|
|
144
|
-
${this.columns.map((col) => html `<td
|
|
309
|
+
${this.columns.map((col) => html `<td
|
|
310
|
+
part="cell"
|
|
311
|
+
role="gridcell"
|
|
312
|
+
data-align=${col.align ?? 'start'}
|
|
313
|
+
data-priority=${col.priority ?? nothing}
|
|
314
|
+
?data-sticky=${col.sticky}
|
|
315
|
+
>
|
|
145
316
|
${col.cell(row)}
|
|
146
317
|
</td>`)}
|
|
147
318
|
</tr>`;
|
|
148
319
|
})}
|
|
149
320
|
</tbody>
|
|
150
321
|
</table>
|
|
322
|
+
${hasPriorityColumns
|
|
323
|
+
? html `<button
|
|
324
|
+
part="reveal-columns-button"
|
|
325
|
+
type="button"
|
|
326
|
+
aria-pressed=${this.showAllColumns ? 'true' : 'false'}
|
|
327
|
+
@click=${this.toggleColumns}
|
|
328
|
+
>
|
|
329
|
+
${this.showAllColumns ? this.hideColumnsLabel : this.revealColumnsLabel}
|
|
330
|
+
</button>`
|
|
331
|
+
: nothing}
|
|
151
332
|
${this.hasMore
|
|
152
333
|
? html `<button
|
|
153
334
|
part="more-button"
|
|
@@ -197,4 +378,19 @@ __decorate([
|
|
|
197
378
|
__decorate([
|
|
198
379
|
property({ attribute: 'no-columns-description' })
|
|
199
380
|
], LyraTable.prototype, "noColumnsDescription", void 0);
|
|
381
|
+
__decorate([
|
|
382
|
+
property({ attribute: 'reveal-columns-label' })
|
|
383
|
+
], LyraTable.prototype, "revealColumnsLabel", void 0);
|
|
384
|
+
__decorate([
|
|
385
|
+
property({ attribute: 'hide-columns-label' })
|
|
386
|
+
], LyraTable.prototype, "hideColumnsLabel", void 0);
|
|
387
|
+
__decorate([
|
|
388
|
+
state()
|
|
389
|
+
], LyraTable.prototype, "showAllColumns", void 0);
|
|
390
|
+
__decorate([
|
|
391
|
+
state()
|
|
392
|
+
], LyraTable.prototype, "activeColKey", void 0);
|
|
393
|
+
__decorate([
|
|
394
|
+
state()
|
|
395
|
+
], LyraTable.prototype, "activeRowKey", void 0);
|
|
200
396
|
defineElement('table', LyraTable);
|
|
@@ -4,3 +4,9 @@ export default meta;
|
|
|
4
4
|
type Story = StoryObj;
|
|
5
5
|
export declare const Default: Story;
|
|
6
6
|
export declare const Empty: Story;
|
|
7
|
+
export declare const NoColumnsConfigured: Story;
|
|
8
|
+
export declare const ActiveSort: Story;
|
|
9
|
+
export declare const SelectedRow: Story;
|
|
10
|
+
export declare const LoadMore: Story;
|
|
11
|
+
export declare const PriorityAndSticky: Story;
|
|
12
|
+
export declare const RowActions: Story;
|
|
@@ -20,3 +20,48 @@ export const Default = {
|
|
|
20
20
|
export const Empty = {
|
|
21
21
|
render: () => html `<lyra-table .columns=${columns} .rows=${[]}></lyra-table>`,
|
|
22
22
|
};
|
|
23
|
+
export const NoColumnsConfigured = {
|
|
24
|
+
render: () => html `<lyra-table .columns=${[]} .rows=${rows}></lyra-table>`,
|
|
25
|
+
};
|
|
26
|
+
export const ActiveSort = {
|
|
27
|
+
render: () => html `<lyra-table .columns=${columns} .rows=${rows} sort-key="score" sort-dir="desc"></lyra-table>`,
|
|
28
|
+
};
|
|
29
|
+
export const SelectedRow = {
|
|
30
|
+
render: () => html `<lyra-table .columns=${columns} .rows=${rows} .selectedKey=${'b'}></lyra-table>`,
|
|
31
|
+
};
|
|
32
|
+
export const LoadMore = {
|
|
33
|
+
render: () => html `<lyra-table .columns=${columns} .rows=${rows} has-more more-label="Load more rows"></lyra-table>`,
|
|
34
|
+
};
|
|
35
|
+
const detailRows = [
|
|
36
|
+
{ id: 'a', name: 'Alpha', score: 92, region: 'EU-West', updated: '2 min ago' },
|
|
37
|
+
{ id: 'b', name: 'Beta', score: 81, region: 'US-East', updated: '5 min ago' },
|
|
38
|
+
{ id: 'c', name: 'Gamma', score: 76, region: 'AP-South', updated: '1 hr ago' },
|
|
39
|
+
];
|
|
40
|
+
// Narrow the story's own container, so the `priority`-hidden columns below
|
|
41
|
+
// actually hide without needing to shrink the whole Storybook viewport.
|
|
42
|
+
const priorityColumns = [
|
|
43
|
+
{ key: 'name', label: 'Name', sortable: true, sticky: true, cell: (r) => r.name },
|
|
44
|
+
{ key: 'score', label: 'Score', sortable: true, align: 'end', cell: (r) => r.score },
|
|
45
|
+
{ key: 'region', label: 'Region', priority: 'medium', cell: (r) => r.region },
|
|
46
|
+
{ key: 'updated', label: 'Updated', priority: 'low', cell: (r) => r.updated },
|
|
47
|
+
];
|
|
48
|
+
export const PriorityAndSticky = {
|
|
49
|
+
render: () => html `<div style="max-width: 420px;">
|
|
50
|
+
<lyra-table .columns=${priorityColumns} .rows=${detailRows}></lyra-table>
|
|
51
|
+
</div>`,
|
|
52
|
+
};
|
|
53
|
+
// A <button> inside cell() must own its own click/Enter activation — the
|
|
54
|
+
// table's row-click delegation must not intercept it (see table.ts's
|
|
55
|
+
// INTERACTIVE_SELECTOR guard).
|
|
56
|
+
const actionColumns = [
|
|
57
|
+
{ key: 'name', label: 'Name', cell: (r) => r.name },
|
|
58
|
+
{ key: 'score', label: 'Score', align: 'end', cell: (r) => r.score },
|
|
59
|
+
{
|
|
60
|
+
key: 'actions',
|
|
61
|
+
label: 'Actions',
|
|
62
|
+
cell: (r) => html `<button type="button" @click=${() => alert(`Editing ${r.name}`)}>Edit</button>`,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
export const RowActions = {
|
|
66
|
+
render: () => html `<lyra-table .columns=${actionColumns} .rows=${rows}></lyra-table>`,
|
|
67
|
+
};
|
|
@@ -9,6 +9,29 @@ export const styles = css `
|
|
|
9
9
|
max-block-size: var(--lyra-table-max-height, none);
|
|
10
10
|
border: 1px solid var(--lyra-color-border);
|
|
11
11
|
border-radius: var(--lyra-radius);
|
|
12
|
+
/* Makes [part='base'] a query container so the @container rules below can
|
|
13
|
+
react to the table's own available width instead of the viewport's. */
|
|
14
|
+
container-type: inline-size;
|
|
15
|
+
}
|
|
16
|
+
/*
|
|
17
|
+
* Column priority (columns[].priority) hides [data-priority='low']/
|
|
18
|
+
* ['medium'] header/cells as the container narrows. showAllColumns
|
|
19
|
+
* (toggled by [part='reveal-columns-button']) needs to override this, but
|
|
20
|
+
* a @container query can only condition on ancestor inline-size, not
|
|
21
|
+
* component state — so it's surfaced instead as the data-force-visible
|
|
22
|
+
* attribute on [part='base'] itself, and the hide rule's :not(...)
|
|
23
|
+
* selector excludes it. Toggling the attribute flips every hidden column
|
|
24
|
+
* back on without a second, state-aware container query.
|
|
25
|
+
*/
|
|
26
|
+
@container (max-width: 899.98px) {
|
|
27
|
+
[part='base']:not([data-force-visible]) [data-priority='low'] {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
@container (max-width: 639.98px) {
|
|
32
|
+
[part='base']:not([data-force-visible]) [data-priority='medium'] {
|
|
33
|
+
display: none;
|
|
34
|
+
}
|
|
12
35
|
}
|
|
13
36
|
[part='table'] {
|
|
14
37
|
inline-size: 100%;
|
|
@@ -33,7 +56,10 @@ export const styles = css `
|
|
|
33
56
|
[part='header-cell'][data-sortable]:hover {
|
|
34
57
|
background: var(--lyra-color-brand-quiet);
|
|
35
58
|
}
|
|
36
|
-
[
|
|
59
|
+
/* Not scoped to [data-sortable] — the roving-tabindex header stop (see
|
|
60
|
+
table.ts's focusedColKey()) can land on any column, sortable or not, so
|
|
61
|
+
every header cell needs its own visible focus indicator. */
|
|
62
|
+
[part='header-cell']:focus-visible {
|
|
37
63
|
outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
|
|
38
64
|
outline-offset: var(--lyra-focus-ring-offset);
|
|
39
65
|
}
|
|
@@ -59,6 +85,11 @@ export const styles = css `
|
|
|
59
85
|
[part='sort-icon'][data-dir='desc'] {
|
|
60
86
|
transform: rotate(90deg);
|
|
61
87
|
}
|
|
88
|
+
@media (prefers-reduced-motion: reduce) {
|
|
89
|
+
[part='sort-icon'] {
|
|
90
|
+
transition: none !important;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
62
93
|
[part='row']:hover {
|
|
63
94
|
background: var(--lyra-color-brand-quiet);
|
|
64
95
|
}
|
|
@@ -76,7 +107,21 @@ export const styles = css `
|
|
|
76
107
|
[part='cell'][data-align='end'] {
|
|
77
108
|
text-align: end;
|
|
78
109
|
}
|
|
79
|
-
[
|
|
110
|
+
/* columns[].sticky pins a column's header/cells to the inline-start edge
|
|
111
|
+
while the table scrolls horizontally — mirrors [part='header-cell']'s
|
|
112
|
+
existing inset-block-start vertical-scroll sticky pattern above, just on
|
|
113
|
+
the other axis. The box-shadow is the seam that separates it from
|
|
114
|
+
content scrolled underneath it. */
|
|
115
|
+
[part='header-cell'][data-sticky],
|
|
116
|
+
[part='cell'][data-sticky] {
|
|
117
|
+
position: sticky;
|
|
118
|
+
inset-inline-start: 0;
|
|
119
|
+
z-index: 1;
|
|
120
|
+
background: var(--lyra-color-surface);
|
|
121
|
+
box-shadow: 1px 0 0 0 var(--lyra-color-border);
|
|
122
|
+
}
|
|
123
|
+
[part='more-button'],
|
|
124
|
+
[part='reveal-columns-button'] {
|
|
80
125
|
display: block;
|
|
81
126
|
inline-size: 100%;
|
|
82
127
|
padding: var(--lyra-space-s);
|
|
@@ -87,10 +132,12 @@ export const styles = css `
|
|
|
87
132
|
cursor: pointer;
|
|
88
133
|
border-block-start: 1px solid var(--lyra-color-border);
|
|
89
134
|
}
|
|
90
|
-
[part='more-button']:hover
|
|
135
|
+
[part='more-button']:hover,
|
|
136
|
+
[part='reveal-columns-button']:hover {
|
|
91
137
|
background: var(--lyra-color-brand-quiet);
|
|
92
138
|
}
|
|
93
|
-
[part='more-button']:focus-visible
|
|
139
|
+
[part='more-button']:focus-visible,
|
|
140
|
+
[part='reveal-columns-button']:focus-visible {
|
|
94
141
|
outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
|
|
95
142
|
outline-offset: var(--lyra-focus-ring-offset);
|
|
96
143
|
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { type TemplateResult, type PropertyValues } from 'lit';
|
|
2
2
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
|
+
/** A single discrete-preset option for the `presets` property. */
|
|
4
|
+
export interface TimeRangePreset {
|
|
5
|
+
label: string;
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
}
|
|
3
9
|
/**
|
|
4
10
|
* `<lyra-time-range>` — a two-handle brush/scrubber over a numeric domain.
|
|
5
11
|
* Callers map their own time axis to `[min, max]`; no date logic lives here
|
|
6
12
|
* (matches the no-date-library constraint used elsewhere in this library).
|
|
7
13
|
*
|
|
14
|
+
* Optionally paired with a row of discrete presets (`presets`) — e.g. "Last
|
|
15
|
+
* 7 days" / "Last 30 days" — rendered above the track; picking one is just a
|
|
16
|
+
* shortcut that sets both handles at once, the continuous brush underneath
|
|
17
|
+
* is unaffected and both interaction modes coexist.
|
|
18
|
+
*
|
|
8
19
|
* @customElement lyra-time-range
|
|
9
|
-
* @event lyra-input - Fired continuously while dragging. `detail: { start, end }`.
|
|
10
|
-
* @event lyra-change - Fired on release / keyup-commit. `detail: { start, end }`.
|
|
11
|
-
* @csspart base, track, range, handle-start, handle-end
|
|
20
|
+
* @event lyra-input - Fired continuously while dragging or on each arrow-key press. `detail: { start, end }`.
|
|
21
|
+
* @event lyra-change - Fired on release / keyup-commit, or when a preset button is clicked. `detail: { start, end }`.
|
|
22
|
+
* @csspart base, track, range, handle-start, handle-end, presets, preset-button
|
|
12
23
|
*/
|
|
13
24
|
export declare class LyraTimeRange extends LyraElement {
|
|
14
25
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -18,17 +29,35 @@ export declare class LyraTimeRange extends LyraElement {
|
|
|
18
29
|
end: number;
|
|
19
30
|
step: number;
|
|
20
31
|
disabled: boolean;
|
|
21
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Optional discrete presets rendered as a `[part="presets"]` button row
|
|
34
|
+
* above the track. Purely additive: leaving this empty (the default)
|
|
35
|
+
* renders nothing extra and leaves the continuous brush untouched.
|
|
36
|
+
*/
|
|
37
|
+
presets: TimeRangePreset[];
|
|
38
|
+
private drags;
|
|
22
39
|
disconnectedCallback(): void;
|
|
40
|
+
private domain;
|
|
23
41
|
private percentOf;
|
|
42
|
+
/** Each handle's actual reachable sub-range, bounded by its sibling
|
|
43
|
+
* handle's current value the same way clamp() already enforces it — used
|
|
44
|
+
* both for aria-valuemin/aria-valuemax and for Home/End's jump targets,
|
|
45
|
+
* instead of reporting/jumping to the component's full [min, max] domain
|
|
46
|
+
* which the sibling handle may make partially unreachable. */
|
|
47
|
+
private reachableBounds;
|
|
24
48
|
private clamp;
|
|
25
49
|
private setValue;
|
|
50
|
+
/**
|
|
51
|
+
* Apply a discrete preset: sets both handles and emits the same
|
|
52
|
+
* lyra-input/lyra-change pair a committed drag or keyboard step would.
|
|
53
|
+
*/
|
|
54
|
+
private applyPreset;
|
|
26
55
|
private onKeyDown;
|
|
27
56
|
private onKeyUp;
|
|
28
57
|
private onPointerDown;
|
|
29
58
|
private onPointerMove;
|
|
30
59
|
private onPointerUp;
|
|
31
|
-
/** Stop
|
|
60
|
+
/** Stop the drag owned by `pointerId`, optionally committing a final lyra-change. */
|
|
32
61
|
private endDrag;
|
|
33
62
|
protected willUpdate(changed: PropertyValues): void;
|
|
34
63
|
render(): TemplateResult;
|