@fusion.dev/helix-headless 0.176.0 → 0.177.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 +610 -696
- package/dist/area-chart/root/area-chart-root.d.ts +18 -1
- package/dist/area-chart/root/area-chart-root.js +2 -2
- package/dist/avatar/root/avatar-root.d.ts +1 -1
- package/dist/avatar/root/avatar-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +19 -1
- package/dist/bar-chart/root/bar-chart-root.js +2 -2
- package/dist/canvas/node/canvas-node.js +1 -1
- package/dist/canvas/root/canvas-root.d.ts +5 -1
- package/dist/canvas/root/canvas-root.js +9 -1
- package/dist/donut-chart/root/donut-chart-root.d.ts +37 -2
- package/dist/donut-chart/root/donut-chart-root.js +22 -8
- package/dist/element-events.generated.js +2 -0
- package/dist/graph/root/graph-root.d.ts +28 -3
- package/dist/graph/root/graph-root.js +38 -3
- package/dist/heatmap/root/heatmap-root.d.ts +28 -5
- package/dist/heatmap/root/heatmap-root.js +7 -2
- package/dist/line-chart/root/line-chart-root.d.ts +18 -1
- package/dist/line-chart/root/line-chart-root.js +2 -2
- package/dist/loader/root/loader-root.d.ts +15 -0
- package/dist/loader/root/loader-root.js +28 -6
- package/dist/rating/root/rating-root.d.ts +2 -1
- package/dist/rating/root/rating-root.js +8 -2
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +29 -6
- package/dist/scatter-chart/root/scatter-chart-root.js +18 -3
- package/dist/select/root/select-root.d.ts +4 -1
- package/dist/select/root/select-root.js +1 -0
- package/dist/sparkline/root/sparkline-root.d.ts +29 -4
- package/dist/sparkline/root/sparkline-root.js +8 -1
- package/dist/tag/group/tag-group.d.ts +4 -3
- package/dist/tag/group/tag-group.js +6 -5
- package/dist/tag/root/tag-root.js +2 -1
- package/dist/tree/item/tree-item.d.ts +4 -4
- package/dist/tree/item/tree-item.js +5 -1
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +532 -364
- package/types/vue.d.ts +86 -19
- package/types/words.d.ts +22 -0
|
@@ -82,7 +82,10 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
82
82
|
keysOf(cells) {
|
|
83
83
|
const offset = this.points.length - cells.length;
|
|
84
84
|
const rows = this.sourceRows;
|
|
85
|
-
return cells.map((_, index) =>
|
|
85
|
+
return cells.map((_, index) => {
|
|
86
|
+
const row = rows[offset + index];
|
|
87
|
+
return row?.when ?? row?.label ?? '';
|
|
88
|
+
});
|
|
86
89
|
}
|
|
87
90
|
choose(next) {
|
|
88
91
|
if (next === this.value) {
|
|
@@ -181,6 +184,8 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
181
184
|
super.updated(changed);
|
|
182
185
|
this.markEmpty();
|
|
183
186
|
this.measure();
|
|
187
|
+
this.toggleState('active', this.pointer.at >= 0);
|
|
188
|
+
this.toggleState('empty', this.drawn.length === 0 && this.sourceKnown);
|
|
184
189
|
const showing = this.visible;
|
|
185
190
|
const written = showing > 0 ? String(showing) : null;
|
|
186
191
|
if (this.getAttribute('visible') !== written) {
|
|
@@ -242,7 +247,7 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
242
247
|
<span part="end"><slot name="end"></slot></span>
|
|
243
248
|
</div>${readable ? this.renderOverview(cells) : nothing}${this.status.spoken
|
|
244
249
|
? html `<span part="selection" role="status">${this.status.said}</span>`
|
|
245
|
-
: nothing}`;
|
|
250
|
+
: nothing}${this.renderTable()}`;
|
|
246
251
|
}
|
|
247
252
|
renderOverview(cells) {
|
|
248
253
|
const rows = this.sourceRows;
|
|
@@ -55,6 +55,18 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
|
|
|
55
55
|
* there until readings arrive. The `empty` and `loading` slots take markup in
|
|
56
56
|
* their place, such as a link to add the first reading.
|
|
57
57
|
*
|
|
58
|
+
* **Keyboard.** The plot is one tab stop.
|
|
59
|
+
*
|
|
60
|
+
* | Key | What it does |
|
|
61
|
+
* |---|---|
|
|
62
|
+
* | Tab | Moves focus to the plot and shows the first reading. |
|
|
63
|
+
* | Right, Left | Moves to the next or the previous reading. On a right-to-left page, Left moves to the next. |
|
|
64
|
+
* | Down, Up | Moves among the series of the reading. With one series, moves to the next or the previous reading. |
|
|
65
|
+
* | Home, End | Moves to the first or the last reading. |
|
|
66
|
+
* | Page Down, Page Up | Moves a tenth of the readings on or back. |
|
|
67
|
+
* | Enter, Space | Presses the reading shown, which sends `helix-reading-press`. |
|
|
68
|
+
* | Escape | Puts the reading and its tooltip away. |
|
|
69
|
+
*
|
|
58
70
|
* @since 0.1.0
|
|
59
71
|
* @status stable
|
|
60
72
|
* @category charts
|
|
@@ -83,9 +95,10 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
|
|
|
83
95
|
* @csspart mark - The invisible point the tooltip is anchored to.
|
|
84
96
|
* @csspart marker - The mark on one reading, under `markers`, and on a reading with a blank on either side. Placed with `inset-inline-start` and `inset-block-start`, and carries its series color as `--chart-series`.
|
|
85
97
|
* @csspart marker-lone - A `marker` on a reading with a blank on either side, which no line reaches. Set alongside `marker`.
|
|
86
|
-
* @csspart plot - The drawing, which takes focus to be read by key.
|
|
98
|
+
* @csspart plot - The drawing, which takes focus to be read by key. With nothing to draw, a group named as the chart is, holding the `empty` or `loading` part.
|
|
87
99
|
* @csspart summary - The chart's name and each series' latest reading, written as a sentence for screen readers. Hide it visually.
|
|
88
100
|
* @csspart svg - The drawing surface the lines and areas sit on.
|
|
101
|
+
* @csspart table - The readings as a table, for a screen reader, rendered only where they were drawn from `data`. Hide it visually.
|
|
89
102
|
* @csspart terminus - The mark on one series' last reading.
|
|
90
103
|
* @csspart tick - One number on the axis, placed with `inset-block-start` at its level.
|
|
91
104
|
* @csspart tooltip - The bubble, forwarded from `Tooltip`.
|
|
@@ -108,6 +121,10 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
|
|
|
108
121
|
* @cssproperty --chart-terminus-x - Where a series' last reading sits horizontally, as a percentage. Written by the component.
|
|
109
122
|
* @cssproperty --chart-terminus-y - Where a series' last reading sits vertically, as a percentage. Written by the component.
|
|
110
123
|
* @cssproperty --line-chart-axis - The width of the axis, in `ch`, set from the widest number on it. Written by the component on the axis.
|
|
124
|
+
*
|
|
125
|
+
* @cssstate active - While a reading is shown, under the pointer or the keys, with its tooltip open.
|
|
126
|
+
* @cssstate empty - While the `empty` part stands in the plot.
|
|
127
|
+
* @cssstate loading - While the `loading` part stands in the plot.
|
|
111
128
|
*/
|
|
112
129
|
export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base {
|
|
113
130
|
/**
|
|
@@ -59,13 +59,13 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartStat
|
|
|
59
59
|
const series = this.series;
|
|
60
60
|
const readings = series.length === 0 ? [] : this.sourceRows.map((row) => row.label);
|
|
61
61
|
if (readings.length === 0) {
|
|
62
|
-
return
|
|
62
|
+
return this.renderEmpty();
|
|
63
63
|
}
|
|
64
64
|
const domain = this.range(series);
|
|
65
65
|
const y = linear(domain, [PLOT_HEIGHT, 0]);
|
|
66
66
|
const slot = PLOT_WIDTH / readings.length;
|
|
67
67
|
const x = linear([0, Math.max(readings.length - 1, 1)], [slot / 2, PLOT_WIDTH - slot / 2]);
|
|
68
|
-
return html `${this.valueAxis ? this.renderAxis(y, domain) : nothing}${this.renderPlot(series, x, y, domain)} ${this.renderLabels(readings)}${this.renderSummary(series)}`;
|
|
68
|
+
return html `${this.valueAxis ? this.renderAxis(y, domain) : nothing}${this.renderPlot(series, x, y, domain)} ${this.renderLabels(readings)}${this.renderSummary(series)}${this.renderTable()}`;
|
|
69
69
|
}
|
|
70
70
|
renderAxis(y, domain) {
|
|
71
71
|
return drawValueAxis(domain, (value) => (y(value) / PLOT_HEIGHT) * 100, formatNumbers(wordsLocale(this)), (widest) => `--line-chart-axis: ${widest}ch`);
|
|
@@ -34,6 +34,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
34
34
|
* hidden, and silent, for that many milliseconds, and appears only if the work
|
|
35
35
|
* is still going. While it waits it carries `:state(waiting)`.
|
|
36
36
|
*
|
|
37
|
+
* **The loader can stand in for what it wraps.** Put the content in the
|
|
38
|
+
* `content` slot, such as a button or a card, and set `idle` while no work is
|
|
39
|
+
* in progress. While the work runs, the content keeps its size and is hidden
|
|
40
|
+
* and inert, and the ring draws over it. While `idle` is set, the loader draws
|
|
41
|
+
* nothing of its own, has no role, and marks no region busy, so only the
|
|
42
|
+
* content shows. Clearing `idle` starts `delay` again.
|
|
43
|
+
*
|
|
37
44
|
* @since 0.1.0
|
|
38
45
|
* @status stable
|
|
39
46
|
* @category feedback
|
|
@@ -41,7 +48,9 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
41
48
|
* @documentation https://fusion.dev/helix/components/loader
|
|
42
49
|
*
|
|
43
50
|
* @slot - An icon or logo that stays still at the center. Empty by default.
|
|
51
|
+
* @slot content - What the loader stands in for while the work runs, such as a button. It keeps its size, hidden and inert, until `idle` is set.
|
|
44
52
|
*
|
|
53
|
+
* @csspart content - The box that holds the `content` slot. Hidden while the work runs, and shown while `idle` is set.
|
|
45
54
|
* @csspart indicator - The arc that turns.
|
|
46
55
|
* @csspart mark - The region that holds the slotted content at the center.
|
|
47
56
|
* @csspart svg - The rotating circle pair.
|
|
@@ -71,6 +80,12 @@ export declare class HelixHeadlessLoader extends HelixElement {
|
|
|
71
80
|
* way `Tooltip.for` does.
|
|
72
81
|
*/
|
|
73
82
|
for: string;
|
|
83
|
+
/**
|
|
84
|
+
* Whether no work is in progress. The loader draws nothing of its own, has
|
|
85
|
+
* no role, and marks no region busy, and what is in the `content` slot
|
|
86
|
+
* shows. Clearing it starts `delay` again.
|
|
87
|
+
*/
|
|
88
|
+
idle: boolean;
|
|
74
89
|
/**
|
|
75
90
|
* The loader's name, announced by screen readers while the work is in
|
|
76
91
|
* progress.
|
|
@@ -5,7 +5,7 @@ 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 { customElement, DelayController, elementById, HelixElement, hostAria, reportRuntime, words, } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html } from 'lit';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { awaitRegion, claimBusy, releaseBusy } from '../busy.js';
|
|
11
11
|
let HelixHeadlessLoader = class HelixHeadlessLoader extends HelixElement {
|
|
@@ -13,6 +13,7 @@ let HelixHeadlessLoader = class HelixHeadlessLoader extends HelixElement {
|
|
|
13
13
|
super(...arguments);
|
|
14
14
|
this.delay = 0;
|
|
15
15
|
this.for = '';
|
|
16
|
+
this.idle = false;
|
|
16
17
|
this.label = 'Loading';
|
|
17
18
|
this.due = new DelayController(this);
|
|
18
19
|
this.region = null;
|
|
@@ -20,7 +21,7 @@ let HelixHeadlessLoader = class HelixHeadlessLoader extends HelixElement {
|
|
|
20
21
|
}
|
|
21
22
|
static { this.words = 'helix-loader'; }
|
|
22
23
|
get waiting() {
|
|
23
|
-
return this.delay > 0 && !this.due.elapsed;
|
|
24
|
+
return !this.idle && this.delay > 0 && !this.due.elapsed;
|
|
24
25
|
}
|
|
25
26
|
connectedCallback() {
|
|
26
27
|
super.connectedCallback();
|
|
@@ -46,7 +47,7 @@ let HelixHeadlessLoader = class HelixHeadlessLoader extends HelixElement {
|
|
|
46
47
|
mark() {
|
|
47
48
|
this.stopAwaiting?.();
|
|
48
49
|
this.stopAwaiting = undefined;
|
|
49
|
-
const named = this.isConnected && this.for !== '';
|
|
50
|
+
const named = this.isConnected && this.for !== '' && !this.idle;
|
|
50
51
|
const region = named ? elementById(this, this.for) : null;
|
|
51
52
|
if (named && !region) {
|
|
52
53
|
this.stopAwaiting = awaitRegion(this.getRootNode(), () => elementById(this, this.for), () => this.mark());
|
|
@@ -73,16 +74,34 @@ let HelixHeadlessLoader = class HelixHeadlessLoader extends HelixElement {
|
|
|
73
74
|
this.found = false;
|
|
74
75
|
this.mark();
|
|
75
76
|
}
|
|
77
|
+
if (changed.has('idle') && changed.get('idle') !== undefined) {
|
|
78
|
+
if (!this.idle && this.delay > 0) {
|
|
79
|
+
this.due.start(this.delay);
|
|
80
|
+
}
|
|
81
|
+
this.mark();
|
|
82
|
+
}
|
|
76
83
|
}
|
|
77
84
|
willUpdate(changed) {
|
|
78
85
|
super.willUpdate(changed);
|
|
79
|
-
hostAria(this.internals, {
|
|
80
|
-
|
|
86
|
+
hostAria(this.internals, {
|
|
87
|
+
label: this.idle ? '' : this.label,
|
|
88
|
+
role: this.idle ? '' : 'progressbar',
|
|
89
|
+
});
|
|
90
|
+
this.internals.ariaBusy = this.idle ? null : 'true';
|
|
81
91
|
this.internals.ariaHidden = this.waiting ? 'true' : null;
|
|
82
92
|
this.toggleState('waiting', this.waiting);
|
|
83
93
|
}
|
|
84
94
|
render() {
|
|
85
|
-
|
|
95
|
+
const content = html `<span
|
|
96
|
+
part="content"
|
|
97
|
+
?inert=${!this.idle}
|
|
98
|
+
style=${this.idle ? nothing : 'visibility: hidden'}
|
|
99
|
+
><slot name="content"></slot
|
|
100
|
+
></span>`;
|
|
101
|
+
if (this.idle) {
|
|
102
|
+
return content;
|
|
103
|
+
}
|
|
104
|
+
return html `${content}<svg part="svg" viewBox="0 0 24 24" aria-hidden="true" ?hidden=${this.waiting}>
|
|
86
105
|
<circle part="track" cx="12" cy="12" r="10" fill="none" />
|
|
87
106
|
<circle part="indicator" cx="12" cy="12" r="10" fill="none" />
|
|
88
107
|
</svg>
|
|
@@ -95,6 +114,9 @@ __decorate([
|
|
|
95
114
|
__decorate([
|
|
96
115
|
property()
|
|
97
116
|
], HelixHeadlessLoader.prototype, "for", void 0);
|
|
117
|
+
__decorate([
|
|
118
|
+
property({ type: Boolean })
|
|
119
|
+
], HelixHeadlessLoader.prototype, "idle", void 0);
|
|
98
120
|
__decorate([
|
|
99
121
|
words,
|
|
100
122
|
property()
|
|
@@ -30,7 +30,8 @@ declare const HelixHeadlessRating_base: (new (...args: any[]) => import("@fusion
|
|
|
30
30
|
*
|
|
31
31
|
* Left and Right swap on a right-to-left page. The marks are a `radiogroup`
|
|
32
32
|
* named by `label`, and each score is a `radio` named by `option-label`, such
|
|
33
|
-
* as "3 out of 5". A read-only rating is one `img` named by its
|
|
33
|
+
* as "3 out of 5". A read-only rating is one `img` named by its label and
|
|
34
|
+
* then its score, such as "Quality 3 out of 5".
|
|
34
35
|
*
|
|
35
36
|
* @since 0.1.0
|
|
36
37
|
* @status stable
|
|
@@ -21,6 +21,11 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
21
21
|
this.valueMissingMessage = 'Choose a rating to continue.';
|
|
22
22
|
this.valueText = '';
|
|
23
23
|
this.aria = new AriaForwardController(this, {
|
|
24
|
+
labelledByAfter: () => {
|
|
25
|
+
const score = this.readOnly ? this.renderRoot?.querySelector('#score') : null;
|
|
26
|
+
return score ? [score] : [];
|
|
27
|
+
},
|
|
28
|
+
named: () => this.labeled,
|
|
24
29
|
target: () => this.partNamed('marks'),
|
|
25
30
|
});
|
|
26
31
|
this.mark = new SlottedGlyph();
|
|
@@ -255,8 +260,8 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
255
260
|
<div
|
|
256
261
|
part="marks"
|
|
257
262
|
role=${this.readOnly ? 'img' : 'radiogroup'}
|
|
258
|
-
aria-label=${this.readOnly ? said : nothing}
|
|
259
|
-
aria-labelledby=${
|
|
263
|
+
aria-label=${this.readOnly && !this.labeled ? said : nothing}
|
|
264
|
+
aria-labelledby=${this.labeled ? (this.readOnly ? `${this.labelId} score` : this.labelId) : nothing}
|
|
260
265
|
aria-describedby=${this.describedBy ?? nothing}
|
|
261
266
|
aria-invalid=${this.invalidity ?? nothing}
|
|
262
267
|
aria-required=${this.required && !this.readOnly ? 'true' : nothing}
|
|
@@ -317,6 +322,7 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
317
322
|
>${showing}</span
|
|
318
323
|
>`
|
|
319
324
|
: nothing}
|
|
325
|
+
${this.readOnly ? html `<span id="score" hidden>${said}</span>` : nothing}
|
|
320
326
|
</div>
|
|
321
327
|
${this.renderHint()}${this.renderFeedback()}`;
|
|
322
328
|
}
|
|
@@ -51,10 +51,10 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
51
51
|
* readers.
|
|
52
52
|
*
|
|
53
53
|
* **The plot is read by key.** It takes focus, named by `label` or the caption.
|
|
54
|
-
* The left and right arrows move from
|
|
55
|
-
* and End go to the first and the last, and the up and down
|
|
56
|
-
* the series of a row. The tooltip sits on that point, the
|
|
57
|
-
* row in words, and Escape puts the tooltip away.
|
|
54
|
+
* The left and right arrows move from point to point, left to right across
|
|
55
|
+
* the plot, Home and End go to the first and the last, and the up and down
|
|
56
|
+
* arrows move among the series of a row. The tooltip sits on that point, the
|
|
57
|
+
* `live` part says the row in words, and Escape puts the tooltip away.
|
|
58
58
|
*
|
|
59
59
|
* Each point is a `<span>` placed by percentage over the drawing, as
|
|
60
60
|
* `LineChart` places its end points, so points stay round when the drawing
|
|
@@ -81,6 +81,18 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
81
81
|
* there until readings arrive. The `empty` and `loading` slots take markup in
|
|
82
82
|
* their place, such as a link to add the first reading.
|
|
83
83
|
*
|
|
84
|
+
* **Keyboard.** The plot is one tab stop.
|
|
85
|
+
*
|
|
86
|
+
* | Key | What it does |
|
|
87
|
+
* |---|---|
|
|
88
|
+
* | Tab | Moves focus to the plot and shows the first reading. |
|
|
89
|
+
* | Right, Left | Moves to the next or the previous point, left to right across the plot. On a right-to-left page, Left moves to the next. |
|
|
90
|
+
* | Down, Up | Moves among the series of the point. With one series, moves to the next or the previous point. |
|
|
91
|
+
* | Home, End | Moves to the first or the last point. |
|
|
92
|
+
* | Page Down, Page Up | Moves a tenth of the points on or back. |
|
|
93
|
+
* | Enter, Space | Presses the point shown, which sends `helix-reading-press`. |
|
|
94
|
+
* | Escape | Puts the point and its tooltip away. |
|
|
95
|
+
*
|
|
84
96
|
* @since 0.1.0
|
|
85
97
|
* @status stable
|
|
86
98
|
* @category charts
|
|
@@ -99,11 +111,12 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
99
111
|
* @csspart loading - The words in place of the drawing while `loading` is set and there are no readings: the `loading` slot, falling back to `loading-text`.
|
|
100
112
|
* @csspart mark - The invisible point the tooltip is anchored to.
|
|
101
113
|
* @csspart plane - The grid that holds the plot, both axes, and their names. It runs left to right on every page.
|
|
102
|
-
* @csspart plot - The drawing, which takes focus to be read by key.
|
|
114
|
+
* @csspart plot - The drawing, which takes focus to be read by key. With nothing to draw, a group named as the chart is, holding the `empty` or `loading` part.
|
|
103
115
|
* @csspart point - One row, as a point.
|
|
104
116
|
* @csspart point-active - A point in the row under the pointer. Set alongside `point`.
|
|
105
117
|
* @csspart summary - The text that says how strongly the measures relate, for people who cannot see the points.
|
|
106
118
|
* @csspart svg - The drawing surface the gridlines and the trend lines sit on.
|
|
119
|
+
* @csspart table - The readings as a table, for a screen reader, rendered only where they were drawn from `data`. Hide it visually.
|
|
107
120
|
* @csspart tooltip - The bubble, forwarded from `Tooltip`.
|
|
108
121
|
* @csspart tooltip-anchor - The `Tooltip` element itself.
|
|
109
122
|
* @csspart tooltip-arrow - The bubble's point, forwarded from `Tooltip`.
|
|
@@ -123,7 +136,7 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
123
136
|
* @csspart trend - One series' line of best fit, under `trend`. Carries its series color as `--chart-series`.
|
|
124
137
|
* @csspart x-axis - The values along the horizontal axis, under the plot.
|
|
125
138
|
* @csspart x-name - The name of the horizontal measure.
|
|
126
|
-
* @csspart x-tick - One labeled value on the horizontal axis. Each axis has its own tick part, because `::part()` cannot tell which axis a tick is on.
|
|
139
|
+
* @csspart x-tick - One labeled value on the horizontal axis. Each axis has its own tick part, because `::part()` cannot tell which axis a tick is on. The one at the far edge carries `data-edge="end"`.
|
|
127
140
|
* @csspart y-axis - The values along the vertical axis, beside the plot.
|
|
128
141
|
* @csspart y-name - The name of the vertical measure.
|
|
129
142
|
* @csspart y-tick - One labeled value on the vertical axis.
|
|
@@ -132,6 +145,10 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
132
145
|
* @cssproperty --chart-point-x - A point's horizontal position, as a percentage. The component writes it.
|
|
133
146
|
* @cssproperty --chart-point-y - A point's vertical position, as a percentage from the top. The component writes it.
|
|
134
147
|
* @cssproperty --chart-tick - A tick's position along its axis, as a percentage. The component writes it.
|
|
148
|
+
*
|
|
149
|
+
* @cssstate active - While a reading is shown, under the pointer or the keys, with its tooltip open.
|
|
150
|
+
* @cssstate empty - While the `empty` part stands in the plot.
|
|
151
|
+
* @cssstate loading - While the `loading` part stands in the plot.
|
|
135
152
|
*/
|
|
136
153
|
export declare class HelixHeadlessScatterChart extends HelixHeadlessScatterChart_base {
|
|
137
154
|
/**
|
|
@@ -228,6 +245,12 @@ export declare class HelixHeadlessScatterChart extends HelixHeadlessScatterChart
|
|
|
228
245
|
* a point with one coordinate has nowhere to be.
|
|
229
246
|
*/
|
|
230
247
|
protected get field(): ScatterField;
|
|
248
|
+
/**
|
|
249
|
+
* @internal The rows in the order the keys walk them: by the measure across,
|
|
250
|
+
* left to right, so a reader moves through the points as they are drawn. A
|
|
251
|
+
* row with nothing across comes last, in the table's order.
|
|
252
|
+
*/
|
|
253
|
+
readingOrder(): number[];
|
|
231
254
|
protected render(): TemplateResult;
|
|
232
255
|
/** The rules and the points, behind a seam the styled tier can move. */
|
|
233
256
|
protected renderPlot(field: ScatterField, along: (value: number) => number, up: (value: number) => number): TemplateResult;
|
|
@@ -135,12 +135,19 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
135
135
|
yNames: ups.map((column) => name(column)),
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
|
+
readingOrder() {
|
|
139
|
+
const across = this.plottedColumns[0];
|
|
140
|
+
const rows = this.sourceRows;
|
|
141
|
+
const x = (at) => (across === undefined ? undefined : rows[at]?.cells[across]?.value) ??
|
|
142
|
+
Number.POSITIVE_INFINITY;
|
|
143
|
+
return rows.map((_, at) => at).sort((one, two) => x(one) - x(two) || one - two);
|
|
144
|
+
}
|
|
138
145
|
render() {
|
|
139
146
|
const field = this.field;
|
|
140
147
|
this.drawn = field.points;
|
|
141
148
|
if (field.points.length === 0) {
|
|
142
149
|
return html `<div dir="ltr" part="plane">
|
|
143
|
-
|
|
150
|
+
${this.renderEmpty()}
|
|
144
151
|
</div>`;
|
|
145
152
|
}
|
|
146
153
|
const format = formatNumbers(wordsLocale(this));
|
|
@@ -149,7 +156,15 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
149
156
|
return html `<div dir="ltr" part="plane">
|
|
150
157
|
${this.renderPlot(field, along, up)}
|
|
151
158
|
<div aria-hidden="true" part="x-axis">
|
|
152
|
-
${ticks(field.x).map((level) =>
|
|
159
|
+
${ticks(field.x).map((level) => {
|
|
160
|
+
const place = along(level);
|
|
161
|
+
return html `<span
|
|
162
|
+
data-edge=${place >= PLOT_WIDTH ? 'end' : nothing}
|
|
163
|
+
part="x-tick"
|
|
164
|
+
style="--chart-tick: ${place}%"
|
|
165
|
+
>${format(level)}</span
|
|
166
|
+
>`;
|
|
167
|
+
})}
|
|
153
168
|
</div>
|
|
154
169
|
<div aria-hidden="true" part="y-axis">
|
|
155
170
|
${ticks(field.y).map((level) => html `<span part="y-tick" style="--chart-tick: ${up(level)}%">${format(level)}</span>`)}
|
|
@@ -157,7 +172,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
157
172
|
<span aria-hidden="true" dir="auto" part="x-name">${field.xName}</span>
|
|
158
173
|
<span aria-hidden="true" dir="auto" part="y-name">${field.yNames.join(', ')}</span>
|
|
159
174
|
</div>
|
|
160
|
-
${this.renderSummary(field)}`;
|
|
175
|
+
${this.renderSummary(field)}${this.renderTable()}`;
|
|
161
176
|
}
|
|
162
177
|
renderPlot(field, along, up) {
|
|
163
178
|
const at = this.pointer.at;
|
|
@@ -2,6 +2,7 @@ import { AriaForwardController, type DataOptionItem, HelixFormElement, PopoverCo
|
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import { type HelixHeadlessOption } from '../../option/root/option-root.js';
|
|
4
4
|
import '../../listbox/index.js';
|
|
5
|
+
import '../../option/index.js';
|
|
5
6
|
declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
6
7
|
/**
|
|
7
8
|
* @summary A control that opens a list of options to choose from.
|
|
@@ -13,7 +14,9 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
13
14
|
* place for focus to return to when the list closes.
|
|
14
15
|
*
|
|
15
16
|
* Your options stay in your light DOM and are slotted through into the listbox,
|
|
16
|
-
* so the listbox looks through slots to find them.
|
|
17
|
+
* so the listbox looks through slots to find them. Write them as `Option`,
|
|
18
|
+
* group them in `Option.Group`, and divide them with `Option.Separator`.
|
|
19
|
+
* Importing Select registers all three in the same tier. For a list too long to draw
|
|
17
20
|
* whole, set `items` instead: the list draws only the options in sight, as
|
|
18
21
|
* Listbox's `items` does, and the trigger, its keys and the form read the
|
|
19
22
|
* whole set.
|
|
@@ -12,6 +12,7 @@ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
|
12
12
|
import { html } from 'lit/static-html.js';
|
|
13
13
|
import { optionsAmong } from '../../option/root/option-root.js';
|
|
14
14
|
import '../../listbox/index.js';
|
|
15
|
+
import '../../option/index.js';
|
|
15
16
|
import { over } from '../align.js';
|
|
16
17
|
let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(MixinControllerValue(MixinField(HelixFormElement))) {
|
|
17
18
|
constructor() {
|
|
@@ -24,6 +24,10 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
|
24
24
|
* the lowest, in `overview-label`: "From 12 to 20, highest 30, lowest 8". An
|
|
25
25
|
* `aria-label` on the element names it as `label` does.
|
|
26
26
|
*
|
|
27
|
+
* `helix-reading-change` says each move of the reading, by pointer, tap or
|
|
28
|
+
* key, and `helix-reading-press` says a reading was clicked, tapped, or pressed
|
|
29
|
+
* with Enter or Space, as on every chart.
|
|
30
|
+
*
|
|
27
31
|
* A pointer resting on the drawing shows the reading under it: the `cursor`
|
|
28
32
|
* part marks it and the `readout` part writes it. `marks` adds a mark on the
|
|
29
33
|
* highest and the lowest reading, and `range` draws a band between two values,
|
|
@@ -38,12 +42,26 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
|
38
42
|
* the component computes and CSS cannot, so a stylesheet can draw the sparkline
|
|
39
43
|
* without measuring anything.
|
|
40
44
|
*
|
|
45
|
+
* **Keyboard.** A sparkline with a `label` is one tab stop.
|
|
46
|
+
*
|
|
47
|
+
* | Key | What it does |
|
|
48
|
+
* |---|---|
|
|
49
|
+
* | Tab | Moves focus to the drawing and shows the first reading, where there is a `label`. |
|
|
50
|
+
* | Any arrow | Right and Down move to the next reading, Left and Up to the previous. On a right-to-left page, Left moves to the next. |
|
|
51
|
+
* | Home, End | Moves to the first or the last reading. |
|
|
52
|
+
* | Page Down, Page Up | Moves a tenth of the readings on or back. |
|
|
53
|
+
* | Enter, Space | Presses the reading shown, which sends `helix-reading-press`. |
|
|
54
|
+
* | Escape | Puts the reading and its tooltip away. |
|
|
55
|
+
*
|
|
41
56
|
* @since 0.1.0
|
|
42
57
|
* @status stable
|
|
43
58
|
* @category charts
|
|
44
59
|
* @aliases Micro Chart, Trend Line, Inline Chart
|
|
45
60
|
* @documentation https://fusion.dev/helix/components/sparkline
|
|
46
61
|
*
|
|
62
|
+
* @event {HelixReadingChangeEvent} helix-reading-change - The reading shown moved, or was put away: `index` is the reading, or `-1` for none, with its row's `label` from a table and the `pointerType` that moved it.
|
|
63
|
+
* @event {HelixReadingPressEvent} helix-reading-press - A reading was clicked, tapped, or pressed with Enter or Space, with the same detail as `helix-reading-change`.
|
|
64
|
+
*
|
|
47
65
|
* @csspart area - The region between the line and the bottom of its range.
|
|
48
66
|
* @csspart bar - One column, drawn when `plot="bar"`.
|
|
49
67
|
* @csspart cursor - The mark on the reading a pointer or a key rests on, rendered only while there is one. Placed with `inset-inline-start` and `inset-block-start`.
|
|
@@ -201,17 +219,24 @@ export declare class HelixHeadlessSparkline extends HelixElement {
|
|
|
201
219
|
values: string | readonly number[];
|
|
202
220
|
protected readonly source: SourceController;
|
|
203
221
|
/**
|
|
204
|
-
* Finds the reading a pointer or a key rests on, as it does for
|
|
205
|
-
* chart, so a sparkline is read the way they are.
|
|
222
|
+
* @internal Finds the reading a pointer or a key rests on, as it does for
|
|
223
|
+
* every chart, so a sparkline is read the way they are.
|
|
206
224
|
*/
|
|
207
225
|
readonly pointer: ChartPointerController;
|
|
208
226
|
/**
|
|
209
|
-
* Hears an `aria-label` written on the sparkline, which no property mirrors,
|
|
227
|
+
* @internal Hears an `aria-label` written on the sparkline, which no property mirrors,
|
|
210
228
|
* because it names the drawing as `label` does, as on every chart.
|
|
211
229
|
*/
|
|
212
230
|
static get observedAttributes(): string[];
|
|
213
|
-
/** Called by the browser when an observed attribute changes; a new `aria-label` renames the drawing. */
|
|
231
|
+
/** @internal Called by the browser when an observed attribute changes; a new `aria-label` renames the drawing. */
|
|
214
232
|
attributeChangedCallback(name: string, old: string | null, value: string | null): void;
|
|
233
|
+
/**
|
|
234
|
+
* Sends the reading's moves and presses as `helix-reading-change` and
|
|
235
|
+
* `helix-reading-press`, named by the table's row where there is one. Here
|
|
236
|
+
* and not in a constructor, where the manifest's analyzer reads the
|
|
237
|
+
* assignment as a member of this class.
|
|
238
|
+
*/
|
|
239
|
+
connectedCallback(): void;
|
|
215
240
|
/** The drawing's name: an `aria-label` written on the sparkline, then `label`. */
|
|
216
241
|
get named(): string;
|
|
217
242
|
/** The two values of `range`, lower first, or none. */
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { CHART_PLOT, ChartPointerController, customElement, extent, extremesOf, formatNumbers, formatWords, HelixElement, linear, linePath, PLOT_WIDTH, SourceController, unbroken, words, wordsLocale, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { CHART_PLOT, ChartPointerController, customElement, extent, extremesOf, formatNumbers, formatWords, HelixElement, HelixReadingChangeEvent, HelixReadingPressEvent, linear, linePath, PLOT_WIDTH, SourceController, unbroken, words, wordsLocale, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing, svg } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { areaPath, overviewWords, readingWords, slotsOf } from '../readings.js';
|
|
@@ -33,6 +33,13 @@ let HelixHeadlessSparkline = class HelixHeadlessSparkline extends HelixElement {
|
|
|
33
33
|
this.requestUpdate();
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
connectedCallback() {
|
|
37
|
+
super.connectedCallback();
|
|
38
|
+
this.pointer.onReading = (heard, detail) => {
|
|
39
|
+
const told = { ...detail, label: this.source.rows[detail.index]?.label ?? '' };
|
|
40
|
+
this.dispatchEvent(heard === 'press' ? new HelixReadingPressEvent(told) : new HelixReadingChangeEvent(told));
|
|
41
|
+
};
|
|
42
|
+
}
|
|
36
43
|
get named() {
|
|
37
44
|
return this.getAttribute?.('aria-label') || this.label;
|
|
38
45
|
}
|
|
@@ -99,8 +99,9 @@ export declare class HelixHeadlessTagGroup extends HelixElement {
|
|
|
99
99
|
*/
|
|
100
100
|
selectionMode?: TagSelectionMode;
|
|
101
101
|
/**
|
|
102
|
-
* The selected tags' values, separated by commas
|
|
103
|
-
* space.
|
|
102
|
+
* The selected tags' values, separated by commas with no space, as Toggle
|
|
103
|
+
* Group and Table write theirs, since a value may hold a space. A value
|
|
104
|
+
* written with a space after each comma is read the same way.
|
|
104
105
|
*
|
|
105
106
|
* Set it to start with tags selected. A tag's value is its `value`, or its
|
|
106
107
|
* words where it has none.
|
|
@@ -159,7 +160,7 @@ export declare class HelixHeadlessTagGroup extends HelixElement {
|
|
|
159
160
|
/** Whether a press or a move selects the tag alone. */
|
|
160
161
|
private get replaces();
|
|
161
162
|
/**
|
|
162
|
-
* Asks for `value` to become `
|
|
163
|
+
* Asks for `value` to become `asked`, where it changes and where it leaves a
|
|
163
164
|
* tag selected under `disallow-empty-selection`.
|
|
164
165
|
*/
|
|
165
166
|
private ask;
|
|
@@ -108,7 +108,7 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
|
|
|
108
108
|
const left = this.tags.map((one) => this.valueFor(one));
|
|
109
109
|
const pruned = prunedValue(this.written, this.valueFor(tag), left);
|
|
110
110
|
if (pruned !== this.written) {
|
|
111
|
-
this.value = pruned;
|
|
111
|
+
this.value = commaList(pruned).join(',');
|
|
112
112
|
this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
113
113
|
}
|
|
114
114
|
const active = document.activeElement;
|
|
@@ -150,7 +150,7 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
|
|
|
150
150
|
: this.value
|
|
151
151
|
.map((one) => String(one).trim())
|
|
152
152
|
.filter((one) => one !== '')
|
|
153
|
-
.join(',
|
|
153
|
+
.join(',');
|
|
154
154
|
}
|
|
155
155
|
get tags() {
|
|
156
156
|
return [...(this.children ?? [])].filter((child) => child instanceof HelixHeadlessTag);
|
|
@@ -212,8 +212,9 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
|
|
|
212
212
|
get replaces() {
|
|
213
213
|
return this.selectionMode !== undefined && this.selectionBehavior === 'replace';
|
|
214
214
|
}
|
|
215
|
-
ask(
|
|
216
|
-
|
|
215
|
+
ask(asked) {
|
|
216
|
+
const next = commaList(asked).join(',');
|
|
217
|
+
if (next === commaList(this.written).join(',')) {
|
|
217
218
|
return;
|
|
218
219
|
}
|
|
219
220
|
if (this.disallowEmptySelection && commaList(next).length === 0) {
|
|
@@ -239,7 +240,7 @@ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
|
|
|
239
240
|
this.choose(this.tags.filter((tag) => chosen.includes(tag)));
|
|
240
241
|
}
|
|
241
242
|
choose(tags) {
|
|
242
|
-
this.ask([...new Set(tags.map((tag) => this.valueFor(tag)))].join(',
|
|
243
|
+
this.ask([...new Set(tags.map((tag) => this.valueFor(tag)))].join(','));
|
|
243
244
|
}
|
|
244
245
|
connectedCallback() {
|
|
245
246
|
super.connectedCallback();
|
|
@@ -70,12 +70,13 @@ let HelixHeadlessTag = class HelixHeadlessTag extends MixinDismissible(HelixElem
|
|
|
70
70
|
}
|
|
71
71
|
render() {
|
|
72
72
|
const content = html `<slot name="start" part="start"></slot>${this.renderLabel()}${this.dismissible ? this.renderDismiss() : nothing}`;
|
|
73
|
+
const stop = this.focusable ? '0' : this.disabled ? nothing : '-1';
|
|
73
74
|
return this.grouped
|
|
74
75
|
? html `<span
|
|
75
76
|
aria-label=${this.words || nothing}
|
|
76
77
|
part="cell"
|
|
77
78
|
role="gridcell"
|
|
78
|
-
tabindex=${
|
|
79
|
+
tabindex=${stop}
|
|
79
80
|
@focus=${this.handleCellFocus}
|
|
80
81
|
@blur=${this.handleCellFocus}
|
|
81
82
|
>${content}</span
|
|
@@ -14,9 +14,9 @@ declare const HelixHeadlessTreeItem_base: (new (...args: any[]) => import("@fusi
|
|
|
14
14
|
* Each item is an element because it holds state: whether it is open, selected,
|
|
15
15
|
* and focused.
|
|
16
16
|
*
|
|
17
|
-
* An item is a branch when
|
|
18
|
-
*
|
|
19
|
-
* appears on hydration.
|
|
17
|
+
* An item is a branch when an item is slotted into `children`, with
|
|
18
|
+
* `slot="children"` on each nested item. This is detected on the client, so
|
|
19
|
+
* server-rendered markup shows a leaf and the twisty appears on hydration.
|
|
20
20
|
*
|
|
21
21
|
* **`href` makes the whole row a link**, rendered as an `<a>`. Enter, middle
|
|
22
22
|
* click, and the status bar then work anywhere on the row.
|
|
@@ -43,7 +43,7 @@ declare const HelixHeadlessTreeItem_base: (new (...args: any[]) => import("@fusi
|
|
|
43
43
|
* @aliases TreeNode, Branch, Leaf
|
|
44
44
|
* @documentation https://fusion.dev/helix/components/tree
|
|
45
45
|
*
|
|
46
|
-
* @slot - The item's label.
|
|
46
|
+
* @slot - The item's label. A nested item does not go here: give it `slot="children"`. In a development build, an item nested here is reported.
|
|
47
47
|
* @slot chevron - Replaces the expand and collapse mark of a branch, such as with your own icon.
|
|
48
48
|
* @slot children - Nested items, which make this a branch.
|
|
49
49
|
* @slot end - Content after the label, at the far side of the row, such as a count or a state.
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, HelixElement, HelixLoadEvent, HelixSelectEvent, MixinControllerOpen, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { auditNesting, customElement, HelixElement, HelixLoadEvent, HelixSelectEvent, MixinControllerOpen, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { caretDown, check, dotsSixVertical, minus } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -68,6 +68,10 @@ let HelixHeadlessTreeItem = class HelixHeadlessTreeItem extends MixinControllerO
|
|
|
68
68
|
slot?.addEventListener('slotchange', () => {
|
|
69
69
|
this.branch = slot.assignedElements().length > 0;
|
|
70
70
|
});
|
|
71
|
+
auditNesting(this, 'children');
|
|
72
|
+
this.renderRoot
|
|
73
|
+
.querySelector('[part="label"] > slot')
|
|
74
|
+
?.addEventListener('slotchange', () => auditNesting(this, 'children'));
|
|
71
75
|
}
|
|
72
76
|
get choosable() {
|
|
73
77
|
return this.value !== '' && !this.heads && !this.checkable && !this.disabled;
|