@fusion.dev/helix-core 0.144.0 → 0.146.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 +5724 -1404
- package/dist/controllers/aria-forward-controller/aria-forward-controller.d.ts +3 -2
- package/dist/controllers/aria-forward-controller/aria-forward-controller.js +4 -14
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.d.ts +65 -3
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.js +37 -9
- package/dist/controllers/chart-pointer-controller/reading-step.d.ts +7 -1
- package/dist/controllers/chart-pointer-controller/reading-step.js +5 -0
- package/dist/controllers/countdown-controller/countdown-controller.d.ts +55 -0
- package/dist/controllers/countdown-controller/countdown-controller.js +57 -0
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.d.ts +20 -57
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.js +11 -40
- package/dist/controllers/relative-clock-controller/relative-clock-controller.d.ts +44 -0
- package/dist/controllers/relative-clock-controller/relative-clock-controller.js +31 -0
- package/dist/controllers/source-controller/source-controller.d.ts +10 -3
- package/dist/controllers/source-controller/source-controller.js +7 -4
- package/dist/controllers/virtualize-controller/virtualize-controller.d.ts +116 -36
- package/dist/controllers/virtualize-controller/virtualize-controller.js +122 -12
- package/dist/events/action.d.ts +12 -0
- package/dist/events/action.js +6 -0
- package/dist/events/activate.d.ts +22 -0
- package/dist/events/activate.js +11 -0
- package/dist/events/aura-fallback.d.ts +12 -0
- package/dist/events/aura-fallback.js +11 -0
- package/dist/events/before-activate.d.ts +24 -0
- package/dist/events/before-activate.js +11 -0
- package/dist/events/before-change.d.ts +26 -0
- package/dist/events/before-change.js +11 -0
- package/dist/events/before-close.d.ts +6 -0
- package/dist/events/before-close.js +11 -0
- package/dist/events/before-collapse.d.ts +6 -0
- package/dist/events/before-collapse.js +11 -0
- package/dist/events/before-edit.d.ts +6 -0
- package/dist/events/before-edit.js +11 -0
- package/dist/events/before-move.d.ts +17 -0
- package/dist/events/before-move.js +11 -0
- package/dist/events/before-open.d.ts +17 -0
- package/dist/events/before-open.js +11 -0
- package/dist/events/before-panel-resize.d.ts +13 -0
- package/dist/events/before-panel-resize.js +11 -0
- package/dist/events/before-pin.d.ts +6 -0
- package/dist/events/before-pin.js +11 -0
- package/dist/events/before-reconnect.d.ts +14 -0
- package/dist/events/before-reconnect.js +11 -0
- package/dist/events/before-relabel.d.ts +15 -0
- package/dist/events/before-relabel.js +11 -0
- package/dist/events/before-resize.d.ts +6 -0
- package/dist/events/before-resize.js +11 -0
- package/dist/events/before-split.d.ts +12 -0
- package/dist/events/before-split.js +11 -0
- package/dist/events/before-toggle.d.ts +23 -0
- package/dist/events/before-toggle.js +11 -0
- package/dist/events/canvas-edit.d.ts +16 -0
- package/dist/events/canvas-edit.js +11 -0
- package/dist/events/canvas-pan.d.ts +13 -0
- package/dist/events/canvas-pan.js +11 -0
- package/dist/events/canvas-view.d.ts +14 -0
- package/dist/events/canvas-view.js +11 -0
- package/dist/events/canvas-zoom.d.ts +6 -0
- package/dist/events/canvas-zoom.js +11 -0
- package/dist/events/caret.d.ts +17 -0
- package/dist/events/caret.js +11 -0
- package/dist/events/clear.d.ts +11 -0
- package/dist/events/clear.js +6 -0
- package/dist/events/collapse.d.ts +12 -0
- package/dist/events/collapse.js +11 -0
- package/dist/events/complete.d.ts +26 -0
- package/dist/events/complete.js +11 -0
- package/dist/events/connect.d.ts +14 -0
- package/dist/events/connect.js +11 -0
- package/dist/events/console.d.ts +13 -0
- package/dist/events/console.js +11 -0
- package/dist/events/copy-error.d.ts +9 -0
- package/dist/events/copy-error.js +6 -0
- package/dist/events/copy.d.ts +12 -0
- package/dist/events/copy.js +10 -0
- package/dist/events/create.d.ts +18 -0
- package/dist/events/create.js +11 -0
- package/dist/events/details.d.ts +454 -0
- package/dist/events/details.js +1 -0
- package/dist/events/dismiss.d.ts +16 -0
- package/dist/events/dismiss.js +11 -0
- package/dist/events/edit.d.ts +12 -0
- package/dist/events/edit.js +11 -0
- package/dist/events/end.d.ts +9 -0
- package/dist/events/end.js +6 -0
- package/dist/events/events.d.ts +125 -1306
- package/dist/events/events.js +105 -739
- package/dist/events/expand.d.ts +10 -0
- package/dist/events/expand.js +11 -0
- package/dist/events/facet.d.ts +17 -0
- package/dist/events/facet.js +11 -0
- package/dist/events/filter.d.ts +12 -0
- package/dist/events/filter.js +11 -0
- package/dist/events/filtered.d.ts +12 -0
- package/dist/events/filtered.js +11 -0
- package/dist/events/graph-filter.d.ts +10 -0
- package/dist/events/graph-filter.js +11 -0
- package/dist/events/graph-layout.d.ts +10 -0
- package/dist/events/graph-layout.js +11 -0
- package/dist/events/graph-pan.d.ts +9 -0
- package/dist/events/graph-pan.js +11 -0
- package/dist/events/graph-part-change.d.ts +10 -0
- package/dist/events/graph-part-change.js +11 -0
- package/dist/events/graph-ready.d.ts +8 -0
- package/dist/events/graph-ready.js +6 -0
- package/dist/events/graph-signal.d.ts +11 -0
- package/dist/events/graph-signal.js +11 -0
- package/dist/events/graph-zoom.d.ts +6 -0
- package/dist/events/graph-zoom.js +11 -0
- package/dist/events/history.d.ts +16 -0
- package/dist/events/history.js +11 -0
- package/dist/events/load-more.d.ts +12 -0
- package/dist/events/load-more.js +6 -0
- package/dist/events/load.d.ts +12 -0
- package/dist/events/load.js +6 -0
- package/dist/events/map-cluster.d.ts +15 -0
- package/dist/events/map-cluster.js +11 -0
- package/dist/events/map-pan.d.ts +18 -0
- package/dist/events/map-pan.js +11 -0
- package/dist/events/map-part-change.d.ts +16 -0
- package/dist/events/map-part-change.js +11 -0
- package/dist/events/map-ready.d.ts +15 -0
- package/dist/events/map-ready.js +6 -0
- package/dist/events/map-rotate.d.ts +9 -0
- package/dist/events/map-rotate.js +11 -0
- package/dist/events/map-tilt.d.ts +9 -0
- package/dist/events/map-tilt.js +11 -0
- package/dist/events/map-zoom.d.ts +13 -0
- package/dist/events/map-zoom.js +11 -0
- package/dist/events/move.d.ts +11 -0
- package/dist/events/move.js +11 -0
- package/dist/events/names.d.ts +15 -0
- package/dist/events/names.js +88 -0
- package/dist/events/navigate.d.ts +13 -0
- package/dist/events/navigate.js +11 -0
- package/dist/events/next.d.ts +23 -0
- package/dist/events/next.js +11 -0
- package/dist/events/panel-resize.d.ts +12 -0
- package/dist/events/panel-resize.js +11 -0
- package/dist/events/pin.d.ts +12 -0
- package/dist/events/pin.js +11 -0
- package/dist/events/press.d.ts +19 -0
- package/dist/events/press.js +11 -0
- package/dist/events/preview.d.ts +14 -0
- package/dist/events/preview.js +11 -0
- package/dist/events/previous.d.ts +6 -0
- package/dist/events/previous.js +11 -0
- package/dist/events/range-change.d.ts +10 -0
- package/dist/events/range-change.js +11 -0
- package/dist/events/read.d.ts +19 -0
- package/dist/events/read.js +11 -0
- package/dist/events/reconnect.d.ts +6 -0
- package/dist/events/reconnect.js +11 -0
- package/dist/events/reject.d.ts +13 -0
- package/dist/events/reject.js +11 -0
- package/dist/events/relabel.d.ts +6 -0
- package/dist/events/relabel.js +11 -0
- package/dist/events/remove.d.ts +12 -0
- package/dist/events/remove.js +11 -0
- package/dist/events/reorder.d.ts +18 -0
- package/dist/events/reorder.js +11 -0
- package/dist/events/reordered.d.ts +12 -0
- package/dist/events/reordered.js +11 -0
- package/dist/events/resize.d.ts +19 -0
- package/dist/events/resize.js +11 -0
- package/dist/events/resized.d.ts +16 -0
- package/dist/events/resized.js +11 -0
- package/dist/events/sample-end.d.ts +5 -0
- package/dist/events/sample-end.js +6 -0
- package/dist/events/sample-start.d.ts +18 -0
- package/dist/events/sample-start.js +6 -0
- package/dist/events/scrolled.d.ts +32 -0
- package/dist/events/scrolled.js +11 -0
- package/dist/events/select.d.ts +12 -0
- package/dist/events/select.js +11 -0
- package/dist/events/selected.d.ts +12 -0
- package/dist/events/selected.js +11 -0
- package/dist/events/send.d.ts +18 -0
- package/dist/events/send.js +11 -0
- package/dist/events/shortcut.d.ts +13 -0
- package/dist/events/shortcut.js +11 -0
- package/dist/events/sort.d.ts +17 -0
- package/dist/events/sort.js +11 -0
- package/dist/events/sorted.d.ts +15 -0
- package/dist/events/sorted.js +11 -0
- package/dist/events/split.d.ts +12 -0
- package/dist/events/split.js +11 -0
- package/dist/events/toggle.d.ts +15 -0
- package/dist/events/toggle.js +11 -0
- package/dist/events/tour-ask.d.ts +16 -0
- package/dist/events/tour-ask.js +11 -0
- package/dist/events/tour-status.d.ts +14 -0
- package/dist/events/tour-status.js +11 -0
- package/dist/events/typing.d.ts +10 -0
- package/dist/events/typing.js +11 -0
- package/dist/helix-element/helix-element.js +14 -1
- package/dist/helix-element/react-bridge.d.ts +19 -4
- package/dist/helix-element/react-bridge.js +15 -2
- package/dist/helix-form-element/helix-form-element.d.ts +5 -20
- package/dist/helix-form-element/helix-form-element.js +4 -56
- package/dist/index.d.ts +17 -3
- package/dist/index.js +17 -3
- package/dist/mixins/mixin-chart-source/mixin-chart-source.d.ts +17 -2
- package/dist/mixins/mixin-chart-source/mixin-chart-source.js +22 -1
- package/dist/mixins/mixin-controller-active/mixin-controller-active.js +4 -3
- package/dist/mixins/mixin-controller-checked/mixin-controller-checked.d.ts +5 -2
- package/dist/mixins/mixin-controller-checked/mixin-controller-checked.js +2 -1
- package/dist/mixins/mixin-controller-value/mixin-controller-value.d.ts +4 -2
- package/dist/mixins/mixin-controller-value/mixin-controller-value.js +7 -2
- package/dist/mixins/mixin-dismissible/mixin-dismissible.js +20 -4
- package/dist/mixins/mixin-field/mixin-field.js +2 -2
- package/dist/mixins/mixin-picker-field/mixin-picker-field.d.ts +15 -3
- package/dist/mixins/mixin-picker-field/mixin-picker-field.js +11 -4
- package/dist/mixins/mixin-segmented-field/mixin-segmented-field.d.ts +1 -1
- package/dist/mixins/mixin-segmented-field/mixin-segmented-field.js +10 -4
- package/dist/utils/audit-name/audit-name-off.d.ts +10 -0
- package/dist/utils/audit-name/audit-name-off.js +1 -0
- package/dist/utils/audit-name/audit-name.d.ts +19 -6
- package/dist/utils/audit-name/audit-name.js +10 -27
- package/dist/utils/calendar/calendar.js +7 -7
- package/dist/utils/draw-icon/draw-icon.d.ts +7 -6
- package/dist/utils/draw-tooltip/draw-tooltip.d.ts +1 -1
- package/dist/utils/draw-tooltip/draw-tooltip.js +3 -1
- package/dist/utils/draw-tooltip/spoken-reading.d.ts +6 -2
- package/dist/utils/draw-tooltip/spoken-reading.js +5 -4
- package/dist/utils/heading-level/heading-level.d.ts +8 -0
- package/dist/utils/heading-level/heading-level.js +4 -0
- package/dist/utils/implicit-submit/implicit-submit.d.ts +25 -0
- package/dist/utils/implicit-submit/implicit-submit.js +52 -0
- package/dist/utils/name-text/name-text.d.ts +12 -0
- package/dist/utils/name-text/name-text.js +25 -0
- package/dist/utils/number-format/number-format.d.ts +2 -1
- package/dist/utils/number-format/number-format.js +13 -5
- package/dist/utils/plain-click/plain-click.d.ts +10 -0
- package/dist/utils/plain-click/plain-click.js +1 -0
- package/dist/utils/press-type/press-type.d.ts +20 -0
- package/dist/utils/press-type/press-type.js +15 -0
- package/dist/utils/range-add/range-add.d.ts +19 -0
- package/dist/utils/range-add/range-add.js +5 -0
- package/dist/utils/reflect-elements/reflect-elements.d.ts +3 -3
- package/dist/utils/report-runtime/report-runtime.d.ts +9 -4
- package/dist/utils/row-data/row-data.d.ts +15 -0
- package/dist/utils/row-data/row-data.js +17 -0
- package/dist/utils/row-order/row-order.d.ts +141 -0
- package/dist/utils/row-order/row-order.js +76 -0
- package/dist/utils/tell-disclosure/tell-disclosure.d.ts +4 -0
- package/dist/utils/tree-arrow/tree-arrow.d.ts +23 -0
- package/dist/utils/tree-arrow/tree-arrow.js +9 -0
- package/dist/utils/typeahead/typeahead.d.ts +67 -0
- package/dist/utils/typeahead/typeahead.js +36 -0
- package/dist/utils/value-as/value-as.d.ts +9 -0
- package/dist/utils/value-as/value-as.js +9 -1
- package/dist/utils/watch-labels/watch-labels.d.ts +16 -0
- package/dist/utils/watch-labels/watch-labels.js +34 -0
- package/dist/utils/words-converter/words-converter.d.ts +14 -0
- package/dist/utils/words-converter/words-converter.js +15 -0
- package/dist/utils/write-time/write-time.d.ts +4 -4
- package/dist/utils/written-list/written-list.d.ts +29 -0
- package/dist/utils/written-list/written-list.js +30 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +18 -5
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export const parse = (spec) => {
|
|
2
|
+
const trimmed = spec.trim();
|
|
3
|
+
if (trimmed === '') {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const [field = '', direction = 'asc'] = trimmed.split(':');
|
|
7
|
+
if (field === '' || (direction !== 'asc' && direction !== 'desc')) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
return { direction, field };
|
|
11
|
+
};
|
|
12
|
+
export const format = (sort) => sort ? `${sort.field}:${sort.direction}` : '';
|
|
13
|
+
export const cycle = (current, field) => {
|
|
14
|
+
if (current?.field !== field) {
|
|
15
|
+
return { direction: 'asc', field };
|
|
16
|
+
}
|
|
17
|
+
return current.direction === 'asc' ? { direction: 'desc', field } : undefined;
|
|
18
|
+
};
|
|
19
|
+
export const filter = (rows, query, axes) => {
|
|
20
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
21
|
+
if (needle === '') {
|
|
22
|
+
return [...rows];
|
|
23
|
+
}
|
|
24
|
+
return rows.filter((row) => axes.some((axis) => text(axis.order(row)).toLocaleLowerCase().includes(needle)));
|
|
25
|
+
};
|
|
26
|
+
export const sort = (rows, spec, axes) => {
|
|
27
|
+
const axis = spec ? axes.find((one) => one.field === spec.field) : undefined;
|
|
28
|
+
if (!spec || !axis) {
|
|
29
|
+
return [...rows];
|
|
30
|
+
}
|
|
31
|
+
const sign = spec.direction === 'asc' ? 1 : -1;
|
|
32
|
+
return [...rows].sort((left, right) => compare(axis.order(left), axis.order(right), sign));
|
|
33
|
+
};
|
|
34
|
+
export const window_ = (rows, page, size) => {
|
|
35
|
+
if (size <= 0) {
|
|
36
|
+
return [...rows];
|
|
37
|
+
}
|
|
38
|
+
const pages = Math.max(1, Math.ceil(rows.length / size));
|
|
39
|
+
const wanted = Math.min(pages, Math.max(1, Math.floor(page) || 1));
|
|
40
|
+
const from = (wanted - 1) * size;
|
|
41
|
+
return rows.slice(from, from + size);
|
|
42
|
+
};
|
|
43
|
+
const text = (value) => {
|
|
44
|
+
if (value === null || value === undefined) {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
if (value instanceof Date) {
|
|
48
|
+
return value.toISOString();
|
|
49
|
+
}
|
|
50
|
+
return String(value);
|
|
51
|
+
};
|
|
52
|
+
const compare = (left, right, sign) => {
|
|
53
|
+
const leftMissing = left === null || left === undefined || left === '';
|
|
54
|
+
const rightMissing = right === null || right === undefined || right === '';
|
|
55
|
+
if (leftMissing || rightMissing) {
|
|
56
|
+
return leftMissing && rightMissing ? 0 : leftMissing ? 1 : -1;
|
|
57
|
+
}
|
|
58
|
+
if (typeof left === 'number' && typeof right === 'number') {
|
|
59
|
+
return sign * (left - right);
|
|
60
|
+
}
|
|
61
|
+
if (typeof left === 'boolean' && typeof right === 'boolean') {
|
|
62
|
+
return sign * (Number(left) - Number(right));
|
|
63
|
+
}
|
|
64
|
+
if (left instanceof Date && right instanceof Date) {
|
|
65
|
+
return sign * (left.getTime() - right.getTime());
|
|
66
|
+
}
|
|
67
|
+
return (sign * text(left).localeCompare(text(right), undefined, { numeric: true, sensitivity: 'base' }));
|
|
68
|
+
};
|
|
69
|
+
export const arranged = (rows, axes, { query, spec }) => ({
|
|
70
|
+
rows: sort(filter(rows, query, axes), parse(spec), axes),
|
|
71
|
+
total: rows.length,
|
|
72
|
+
});
|
|
73
|
+
export const ordered = (rows, axes, { page, query, size, spec }) => {
|
|
74
|
+
const { rows: inOrder, total } = arranged(rows, axes, { query, spec });
|
|
75
|
+
return { matched: inOrder.length, rows: window_(inOrder, page, size), total };
|
|
76
|
+
};
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
* menu nothing no
|
|
23
23
|
* ```
|
|
24
24
|
*
|
|
25
|
+
* The popover row holds for the first render. Since then Popover writes
|
|
26
|
+
* `aria-expanded` onto a plain `<button>` trigger from the reader's first
|
|
27
|
+
* press on, after hydration, and calls this only for a Helix trigger.
|
|
28
|
+
*
|
|
25
29
|
* React reports "some attributes of the server rendered HTML didn't match the
|
|
26
30
|
* client properties. This won't be patched up", and the cost is not the console
|
|
27
31
|
* line: it answers a mismatch by discarding the server's HTML for that subtree
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** What a tree row is, for the arrow along the line. */
|
|
2
|
+
export interface TreeArrowRow {
|
|
3
|
+
/** Whether the row holds rows of its own. */
|
|
4
|
+
branch: boolean;
|
|
5
|
+
/** Whether a disabled branch, which neither opens nor shuts. */
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
/** Whether the branch is open. */
|
|
8
|
+
open: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** What the arrow along the line does on a row. */
|
|
11
|
+
export type TreeArrow = 'child' | 'close' | 'open' | 'parent';
|
|
12
|
+
/**
|
|
13
|
+
* What Right or Left does on a tree row, as the APG tree view says: `along` is
|
|
14
|
+
* `1` for the key that points into a branch, where its caret points (Right on
|
|
15
|
+
* a left-to-right page), and `-1` for the other.
|
|
16
|
+
*
|
|
17
|
+
* In: a shut branch opens, and an open one moves to its first child; a leaf
|
|
18
|
+
* does nothing (`undefined`). Out: an open branch shuts, and anything else
|
|
19
|
+
* moves to its parent. A disabled branch neither opens nor shuts. Tree, Object
|
|
20
|
+
* Inspector and Data Table's tree column read their keys through this, and
|
|
21
|
+
* Data Table takes `child` and `undefined` as the next column.
|
|
22
|
+
*/
|
|
23
|
+
export declare const treeArrow: (row: TreeArrowRow, along: -1 | 1) => TreeArrow | undefined;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a press types a character, which is what typeahead reads.
|
|
3
|
+
*
|
|
4
|
+
* One character with no Control, Command or Alt held, so a shortcut such as
|
|
5
|
+
* Control+A is never taken for the letter A. Shift is allowed, because a
|
|
6
|
+
* capital is still a letter.
|
|
7
|
+
*/
|
|
8
|
+
export declare const typesCharacter: (event: KeyboardEvent) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Finds an item by the letters a reader types at a set, the way a native
|
|
11
|
+
* `<select>` does.
|
|
12
|
+
*
|
|
13
|
+
* Letters typed within `timeout` milliseconds of each other build one search,
|
|
14
|
+
* so typing "ca" moves to "Canada" past "Cambodia". The same letter typed again
|
|
15
|
+
* moves to the next item that starts with it, so pressing "c" three times visits
|
|
16
|
+
* the first three. A pause starts a new search.
|
|
17
|
+
*
|
|
18
|
+
* Matching ignores case and leading spaces, and searches from the reader's
|
|
19
|
+
* position, wrapping at the end. A search that matches nothing moves nothing.
|
|
20
|
+
*
|
|
21
|
+
* Holds only the letters, so one instance serves any set: the caller passes the
|
|
22
|
+
* words of the items and where the reader is on every key.
|
|
23
|
+
*/
|
|
24
|
+
export declare class Typeahead {
|
|
25
|
+
private letters;
|
|
26
|
+
private last;
|
|
27
|
+
private readonly timeout;
|
|
28
|
+
constructor({ timeout }?: {
|
|
29
|
+
timeout?: number;
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Whether a search is under way.
|
|
33
|
+
*
|
|
34
|
+
* A set that chooses on Space asks this first, because a Space typed in the
|
|
35
|
+
* middle of a search is part of the words, as in "New York".
|
|
36
|
+
*/
|
|
37
|
+
typing(now?: number): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Adds a character to the search, and returns the index of the item it
|
|
40
|
+
* matches, or `-1` where none does.
|
|
41
|
+
*
|
|
42
|
+
* `texts` are the words of the items a reader can reach, in order, and
|
|
43
|
+
* `from` is the index of the item the reader is on, or `-1`.
|
|
44
|
+
*/
|
|
45
|
+
match(key: string, texts: readonly string[], from: number, now?: number): number;
|
|
46
|
+
/** Ends the search, so the next letter starts a new one. */
|
|
47
|
+
reset(): void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A typeahead over a set's items: how to read an item's words, and the search
|
|
51
|
+
* that remembers the letters typed so far.
|
|
52
|
+
*
|
|
53
|
+
* What `KeyboardNavigationController` takes as its `typeahead` option. A set
|
|
54
|
+
* builds one with `typeaheadBy`, so the search's code ships only with the sets
|
|
55
|
+
* that type ahead, and Rating, Tabs or Radio, which never do, carry none of it.
|
|
56
|
+
*/
|
|
57
|
+
export interface TypeaheadBy<Item> {
|
|
58
|
+
/** The letters typed so far, matched against the words. */
|
|
59
|
+
readonly search: Typeahead;
|
|
60
|
+
/** The words of an item, which a reader types the start of. */
|
|
61
|
+
readonly words: (item: Item) => string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Turns on typeahead for a set whose items have these words. See
|
|
65
|
+
* `TypeaheadBy`.
|
|
66
|
+
*/
|
|
67
|
+
export declare const typeaheadBy: <Item>(words: (item: Item) => string) => TypeaheadBy<Item>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const typesCharacter = (event) => event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
2
|
+
export class Typeahead {
|
|
3
|
+
constructor({ timeout = 500 } = {}) {
|
|
4
|
+
this.letters = '';
|
|
5
|
+
this.last = 0;
|
|
6
|
+
this.timeout = timeout;
|
|
7
|
+
}
|
|
8
|
+
typing(now = Date.now()) {
|
|
9
|
+
return this.letters !== '' && now - this.last <= this.timeout;
|
|
10
|
+
}
|
|
11
|
+
match(key, texts, from, now = Date.now()) {
|
|
12
|
+
if (!this.typing(now)) {
|
|
13
|
+
this.letters = '';
|
|
14
|
+
}
|
|
15
|
+
this.last = now;
|
|
16
|
+
this.letters += key.toLowerCase();
|
|
17
|
+
const words = texts.map((text) => text.trim().toLowerCase());
|
|
18
|
+
const repeated = [...this.letters].every((letter) => letter === this.letters[0]);
|
|
19
|
+
const needle = repeated ? (this.letters[0] ?? '') : this.letters;
|
|
20
|
+
const start = repeated ? from + 1 : Math.max(from, 0);
|
|
21
|
+
for (let step = 0; step < words.length; step += 1) {
|
|
22
|
+
const at = (start + step) % words.length;
|
|
23
|
+
if (words[at]?.startsWith(needle)) {
|
|
24
|
+
return at;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return -1;
|
|
28
|
+
}
|
|
29
|
+
reset() {
|
|
30
|
+
this.letters = '';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export const typeaheadBy = (words) => ({
|
|
34
|
+
search: new Typeahead(),
|
|
35
|
+
words,
|
|
36
|
+
});
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Midnight UTC on a day, with the year as written.
|
|
3
|
+
*
|
|
4
|
+
* `Date.UTC` reads a year from 0 to 99 as 1900 to 1999, so year 1, which a
|
|
5
|
+
* native date input accepts and a year segment reaches with Home, became 1901
|
|
6
|
+
* and the date was refused. `setUTCFullYear` takes the year as given, and
|
|
7
|
+
* rolls a month or a day past its end the way `Date.UTC` does.
|
|
8
|
+
*/
|
|
9
|
+
export declare const utcDate: (year: number, month: number, day: number) => Date;
|
|
1
10
|
/**
|
|
2
11
|
* The date a `YYYY-MM-DD` value names, at midnight UTC, or `null`.
|
|
3
12
|
*
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
2
2
|
const ISO_TIME = /^(\d{2}):(\d{2})(?::(\d{2}(?:\.\d{1,3})?))?$/;
|
|
3
3
|
const DAY = 86_400_000;
|
|
4
|
+
export const utcDate = (year, month, day) => {
|
|
5
|
+
const date = new Date(0);
|
|
6
|
+
date.setUTCFullYear(year, month, day);
|
|
7
|
+
return date;
|
|
8
|
+
};
|
|
4
9
|
export const valueAsDate = (value) => {
|
|
5
10
|
const parts = ISO_DATE.exec(value);
|
|
6
11
|
if (!parts) {
|
|
7
12
|
return null;
|
|
8
13
|
}
|
|
9
14
|
const [year, month, day] = [Number(parts[1]), Number(parts[2]), Number(parts[3])];
|
|
10
|
-
|
|
15
|
+
if (year < 1) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const date = utcDate(year, month - 1, day);
|
|
11
19
|
const rolled = date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day;
|
|
12
20
|
return rolled ? null : date;
|
|
13
21
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calls `heard` whenever a `<label>` changes in the tree `host` is in: one is
|
|
3
|
+
* added or taken out, its `for` changes, or its words do.
|
|
4
|
+
*
|
|
5
|
+
* **For a label that arrives after the control renders**, which a framework
|
|
6
|
+
* does freely and which no attribute on the host reports: the platform adds the
|
|
7
|
+
* label to the host's `labels` and says nothing. `HelixFormElement` updates
|
|
8
|
+
* when this calls, so `AriaForwardController` names the control inside as the
|
|
9
|
+
* label appears, where it used to wait for focus.
|
|
10
|
+
*
|
|
11
|
+
* **One observer per tree, whatever the number of controls in it**, so a form
|
|
12
|
+
* of forty fields watches the page once, and a change that touches no label
|
|
13
|
+
* costs one check per record. The returned function stops the watch, and an
|
|
14
|
+
* observer whose controls have all gone stops at the next change it sees.
|
|
15
|
+
*/
|
|
16
|
+
export declare const watchLabels: (host: Node, heard: () => void) => (() => void);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const trees = new Map();
|
|
2
|
+
const touchesLabel = ({ addedNodes, removedNodes, target }) => [target, ...addedNodes, ...removedNodes].some((node) => (node instanceof Element ? node : node.parentElement)?.closest('label') != null ||
|
|
3
|
+
(node instanceof Element && node.querySelector('label') !== null));
|
|
4
|
+
export const watchLabels = (host, heard) => {
|
|
5
|
+
const root = host.getRootNode();
|
|
6
|
+
let callbacks = trees.get(root);
|
|
7
|
+
if (!callbacks) {
|
|
8
|
+
const made = new Set();
|
|
9
|
+
const observer = new MutationObserver((records) => {
|
|
10
|
+
if (made.size === 0) {
|
|
11
|
+
observer.disconnect();
|
|
12
|
+
trees.delete(root);
|
|
13
|
+
}
|
|
14
|
+
else if (records.some(touchesLabel)) {
|
|
15
|
+
for (const callback of [...made]) {
|
|
16
|
+
callback();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
observer.observe(root, {
|
|
21
|
+
attributeFilter: ['for'],
|
|
22
|
+
characterData: true,
|
|
23
|
+
childList: true,
|
|
24
|
+
subtree: true,
|
|
25
|
+
});
|
|
26
|
+
callbacks = made;
|
|
27
|
+
trees.set(root, made);
|
|
28
|
+
}
|
|
29
|
+
callbacks.add(heard);
|
|
30
|
+
const watched = callbacks;
|
|
31
|
+
return () => {
|
|
32
|
+
watched.delete(heard);
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads an attribute holding words keyed by name, written as a JSON object,
|
|
3
|
+
* such as Orb's `state-labels`, Sandbox Terminal's `level-words` or Color
|
|
4
|
+
* Picker's `color-words`. A property declares it as its `converter`.
|
|
5
|
+
*
|
|
6
|
+
* **Anything else is no words, never `null`.** JSON that does not parse, an
|
|
7
|
+
* array, a string or `null` gives an empty object, and a key whose value is
|
|
8
|
+
* not a string is dropped, so every key keeps its default words. Lit's own
|
|
9
|
+
* `Object` converter answers `null` for JSON that does not parse, and a render
|
|
10
|
+
* that reads a key off it throws and draws nothing, over a typo in markup.
|
|
11
|
+
*/
|
|
12
|
+
export declare const wordsConverter: {
|
|
13
|
+
fromAttribute: (value: string | null) => Record<string, string>;
|
|
14
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const wordsConverter = {
|
|
2
|
+
fromAttribute: (value) => {
|
|
3
|
+
let parsed;
|
|
4
|
+
try {
|
|
5
|
+
parsed = JSON.parse(value ?? '');
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
return Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === 'string'));
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `Intl` decides between a twelve and a twenty-four hour clock, because that is
|
|
5
5
|
* a property of the locale rather than of any component: `en-US` gets `2:30 PM`
|
|
6
|
-
* and `en-GB` gets `14:30` without either being configured.
|
|
7
|
-
* force one
|
|
8
|
-
*
|
|
9
|
-
* 24 hour regardless.
|
|
6
|
+
* and `en-GB` gets `14:30` without either being configured. This function takes
|
|
7
|
+
* no flag to force one. A family that offers the choice, such as Time Picker
|
|
8
|
+
* and Time Input with `hour-cycle`, passes it in the locale, as its `-u-hc-`
|
|
9
|
+
* extension (`en-US-u-hc-h23`). The value is 24 hour regardless.
|
|
10
10
|
*
|
|
11
11
|
* A value this cannot read is handed back unchanged, so a field showing what is
|
|
12
12
|
* being typed shows the letters rather than blanking under the reader. Minute
|
|
@@ -61,3 +61,32 @@ export declare const commaList: (value: string) => string[];
|
|
|
61
61
|
* holds, so a set of pressed items reads the same whichever was pressed first.
|
|
62
62
|
*/
|
|
63
63
|
export declare const toggleValue: (list: readonly string[], value: string, order?: readonly string[]) => string[];
|
|
64
|
+
/**
|
|
65
|
+
* `chosen` with every one of `values` added, or with every one taken out
|
|
66
|
+
* where each was already in it: a select-all box, or a branch of a checkbox
|
|
67
|
+
* tree pressed. `values` empty changes nothing.
|
|
68
|
+
*
|
|
69
|
+
* With `order`, the result is put in that order and holds only what `order`
|
|
70
|
+
* holds. Without it, what was chosen keeps its place and what is added
|
|
71
|
+
* follows.
|
|
72
|
+
*/
|
|
73
|
+
export declare const toggleEvery: (chosen: Iterable<string>, values: readonly string[], order?: readonly string[]) => string[];
|
|
74
|
+
/** How many items a set lets a reader select: Tag Group's and List's `selection-mode`. */
|
|
75
|
+
export type SelectionMode = 'multiple' | 'none' | 'single';
|
|
76
|
+
/**
|
|
77
|
+
* The comma-separated `value` a press on the item carrying `pressed` leaves.
|
|
78
|
+
*
|
|
79
|
+
* `single` selects that item alone, or none where it was the one selected.
|
|
80
|
+
* `multiple` adds it, or takes it out. `none` selects nothing and leaves the
|
|
81
|
+
* value as it was. Tag Group and List answer the same question for their
|
|
82
|
+
* tags and rows.
|
|
83
|
+
*/
|
|
84
|
+
export declare const pressedValue: (mode: SelectionMode, value: string, pressed: string) => string;
|
|
85
|
+
/**
|
|
86
|
+
* The comma-separated `value` once an item carrying `removed` has left, where
|
|
87
|
+
* `left` is what the items still there stand for.
|
|
88
|
+
*
|
|
89
|
+
* Taken out only where no item left still stands for it, so two items with
|
|
90
|
+
* one value keep it while either remains. The rest is written back as it was.
|
|
91
|
+
*/
|
|
92
|
+
export declare const prunedValue: (value: string, removed: string, left: readonly string[]) => string;
|
|
@@ -12,3 +12,33 @@ export const toggleValue = (list, value, order) => {
|
|
|
12
12
|
const next = list.includes(value) ? list.filter((one) => one !== value) : [...list, value];
|
|
13
13
|
return order ? order.filter((one) => next.includes(one)) : next;
|
|
14
14
|
};
|
|
15
|
+
export const toggleEvery = (chosen, values, order) => {
|
|
16
|
+
const next = new Set(chosen);
|
|
17
|
+
const every = values.length > 0 && values.every((value) => next.has(value));
|
|
18
|
+
for (const value of values) {
|
|
19
|
+
if (every) {
|
|
20
|
+
next.delete(value);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
next.add(value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return order ? order.filter((value) => next.has(value)) : [...next];
|
|
27
|
+
};
|
|
28
|
+
export const pressedValue = (mode, value, pressed) => {
|
|
29
|
+
const now = commaList(value);
|
|
30
|
+
if (mode === 'single') {
|
|
31
|
+
return now.includes(pressed) ? '' : pressed;
|
|
32
|
+
}
|
|
33
|
+
if (mode === 'multiple') {
|
|
34
|
+
return toggleValue(now, pressed).join(', ');
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
export const prunedValue = (value, removed, left) => {
|
|
39
|
+
const now = commaList(value);
|
|
40
|
+
if (!now.includes(removed) || left.includes(removed)) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
return now.filter((one) => one !== removed).join(', ');
|
|
44
|
+
};
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.146.0';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-core",
|
|
3
3
|
"description": "Helix element primitives: base classes, mixins, decorators, utilities.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.146.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -28,21 +28,34 @@
|
|
|
28
28
|
"scripts": {
|
|
29
29
|
"analyze": "bun --bun helix-cem",
|
|
30
30
|
"build": "tsc -p tsconfig.build.json && tsc -p tsconfig.types.json",
|
|
31
|
-
"test": "bun test src",
|
|
31
|
+
"test": "bun test src --conditions helix-source --conditions helix-development",
|
|
32
32
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
33
33
|
},
|
|
34
34
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@floating-ui/dom": "^1.8.0",
|
|
37
|
-
"@fusion.dev/helix-icons": "0.
|
|
37
|
+
"@fusion.dev/helix-icons": "0.146.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@fusion.dev/helix-cem": "0.
|
|
41
|
-
"@fusion.dev/helix-testing": "0.
|
|
40
|
+
"@fusion.dev/helix-cem": "0.146.0",
|
|
41
|
+
"@fusion.dev/helix-testing": "0.146.0",
|
|
42
42
|
"@lit-labs/ssr": "^4.1.0",
|
|
43
43
|
"lit": "^3.2.1"
|
|
44
44
|
},
|
|
45
45
|
"homepage": "https://fusion.dev",
|
|
46
|
+
"imports": {
|
|
47
|
+
"#audit-name": {
|
|
48
|
+
"helix-source": {
|
|
49
|
+
"development": "./src/utils/audit-name/audit-name.ts",
|
|
50
|
+
"helix-development": "./src/utils/audit-name/audit-name.ts",
|
|
51
|
+
"default": "./src/utils/audit-name/audit-name-off.ts"
|
|
52
|
+
},
|
|
53
|
+
"types": "./dist/utils/audit-name/audit-name.d.ts",
|
|
54
|
+
"development": "./dist/utils/audit-name/audit-name.js",
|
|
55
|
+
"helix-development": "./dist/utils/audit-name/audit-name.js",
|
|
56
|
+
"default": "./dist/utils/audit-name/audit-name-off.js"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
46
59
|
"keywords": [
|
|
47
60
|
"web-components",
|
|
48
61
|
"custom-elements",
|