@fusion.dev/helix-headless 0.150.0 → 0.151.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 +741 -66
- package/dist/area-chart/root/area-chart-root.d.ts +36 -0
- package/dist/area-chart/root/area-chart-root.js +17 -2
- package/dist/bar-chart/root/bar-chart-root.d.ts +28 -4
- package/dist/bar-chart/root/bar-chart-root.js +17 -4
- package/dist/callout/root/callout-root.d.ts +20 -0
- package/dist/callout/root/callout-root.js +19 -4
- package/dist/chat/composer/chat-composer.d.ts +30 -0
- package/dist/chat/composer/chat-composer.js +47 -2
- package/dist/chat/root/chat-root.d.ts +10 -0
- package/dist/chat/root/chat-root.js +14 -0
- package/dist/data-table/root/data-table-root.d.ts +34 -2
- package/dist/data-table/root/data-table-root.js +63 -2
- package/dist/divider/root/divider-root.d.ts +8 -6
- package/dist/divider/root/divider-root.js +10 -2
- package/dist/element-events.generated.js +4 -0
- package/dist/kbd/root/kbd-root.d.ts +7 -1
- package/dist/kbd/root/kbd-root.js +8 -4
- package/dist/line-chart/root/line-chart-root.d.ts +36 -0
- package/dist/line-chart/root/line-chart-root.js +15 -2
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +18 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +38 -15
- package/dist/table/column/table-column.js +3 -2
- package/dist/table/grid-controller.d.ts +14 -2
- package/dist/table/grid-controller.js +27 -1
- package/dist/table/root/table-root.d.ts +30 -4
- package/dist/table/root/table-root.js +45 -7
- package/dist/table/row/table-row.d.ts +12 -2
- package/dist/table/row/table-row.js +8 -2
- package/dist/video/root/video-root.d.ts +6 -0
- package/dist/video/root/video-root.js +5 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +4 -0
- package/dist/video-playlist/root/video-playlist-root.js +4 -1
- package/dist/virtual-list/root/virtual-list-root.d.ts +23 -1
- package/dist/virtual-list/root/virtual-list-root.js +21 -2
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +648 -98
- package/types/vue.d.ts +195 -43
- package/types/words.d.ts +4 -2
|
@@ -40,6 +40,10 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
40
40
|
* and shows a dash while only some are chosen.
|
|
41
41
|
* - Shift with a press on a checkbox selects every row between it and the row
|
|
42
42
|
* last chosen.
|
|
43
|
+
* - `selection-behavior="replace"` makes a press or a move select the row
|
|
44
|
+
* alone, as a file list does. Control or Command with a press adds or takes
|
|
45
|
+
* out one row, and Shift with a press selects every row from the one last
|
|
46
|
+
* chosen.
|
|
43
47
|
*
|
|
44
48
|
* To act on a single row, such as opening it, put a link or a button in a cell.
|
|
45
49
|
*
|
|
@@ -56,7 +60,8 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
56
60
|
* | Enter, F2 | Moves into the cell's controls. Escape moves back to the cell, and Tab moves between the controls of one cell. |
|
|
57
61
|
* | Enter, Space on a sortable heading | Sorts by the column. |
|
|
58
62
|
* | Enter, Space on the `load-more` row | Sends `helix-load-more`. |
|
|
59
|
-
* | Space on a row | Selects the row, in a `selectable` table. |
|
|
63
|
+
* | Space on a row | Selects the row, in a `selectable` table. Under `selection-behavior="replace"`, selects it alone, and Control or Command with Space adds or takes out the row. |
|
|
64
|
+
* | Down, Up, Page Down, Page Up under `selection-behavior="replace"` | Selects the row it moves to alone. Control or Command with the key moves without selecting. |
|
|
60
65
|
* | Shift with Down or Up | Selects the rows it moves across, in a `selectable` table. |
|
|
61
66
|
* | Shift with Space | Selects every row from the one last chosen, in a `selectable` table. |
|
|
62
67
|
* | Control or Command with A | Selects every row, in a `selectable` table. |
|
|
@@ -123,7 +128,9 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
123
128
|
* @documentation https://fusion.dev/helix/components/data-table
|
|
124
129
|
*
|
|
125
130
|
* @slot - The columns, as `TableColumn` elements.
|
|
131
|
+
* @slot empty - Content shown when there are no rows to show and none are loading, such as a picture and a link. Falls back to `empty-text`, which the live region still says.
|
|
126
132
|
* @slot footer - Content below the grid. It replaces the built-in pagination.
|
|
133
|
+
* @slot loading - Content shown while the rows load, such as a spinner. Falls back to `loading-text`, which the live region still says.
|
|
127
134
|
* @slot toolbar - Content above the grid, such as a search field or actions.
|
|
128
135
|
*
|
|
129
136
|
* @event {HelixActivateEvent} helix-activate - Fired after the page changes, with the new page as a string in `detail.value`.
|
|
@@ -216,6 +223,8 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
216
223
|
* `registerWords('de', { 'helix-data-table': { nextLabel: 'Nächste Seite' } })`.
|
|
217
224
|
*/
|
|
218
225
|
static words: string;
|
|
226
|
+
/** The empty and loading lines are the `empty` and `loading` slots. */
|
|
227
|
+
protected statusSlots: boolean;
|
|
219
228
|
/**
|
|
220
229
|
* The word for an ascending sort, in a `sorted-label` that writes `{order}`.
|
|
221
230
|
*
|
|
@@ -490,6 +499,15 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
490
499
|
* {# wybranych} other {# wybranego}}`.
|
|
491
500
|
*/
|
|
492
501
|
selectedLabel: string;
|
|
502
|
+
/**
|
|
503
|
+
* What a key or a press on a row does to the rows already selected, in a
|
|
504
|
+
* `selectable` table. `toggle`, the default, keeps them: Space adds or takes
|
|
505
|
+
* out the row. `replace` selects the row alone, as a file list does: Down and
|
|
506
|
+
* Up carry the selection with them, and a press on a row selects it. Control
|
|
507
|
+
* or Command with a press or Space adds or takes out one row, and with a move
|
|
508
|
+
* goes without selecting. The checkboxes add or take out one row either way.
|
|
509
|
+
*/
|
|
510
|
+
selectionBehavior: 'replace' | 'toggle';
|
|
493
511
|
/**
|
|
494
512
|
* The name of a row's checkbox. `{row}` is replaced with the row's value in
|
|
495
513
|
* the first column that has a field, or with its key.
|
|
@@ -954,7 +972,7 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
954
972
|
*/
|
|
955
973
|
toggleSort(field: string): boolean;
|
|
956
974
|
/**
|
|
957
|
-
* The columns into the header row, everything else into the
|
|
975
|
+
* The columns into the header row, everything else into the slot it names.
|
|
958
976
|
*
|
|
959
977
|
* Manual assignment, so a consumer's own markup is never written to.
|
|
960
978
|
*/
|
|
@@ -1124,6 +1142,20 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
1124
1142
|
* request carries only the state it asks for.
|
|
1125
1143
|
*/
|
|
1126
1144
|
private readonly notePress;
|
|
1145
|
+
/** Whether a press or a move on a row selects it alone. */
|
|
1146
|
+
private get replaces();
|
|
1147
|
+
/**
|
|
1148
|
+
* Selects the row at `row` on the page alone, and makes it where a range
|
|
1149
|
+
* runs from. Asks nothing where it is already the only one selected.
|
|
1150
|
+
*/
|
|
1151
|
+
private chooseOnly;
|
|
1152
|
+
/**
|
|
1153
|
+
* A press on a row under `selection-behavior="replace"`: it selects the row
|
|
1154
|
+
* alone, Control or Command adds or takes out the row, and Shift selects
|
|
1155
|
+
* every row from the one last chosen. A press on a control in a cell, or on
|
|
1156
|
+
* the checkbox or grip column, is the control's.
|
|
1157
|
+
*/
|
|
1158
|
+
private readonly handleRowClick;
|
|
1127
1159
|
/**
|
|
1128
1160
|
* A click on a sortable heading, anywhere but its grip or its edge.
|
|
1129
1161
|
*
|
|
@@ -30,6 +30,7 @@ const isControl = (element) => element.matches(CONTROL) || element.shadowRoot?.d
|
|
|
30
30
|
let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollection(HelixElement) {
|
|
31
31
|
constructor() {
|
|
32
32
|
super(...arguments);
|
|
33
|
+
this.statusSlots = true;
|
|
33
34
|
this.ascendingLabel = 'ascending';
|
|
34
35
|
this.canceledLabel = 'Canceled';
|
|
35
36
|
this.defaultExpanded = '';
|
|
@@ -64,6 +65,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
64
65
|
this.selectable = false;
|
|
65
66
|
this.selectAllLabel = 'Select every row';
|
|
66
67
|
this.selectedLabel = '{count} selected';
|
|
68
|
+
this.selectionBehavior = 'toggle';
|
|
67
69
|
this.selectRowLabel = 'Select {row}';
|
|
68
70
|
this.sortedLabel = '{direction, select, ascending {Sorted by {column}, ascending} descending {Sorted by {column}, descending} other {Sorted by {column}}}';
|
|
69
71
|
this.total = 0;
|
|
@@ -178,6 +180,30 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
178
180
|
this.notePress = (event) => {
|
|
179
181
|
this.shiftPressed = event.shiftKey;
|
|
180
182
|
};
|
|
183
|
+
this.handleRowClick = (event) => {
|
|
184
|
+
if (!this.replaces || event.defaultPrevented) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const place = this.placeOf(event);
|
|
188
|
+
if (!place || place.row < 0 || place.row >= this.drawnPage.length || place.column < this.lead) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const origin = event.composedPath()[0];
|
|
192
|
+
if (origin instanceof Node && this.controlsIn(place).some((one) => deepContains(one, origin))) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (event.shiftKey && this.anchorKey !== undefined) {
|
|
196
|
+
this.selectRange(place.row);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (event.ctrlKey || event.metaKey) {
|
|
200
|
+
const data = this.drawnPage[place.row];
|
|
201
|
+
const key = this.keyOf(data, this.rowIndex(place.row) - 2);
|
|
202
|
+
this.chooseRow(key, !this.chosen.has(key));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this.chooseOnly(place.row);
|
|
206
|
+
};
|
|
181
207
|
this.handleHeadClick = (event) => {
|
|
182
208
|
if (this.partIn(event, 'grip') || this.partIn(event, 'resizer')) {
|
|
183
209
|
return;
|
|
@@ -251,14 +277,22 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
251
277
|
}
|
|
252
278
|
const { column, row } = to;
|
|
253
279
|
event.preventDefault();
|
|
280
|
+
const onRow = row >= 0 && row < this.drawnPage.length;
|
|
254
281
|
if (event.shiftKey &&
|
|
255
282
|
this.selectable &&
|
|
256
283
|
(event.key === 'ArrowUp' || event.key === 'ArrowDown') &&
|
|
257
284
|
place.row >= 0 &&
|
|
258
|
-
|
|
259
|
-
row < this.drawnPage.length) {
|
|
285
|
+
onRow) {
|
|
260
286
|
this.selectRange(row, place.row);
|
|
261
287
|
}
|
|
288
|
+
else if (this.replaces &&
|
|
289
|
+
onRow &&
|
|
290
|
+
row !== place.row &&
|
|
291
|
+
!event.shiftKey &&
|
|
292
|
+
!event.ctrlKey &&
|
|
293
|
+
!event.metaKey) {
|
|
294
|
+
this.chooseOnly(row);
|
|
295
|
+
}
|
|
262
296
|
if (row !== place.row || column !== place.column) {
|
|
263
297
|
this.moveTo(row, column);
|
|
264
298
|
}
|
|
@@ -878,6 +912,8 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
878
912
|
for (const [name, wanted] of [
|
|
879
913
|
['toolbar', true],
|
|
880
914
|
['footer', true],
|
|
915
|
+
['empty', true],
|
|
916
|
+
['loading', true],
|
|
881
917
|
]) {
|
|
882
918
|
const slot = root.querySelector(`slot[name="${name}"]`);
|
|
883
919
|
if (slot?.assign && wanted) {
|
|
@@ -1201,6 +1237,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1201
1237
|
connectedCallback() {
|
|
1202
1238
|
super.connectedCallback();
|
|
1203
1239
|
this.addEventListener('click', this.handleHeadClick);
|
|
1240
|
+
this.addEventListener('click', this.handleRowClick);
|
|
1204
1241
|
this.addEventListener('pointerdown', this.notePress, true);
|
|
1205
1242
|
this.addEventListener('keydown', this.notePress, true);
|
|
1206
1243
|
this.addEventListener('focusin', this.handleFocusIn);
|
|
@@ -1212,6 +1249,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1212
1249
|
disconnectedCallback() {
|
|
1213
1250
|
super.disconnectedCallback();
|
|
1214
1251
|
this.removeEventListener('click', this.handleHeadClick);
|
|
1252
|
+
this.removeEventListener('click', this.handleRowClick);
|
|
1215
1253
|
this.removeEventListener('pointerdown', this.notePress, true);
|
|
1216
1254
|
this.removeEventListener('keydown', this.notePress, true);
|
|
1217
1255
|
this.removeEventListener('focusin', this.handleFocusIn);
|
|
@@ -1220,6 +1258,22 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1220
1258
|
this.removeEventListener('keydown', this.handleGripKey);
|
|
1221
1259
|
this.removeEventListener('helix-before-resize', this.handleResize);
|
|
1222
1260
|
}
|
|
1261
|
+
get replaces() {
|
|
1262
|
+
return this.selectable && this.selectionBehavior === 'replace';
|
|
1263
|
+
}
|
|
1264
|
+
chooseOnly(row) {
|
|
1265
|
+
const data = this.drawnPage[row];
|
|
1266
|
+
if (!data) {
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
const key = this.keyOf(data, this.rowIndex(row) - 2);
|
|
1270
|
+
this.anchorKey = key;
|
|
1271
|
+
const now = this.chosen;
|
|
1272
|
+
if (now.size === 1 && now.has(key)) {
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
this.requestSelected(new Set([key]));
|
|
1276
|
+
}
|
|
1223
1277
|
cellAt(row, column) {
|
|
1224
1278
|
const offset = this.lead;
|
|
1225
1279
|
if (row === -1) {
|
|
@@ -1402,6 +1456,10 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1402
1456
|
event.preventDefault();
|
|
1403
1457
|
this.selectRange(place.row);
|
|
1404
1458
|
}
|
|
1459
|
+
else if (this.replaces && row && !event.ctrlKey && !event.metaKey) {
|
|
1460
|
+
event.preventDefault();
|
|
1461
|
+
this.chooseOnly(place.row);
|
|
1462
|
+
}
|
|
1405
1463
|
else if (this.selectable && row) {
|
|
1406
1464
|
event.preventDefault();
|
|
1407
1465
|
const key = this.keyOf(row, this.rowIndex(place.row) - 2);
|
|
@@ -1595,6 +1653,9 @@ __decorate([
|
|
|
1595
1653
|
words,
|
|
1596
1654
|
property({ attribute: 'selected-label' })
|
|
1597
1655
|
], HelixHeadlessDataTable.prototype, "selectedLabel", void 0);
|
|
1656
|
+
__decorate([
|
|
1657
|
+
property({ attribute: 'selection-behavior' })
|
|
1658
|
+
], HelixHeadlessDataTable.prototype, "selectionBehavior", void 0);
|
|
1598
1659
|
__decorate([
|
|
1599
1660
|
words,
|
|
1600
1661
|
property({ attribute: 'select-row-label' })
|
|
@@ -12,9 +12,10 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
12
12
|
* **The line is a separator**, as `<hr>` is, and as Radix Separator, React
|
|
13
13
|
* Aria Separator, and Web Awesome's divider are. It is named by any content
|
|
14
14
|
* set into it, so a screen reader says "Or, separator" where you wrote "Or" on
|
|
15
|
-
* the line
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* the line, and the words are read once, as that name. Set words into a
|
|
16
|
+
* separator and no controls, which are hidden with them. Set `decorative` on
|
|
17
|
+
* a rule that separates nothing, such as one under a heading or between the
|
|
18
|
+
* facts of a byline, and it leaves the accessibility tree.
|
|
18
19
|
*
|
|
19
20
|
* Use `orientation="vertical"` between items on one line. A vertical divider
|
|
20
21
|
* stretches to fit its flex parent and sets no height of its own.
|
|
@@ -44,9 +45,10 @@ export declare class HelixHeadlessDivider extends HelixElement {
|
|
|
44
45
|
* Whether screen readers announce the line as a separator, which they now do
|
|
45
46
|
* by default.
|
|
46
47
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
48
|
+
* @deprecated Remove it: a divider is a separator unless `decorative` is
|
|
49
|
+
* set. It dates from when the line was decorative by default, and it is
|
|
50
|
+
* still read and wins over `decorative`, so a divider written with it stays
|
|
51
|
+
* a separator.
|
|
50
52
|
*/
|
|
51
53
|
announced: boolean;
|
|
52
54
|
/**
|
|
@@ -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, markRegion, toolbarAround, toolbarAxis, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, markRegion, reportRuntime, toolbarAround, toolbarAxis, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessDivider = class HelixHeadlessDivider extends HelixElement {
|
|
@@ -38,6 +38,14 @@ let HelixHeadlessDivider = class HelixHeadlessDivider extends HelixElement {
|
|
|
38
38
|
updated(changed) {
|
|
39
39
|
super.updated(changed);
|
|
40
40
|
this.markEmpty();
|
|
41
|
+
if (changed.has('announced') && this.announced && changed.get('announced') === undefined) {
|
|
42
|
+
reportRuntime({
|
|
43
|
+
kind: 'deprecated',
|
|
44
|
+
message: `<${this.localName} announced> is deprecated: remove it. A divider is a separator ` +
|
|
45
|
+
'unless `decorative` is set.',
|
|
46
|
+
tag: this.localName,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
41
49
|
}
|
|
42
50
|
render() {
|
|
43
51
|
const separator = this.announced || !this.decorative;
|
|
@@ -47,7 +55,7 @@ let HelixHeadlessDivider = class HelixHeadlessDivider extends HelixElement {
|
|
|
47
55
|
aria-labelledby=${separator ? 'content' : nothing}
|
|
48
56
|
aria-orientation=${separator ? this.drawn : nothing}
|
|
49
57
|
></div>
|
|
50
|
-
<span id="content" part="content"><slot @slotchange=${() => this.markEmpty()}></slot></span>
|
|
58
|
+
<span id="content" part="content" aria-hidden=${separator ? 'true' : nothing}><slot @slotchange=${() => this.markEmpty()}></slot></span>
|
|
51
59
|
<div part="line" role="presentation"></div>`;
|
|
52
60
|
}
|
|
53
61
|
};
|
|
@@ -3,7 +3,9 @@ registerElementEvents({
|
|
|
3
3
|
'helix-headless-accordion-item': ['helix-before-close', 'helix-before-open', 'toggle'],
|
|
4
4
|
'helix-headless-announcement': ['helix-dismiss'],
|
|
5
5
|
'helix-headless-app-header': ['helix-scrolled'],
|
|
6
|
+
'helix-headless-area-chart': ['helix-reading-change', 'helix-reading-press'],
|
|
6
7
|
'helix-headless-avatar': ['error', 'load'],
|
|
8
|
+
'helix-headless-bar-chart': ['helix-reading-change', 'helix-reading-press'],
|
|
7
9
|
'helix-headless-button': ['helix-press'],
|
|
8
10
|
'helix-headless-button-group': ['change', 'helix-before-change'],
|
|
9
11
|
'helix-headless-callout': ['helix-dismiss'],
|
|
@@ -132,6 +134,7 @@ registerElementEvents({
|
|
|
132
134
|
'helix-before-open',
|
|
133
135
|
'toggle',
|
|
134
136
|
],
|
|
137
|
+
'helix-headless-line-chart': ['helix-reading-change', 'helix-reading-press'],
|
|
135
138
|
'helix-headless-list': [
|
|
136
139
|
'change',
|
|
137
140
|
'helix-action',
|
|
@@ -208,6 +211,7 @@ registerElementEvents({
|
|
|
208
211
|
'helix-preview',
|
|
209
212
|
'input',
|
|
210
213
|
],
|
|
214
|
+
'helix-headless-scatter-chart': ['helix-reading-change', 'helix-reading-press'],
|
|
211
215
|
'helix-headless-scroll-area': ['scroll', 'scrollend'],
|
|
212
216
|
'helix-headless-select': [
|
|
213
217
|
'change',
|
|
@@ -23,6 +23,11 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
23
23
|
* the shortcut with the control. A chord the page wrote there itself is left
|
|
24
24
|
* alone, and the key takes back only what it added.
|
|
25
25
|
*
|
|
26
|
+
* A chord is drawn with the platform's modifiers first, in its order, so one
|
|
27
|
+
* `keys` value is right everywhere: `mod+shift+p` is `⇧⌘P` on an Apple
|
|
28
|
+
* keyboard and `Ctrl+Shift+P` elsewhere. Where it is drawn in glyphs, it is
|
|
29
|
+
* read in words, such as `Shift Command P`.
|
|
30
|
+
*
|
|
26
31
|
* `caps` draws a chord as a key per key: each is a `key` part and the `+`
|
|
27
32
|
* between two a `separator` part, so a sheet can draw a cap for each.
|
|
28
33
|
* `key-labels` renames any key, on every platform, such as
|
|
@@ -141,7 +146,8 @@ export declare class HelixHeadlessKbd extends HelixElement {
|
|
|
141
146
|
/**
|
|
142
147
|
* The chord under `caps`, a part for each key and for each `+` between two,
|
|
143
148
|
* so a sheet can draw a cap per key. Written with no space between, so a
|
|
144
|
-
* chord reads as the one label it was.
|
|
149
|
+
* chord reads as the one label it was. Where the chord is said in words,
|
|
150
|
+
* the parts are hidden from a screen reader, which reads the words.
|
|
145
151
|
*/
|
|
146
152
|
protected renderChord(): TemplateResult;
|
|
147
153
|
}
|
|
@@ -135,12 +135,16 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
|
|
|
135
135
|
if (this.keys === '') {
|
|
136
136
|
return html `<kbd part="kbd"><slot></slot></kbd>`;
|
|
137
137
|
}
|
|
138
|
-
const { keys, separator } = this.label;
|
|
139
|
-
|
|
138
|
+
const { keys, separator, spoken } = this.label;
|
|
139
|
+
if (spoken === '') {
|
|
140
|
+
return html `<kbd part="kbd">${this.caps ? this.renderChord() : keys.join(separator)}</kbd>`;
|
|
141
|
+
}
|
|
142
|
+
return html `<kbd part="kbd">${this.caps ? this.renderChord() : html `<span aria-hidden="true">${keys.join(separator)}</span>`}<span data-spoken>${spoken}</span></kbd>`;
|
|
140
143
|
}
|
|
141
144
|
renderChord() {
|
|
142
|
-
const { keys, separator } = this.label;
|
|
143
|
-
|
|
145
|
+
const { keys, separator, spoken } = this.label;
|
|
146
|
+
const hidden = spoken === '' ? nothing : 'true';
|
|
147
|
+
return html `${keys.map((key, index) => html `${index > 0 && separator !== '' ? html `<span part="separator" aria-hidden=${hidden}>${separator}</span>` : nothing}<span part="key" aria-hidden=${hidden}>${key}</span>`)}`;
|
|
144
148
|
}
|
|
145
149
|
};
|
|
146
150
|
__decorate([
|
|
@@ -27,6 +27,9 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
|
|
|
27
27
|
* `<svg>` that fills its box scales with the box, so the same `font-size` can
|
|
28
28
|
* render at 10px in a narrow chart and 43px in a wide one.
|
|
29
29
|
*
|
|
30
|
+
* `value-axis` draws the scale's numbers beside the plot, at the levels
|
|
31
|
+
* `gridlines` rules, written in `locale`.
|
|
32
|
+
*
|
|
30
33
|
* The table is the accessible representation, and the drawing is hidden from
|
|
31
34
|
* screen readers, who get the numbers. The `summary` part names the chart, from
|
|
32
35
|
* `label` or the table's caption, and gives each series' latest reading.
|
|
@@ -37,13 +40,22 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
|
|
|
37
40
|
* a reading. The tooltip follows, the `live` part says the reading in words,
|
|
38
41
|
* and Escape puts the tooltip away.
|
|
39
42
|
*
|
|
43
|
+
* **A tap shows the reading under it**, and keeps it until a tap lands
|
|
44
|
+
* elsewhere. `helix-reading-change` says each move of the reading, by pointer,
|
|
45
|
+
* tap or key, and `helix-reading-press` says a reading was clicked, tapped, or
|
|
46
|
+
* pressed with Enter or Space, for a page that opens what a reading stands for.
|
|
47
|
+
*
|
|
40
48
|
* @since 0.1.0
|
|
41
49
|
* @status stable
|
|
42
50
|
* @category charts
|
|
43
51
|
* @aliases Time Series, Trend Chart, Multi-line Chart
|
|
44
52
|
* @documentation https://fusion.dev/helix/components/line-chart
|
|
45
53
|
*
|
|
54
|
+
* @event {HelixReadingChangeEvent} helix-reading-change - The reading shown moved, or was put away: `index` is the row, or `-1` for none, with its `label`, the `series` the keys rest on, and the `pointerType` that moved it.
|
|
55
|
+
* @event {HelixReadingPressEvent} helix-reading-press - A reading was clicked, tapped, or pressed with Enter or Space, with the same detail as `helix-reading-change`.
|
|
56
|
+
*
|
|
46
57
|
* @csspart area - The wash under one line, where `area` is set.
|
|
58
|
+
* @csspart axis - The numbers of the scale beside the plot, under `value-axis`.
|
|
47
59
|
* @csspart band - The band around the reading under the pointer.
|
|
48
60
|
* @csspart baseline - The rule at zero, where zero is inside the range.
|
|
49
61
|
* @csspart gridline - One rule across the plot, under `gridlines`.
|
|
@@ -60,6 +72,7 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
|
|
|
60
72
|
* @csspart summary - The chart's name and each series' latest reading, written as a sentence for screen readers. Hide it visually.
|
|
61
73
|
* @csspart svg - The drawing surface the lines and areas sit on.
|
|
62
74
|
* @csspart terminus - The mark on one series' last reading.
|
|
75
|
+
* @csspart tick - One number on the axis, placed with `inset-block-start` at its level.
|
|
63
76
|
* @csspart tooltip - The bubble, forwarded from `Tooltip`.
|
|
64
77
|
* @csspart tooltip-anchor - The `Tooltip` element itself.
|
|
65
78
|
* @csspart tooltip-arrow - The bubble's point, forwarded from `Tooltip`.
|
|
@@ -79,6 +92,7 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
|
|
|
79
92
|
*
|
|
80
93
|
* @cssproperty --chart-terminus-x - Where a series' last reading sits horizontally, as a percentage. Written by the component.
|
|
81
94
|
* @cssproperty --chart-terminus-y - Where a series' last reading sits vertically, as a percentage. Written by the component.
|
|
95
|
+
* @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.
|
|
82
96
|
*/
|
|
83
97
|
export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base {
|
|
84
98
|
/**
|
|
@@ -86,6 +100,13 @@ export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base
|
|
|
86
100
|
* `registerWords('de', { 'helix-line-chart': { positionLabel: '{position} von {count}' } })`.
|
|
87
101
|
*/
|
|
88
102
|
static words: string;
|
|
103
|
+
/**
|
|
104
|
+
* Sends the reading's moves and presses as `helix-reading-change` and
|
|
105
|
+
* `helix-reading-press`, which the pointer hears. Here and not in a
|
|
106
|
+
* constructor, where the manifest's analyzer reads the assignment as a
|
|
107
|
+
* member of this class.
|
|
108
|
+
*/
|
|
109
|
+
connectedCallback(): void;
|
|
89
110
|
/**
|
|
90
111
|
* Draws a wash under each line, down to the floor of the plot. The washes
|
|
91
112
|
* overlap and do not add up, so for parts that make a total, use
|
|
@@ -202,6 +223,15 @@ export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base
|
|
|
202
223
|
* layers; a single `mask-image` would only ever cut the last one.
|
|
203
224
|
*/
|
|
204
225
|
terminus?: 'none' | 'ring' | 'square' | 'triangle';
|
|
226
|
+
/**
|
|
227
|
+
* Draws the scale's numbers beside the plot, the `axis` part, at the levels
|
|
228
|
+
* `gridlines` rules, so a reading can be measured off the drawing as well
|
|
229
|
+
* as read from the tooltip.
|
|
230
|
+
*
|
|
231
|
+
* Absent draws none: a line read for its shape needs no numbers beside it,
|
|
232
|
+
* and the tooltip and the table hold every reading.
|
|
233
|
+
*/
|
|
234
|
+
valueAxis: boolean;
|
|
205
235
|
/** The domain every series is drawn against, which the tooltip also needs. */
|
|
206
236
|
private range;
|
|
207
237
|
/**
|
|
@@ -223,6 +253,12 @@ export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base
|
|
|
223
253
|
*/
|
|
224
254
|
private ends;
|
|
225
255
|
protected render(): TemplateResult;
|
|
256
|
+
/**
|
|
257
|
+
* The scale's numbers beside the plot, under `value-axis`, written in the
|
|
258
|
+
* chart's locale. A seam, so a subclass can write the numbers its own way,
|
|
259
|
+
* such as a currency.
|
|
260
|
+
*/
|
|
261
|
+
protected renderAxis(y: (value: number) => number, domain: [number, number]): TemplateResult;
|
|
226
262
|
/**
|
|
227
263
|
* What a reader who cannot see the lines is told: the chart's name and the
|
|
228
264
|
* latest reading of each series.
|
|
@@ -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 { byRow, CHART_PLOT, commaList, customElement, drawTooltip, extent, HelixElement, linear, linePath, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, seriesKey, ticks, unbroken, wordsLocale, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { byRow, CHART_PLOT, commaList, customElement, drawTooltip, drawValueAxis, extent, formatNumbers, HelixElement, HelixReadingChangeEvent, HelixReadingPressEvent, linear, linePath, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, seriesKey, ticks, unbroken, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing, svg } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import '../../tooltip/index.js';
|
|
@@ -14,9 +14,16 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
|
|
|
14
14
|
this.area = false;
|
|
15
15
|
this.dashed = '';
|
|
16
16
|
this.markers = false;
|
|
17
|
+
this.valueAxis = false;
|
|
17
18
|
this.zero = false;
|
|
18
19
|
}
|
|
19
20
|
static { this.words = 'helix-line-chart'; }
|
|
21
|
+
connectedCallback() {
|
|
22
|
+
super.connectedCallback();
|
|
23
|
+
this.pointer.onReading = (heard, detail) => this.dispatchEvent(heard === 'press'
|
|
24
|
+
? new HelixReadingPressEvent(detail)
|
|
25
|
+
: new HelixReadingChangeEvent(detail));
|
|
26
|
+
}
|
|
20
27
|
get rulesValue() {
|
|
21
28
|
return this.gridlines !== undefined && this.gridlines !== 'category';
|
|
22
29
|
}
|
|
@@ -58,7 +65,10 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
|
|
|
58
65
|
const y = linear(domain, [PLOT_HEIGHT, 0]);
|
|
59
66
|
const slot = PLOT_WIDTH / readings.length;
|
|
60
67
|
const x = linear([0, Math.max(readings.length - 1, 1)], [slot / 2, PLOT_WIDTH - slot / 2]);
|
|
61
|
-
return html `${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)}`;
|
|
69
|
+
}
|
|
70
|
+
renderAxis(y, domain) {
|
|
71
|
+
return drawValueAxis(domain, (value) => (y(value) / PLOT_HEIGHT) * 100, formatNumbers(wordsLocale(this)), (widest) => `--line-chart-axis: ${widest}ch`);
|
|
62
72
|
}
|
|
63
73
|
renderSummary(series) {
|
|
64
74
|
const rows = this.sourceRows;
|
|
@@ -254,6 +264,9 @@ __decorate([
|
|
|
254
264
|
__decorate([
|
|
255
265
|
property({ reflect: true })
|
|
256
266
|
], HelixHeadlessLineChart.prototype, "terminus", void 0);
|
|
267
|
+
__decorate([
|
|
268
|
+
property({ attribute: 'value-axis', reflect: true, type: Boolean })
|
|
269
|
+
], HelixHeadlessLineChart.prototype, "valueAxis", void 0);
|
|
257
270
|
__decorate([
|
|
258
271
|
property({ reflect: true, type: Boolean })
|
|
259
272
|
], HelixHeadlessLineChart.prototype, "zero", void 0);
|
|
@@ -66,12 +66,20 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
66
66
|
* reads in its own direction. The summary and the tooltip bubble follow the
|
|
67
67
|
* page's direction.
|
|
68
68
|
*
|
|
69
|
+
* **A tap shows the reading under it**, and keeps it until a tap lands
|
|
70
|
+
* elsewhere. `helix-reading-change` says each move of the reading, by pointer,
|
|
71
|
+
* tap or key, and `helix-reading-press` says a reading was clicked, tapped, or
|
|
72
|
+
* pressed with Enter or Space, for a page that opens what a reading stands for.
|
|
73
|
+
*
|
|
69
74
|
* @since 0.1.0
|
|
70
75
|
* @status stable
|
|
71
76
|
* @category charts
|
|
72
77
|
* @aliases Scatter Plot, XY Chart, Correlation Chart, Dot Plot
|
|
73
78
|
* @documentation https://fusion.dev/helix/components/scatter-chart
|
|
74
79
|
*
|
|
80
|
+
* @event {HelixReadingChangeEvent} helix-reading-change - The reading shown moved, or was put away: `index` is the row, or `-1` for none, with its `label`, the `series` the keys rest on, and the `pointerType` that moved it.
|
|
81
|
+
* @event {HelixReadingPressEvent} helix-reading-press - A reading was clicked, tapped, or pressed with Enter or Space, with the same detail as `helix-reading-change`.
|
|
82
|
+
*
|
|
75
83
|
* @csspart gridline - One line across the plot, drawn when `gridlines` is set.
|
|
76
84
|
* @csspart live - The readout: a polite live region that says the row the keys moved to. Hide it visually.
|
|
77
85
|
* @csspart mark - The invisible point the tooltip is anchored to.
|
|
@@ -238,6 +246,16 @@ export declare class HelixHeadlessScatterChart extends HelixHeadlessScatterChart
|
|
|
238
246
|
* rest on a point with.
|
|
239
247
|
*/
|
|
240
248
|
private readonly handleMove;
|
|
249
|
+
/**
|
|
250
|
+
* The point a tap lands nearest, within twice a pointer's reach, a finger
|
|
251
|
+
* being broader than a cursor. It stays shown until a tap lands elsewhere.
|
|
252
|
+
*/
|
|
253
|
+
private readonly handleTap;
|
|
254
|
+
/**
|
|
255
|
+
* The drawn point nearest a pointer, within `reach` pixels, `undefined` for
|
|
256
|
+
* none in reach, and `null` with no plot to measure.
|
|
257
|
+
*/
|
|
258
|
+
private pointNear;
|
|
241
259
|
private readonly handleLeave;
|
|
242
260
|
}
|
|
243
261
|
declare global {
|
|
@@ -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, customElement, drawTooltip, extent, formatNumbers, formatWords, HelixElement, isRtl, linear, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, ticks, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { CHART_PLOT, customElement, drawTooltip, extent, formatNumbers, formatWords, HelixElement, HelixReadingChangeEvent, HelixReadingPressEvent, isRtl, linear, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, ticks, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing, svg } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import '../../tooltip/index.js';
|
|
@@ -47,28 +47,27 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
47
47
|
if (event.pointerType !== 'mouse' && event.pointerType !== 'pen') {
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
50
|
+
const found = this.pointNear(event, REACH);
|
|
51
|
+
if (found === null) {
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
-
const across = event.clientX - box.left;
|
|
55
|
-
const up = event.clientY - box.top;
|
|
56
|
-
let found;
|
|
57
|
-
let best = REACH ** 2;
|
|
58
|
-
for (const point of this.drawn) {
|
|
59
|
-
const distance = ((point.x / PLOT_WIDTH) * box.width - across) ** 2 +
|
|
60
|
-
((point.y / PLOT_HEIGHT) * box.height - up) ** 2;
|
|
61
|
-
if (distance <= best) {
|
|
62
|
-
best = distance;
|
|
63
|
-
found = point;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
54
|
if (found !== this.nearest) {
|
|
67
55
|
this.nearest = found;
|
|
68
56
|
this.pointer.set(found?.row ?? -1);
|
|
69
57
|
this.requestUpdate();
|
|
70
58
|
}
|
|
71
59
|
};
|
|
60
|
+
this.handleTap = (event) => {
|
|
61
|
+
if (event.pointerType !== 'touch') {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const found = this.pointNear(event, REACH * 2);
|
|
65
|
+
if (found) {
|
|
66
|
+
this.nearest = found;
|
|
67
|
+
this.pointer.tapTo(found.row);
|
|
68
|
+
this.requestUpdate();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
72
71
|
this.handleLeave = () => {
|
|
73
72
|
this.nearest = undefined;
|
|
74
73
|
};
|
|
@@ -77,13 +76,18 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
77
76
|
connectedCallback() {
|
|
78
77
|
super.connectedCallback();
|
|
79
78
|
this.pointer.axis = 'none';
|
|
79
|
+
this.pointer.onReading = (heard, detail) => this.dispatchEvent(heard === 'press'
|
|
80
|
+
? new HelixReadingPressEvent(detail)
|
|
81
|
+
: new HelixReadingChangeEvent(detail));
|
|
80
82
|
this.addEventListener('pointermove', this.handleMove);
|
|
81
83
|
this.addEventListener('pointerleave', this.handleLeave);
|
|
84
|
+
this.addEventListener('pointerup', this.handleTap);
|
|
82
85
|
}
|
|
83
86
|
disconnectedCallback() {
|
|
84
87
|
super.disconnectedCallback();
|
|
85
88
|
this.removeEventListener('pointermove', this.handleMove);
|
|
86
89
|
this.removeEventListener('pointerleave', this.handleLeave);
|
|
90
|
+
this.removeEventListener('pointerup', this.handleTap);
|
|
87
91
|
}
|
|
88
92
|
seriesOf(cell) {
|
|
89
93
|
const depth = this.measures.ups.indexOf(cell);
|
|
@@ -253,6 +257,25 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
253
257
|
y: `${point.y}%`,
|
|
254
258
|
}, (cell) => this.seriesOf(cell), this.pointer);
|
|
255
259
|
}
|
|
260
|
+
pointNear(event, reach) {
|
|
261
|
+
const box = this.partNamed('plot')?.getBoundingClientRect();
|
|
262
|
+
if (!box || box.width === 0 || box.height === 0) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
const across = event.clientX - box.left;
|
|
266
|
+
const up = event.clientY - box.top;
|
|
267
|
+
let found;
|
|
268
|
+
let best = reach ** 2;
|
|
269
|
+
for (const point of this.drawn) {
|
|
270
|
+
const distance = ((point.x / PLOT_WIDTH) * box.width - across) ** 2 +
|
|
271
|
+
((point.y / PLOT_HEIGHT) * box.height - up) ** 2;
|
|
272
|
+
if (distance <= best) {
|
|
273
|
+
best = distance;
|
|
274
|
+
found = point;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return found;
|
|
278
|
+
}
|
|
256
279
|
};
|
|
257
280
|
__decorate([
|
|
258
281
|
words,
|
|
@@ -174,6 +174,7 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
174
174
|
const named = { name, named: name ? 'yes' : 'no' };
|
|
175
175
|
const grid = this.gridCell;
|
|
176
176
|
const control = grid ? '-1' : nothing;
|
|
177
|
+
const width = Math.min(4096, Math.max(HelixHeadlessTableColumn_1.NARROWEST, this.drawn));
|
|
177
178
|
return html `<span
|
|
178
179
|
part="column"
|
|
179
180
|
role=${grid ? 'columnheader' : nothing}
|
|
@@ -197,8 +198,8 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
197
198
|
aria-orientation="vertical"
|
|
198
199
|
aria-valuemin=${HelixHeadlessTableColumn_1.NARROWEST}
|
|
199
200
|
aria-valuemax="4096"
|
|
200
|
-
aria-valuenow=${
|
|
201
|
-
aria-valuetext=${formatWords(this, 'widthLabel', { width
|
|
201
|
+
aria-valuenow=${width}
|
|
202
|
+
aria-valuetext=${formatWords(this, 'widthLabel', { width })}
|
|
202
203
|
@keydown=${this.handleResizeKey}
|
|
203
204
|
@pointerdown=${this.handleResizeStart}
|
|
204
205
|
@pointermove=${this.handleResizeMove}
|