@fusion.dev/helix-headless 0.23.0 → 0.24.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/custom-elements.json +48376 -26638
- package/dist/announcement/root/announcement-root.d.ts +19 -5
- package/dist/area-chart/index.d.ts +1 -0
- package/dist/area-chart/index.js +1 -0
- package/dist/area-chart/root/area-chart-root.d.ts +182 -0
- package/dist/area-chart/root/area-chart-root.js +205 -0
- package/dist/carousel/root/carousel-root.d.ts +1 -0
- package/dist/carousel/root/carousel-root.js +18 -2
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/message/chat-message.d.ts +7 -0
- package/dist/chat/message/chat-message.js +2 -1
- package/dist/chat/root/chat-root.d.ts +195 -4
- package/dist/chat/root/chat-root.js +316 -23
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +2 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +12 -2
- package/dist/code-block/index.d.ts +1 -0
- package/dist/code-block/index.js +1 -0
- package/dist/code-block/patch.d.ts +62 -0
- package/dist/code-block/patch.js +93 -0
- package/dist/code-block/root/code-block-root.d.ts +82 -17
- package/dist/code-block/root/code-block-root.js +83 -6
- package/dist/color-picker/root/color-picker-root.d.ts +4 -3
- package/dist/color-picker/root/color-picker-root.js +4 -1
- package/dist/data-table/root/data-table-root.d.ts +195 -23
- package/dist/data-table/root/data-table-root.js +308 -27
- package/dist/description-list/index.d.ts +2 -0
- package/dist/description-list/index.js +2 -0
- package/dist/description-list/item/description-list-item.d.ts +39 -0
- package/dist/description-list/item/description-list-item.js +26 -0
- package/dist/description-list/root/description-list-root.d.ts +56 -0
- package/dist/description-list/root/description-list-root.js +21 -0
- package/dist/element-events.generated.js +27 -6
- package/dist/filter-input/chip/filter-chip.d.ts +114 -0
- package/dist/filter-input/chip/filter-chip.js +61 -0
- package/dist/filter-input/field/filter-field.d.ts +128 -0
- package/dist/filter-input/field/filter-field.js +70 -0
- package/dist/filter-input/grammar.d.ts +96 -0
- package/dist/filter-input/grammar.js +133 -0
- package/dist/filter-input/index.d.ts +5 -0
- package/dist/filter-input/index.js +5 -0
- package/dist/filter-input/menu/filter-menu.d.ts +153 -0
- package/dist/filter-input/menu/filter-menu.js +164 -0
- package/dist/filter-input/operator/filter-operator.d.ts +105 -0
- package/dist/filter-input/operator/filter-operator.js +39 -0
- package/dist/filter-input/root/filter-input-root.d.ts +118 -9
- package/dist/filter-input/root/filter-input-root.js +96 -2
- package/dist/format-date/root/format-date-root.js +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/line-chart/root/line-chart-root.d.ts +9 -2
- package/dist/listbox/root/listbox-root.d.ts +8 -7
- package/dist/listbox/root/listbox-root.js +7 -2
- package/dist/menu/item/menu-item.d.ts +31 -6
- package/dist/menu/item/menu-item.js +18 -5
- package/dist/menu/root/menu-root.js +7 -2
- package/dist/notifications/group/notification-group.d.ts +129 -0
- package/dist/notifications/group/notification-group.js +106 -0
- package/dist/notifications/index.d.ts +1 -0
- package/dist/notifications/index.js +1 -0
- package/dist/notifications/notification/notification.d.ts +39 -13
- package/dist/notifications/notification/notification.js +11 -8
- package/dist/notifications/root/notifications-root.d.ts +57 -1
- package/dist/notifications/root/notifications-root.js +35 -4
- package/dist/number-input/root/number-input-root.d.ts +21 -1
- package/dist/number-input/root/number-input-root.js +18 -5
- package/dist/object-inspector/index.d.ts +1 -0
- package/dist/object-inspector/index.js +1 -0
- package/dist/object-inspector/root/object-inspector-root.d.ts +183 -0
- package/dist/object-inspector/root/object-inspector-root.js +348 -0
- package/dist/outline/root/outline-root.d.ts +16 -1
- package/dist/outline/root/outline-root.js +27 -9
- package/dist/radio/group/radio-group.d.ts +1 -0
- package/dist/scatter-chart/index.d.ts +1 -0
- package/dist/scatter-chart/index.js +1 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +144 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +205 -0
- package/dist/skip-link/index.d.ts +1 -0
- package/dist/skip-link/index.js +1 -0
- package/dist/skip-link/root/skip-link-root.d.ts +81 -0
- package/dist/skip-link/root/skip-link-root.js +58 -0
- package/dist/speed-dial/root/speed-dial-root.d.ts +1 -0
- package/dist/speed-dial/root/speed-dial-root.js +6 -2
- package/dist/steps/root/steps-root.d.ts +1 -0
- package/dist/table/column/table-column.d.ts +79 -0
- package/dist/table/column/table-column.js +125 -5
- package/dist/table/root/table-root.d.ts +2 -0
- package/dist/table/root/table-root.js +12 -3
- package/dist/time-picker/root/time-picker-root.d.ts +9 -0
- package/dist/time-picker/root/time-picker-root.js +5 -0
- package/dist/toast/root/toast-root.d.ts +2 -0
- package/dist/tooltip/root/tooltip-root.js +1 -1
- package/dist/tour/root/tour-root.d.ts +1 -0
- package/dist/tree/item/tree-item.d.ts +7 -4
- package/dist/tree/item/tree-item.js +4 -1
- package/dist/video/root/video-root.d.ts +23 -1
- package/dist/video/root/video-root.js +42 -22
- package/dist/virtual-list/root/virtual-list-root.d.ts +10 -6
- package/dist/virtual-list/root/virtual-list-root.js +10 -4
- package/package.json +5 -5
- package/types/jsx.d.ts +4535 -346
- package/types/svelte.d.ts +11 -0
- package/types/vue.d.ts +737 -39
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type TemplateResult } from 'lit';
|
|
2
|
+
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../copy-button/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* @summary A block of code, with somewhere to put its name and a way to take it.
|
|
@@ -23,6 +23,24 @@ import '../../copy-button/index.js';
|
|
|
23
23
|
* A `Code` for a fragment inside a sentence. Separate families, because one
|
|
24
24
|
* flows with prose and the other is a figure.
|
|
25
25
|
*
|
|
26
|
+
* **`diff` reads the code as a change.** The content is then a unified diff,
|
|
27
|
+
* what `git diff` and `diff -u` write, in the same slot ordinary code goes in,
|
|
28
|
+
* and it is drawn as the lines it added and removed. The block reads a diff and
|
|
29
|
+
* never computes one, so the algorithm stays wherever the two versions are.
|
|
30
|
+
* Numbers come from the hunk headers, which makes them the file's; changed lines
|
|
31
|
+
* are `<ins>` and `<del>` with the `+` and `-` kept as text, so the change is not
|
|
32
|
+
* carried by color; the numbers are hidden from the accessibility tree. Each
|
|
33
|
+
* file in the patch is a block of its own under its own name, and its copy
|
|
34
|
+
* button takes the file as it now reads. `variant="split"` sets the old version
|
|
35
|
+
* beside the new, each removal opposite its replacement.
|
|
36
|
+
*
|
|
37
|
+
* **Before the script runs, a diff is its own text.** A server has no children
|
|
38
|
+
* to read, so it renders the slot as ordinary code, which for a diff is the
|
|
39
|
+
* patch in a `<pre>`: a legible diff, and the first render the client makes
|
|
40
|
+
* too, which is what keeps hydration clean. The drawn diff replaces it once the
|
|
41
|
+
* content can be read. Diff mode is experimental while the rest of the family
|
|
42
|
+
* is stable.
|
|
43
|
+
*
|
|
26
44
|
* @since 0.1.0
|
|
27
45
|
* @status stable
|
|
28
46
|
* @category typography
|
|
@@ -31,20 +49,42 @@ import '../../copy-button/index.js';
|
|
|
31
49
|
*
|
|
32
50
|
* @slot - The code.
|
|
33
51
|
*
|
|
52
|
+
* @csspart added - In a diff, a line only the new version has, an `<ins>`.
|
|
34
53
|
* @csspart block - The scrolling `<pre>`.
|
|
35
54
|
* @csspart code - The `<code>` inside it.
|
|
55
|
+
* @csspart context - In a diff, a line both versions share.
|
|
36
56
|
* @csspart copy - The copy button.
|
|
37
57
|
* @csspart copy-button - The inner button.
|
|
38
58
|
* @csspart copy-mark - The clipboard glyph, and the confirmation that replaces it.
|
|
39
59
|
* @csspart copy-tooltip - The bubble, forwarded from the tooltip inside.
|
|
40
60
|
* @csspart copy-tooltip-arrow - The point, resting against the trigger.
|
|
61
|
+
* @csspart file - In a diff, one file's header and block.
|
|
62
|
+
* @csspart filler - In a split diff, the empty row opposite a line the other side does not have.
|
|
41
63
|
* @csspart frame - The code and the copy button beside it.
|
|
42
64
|
* @csspart header - The bar carrying the name, where there is one.
|
|
65
|
+
* @csspart hunk - In a diff, a `@@` line saying where the lines under it are.
|
|
43
66
|
* @csspart label - The file name or language, where one is given.
|
|
67
|
+
* @csspart marker - In a diff, the `+`, `-` or space that opens a line.
|
|
68
|
+
* @csspart new - In a split diff, the new version's `<pre>`.
|
|
69
|
+
* @csspart number - In a diff, a line number.
|
|
70
|
+
* @csspart old - In a split diff, the old version's `<pre>`.
|
|
71
|
+
* @csspart removed - In a diff, a line only the old version has, a `<del>`.
|
|
72
|
+
* @csspart split - In a split diff, the two versions side by side.
|
|
73
|
+
* @csspart text - In a diff, a line's code.
|
|
44
74
|
*/
|
|
45
75
|
export declare class HelixHeadlessCodeBlock extends HelixElement {
|
|
76
|
+
/**
|
|
77
|
+
* Whether the content is a unified diff, drawn as the lines it changed.
|
|
78
|
+
*
|
|
79
|
+
* Reflected, because the stylesheet paints a diff differently from code, and
|
|
80
|
+
* `false` reflects as no attribute at all.
|
|
81
|
+
*/
|
|
82
|
+
diff: boolean;
|
|
46
83
|
/**
|
|
47
84
|
* What to call this block, usually a file name or a language.
|
|
85
|
+
*
|
|
86
|
+
* In a diff, each file is named from the patch, and this names a patch that
|
|
87
|
+
* carries no name of its own.
|
|
48
88
|
*/
|
|
49
89
|
label: string;
|
|
50
90
|
/**
|
|
@@ -70,27 +110,34 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
70
110
|
*/
|
|
71
111
|
noCopy: boolean;
|
|
72
112
|
/**
|
|
73
|
-
*
|
|
113
|
+
* How a diff's two versions are arranged; nothing without `diff`.
|
|
114
|
+
*
|
|
115
|
+
* Absent is unified, each removal above its replacement, which fits any
|
|
116
|
+
* width. `split` sets the old version beside the new one. Optional rather
|
|
117
|
+
* than defaulted, so the host carries no attribute the consumer did not write.
|
|
118
|
+
*/
|
|
119
|
+
variant?: 'split';
|
|
120
|
+
/** The last text read as a diff, and what it read as, so a render does not parse twice. */
|
|
121
|
+
private parsed;
|
|
122
|
+
/** The files in the content, when it is a diff and it can be read yet. */
|
|
123
|
+
private get files();
|
|
124
|
+
/**
|
|
125
|
+
* The code as text, read from what the default slot is given rather than
|
|
126
|
+
* stored.
|
|
127
|
+
*
|
|
128
|
+
* **The host's own children rather than the slot's assigned nodes**, which
|
|
129
|
+
* are the same nodes: text, and every element without a `slot`. A slot exists
|
|
130
|
+
* only once a render has made it, so reading through one left the first render
|
|
131
|
+
* with nothing to copy.
|
|
74
132
|
*
|
|
75
133
|
* Client only, and it has to be: the server has no children to read. The
|
|
76
134
|
* copy button is a client-side affordance anyway, so nothing is lost, and
|
|
77
135
|
* taking the text from a property instead would be a second copy of the code
|
|
78
|
-
* that goes stale the moment the slot changes.
|
|
136
|
+
* that goes stale the moment the slot changes. Empty while hydrating what a
|
|
137
|
+
* server sent, which rendered it empty.
|
|
79
138
|
*/
|
|
80
139
|
private get text();
|
|
81
|
-
|
|
82
|
-
* One more render, once there is a slot to read.
|
|
83
|
-
*
|
|
84
|
-
* The first render has no shadow children yet, so `text` is empty and the
|
|
85
|
-
* copy button is bound to nothing. `slotchange` normally schedules the render
|
|
86
|
-
* that fixes it, and leaning on that alone was measured to leave the button
|
|
87
|
-
* empty through four update cycles: the event is not guaranteed to have
|
|
88
|
-
* arrived, and in one environment never arrives at all. A component should not
|
|
89
|
-
* need an event to show its own content, so it asks for the second render
|
|
90
|
-
* itself and `slotchange` is left to handle the case it is actually for, which
|
|
91
|
-
* is content changing later.
|
|
92
|
-
*/
|
|
93
|
-
protected firstUpdated(): void;
|
|
140
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
94
141
|
protected render(): TemplateResult;
|
|
95
142
|
/**
|
|
96
143
|
* The button that takes the code, behind a seam the styled tier can move.
|
|
@@ -102,7 +149,25 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
102
149
|
* base button, and a styled subclass that sets `tier` renders the styled one
|
|
103
150
|
* from the same template.
|
|
104
151
|
*/
|
|
105
|
-
protected renderCopyButton(): TemplateResult;
|
|
152
|
+
protected renderCopyButton(value?: string): TemplateResult;
|
|
153
|
+
/** A number padded to the widest in its file, so the columns line up as text. */
|
|
154
|
+
private renderNumber;
|
|
155
|
+
private renderLine;
|
|
156
|
+
private renderHunk;
|
|
157
|
+
/**
|
|
158
|
+
* The old version beside the new one, row for row.
|
|
159
|
+
*
|
|
160
|
+
* The new side's hunk headers are hidden from the accessibility tree, being
|
|
161
|
+
* the old side's text again and there only to keep the rows level.
|
|
162
|
+
*/
|
|
163
|
+
private renderSplit;
|
|
164
|
+
/**
|
|
165
|
+
* Each file as a block of its own, the way one block of code is drawn.
|
|
166
|
+
*
|
|
167
|
+
* The slot stays in the tree, hidden, because it is still where the content
|
|
168
|
+
* comes from: a diff edited later arrives by `slotchange` like any other.
|
|
169
|
+
*/
|
|
170
|
+
private renderDiff;
|
|
106
171
|
}
|
|
107
172
|
declare global {
|
|
108
173
|
interface HTMLElementTagNameMap {
|
|
@@ -9,42 +9,119 @@ import { nothing } from 'lit';
|
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { html } from 'lit/static-html.js';
|
|
11
11
|
import '../../copy-button/index.js';
|
|
12
|
+
import { pairLines, parsePatch } from '../patch.js';
|
|
12
13
|
let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
13
14
|
constructor() {
|
|
14
15
|
super(...arguments);
|
|
16
|
+
this.diff = false;
|
|
15
17
|
this.label = '';
|
|
16
18
|
this.noCopy = false;
|
|
19
|
+
this.parsed = { files: [], text: '' };
|
|
20
|
+
}
|
|
21
|
+
get files() {
|
|
22
|
+
if (!this.diff) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const text = this.text;
|
|
26
|
+
if (text !== this.parsed.text) {
|
|
27
|
+
this.parsed = { files: parsePatch(text), text };
|
|
28
|
+
}
|
|
29
|
+
return this.parsed.files;
|
|
17
30
|
}
|
|
18
31
|
get text() {
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
if (this.hydrating) {
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
return [...(this.childNodes ?? [])]
|
|
36
|
+
.filter((node) => node.nodeType === Node.TEXT_NODE ||
|
|
37
|
+
(node.nodeType === Node.ELEMENT_NODE && node.slot === ''))
|
|
38
|
+
.map((node) => node.textContent ?? '')
|
|
39
|
+
.join('');
|
|
21
40
|
}
|
|
22
|
-
firstUpdated() {
|
|
23
|
-
|
|
41
|
+
firstUpdated(changed) {
|
|
42
|
+
super.firstUpdated(changed);
|
|
43
|
+
this.finishHydration();
|
|
24
44
|
}
|
|
25
45
|
render() {
|
|
46
|
+
const files = this.files;
|
|
47
|
+
if (files.length > 0) {
|
|
48
|
+
return this.renderDiff(files);
|
|
49
|
+
}
|
|
26
50
|
return html `${this.label ? html `<div part="header"><span part="label">${this.label}</span></div>` : nothing}
|
|
27
51
|
<div part="frame">
|
|
28
52
|
<pre part="block"><code part="code"><slot @slotchange=${() => this.requestUpdate()}></slot></code></pre>
|
|
29
53
|
${this.noCopy ? nothing : this.renderCopyButton()}
|
|
30
54
|
</div>`;
|
|
31
55
|
}
|
|
32
|
-
renderCopyButton() {
|
|
56
|
+
renderCopyButton(value = this.text) {
|
|
33
57
|
return html `<${this.tag('copy-button')}
|
|
34
58
|
part="copy"
|
|
35
59
|
exportparts="button: copy-button, mark: copy-mark, tooltip: copy-tooltip,
|
|
36
60
|
tooltip-arrow: copy-tooltip-arrow"
|
|
37
61
|
label="Copy code"
|
|
38
|
-
.value=${
|
|
62
|
+
.value=${value}
|
|
39
63
|
></${this.tag('copy-button')}>`;
|
|
40
64
|
}
|
|
65
|
+
renderNumber(value, width) {
|
|
66
|
+
return html `<span part="number" aria-hidden="true">${String(value ?? '').padStart(width)} </span>`;
|
|
67
|
+
}
|
|
68
|
+
renderLine(line, width, side) {
|
|
69
|
+
const numbers = side
|
|
70
|
+
? this.renderNumber(side === 'old' ? line.old : line.new, width)
|
|
71
|
+
: html `${this.renderNumber(line.old, width)}${this.renderNumber(line.new, width)}`;
|
|
72
|
+
const text = html `<span part="text">${line.text}\n</span>`;
|
|
73
|
+
if (line.kind === 'added') {
|
|
74
|
+
return html `<ins part="added">${numbers}<span part="marker">+</span>${text}</ins>`;
|
|
75
|
+
}
|
|
76
|
+
if (line.kind === 'removed') {
|
|
77
|
+
return html `<del part="removed">${numbers}<span part="marker">-</span>${text}</del>`;
|
|
78
|
+
}
|
|
79
|
+
return html `<span part="context">${numbers}<span part="marker"> </span>${text}</span>`;
|
|
80
|
+
}
|
|
81
|
+
renderHunk(hunk, hidden = false) {
|
|
82
|
+
return html `<span part="hunk" aria-hidden=${hidden ? 'true' : nothing}>${hunk.header}\n</span>`;
|
|
83
|
+
}
|
|
84
|
+
renderSplit(file, width) {
|
|
85
|
+
const hunks = file.hunks.map((hunk) => ({ hunk, rows: pairLines(hunk.lines) }));
|
|
86
|
+
const filler = html `<span part="filler" aria-hidden="true">\n</span>`;
|
|
87
|
+
return html `<div part="split">
|
|
88
|
+
<pre part="old"><code part="code">${hunks.map(({ hunk, rows }) => html `${this.renderHunk(hunk)}${rows.map(({ left }) => left ? this.renderLine(left, width, 'old') : filler)}`)}</code></pre>
|
|
89
|
+
<pre part="new"><code part="code">${hunks.map(({ hunk, rows }) => html `${this.renderHunk(hunk, true)}${rows.map(({ right }) => right ? this.renderLine(right, width, 'new') : filler)}`)}</code></pre>
|
|
90
|
+
</div>`;
|
|
91
|
+
}
|
|
92
|
+
renderDiff(files) {
|
|
93
|
+
return html `${files.map((file) => {
|
|
94
|
+
const name = file.name || this.label;
|
|
95
|
+
const widest = Math.max(0, ...file.hunks.flatMap((hunk) => hunk.lines.map((line) => Math.max(line.old ?? 0, line.new ?? 0))));
|
|
96
|
+
const width = String(widest).length;
|
|
97
|
+
const now = file.hunks
|
|
98
|
+
.flatMap((hunk) => hunk.lines.filter((line) => line.kind !== 'removed'))
|
|
99
|
+
.map((line) => line.text)
|
|
100
|
+
.join('\n');
|
|
101
|
+
return html `<div part="file">
|
|
102
|
+
${name ? html `<div part="header"><span part="label">${name}</span></div>` : nothing}
|
|
103
|
+
<div part="frame">
|
|
104
|
+
${this.variant === 'split'
|
|
105
|
+
? this.renderSplit(file, width)
|
|
106
|
+
: html `<pre part="block"><code part="code">${file.hunks.map((hunk) => html `${this.renderHunk(hunk)}${hunk.lines.map((line) => this.renderLine(line, width))}`)}</code></pre>`}
|
|
107
|
+
${this.noCopy ? nothing : this.renderCopyButton(now)}
|
|
108
|
+
</div>
|
|
109
|
+
</div>`;
|
|
110
|
+
})}<slot hidden @slotchange=${() => this.requestUpdate()}></slot>`;
|
|
111
|
+
}
|
|
41
112
|
};
|
|
113
|
+
__decorate([
|
|
114
|
+
property({ reflect: true, type: Boolean })
|
|
115
|
+
], HelixHeadlessCodeBlock.prototype, "diff", void 0);
|
|
42
116
|
__decorate([
|
|
43
117
|
property()
|
|
44
118
|
], HelixHeadlessCodeBlock.prototype, "label", void 0);
|
|
45
119
|
__decorate([
|
|
46
120
|
property({ attribute: 'no-copy', reflect: true, type: Boolean })
|
|
47
121
|
], HelixHeadlessCodeBlock.prototype, "noCopy", void 0);
|
|
122
|
+
__decorate([
|
|
123
|
+
property({ reflect: true })
|
|
124
|
+
], HelixHeadlessCodeBlock.prototype, "variant", void 0);
|
|
48
125
|
HelixHeadlessCodeBlock = __decorate([
|
|
49
126
|
customElement('helix-headless-code-block')
|
|
50
127
|
], HelixHeadlessCodeBlock);
|
|
@@ -143,9 +143,10 @@ export declare class HelixHeadlessColorPicker extends HelixHeadlessColorPicker_b
|
|
|
143
143
|
/**
|
|
144
144
|
* Whether this browser can sample a color off the screen.
|
|
145
145
|
*
|
|
146
|
-
* Settled
|
|
147
|
-
* no `
|
|
148
|
-
*
|
|
146
|
+
* Settled before each render rather than at construction, because a server
|
|
147
|
+
* has no `EyeDropper` and a button that ships in the markup and does nothing
|
|
148
|
+
* in Firefox is worse than one that is never offered. Not while hydrating a
|
|
149
|
+
* server's markup, which was rendered without it.
|
|
149
150
|
*/
|
|
150
151
|
private sampling;
|
|
151
152
|
/**
|
|
@@ -103,7 +103,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
103
103
|
}
|
|
104
104
|
firstUpdated(changed) {
|
|
105
105
|
super.firstUpdated(changed);
|
|
106
|
-
this.
|
|
106
|
+
this.finishHydration();
|
|
107
107
|
}
|
|
108
108
|
updated(changed) {
|
|
109
109
|
super.updated(changed);
|
|
@@ -151,6 +151,9 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
151
151
|
willUpdate(changed) {
|
|
152
152
|
super.willUpdate(changed);
|
|
153
153
|
this.internals.ariaInvalid = this.invalid ? 'true' : null;
|
|
154
|
+
if (!this.hydrating) {
|
|
155
|
+
this.sampling = 'EyeDropper' in globalThis;
|
|
156
|
+
}
|
|
154
157
|
}
|
|
155
158
|
renderTools() {
|
|
156
159
|
return html `<${this.tag('button-group')} part="actions" label="Color tools">
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
import type
|
|
3
|
+
import { type HelixHeadlessTableColumn } from '../../table/column/table-column.js';
|
|
4
|
+
import '../../checkbox/index.js';
|
|
4
5
|
import '../../pagination/index.js';
|
|
5
6
|
import { type DataRow } from './order.js';
|
|
6
7
|
declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & typeof HelixElement;
|
|
@@ -32,6 +33,25 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
32
33
|
* right shape with nothing in it. That is the cost of the first paragraph: use
|
|
33
34
|
* `helix-table` where the served HTML has to carry the values.
|
|
34
35
|
*
|
|
36
|
+
* **`selectable` adds a column of checkboxes, keyed on `row-key`.** A row is
|
|
37
|
+
* selected by its identity rather than its position, so a selection survives a
|
|
38
|
+
* sort, a filter and a page. `selected` is the chosen keys, comma separated, the
|
|
39
|
+
* shape Listbox uses for a multiple choice, and like `sort` it is controlled
|
|
40
|
+
* when set and seeded by `default-selected`. The box in the heading selects every
|
|
41
|
+
* row in the result, across pages, and shows a dash while only some are chosen.
|
|
42
|
+
* Choosing one of many, rather than several, is opening a row, and that is a
|
|
43
|
+
* link or a button in a cell rather than a selection.
|
|
44
|
+
*
|
|
45
|
+
* **A reader can size and order the columns.** `resizable` on a column puts a
|
|
46
|
+
* separator on its edge; `reorderable` on the table puts a grip on each heading
|
|
47
|
+
* that has a `field`, moved by dragging or with the arrow keys. The order lands
|
|
48
|
+
* in `order` as fields, and the consumer's own markup is never rewritten: the
|
|
49
|
+
* table assigns the headings to its header in that order instead.
|
|
50
|
+
*
|
|
51
|
+
* **`csv()` hands back the result as text**: every row the filter lets through,
|
|
52
|
+
* in the order on screen, in the columns on screen. Saving it is the page's
|
|
53
|
+
* business, the same as any other file.
|
|
54
|
+
*
|
|
35
55
|
* @since 0.1.0
|
|
36
56
|
* @status experimental
|
|
37
57
|
* @category data
|
|
@@ -44,17 +64,29 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
44
64
|
*
|
|
45
65
|
* @event {HelixFilterEvent} helix-filter - Fired when the query changes, and cancelable.
|
|
46
66
|
* @event {HelixNavigateEvent} helix-navigate - Fired when a reader asks for another page, and cancelable.
|
|
67
|
+
* @event {HelixReorderEvent} helix-reorder - Fired when a reader asks for the columns in another order, with every field in the new one, and cancelable.
|
|
68
|
+
* @event {HelixSelectEvent} helix-select - Fired when a reader changes which rows are selected, with every selected key comma separated, and cancelable.
|
|
47
69
|
* @event {HelixSortEvent} helix-sort - Fired when a reader asks for a different order, and cancelable.
|
|
48
70
|
*
|
|
49
71
|
* @csspart after - The room the rows below the window would have taken. Windowed only.
|
|
50
72
|
* @csspart before - The room the rows above the window would have taken. Windowed only.
|
|
51
73
|
* @csspart cell - One cell.
|
|
74
|
+
* @csspart checkbox - A row's checkbox, or the one in the heading that selects them all.
|
|
75
|
+
* @csspart checkbox-box - The frame the checkbox's input is painted as.
|
|
76
|
+
* @csspart checkbox-control - The checkbox's input.
|
|
77
|
+
* @csspart checkbox-feedback - Forwarded from the checkbox, and never drawn here.
|
|
78
|
+
* @csspart checkbox-field - The row the checkbox's box sits in.
|
|
79
|
+
* @csspart checkbox-hint - Forwarded from the checkbox, and never drawn here.
|
|
80
|
+
* @csspart checkbox-label - Forwarded from the checkbox; the label is spoken, not shown.
|
|
81
|
+
* @csspart checkbox-mark - The tick, or the dash while some rows are selected.
|
|
52
82
|
* @csspart empty - Shown when no rows match.
|
|
53
83
|
* @csspart footer - The region below the grid.
|
|
54
84
|
* @csspart head - The row the column headings sit in. `display: contents`, so it takes no space.
|
|
55
85
|
* @csspart loading - Shown while the rows are still on their way.
|
|
56
86
|
* @csspart pagination - The pagination, where this draws one.
|
|
57
87
|
* @csspart row - One row of data.
|
|
88
|
+
* @csspart select - The cell holding a row's checkbox.
|
|
89
|
+
* @csspart select-all - The heading holding the checkbox that selects every row.
|
|
58
90
|
* @csspart table - The grid.
|
|
59
91
|
* @csspart toolbar - The region above the grid.
|
|
60
92
|
*
|
|
@@ -75,6 +107,10 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
75
107
|
* Query to open with, where nothing declared one.
|
|
76
108
|
*/
|
|
77
109
|
defaultFilter: string;
|
|
110
|
+
/**
|
|
111
|
+
* Column order to open with, where nothing declared one.
|
|
112
|
+
*/
|
|
113
|
+
defaultOrder: string;
|
|
78
114
|
/**
|
|
79
115
|
* Page to open on, where nothing declared one.
|
|
80
116
|
*/
|
|
@@ -83,6 +119,10 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
83
119
|
* Page size to open with, where nothing declared one.
|
|
84
120
|
*/
|
|
85
121
|
defaultPageSize: number;
|
|
122
|
+
/**
|
|
123
|
+
* Keys to open with selected, comma separated, where nothing declared any.
|
|
124
|
+
*/
|
|
125
|
+
defaultSelected: string;
|
|
86
126
|
/**
|
|
87
127
|
* Order to open on, where nothing declared one.
|
|
88
128
|
*/
|
|
@@ -107,16 +147,9 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
107
147
|
get sort(): string;
|
|
108
148
|
set sort(next: string);
|
|
109
149
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* **Needed before selection exists, not after.** Lit keys the rendered rows by
|
|
113
|
-
* it, so a sort moves a row's element rather than rewriting every cell in
|
|
114
|
-
* place, which is what keeps focus inside a cell and keeps a CSS transition
|
|
115
|
-
* attached to the row it belongs to. Left unset the index is the key, which is
|
|
116
|
-
* correct only while nothing reorders: it is why this defaults to something
|
|
117
|
-
* that works and is worth setting anyway.
|
|
150
|
+
* Accessible name for the grid.
|
|
118
151
|
*/
|
|
119
|
-
|
|
152
|
+
label: string;
|
|
120
153
|
/**
|
|
121
154
|
* What the rows are narrowed to, as one query across every column.
|
|
122
155
|
*
|
|
@@ -127,9 +160,16 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
127
160
|
get filter(): string;
|
|
128
161
|
set filter(next: string);
|
|
129
162
|
/**
|
|
130
|
-
*
|
|
163
|
+
* Whether this element does the work or asks the consumer to.
|
|
164
|
+
*
|
|
165
|
+
* `client` filters, sorts and pages `rows` itself. `server` applies none of
|
|
166
|
+
* them: `rows` is the page, `total` is the size of the whole result, and the
|
|
167
|
+
* three events are requests the consumer answers by fetching. Past some size
|
|
168
|
+
* the client cannot hold the data, so this is not an optimization, it is the
|
|
169
|
+
* only mode that works, and it is here from the start because adding it later
|
|
170
|
+
* inverts the data flow.
|
|
131
171
|
*/
|
|
132
|
-
|
|
172
|
+
mode: 'client' | 'server';
|
|
133
173
|
/**
|
|
134
174
|
* The page on show, from 1.
|
|
135
175
|
*
|
|
@@ -140,16 +180,38 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
140
180
|
get page(): number;
|
|
141
181
|
set page(next: number);
|
|
142
182
|
/**
|
|
143
|
-
* Whether
|
|
183
|
+
* Whether a reader may move the columns.
|
|
144
184
|
*
|
|
145
|
-
* `
|
|
146
|
-
*
|
|
147
|
-
* three events are requests the consumer answers by fetching. Past some size
|
|
148
|
-
* the client cannot hold the data, so this is not an optimization, it is the
|
|
149
|
-
* only mode that works, and it is here from the start because adding it later
|
|
150
|
-
* inverts the data flow.
|
|
185
|
+
* Each heading with a `field` gets a grip, dragged along the header or moved a
|
|
186
|
+
* place at a time with the arrow keys once it has focus.
|
|
151
187
|
*/
|
|
152
|
-
|
|
188
|
+
reorderable: boolean;
|
|
189
|
+
/**
|
|
190
|
+
* The columns' order, as their fields separated by spaces.
|
|
191
|
+
*
|
|
192
|
+
* A reader's move fires `helix-reorder` first, and refusing it leaves the
|
|
193
|
+
* columns where they were, which is how a consumer who stores the order takes
|
|
194
|
+
* the decision. `default-order` seeds an order this element then owns. A field not named
|
|
195
|
+
* keeps its place after the named ones, and a column with no field never
|
|
196
|
+
* moves.
|
|
197
|
+
*/
|
|
198
|
+
get order(): string;
|
|
199
|
+
set order(next: string);
|
|
200
|
+
/**
|
|
201
|
+
* The field naming a row's stable identity.
|
|
202
|
+
*
|
|
203
|
+
* **Needed before selection exists, not after.** Lit keys the rendered rows by
|
|
204
|
+
* it, so a sort moves a row's element rather than rewriting every cell in
|
|
205
|
+
* place, which is what keeps focus inside a cell and keeps a CSS transition
|
|
206
|
+
* attached to the row it belongs to. Left unset the index is the key, which is
|
|
207
|
+
* correct only while nothing reorders: it is why this defaults to something
|
|
208
|
+
* that works and is worth setting anyway.
|
|
209
|
+
*
|
|
210
|
+
* **`row-key` and not `key`**, which is what it was called until selection
|
|
211
|
+
* needed it from React: `key` is reserved there, and a JSX `key` never reaches
|
|
212
|
+
* the element, so a React page could not tell the table which field a row is.
|
|
213
|
+
*/
|
|
214
|
+
rowKey: string;
|
|
153
215
|
/**
|
|
154
216
|
* The whole result, in the order it arrived.
|
|
155
217
|
*
|
|
@@ -162,6 +224,24 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
162
224
|
* holds and reordering it under them is a mutation they did not ask for.
|
|
163
225
|
*/
|
|
164
226
|
rows: readonly DataRow[];
|
|
227
|
+
/**
|
|
228
|
+
* Whether a reader may select rows, with a column of checkboxes.
|
|
229
|
+
*
|
|
230
|
+
* Wants `row-key`: a selection is a set of identities, and without one the rows
|
|
231
|
+
* are known by their place in the result, which a sort changes.
|
|
232
|
+
*/
|
|
233
|
+
selectable: boolean;
|
|
234
|
+
/**
|
|
235
|
+
* The keys of the selected rows, comma separated.
|
|
236
|
+
*
|
|
237
|
+
* A string rather than an array, so it is an attribute a server writes and a
|
|
238
|
+
* framework's hydration keeps, and the shape a multiple Listbox already uses.
|
|
239
|
+
* A key holding a comma cannot be told apart from two keys, which is the
|
|
240
|
+
* price of the shape. A reader's choice fires `helix-select` first, and
|
|
241
|
+
* refusing it leaves the selection as it was.
|
|
242
|
+
*/
|
|
243
|
+
get selected(): string;
|
|
244
|
+
set selected(next: string);
|
|
165
245
|
/**
|
|
166
246
|
* How many rows a page holds. Zero is every row, which is what "no paging" means.
|
|
167
247
|
*
|
|
@@ -217,6 +297,14 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
217
297
|
private pageState;
|
|
218
298
|
private pageSizeState;
|
|
219
299
|
private paginatedState;
|
|
300
|
+
private orderState;
|
|
301
|
+
private selectedState;
|
|
302
|
+
/** The order while a grip is being dragged, before anybody has been asked. */
|
|
303
|
+
private dragOrder;
|
|
304
|
+
/** The column a grip is dragging, and the pointer doing it. */
|
|
305
|
+
private dragging;
|
|
306
|
+
/** Said once, so a table that re-renders does not repeat it. */
|
|
307
|
+
private warnedAboutKey;
|
|
220
308
|
private readonly virtualize;
|
|
221
309
|
/**
|
|
222
310
|
* The rows in the shadow tree, each with the row of the page it drew.
|
|
@@ -259,6 +347,16 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
259
347
|
private windowOf;
|
|
260
348
|
/** The columns declared as children, in the order they are written. */
|
|
261
349
|
get tableColumns(): HelixHeadlessTableColumn[];
|
|
350
|
+
/**
|
|
351
|
+
* The columns in the order a reader arranged them.
|
|
352
|
+
*
|
|
353
|
+
* The ones with a field are put in `order`'s order, those it does not name
|
|
354
|
+
* after them in the order they were written, and a column with no field stays
|
|
355
|
+
* where it was written: it has nothing to be named by.
|
|
356
|
+
*/
|
|
357
|
+
get orderedColumns(): HelixHeadlessTableColumn[];
|
|
358
|
+
/** The fields in the order on screen. */
|
|
359
|
+
private get fields();
|
|
262
360
|
/** The columns reduced to what the ordering needs. */
|
|
263
361
|
private get axes();
|
|
264
362
|
/** The track list, from the columns if there are any. */
|
|
@@ -337,6 +435,47 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
337
435
|
* consumer refuses the local reorder, fetches, and hands back a new set.
|
|
338
436
|
*/
|
|
339
437
|
private requestSort;
|
|
438
|
+
/** Asks for the columns in a different order, as every field in the new one. */
|
|
439
|
+
private requestOrder;
|
|
440
|
+
/** Asks for a different set of selected rows. */
|
|
441
|
+
private requestSelected;
|
|
442
|
+
/** The keys selected now. */
|
|
443
|
+
private get chosen();
|
|
444
|
+
/**
|
|
445
|
+
* A row's identity: its `row-key` field, or its place in the whole result.
|
|
446
|
+
*
|
|
447
|
+
* The place is a fallback that is right only while nothing reorders, and a
|
|
448
|
+
* selection outlives an order, so `selectable` without a `row-key` says so once.
|
|
449
|
+
*/
|
|
450
|
+
private keyOf;
|
|
451
|
+
/**
|
|
452
|
+
* Every key the box in the heading answers for: the whole result in `client`
|
|
453
|
+
* mode, across every page, and the page it was handed in `server` mode, which
|
|
454
|
+
* is all it holds.
|
|
455
|
+
*/
|
|
456
|
+
private get everyKey();
|
|
457
|
+
/** Ticks or clears one row, which the checkbox asked for and was refused. */
|
|
458
|
+
private readonly toggleRow;
|
|
459
|
+
/** Selects every row, or clears them all where every one already was. */
|
|
460
|
+
private readonly toggleAll;
|
|
461
|
+
/** Moves a column by some places among the ones that move. */
|
|
462
|
+
private moveColumn;
|
|
463
|
+
/**
|
|
464
|
+
* The result as CSV: every row the filter lets through, in the order on
|
|
465
|
+
* screen, in the columns on screen, headed by their headings.
|
|
466
|
+
*
|
|
467
|
+
* **Values, not cells.** A cell may be a template, a badge or a link, so each
|
|
468
|
+
* column gives its field's value, which is what a spreadsheet wants anyway.
|
|
469
|
+
* A column with no field has no value and is left out. In `server` mode this
|
|
470
|
+
* is the page it holds, which is all it can know.
|
|
471
|
+
*
|
|
472
|
+
* **A text value that a spreadsheet would run is quoted as text.** A cell
|
|
473
|
+
* opening with `=`, `+`, `-` or `@` is a formula to a spreadsheet, and a
|
|
474
|
+
* result is often something a reader did not write: those values gain a
|
|
475
|
+
* leading apostrophe, the mark spreadsheets read as "this is text". Numbers are
|
|
476
|
+
* left alone, so a negative one stays a number.
|
|
477
|
+
*/
|
|
478
|
+
csv(): string;
|
|
340
479
|
/** Asks for a different query. */
|
|
341
480
|
private requestFilter;
|
|
342
481
|
/** Asks for a different page. */
|
|
@@ -402,6 +541,13 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
402
541
|
/** Columns arrive from the light DOM, which changes no property here. */
|
|
403
542
|
private readonly handleSlotChange;
|
|
404
543
|
private renderCell;
|
|
544
|
+
/**
|
|
545
|
+
* A checkbox, named for what it chooses, whose change the table takes.
|
|
546
|
+
*
|
|
547
|
+
* Refused and re-asked rather than left to tick itself: the selection is the
|
|
548
|
+
* table's, so the box only ever shows what `selected` says.
|
|
549
|
+
*/
|
|
550
|
+
private renderCheckbox;
|
|
405
551
|
private renderRows;
|
|
406
552
|
/**
|
|
407
553
|
* A row's place in the whole result, counting the header as row 1.
|
|
@@ -439,6 +585,8 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
439
585
|
private renderSpacer;
|
|
440
586
|
/** The controller owns the geometry; this is only what tells it to look again. */
|
|
441
587
|
private readonly handleScroll;
|
|
588
|
+
/** The heading of the checkbox column, which selects the whole result. */
|
|
589
|
+
private renderSelectAll;
|
|
442
590
|
protected render(): TemplateResult;
|
|
443
591
|
/**
|
|
444
592
|
* Listens on the host, not on the slot the columns are assigned to.
|
|
@@ -457,10 +605,34 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
457
605
|
*/
|
|
458
606
|
connectedCallback(): void;
|
|
459
607
|
disconnectedCallback(): void;
|
|
460
|
-
/**
|
|
608
|
+
/**
|
|
609
|
+
* A click on a sortable heading, anywhere but its grip or its edge.
|
|
610
|
+
*
|
|
611
|
+
* Enter and Space arrive here too, as the click the heading's sort button
|
|
612
|
+
* makes of them, so a keyboard needs nothing of its own.
|
|
613
|
+
*/
|
|
461
614
|
private readonly handleHeadClick;
|
|
462
|
-
/**
|
|
463
|
-
private
|
|
615
|
+
/** Whether the event passed through a part of that name on its way here. */
|
|
616
|
+
private partIn;
|
|
617
|
+
/** The arrow keys on a grip move its column a place, along the writing direction. */
|
|
618
|
+
private readonly handleGripKey;
|
|
619
|
+
/**
|
|
620
|
+
* A grip taken hold of: the headings follow the pointer and the order is asked
|
|
621
|
+
* for once it lets go.
|
|
622
|
+
*
|
|
623
|
+
* Previewed without an event, because a drag passes through a dozen orders on
|
|
624
|
+
* its way to the one the reader meant, and a consumer should hear the one.
|
|
625
|
+
*/
|
|
626
|
+
private readonly handleGripDown;
|
|
627
|
+
private readonly handleGripMove;
|
|
628
|
+
private readonly handleGripUp;
|
|
629
|
+
private readonly handleGripCancel;
|
|
630
|
+
private stopDrag;
|
|
631
|
+
/**
|
|
632
|
+
* A column asked for a width. The column keeps its own, so all this does is
|
|
633
|
+
* draw the grid again once it has, a microtask on, when the width has landed.
|
|
634
|
+
*/
|
|
635
|
+
private readonly handleResize;
|
|
464
636
|
private columnFrom;
|
|
465
637
|
/**
|
|
466
638
|
* The composed pagination's request, relayed as this element's own.
|