@fusion.dev/helix-core 0.147.0 → 0.148.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 +1741 -133
- package/dist/controllers/children-controller/children-controller.d.ts +28 -0
- package/dist/controllers/children-controller/children-controller.js +18 -0
- package/dist/controllers/countdown-controller/countdown-controller.d.ts +15 -1
- package/dist/controllers/countdown-controller/countdown-controller.js +27 -2
- package/dist/controllers/floating-controller/floating-controller.d.ts +12 -1
- package/dist/controllers/floating-controller/floating-controller.js +2 -1
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.d.ts +25 -0
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.js +8 -0
- package/dist/controllers/open-phase-controller/open-phase-controller.d.ts +10 -0
- package/dist/controllers/open-phase-controller/open-phase-controller.js +7 -4
- package/dist/controllers/option-window-controller/option-window-controller.d.ts +96 -0
- package/dist/controllers/option-window-controller/option-window-controller.js +81 -0
- package/dist/controllers/popover-controller/popover-controller.js +1 -1
- package/dist/helix-element/helix-element.d.ts +14 -5
- package/dist/helix-element/helix-element.js +4 -2
- package/dist/index.d.ts +24 -10
- package/dist/index.js +22 -8
- package/dist/mixins/mixin-chart-source/mixin-chart-source.d.ts +5 -0
- package/dist/mixins/mixin-chart-source/mixin-chart-source.js +3 -0
- package/dist/mixins/mixin-viewport/mixin-viewport.js +8 -7
- package/dist/utils/assign-slots/assign-slots.d.ts +18 -0
- package/dist/utils/assign-slots/assign-slots.js +14 -0
- package/dist/utils/autofill-select/autofill-select.d.ts +40 -0
- package/dist/utils/autofill-select/autofill-select.js +14 -0
- package/dist/utils/center-in-view/center-in-view.d.ts +18 -0
- package/dist/utils/center-in-view/center-in-view.js +14 -0
- package/dist/utils/chord/key-names.d.ts +30 -0
- package/dist/utils/chord/key-names.js +52 -0
- package/dist/utils/column-step/column-step.d.ts +13 -0
- package/dist/utils/column-step/column-step.js +9 -0
- package/dist/utils/data-options/data-options.d.ts +60 -0
- package/dist/utils/data-options/data-options.js +46 -0
- package/dist/utils/draw-tooltip/draw-tooltip.d.ts +7 -2
- package/dist/utils/draw-tooltip/draw-tooltip.js +1 -1
- package/dist/utils/draw-tooltip/spoken-reading.d.ts +3 -2
- package/dist/utils/draw-tooltip/spoken-reading.js +3 -2
- package/dist/utils/export-parts/export-parts.d.ts +14 -0
- package/dist/utils/export-parts/export-parts.js +1 -0
- package/dist/utils/fill-template/fill-template.d.ts +9 -0
- package/dist/utils/fill-template/fill-template.js +3 -0
- package/dist/utils/filter-marks/filter-marks.d.ts +36 -0
- package/dist/utils/filter-marks/filter-marks.js +41 -0
- package/dist/utils/focus-target/focus-target.d.ts +12 -0
- package/dist/utils/focus-target/focus-target.js +9 -0
- package/dist/utils/focusable-elements/focusable-elements.d.ts +17 -0
- package/dist/utils/focusable-elements/focusable-elements.js +8 -0
- package/dist/utils/grid-move/grid-move.d.ts +56 -0
- package/dist/utils/grid-move/grid-move.js +28 -0
- package/dist/utils/number-format/number-format.d.ts +7 -0
- package/dist/utils/number-format/number-format.js +1 -0
- package/dist/utils/report-runtime/report-runtime.d.ts +7 -1
- package/dist/utils/report-values/report-values.d.ts +16 -4
- package/dist/utils/report-values/report-values.js +2 -2
- package/dist/utils/request-change/request-change.d.ts +11 -0
- package/dist/utils/request-change/request-change.js +10 -0
- package/dist/utils/scroll-item-into-view/scroll-item-into-view.d.ts +17 -0
- package/dist/utils/scroll-item-into-view/scroll-item-into-view.js +1 -0
- package/dist/utils/slot-filled/slot-filled.d.ts +8 -0
- package/dist/utils/slot-filled/slot-filled.js +1 -0
- package/dist/utils/toolbar-around/toolbar-around.d.ts +18 -0
- package/dist/utils/toolbar-around/toolbar-around.js +5 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export { auditName } from '#audit-name';
|
|
|
2
2
|
export { AriaForwardController, } from './controllers/aria-forward-controller/aria-forward-controller.js';
|
|
3
3
|
export { ArrivalController, } from './controllers/arrival-controller/arrival-controller.js';
|
|
4
4
|
export { ChartPointerController, } from './controllers/chart-pointer-controller/chart-pointer-controller.js';
|
|
5
|
+
export { ChildrenController } from './controllers/children-controller/children-controller.js';
|
|
5
6
|
export { CommandController, HelixFallbackCommandEvent, supportsInvokers, } from './controllers/command-controller/command-controller.js';
|
|
6
7
|
export { CopyController, } from './controllers/copy-controller/copy-controller.js';
|
|
7
8
|
export { CountdownController, } from './controllers/countdown-controller/countdown-controller.js';
|
|
@@ -16,9 +17,10 @@ export { FullscreenController } from './controllers/fullscreen-controller/fullsc
|
|
|
16
17
|
export { HostClickController } from './controllers/host-click-controller/host-click-controller.js';
|
|
17
18
|
export { IdleController } from './controllers/idle-controller/idle-controller.js';
|
|
18
19
|
export { IndicatorController, } from './controllers/indicator-controller/indicator-controller.js';
|
|
19
|
-
export { KeyboardNavigationController, } from './controllers/keyboard-navigation-controller/keyboard-navigation-controller.js';
|
|
20
|
+
export { focusItemOf, KeyboardNavigationController, } from './controllers/keyboard-navigation-controller/keyboard-navigation-controller.js';
|
|
20
21
|
export { MediaSessionController, SKIP_SECONDS, } from './controllers/media-session-controller/media-session-controller.js';
|
|
21
|
-
export { animationsSettled, OpenPhaseController, } from './controllers/open-phase-controller/open-phase-controller.js';
|
|
22
|
+
export { animationsFinished, animationsSettled, OpenPhaseController, } from './controllers/open-phase-controller/open-phase-controller.js';
|
|
23
|
+
export { OptionWindowController, } from './controllers/option-window-controller/option-window-controller.js';
|
|
22
24
|
export { MAX_FRAME_STEP, PaintGateController, } from './controllers/paint-gate-controller/paint-gate-controller.js';
|
|
23
25
|
export { PlacementController } from './controllers/placement-controller/placement-controller.js';
|
|
24
26
|
export { PopoverController, } from './controllers/popover-controller/popover-controller.js';
|
|
@@ -50,27 +52,37 @@ export { MixinTokens } from './mixins/mixin-tokens/mixin-tokens.js';
|
|
|
50
52
|
export { MixinViewport, } from './mixins/mixin-viewport/mixin-viewport.js';
|
|
51
53
|
export { anchorElement } from './utils/anchor-element/anchor-element.js';
|
|
52
54
|
export { arrowReach, sideOf } from './utils/arrow/arrow.js';
|
|
55
|
+
export { assignSlots } from './utils/assign-slots/assign-slots.js';
|
|
56
|
+
export { drawAutofill, } from './utils/autofill-select/autofill-select.js';
|
|
53
57
|
export { addDays, addMonths, barredBy, localToday, monthOf, monthOut, periodCells, periodKey, periodMove, sameMonth, weekStartOf, YEARS_SHOWN, yearOut, yearPageOf, } from './utils/calendar/calendar.js';
|
|
54
58
|
export { capturePointer } from './utils/capture-pointer/capture-pointer.js';
|
|
59
|
+
export { centerInView } from './utils/center-in-view/center-in-view.js';
|
|
55
60
|
export { ariaChord, chordParts, matchesChord, printableChord, selectsAll, } from './utils/chord/chord.js';
|
|
61
|
+
export { keyNames } from './utils/chord/key-names.js';
|
|
56
62
|
export { clamp } from './utils/clamp/clamp.js';
|
|
57
63
|
export { clockLocale, dayPeriod, isTwelveHour, nearestTime, offeredTimes, timeBarred, timeFault, wheelParts, wholeHour, } from './utils/clock/clock.js';
|
|
58
64
|
export { closestInstance } from './utils/closest-instance/closest-instance.js';
|
|
59
65
|
export { colorName, hueName } from './utils/color-name/color-name.js';
|
|
66
|
+
export { columnStep } from './utils/column-step/column-step.js';
|
|
60
67
|
export { countLabel } from './utils/count-label/count-label.js';
|
|
61
68
|
export { createSheet } from './utils/create-sheet/create-sheet.js';
|
|
62
69
|
export { formatColor, parseColor, toCss, toHsl, toRgb, } from './utils/css-color/css-color.js';
|
|
63
70
|
export { customElement, definedTags, duplicateRegistrations, } from './utils/custom-element/custom-element.js';
|
|
71
|
+
export { dataOptions, drawOptions, windowOf, } from './utils/data-options/data-options.js';
|
|
64
72
|
export { segmentName } from './utils/date-segments/date-segments.js';
|
|
65
73
|
export { drawDismiss, drawDismissGlyph, } from './utils/draw-dismiss/draw-dismiss.js';
|
|
66
74
|
export { drawIcon } from './utils/draw-icon/draw-icon.js';
|
|
67
75
|
export { CHART_PLOT, drawTooltip } from './utils/draw-tooltip/draw-tooltip.js';
|
|
68
76
|
export { elapsedTime } from './utils/elapsed-time/elapsed-time.js';
|
|
69
77
|
export { elementById, searchableById, } from './utils/element-by-id/element-by-id.js';
|
|
70
|
-
export {
|
|
71
|
-
export {
|
|
78
|
+
export { exportParts } from './utils/export-parts/export-parts.js';
|
|
79
|
+
export { fillTemplate, labelWith } from './utils/fill-template/fill-template.js';
|
|
80
|
+
export { FILTER_MARK, markMatches, rangeOf } from './utils/filter-marks/filter-marks.js';
|
|
81
|
+
export { focusTarget } from './utils/focus-target/focus-target.js';
|
|
82
|
+
export { deepActiveElement, deepContains, focusableElements, PRESSABLE, pressedOwnControl, } from './utils/focusable-elements/focusable-elements.js';
|
|
72
83
|
export { afterLinkFollowed, followLink, } from './utils/follow-link/follow-link.js';
|
|
73
84
|
export { formatNumbers } from './utils/format-numbers/format-numbers.js';
|
|
85
|
+
export { gridMove, pageRows, } from './utils/grid-move/grid-move.js';
|
|
74
86
|
export { headingIn, headingsIn } from './utils/heading-in/heading-in.js';
|
|
75
87
|
export { headingLevel } from './utils/heading-level/heading-level.js';
|
|
76
88
|
export { hostAria } from './utils/host-aria/host-aria.js';
|
|
@@ -87,7 +99,7 @@ export { markRegion } from './utils/mark-region/mark-region.js';
|
|
|
87
99
|
export { copiesOf, sameCopies, } from './utils/media-copy/media-copy.js';
|
|
88
100
|
export { nameText } from './utils/name-text/name-text.js';
|
|
89
101
|
export { nearest } from './utils/nearest/nearest.js';
|
|
90
|
-
export { formatNumber, parseNumber, readingText } from './utils/number-format/number-format.js';
|
|
102
|
+
export { formatNumber, formatPercent, parseNumber, readingText, } from './utils/number-format/number-format.js';
|
|
91
103
|
export { onUnlessFalse } from './utils/on-unless-false/on-unless-false.js';
|
|
92
104
|
export { applyOwnRule } from './utils/own-rule/own-rule.js';
|
|
93
105
|
export { plainClick } from './utils/plain-click/plain-click.js';
|
|
@@ -102,7 +114,7 @@ export { measuring, RENDER_SLOT, reportRender } from './utils/report-render/repo
|
|
|
102
114
|
export { RUNTIME_LOG, RUNTIME_SLOT, reportRuntime, } from './utils/report-runtime/report-runtime.js';
|
|
103
115
|
export { noteVersion, reportUsage, USAGE_SLOT, VERSIONS_SLOT, } from './utils/report-usage/report-usage.js';
|
|
104
116
|
export { reportValues } from './utils/report-values/report-values.js';
|
|
105
|
-
export { requestChange, } from './utils/request-change/request-change.js';
|
|
117
|
+
export { requestChange, requestValue, } from './utils/request-change/request-change.js';
|
|
106
118
|
export { resolveActiveItem, } from './utils/resolve-active-item/resolve-active-item.js';
|
|
107
119
|
export { holdCaret, restoreValue } from './utils/restore-value/restore-value.js';
|
|
108
120
|
export { rovingStop } from './utils/roving-stop/roving-stop.js';
|
|
@@ -110,9 +122,9 @@ export { valueAt } from './utils/row-data/row-data.js';
|
|
|
110
122
|
export { arranged, cycle, filter, format, ordered, parse, sort, window_, } from './utils/row-order/row-order.js';
|
|
111
123
|
export { extent, linear } from './utils/scale/scale.js';
|
|
112
124
|
export { ticks } from './utils/scale/ticks.js';
|
|
113
|
-
export { scrollItemIntoView, scrollingAncestor, } from './utils/scroll-item-into-view/scroll-item-into-view.js';
|
|
125
|
+
export { scrollItemIntoView, scrollingAncestor, scrollRoom, } from './utils/scroll-item-into-view/scroll-item-into-view.js';
|
|
114
126
|
export { lockScroll, scrollHolders, unlockScroll } from './utils/scroll-lock/scroll-lock.js';
|
|
115
|
-
export { slotFilled } from './utils/slot-filled/slot-filled.js';
|
|
127
|
+
export { slotFilled, slotNamed } from './utils/slot-filled/slot-filled.js';
|
|
116
128
|
export { SlottedGlyph } from './utils/slotted-glyph/slotted-glyph.js';
|
|
117
129
|
export { slottedWords } from './utils/slotted-words/slotted-words.js';
|
|
118
130
|
export { splitValues } from './utils/split-values/split-values.js';
|
|
@@ -120,9 +132,11 @@ export { edgeOffset, FLING, parseSnapPoints, settleSwipe, snapTravel, swipeAxis,
|
|
|
120
132
|
export { tellDisclosure } from './utils/tell-disclosure/tell-disclosure.js';
|
|
121
133
|
export { subscribe } from './utils/ticker/ticker.js';
|
|
122
134
|
export { TONE_MARKS, toneMark, } from './utils/tone-marks/tone-marks.js';
|
|
135
|
+
export { toolbarAround, toolbarAxis } from './utils/toolbar-around/toolbar-around.js';
|
|
123
136
|
export { treeArrow } from './utils/tree-arrow/tree-arrow.js';
|
|
124
137
|
export { Typeahead, typeaheadBy, typeaheadByWords, typesCharacter, } from './utils/typeahead/typeahead.js';
|
|
125
138
|
export { dateAsValue, isClockValue, isDateValue, isTimeValue, minutesAsValue, numberAsValue, secondsAsValue, timeAsValue, valueAsDate, valueAsMinutes, valueAsNumber, valueAsSeconds, valueAsTime, } from './utils/value-as/value-as.js';
|
|
139
|
+
export { verdictFlags } from './utils/verdict-flags/verdict-flags.js';
|
|
126
140
|
export { watchTheme } from './utils/watch-theme/watch-theme.js';
|
|
127
141
|
export { wordsConverter } from './utils/words-converter/words-converter.js';
|
|
128
142
|
export { writeClock, writeTime } from './utils/write-time/write-time.js';
|
|
@@ -178,6 +178,11 @@ export declare class MixinChartSourceInterface {
|
|
|
178
178
|
* hid.
|
|
179
179
|
*/
|
|
180
180
|
showsColumn(cell: number): boolean;
|
|
181
|
+
/**
|
|
182
|
+
* The heading of the column at this place in a row, read from the first row
|
|
183
|
+
* that has a cell there, or `''` where none has.
|
|
184
|
+
*/
|
|
185
|
+
columnName(cell: number): string;
|
|
181
186
|
/**
|
|
182
187
|
* The number of readings, which the pointer position maps onto.
|
|
183
188
|
*/
|
|
@@ -70,6 +70,9 @@ export const MixinChartSource = (Base) => {
|
|
|
70
70
|
const name = this.sourceRows[0]?.cells[cell]?.name;
|
|
71
71
|
return name === undefined || this.showsSeries(name);
|
|
72
72
|
}
|
|
73
|
+
columnName(cell) {
|
|
74
|
+
return this.sourceRows.find((row) => row.cells[cell])?.cells[cell]?.name ?? '';
|
|
75
|
+
}
|
|
73
76
|
get readings() {
|
|
74
77
|
return this.sourceRows.length;
|
|
75
78
|
}
|
|
@@ -286,27 +286,28 @@ export const MixinViewport = (Base) => {
|
|
|
286
286
|
if (!pan && !zoom && !fullscreen && more === nothing) {
|
|
287
287
|
return nothing;
|
|
288
288
|
}
|
|
289
|
+
const [up, start, end, down] = ['up', 'start', 'end', 'down'].map((way) => this.panGlyph(way));
|
|
289
290
|
return html `<div part="controls" role="group" aria-label=${this.controlsLabel ?? this.restingControlsLabel}>
|
|
290
291
|
${pan
|
|
291
292
|
? html `<button part="pan-up" aria-label=${this.panLabel('up')} type="button" @click=${() => this.pan('up')}>
|
|
292
|
-
|
|
293
|
+
<slot name="pan-up-icon">${up}</slot>
|
|
293
294
|
</button>
|
|
294
295
|
<button part="pan-start" aria-label=${this.panLabel('start')} type="button" @click=${() => this.pan('start')}>
|
|
295
|
-
|
|
296
|
+
<slot name="pan-start-icon">${start}</slot>
|
|
296
297
|
</button>
|
|
297
298
|
<button part="pan-end" aria-label=${this.panLabel('end')} type="button" @click=${() => this.pan('end')}>
|
|
298
|
-
|
|
299
|
+
<slot name="pan-end-icon">${end}</slot>
|
|
299
300
|
</button>
|
|
300
301
|
<button part="pan-down" aria-label=${this.panLabel('down')} type="button" @click=${() => this.pan('down')}>
|
|
301
|
-
|
|
302
|
+
<slot name="pan-down-icon">${down}</slot>
|
|
302
303
|
</button>`
|
|
303
304
|
: nothing}
|
|
304
305
|
${zoom
|
|
305
306
|
? html `<button part="zoom-in" aria-label=${this.zoomInLabel} type="button" @click=${() => this.zoom(1)}>
|
|
306
|
-
|
|
307
|
+
<slot name="zoom-in-icon">+</slot>
|
|
307
308
|
</button>
|
|
308
309
|
<button part="zoom-out" aria-label=${this.zoomOutLabel} type="button" @click=${() => this.zoom(-1)}>
|
|
309
|
-
|
|
310
|
+
<slot name="zoom-out-icon">−</slot>
|
|
310
311
|
</button>`
|
|
311
312
|
: nothing}
|
|
312
313
|
${more}
|
|
@@ -318,7 +319,7 @@ export const MixinViewport = (Base) => {
|
|
|
318
319
|
type="button"
|
|
319
320
|
@click=${this.toggleFullscreen}
|
|
320
321
|
>
|
|
321
|
-
|
|
322
|
+
<slot name="fullscreen-icon">⤢</slot>
|
|
322
323
|
</button>`
|
|
323
324
|
: nothing}
|
|
324
325
|
</div>`;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sends each child to the slot it names, and every other child to the default
|
|
3
|
+
* slot, in a shadow root that assigns its slots by hand.
|
|
4
|
+
*
|
|
5
|
+
* **A root that assigns by hand routes nothing by itself**, its named slots
|
|
6
|
+
* included, so a header, a footer or an empty state slotted by name reaches
|
|
7
|
+
* nothing unless it is assigned here too. `place` says where a child goes when
|
|
8
|
+
* the host decides it, a row to its list or a card to the slot the layout drew
|
|
9
|
+
* for it, and a child it gives no slot to goes where its `slot` attribute says,
|
|
10
|
+
* as it would under the default assignment.
|
|
11
|
+
*
|
|
12
|
+
* **A slot already holding exactly what it would be given is left alone**, so
|
|
13
|
+
* calling this after every update fires no `slotchange` that nothing changed.
|
|
14
|
+
*
|
|
15
|
+
* Pair it with `ChildrenController`, which calls back when a child arrives
|
|
16
|
+
* after the first render, the case no `slotchange` reports.
|
|
17
|
+
*/
|
|
18
|
+
export declare const assignSlots: (root: ParentNode | null | undefined, children: Iterable<Element>, place?: (child: Element) => string | undefined) => void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const assignSlots = (root, children, place = () => undefined) => {
|
|
2
|
+
const named = new Map();
|
|
3
|
+
for (const child of children) {
|
|
4
|
+
const name = place(child) ?? child.getAttribute('slot') ?? '';
|
|
5
|
+
named.set(name, [...(named.get(name) ?? []), child]);
|
|
6
|
+
}
|
|
7
|
+
for (const slot of root?.querySelectorAll?.('slot') ?? []) {
|
|
8
|
+
const wanted = named.get(slot.name) ?? [];
|
|
9
|
+
const had = slot.assignedNodes();
|
|
10
|
+
if (had.length !== wanted.length || had.some((one, at) => one !== wanted[at])) {
|
|
11
|
+
slot.assign?.(...wanted);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { nothing, type TemplateResult } from 'lit';
|
|
2
|
+
/** What the hidden native select offers a browser's autofill, and what it does with the answer. */
|
|
3
|
+
export interface DrawAutofillOptions {
|
|
4
|
+
/** The autofill token, such as `country` or `cc-exp-month`. Empty draws nothing. */
|
|
5
|
+
autocomplete: string;
|
|
6
|
+
/** Whether the select is disabled, which takes it out of autofill too. */
|
|
7
|
+
disabled: boolean;
|
|
8
|
+
/** Whether more than one option can be chosen. */
|
|
9
|
+
multiple: boolean;
|
|
10
|
+
/** Takes what the browser filled in, as a value: several are joined by commas. */
|
|
11
|
+
onFill: (value: string) => void;
|
|
12
|
+
/** The options, each with its value and its words, in order. */
|
|
13
|
+
options: readonly {
|
|
14
|
+
text: string;
|
|
15
|
+
value: string;
|
|
16
|
+
}[];
|
|
17
|
+
/** The value now, several joined by commas. */
|
|
18
|
+
value: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A native `<select>` that a browser's autofill can fill, holding the same
|
|
22
|
+
* options as the custom select beside it. Select, Combobox and Listbox draw it
|
|
23
|
+
* under `autocomplete`.
|
|
24
|
+
*
|
|
25
|
+
* **A browser fills native fields only.** It reads `autocomplete`, picks an
|
|
26
|
+
* option by its value or its words, and sends `change`, which `onFill` turns
|
|
27
|
+
* into the custom select's value. Chromium fills a select inside a shadow root
|
|
28
|
+
* when its host is inside the form being filled.
|
|
29
|
+
*
|
|
30
|
+
* **The select's own `input` stops here.** It is composed, so it crossed the
|
|
31
|
+
* shadow root and reached the host before `change` did, with the host's value
|
|
32
|
+
* still the old one: measured in Chromium, a fill sent a page's `input`
|
|
33
|
+
* listener two events, the first carrying the old value. The host sends its
|
|
34
|
+
* own `input` and `change` once the value is taken.
|
|
35
|
+
*
|
|
36
|
+
* **Hidden from everyone but the browser**: clipped to a pixel, `aria-hidden`,
|
|
37
|
+
* and out of the tab order, with no `name`, so the form still receives the
|
|
38
|
+
* value once, from the custom select itself.
|
|
39
|
+
*/
|
|
40
|
+
export declare const drawAutofill: ({ autocomplete, disabled, multiple, onFill, options, value, }: DrawAutofillOptions) => TemplateResult | typeof nothing;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { html, nothing } from 'lit';
|
|
2
|
+
const HIDDEN = 'position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none';
|
|
3
|
+
export const drawAutofill = ({ autocomplete, disabled, multiple, onFill, options, value, }) => {
|
|
4
|
+
if (autocomplete === '') {
|
|
5
|
+
return nothing;
|
|
6
|
+
}
|
|
7
|
+
const chosen = value.split(',');
|
|
8
|
+
const fill = (event) => onFill([...event.currentTarget.selectedOptions]
|
|
9
|
+
.map((option) => option.value)
|
|
10
|
+
.filter(Boolean)
|
|
11
|
+
.join(','));
|
|
12
|
+
const stop = (event) => event.stopPropagation();
|
|
13
|
+
return html `<select aria-hidden="true" autocomplete=${autocomplete} style=${HIDDEN} tabindex="-1" ?disabled=${disabled} ?multiple=${multiple} @change=${fill} @input=${stop}><option value=""></option>${options.map((option) => html `<option value=${option.value} ?selected=${chosen.includes(option.value)}>${option.text}</option>`)}</select>`;
|
|
14
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrolls `box` to put `item`, one of the things it scrolls, in its middle.
|
|
3
|
+
*
|
|
4
|
+
* For a list read as a dial rather than scanned, as Time Picker's wheels read
|
|
5
|
+
* a Listbox. A delta from the two boxes rather than `offsetTop`: a slotted
|
|
6
|
+
* item's `offsetParent` is whatever is positioned above it, which is not the
|
|
7
|
+
* box and is not guaranteed to be anything.
|
|
8
|
+
*
|
|
9
|
+
* **Twice, and the second pass is not superstition.** The first delta is
|
|
10
|
+
* computed against whatever layout is current when this is called, and inside
|
|
11
|
+
* a panel that has just been revealed it is a frame behind: measured, one call
|
|
12
|
+
* landed a whole row short, 672 where 704 was wanted, and calling it again
|
|
13
|
+
* from a settled layout put it exactly on center. Reading a rect forces
|
|
14
|
+
* layout, so the second pass sees the result of the first and corrects the
|
|
15
|
+
* remainder. It stops as soon as there is nothing left to correct, and where
|
|
16
|
+
* either box has no height, as on a page not laid out.
|
|
17
|
+
*/
|
|
18
|
+
export declare const centerInView: (box: HTMLElement, item: Element) => void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const centerInView = (box, item) => {
|
|
2
|
+
for (let pass = 0; pass < 2; pass += 1) {
|
|
3
|
+
const outer = box.getBoundingClientRect();
|
|
4
|
+
const inner = item.getBoundingClientRect();
|
|
5
|
+
if (outer.height === 0 || inner.height === 0) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const off = inner.top + inner.height / 2 - (outer.top + outer.height / 2);
|
|
9
|
+
if (Math.abs(off) < 1) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
box.scrollTop += off;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words and glyphs a chord is drawn with, per platform.
|
|
3
|
+
*
|
|
4
|
+
* In core beside `ariaChord`, which says a chord to a reader as this draws it
|
|
5
|
+
* for the eye: Kbd draws a chord with it, and Speed Dial draws an action's
|
|
6
|
+
* shortcut with it where nothing is slotted, without importing Kbd.
|
|
7
|
+
*/
|
|
8
|
+
/** A chord's keys as they are shown, and what is shown between two of them. */
|
|
9
|
+
export interface KeyNames {
|
|
10
|
+
/** Each key's label, in the order the chord names them. */
|
|
11
|
+
keys: string[];
|
|
12
|
+
/** What goes between two keys: `+`, a hyphen, or nothing. */
|
|
13
|
+
separator: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The labels of a chord's keys on a platform, with `own` labels in place of
|
|
17
|
+
* the platform's, and what goes between two keys.
|
|
18
|
+
*
|
|
19
|
+
* `parts` are the chord's names as `chordParts` splits them. A name `own`
|
|
20
|
+
* holds takes that label, a name the platform knows takes its glyph or word,
|
|
21
|
+
* and any other single character is shown in capitals.
|
|
22
|
+
*
|
|
23
|
+
* **On an Apple keyboard glyphs run together and words are joined with a
|
|
24
|
+
* hyphen**, as Apple writes `Command-K`. A label of more than one character
|
|
25
|
+
* from `own` is a word, so `{"mod": "Command"}` shows `Command-K` there, where
|
|
26
|
+
* nothing between the two ran them into `CommandK`. The platform's own `Esc`
|
|
27
|
+
* and `Space` keep running on from a glyph, as `⌘Esc` always has. Everywhere
|
|
28
|
+
* else keys are joined with `+`.
|
|
29
|
+
*/
|
|
30
|
+
export declare const keyNames: (parts: readonly string[], apple: boolean, own?: Readonly<Record<string, string>>) => KeyNames;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const APPLE = {
|
|
2
|
+
alt: '⌥',
|
|
3
|
+
backspace: '⌫',
|
|
4
|
+
cmd: '⌘',
|
|
5
|
+
ctrl: '⌃',
|
|
6
|
+
del: '⌦',
|
|
7
|
+
down: '↓',
|
|
8
|
+
enter: '↵',
|
|
9
|
+
esc: 'Esc',
|
|
10
|
+
left: '←',
|
|
11
|
+
meta: '⌘',
|
|
12
|
+
mod: '⌘',
|
|
13
|
+
opt: '⌥',
|
|
14
|
+
right: '→',
|
|
15
|
+
shift: '⇧',
|
|
16
|
+
space: 'Space',
|
|
17
|
+
tab: '⇥',
|
|
18
|
+
up: '↑',
|
|
19
|
+
};
|
|
20
|
+
const ELSEWHERE = {
|
|
21
|
+
alt: 'Alt',
|
|
22
|
+
backspace: 'Backspace',
|
|
23
|
+
cmd: 'Win',
|
|
24
|
+
ctrl: 'Ctrl',
|
|
25
|
+
del: 'Del',
|
|
26
|
+
down: '↓',
|
|
27
|
+
enter: 'Enter',
|
|
28
|
+
esc: 'Esc',
|
|
29
|
+
left: '←',
|
|
30
|
+
meta: 'Win',
|
|
31
|
+
mod: 'Ctrl',
|
|
32
|
+
opt: 'Alt',
|
|
33
|
+
right: '→',
|
|
34
|
+
shift: 'Shift',
|
|
35
|
+
space: 'Space',
|
|
36
|
+
tab: 'Tab',
|
|
37
|
+
up: '↑',
|
|
38
|
+
};
|
|
39
|
+
export const keyNames = (parts, apple, own = {}) => {
|
|
40
|
+
const names = apple ? APPLE : ELSEWHERE;
|
|
41
|
+
let worded = false;
|
|
42
|
+
const keys = parts.map((part) => {
|
|
43
|
+
const name = part.toLowerCase();
|
|
44
|
+
const mine = own[name];
|
|
45
|
+
if (mine !== undefined) {
|
|
46
|
+
worded ||= [...mine].length > 1;
|
|
47
|
+
return mine;
|
|
48
|
+
}
|
|
49
|
+
return names[name] ?? (part.length === 1 ? part.toUpperCase() : part);
|
|
50
|
+
});
|
|
51
|
+
return { keys, separator: apple ? (worded ? '-' : '') : '+' };
|
|
52
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where Up or Down moves in a list laid out in columns, as a grid of tiles or
|
|
3
|
+
* a wrapping row is: to the next item after `at` (with `by` of `1`) or the
|
|
4
|
+
* last one before it (`-1`) that starts at the same inline offset, which is
|
|
5
|
+
* the item above or below it. `at` itself where there is none, so the key
|
|
6
|
+
* stops at the edge, as React Aria's grid layout stops.
|
|
7
|
+
*
|
|
8
|
+
* Read from where the items are drawn rather than from a column count, so it
|
|
9
|
+
* holds for a grid of any width, a row that wraps, and a column cut short.
|
|
10
|
+
* `starts` are the items' inline offsets in the order of the list, such as
|
|
11
|
+
* each one's `getBoundingClientRect().left`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const columnStep: (starts: readonly number[], at: number, by: -1 | 1) => number;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** One option of a list fed as data, as the list reads and marks it. */
|
|
2
|
+
export interface DataOption {
|
|
3
|
+
/** Whether the keyboard is on it. The list writes this. */
|
|
4
|
+
active: boolean;
|
|
5
|
+
/** Whether it can be chosen. */
|
|
6
|
+
disabled: boolean;
|
|
7
|
+
/** Whether a filter hides it. The list writes this. */
|
|
8
|
+
hidden: boolean;
|
|
9
|
+
/** Whether it is chosen. The list writes this. */
|
|
10
|
+
selected: boolean;
|
|
11
|
+
/** The words a reader sees, which the filter and the typeahead match. */
|
|
12
|
+
text: string;
|
|
13
|
+
/** What choosing it puts in the value. */
|
|
14
|
+
value: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* An option as a page hands it over: its value alone, which is also its words,
|
|
18
|
+
* or a record with a `value`, the `label` a reader sees (the value where it is
|
|
19
|
+
* left out) and `disabled`.
|
|
20
|
+
*/
|
|
21
|
+
export type DataOptionItem = number | string | {
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
label?: string;
|
|
24
|
+
value: number | string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The options a page handed over as data, as a list reads them, built once per
|
|
28
|
+
* array.
|
|
29
|
+
*
|
|
30
|
+
* Values and words are strings, as an option element's are, so a number and
|
|
31
|
+
* its digits choose the same option.
|
|
32
|
+
*/
|
|
33
|
+
export declare const dataOptions: (items: readonly DataOptionItem[]) => DataOption[];
|
|
34
|
+
/**
|
|
35
|
+
* The positions a window draws, in order, with `kept` added where it lies
|
|
36
|
+
* outside the window: before it where it comes first, after it where it comes
|
|
37
|
+
* later. `-1` keeps nothing. Positions past `count` are left out.
|
|
38
|
+
*
|
|
39
|
+
* `kept` is the option the keyboard is on. **It has to be drawn wherever it
|
|
40
|
+
* is**, because `aria-activedescendant` points at an element, and an option
|
|
41
|
+
* that is not drawn is one a screen reader cannot be told about.
|
|
42
|
+
* `VirtualizeController.spacers(kept)` takes its room out of the spacer on its
|
|
43
|
+
* side, so the scrollbar still measures the set.
|
|
44
|
+
*/
|
|
45
|
+
export declare const windowOf: (first: number, last: number, count: number, kept: number) => number[];
|
|
46
|
+
/**
|
|
47
|
+
* Draws `rows[index]` for each of `at` into `box`, as elements named `tag`,
|
|
48
|
+
* and returns them in order.
|
|
49
|
+
*
|
|
50
|
+
* **Reused by position.** A scroll moves the window by a row or two at a time,
|
|
51
|
+
* so the elements already drawn take the next rows' words and state rather than
|
|
52
|
+
* being thrown away: a list of ten thousand keeps the twenty or so elements a
|
|
53
|
+
* screen holds.
|
|
54
|
+
*
|
|
55
|
+
* Each element carries its place in the whole set, `aria-posinset` and
|
|
56
|
+
* `aria-setsize`, so a reader on the four-thousandth of ten thousand hears
|
|
57
|
+
* that, and not its place in what happens to be drawn. `disabled` holds every
|
|
58
|
+
* row down, for a list that is disabled itself.
|
|
59
|
+
*/
|
|
60
|
+
export declare const drawOptions: (box: Element, tag: string, rows: readonly DataOption[], at: readonly number[], disabled: boolean) => HTMLElement[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const dataOptions = (items) => items.map((item) => {
|
|
2
|
+
const record = typeof item === 'object' ? item : { value: item };
|
|
3
|
+
return {
|
|
4
|
+
active: false,
|
|
5
|
+
disabled: Boolean(record.disabled),
|
|
6
|
+
hidden: false,
|
|
7
|
+
selected: false,
|
|
8
|
+
text: String(record.label ?? record.value),
|
|
9
|
+
value: String(record.value),
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
export const windowOf = (first, last, count, kept) => {
|
|
13
|
+
const at = [];
|
|
14
|
+
for (let index = first; index < Math.min(last, count); index += 1) {
|
|
15
|
+
at.push(index);
|
|
16
|
+
}
|
|
17
|
+
if (kept >= 0 && kept < count && !at.includes(kept)) {
|
|
18
|
+
kept < first ? at.unshift(kept) : at.push(kept);
|
|
19
|
+
}
|
|
20
|
+
return at;
|
|
21
|
+
};
|
|
22
|
+
export const drawOptions = (box, tag, rows, at, disabled) => {
|
|
23
|
+
const drawn = [...box.children];
|
|
24
|
+
while (drawn.length > at.length) {
|
|
25
|
+
drawn.pop()?.remove();
|
|
26
|
+
}
|
|
27
|
+
while (drawn.length < at.length) {
|
|
28
|
+
drawn.push(box.appendChild(box.ownerDocument.createElement(tag)));
|
|
29
|
+
}
|
|
30
|
+
at.forEach((index, i) => {
|
|
31
|
+
const row = rows[index];
|
|
32
|
+
const element = drawn[i];
|
|
33
|
+
Object.assign(element, {
|
|
34
|
+
active: row.active,
|
|
35
|
+
disabled: row.disabled || disabled,
|
|
36
|
+
selected: row.selected,
|
|
37
|
+
value: row.value,
|
|
38
|
+
});
|
|
39
|
+
if (element.textContent !== row.text) {
|
|
40
|
+
element.textContent = row.text;
|
|
41
|
+
}
|
|
42
|
+
element.setAttribute('aria-posinset', String(index + 1));
|
|
43
|
+
element.setAttribute('aria-setsize', String(rows.length));
|
|
44
|
+
});
|
|
45
|
+
return drawn;
|
|
46
|
+
};
|
|
@@ -44,9 +44,14 @@ export interface TooltipAt {
|
|
|
44
44
|
/**
|
|
45
45
|
* What the keyboard is reading, which `drawTooltip` says aloud and marks.
|
|
46
46
|
*
|
|
47
|
-
* The chart's `pointer` is one, and is what every chart passes.
|
|
47
|
+
* The chart's `pointer` is one, and is what every chart passes. A chart whose
|
|
48
|
+
* readings can be chosen passes one with `state` as well, a word such as
|
|
49
|
+
* "selected" said after where the reading stands.
|
|
48
50
|
*/
|
|
49
|
-
export type ReadingCursor = Pick<ChartPointerController, 'column' | 'keyed'> & Partial<Pick<ChartPointerController, 'position' | 'shows'
|
|
51
|
+
export type ReadingCursor = Pick<ChartPointerController, 'column' | 'keyed'> & Partial<Pick<ChartPointerController, 'position' | 'shows'>> & {
|
|
52
|
+
/** A word said after the reading's position, such as "selected", or nothing. */
|
|
53
|
+
state?: string;
|
|
54
|
+
};
|
|
50
55
|
/**
|
|
51
56
|
* What a pointer resting on a reading shows, as `Tooltip` pointed at a mark.
|
|
52
57
|
*
|
|
@@ -11,7 +11,7 @@ export const drawTooltip = (rows, at, tag, where, slotOf, reading) => {
|
|
|
11
11
|
const live = reading === undefined || rows.length === 0
|
|
12
12
|
? nothing
|
|
13
13
|
: html `<span aria-live="polite" part="live" role="status">${reading.keyed && row
|
|
14
|
-
? spokenReading(row, reading.column, (cell) => reading.shows?.(cell) !== false, reading.position)
|
|
14
|
+
? spokenReading(row, reading.column, (cell) => reading.shows?.(cell) !== false, reading.position, reading.state)
|
|
15
15
|
: ''}</span>`;
|
|
16
16
|
if (!row || rows.length === 0) {
|
|
17
17
|
return live;
|
|
@@ -9,6 +9,7 @@ import type { Row } from '../read-series/read-series.js';
|
|
|
9
9
|
* false for, which is a series a legend hid.
|
|
10
10
|
*
|
|
11
11
|
* `position` follows in brackets, such as "2 of 12", where the chart gives
|
|
12
|
-
* one: last, so the reading is heard before where it stands.
|
|
12
|
+
* one: last, so the reading is heard before where it stands. `state`, a word
|
|
13
|
+
* such as "selected", follows it in the same brackets, "2 of 12, selected".
|
|
13
14
|
*/
|
|
14
|
-
export declare const spokenReading: (row: Row, column?: number, shows?: (cell: number) => boolean, position?: string) => string;
|
|
15
|
+
export declare const spokenReading: (row: Row, column?: number, shows?: (cell: number) => boolean, position?: string, state?: string) => string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export const spokenReading = (row, column, shows = () => true, position = '') => {
|
|
2
|
-
const
|
|
1
|
+
export const spokenReading = (row, column, shows = () => true, position = '', state = '') => {
|
|
2
|
+
const bracket = [position, state].filter((word) => word !== '').join(', ');
|
|
3
|
+
const after = bracket === '' ? '' : ` (${bracket})`;
|
|
3
4
|
const cell = column === undefined ? undefined : row.cells[column];
|
|
4
5
|
if (cell) {
|
|
5
6
|
return `${`${row.label}, ${cell.name} ${cell.text}`.trim()}${after}`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An `exportparts` list that forwards each of an inner component's parts under
|
|
3
|
+
* a prefix: `exportParts(['button', 'text'], 'copy')` is
|
|
4
|
+
* `button: copy-button, text: copy-text`.
|
|
5
|
+
*
|
|
6
|
+
* **One list per inner component, written once beside it**, so the next part
|
|
7
|
+
* Button gains reaches every family that renders a Button. Ten lists written
|
|
8
|
+
* out by hand each had to be found and edited when Button gained `spinner`.
|
|
9
|
+
*
|
|
10
|
+
* The inner component's parts are its own declared list, never ones read from
|
|
11
|
+
* a rendered element: the attribute is written on the server too, before
|
|
12
|
+
* anything has rendered.
|
|
13
|
+
*/
|
|
14
|
+
export declare const exportParts: (parts: readonly string[], prefix: string) => string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const exportParts = (parts, prefix) => parts.map((part) => `${part}: ${prefix}-${part}`).join(', ');
|
|
@@ -11,3 +11,12 @@
|
|
|
11
11
|
* shows up on the page as the mistake it is.
|
|
12
12
|
*/
|
|
13
13
|
export declare const fillTemplate: (template: string, values: Record<string, string | number>) => string;
|
|
14
|
+
/**
|
|
15
|
+
* A name made from a template and the words of what it acts on: `{key}` in
|
|
16
|
+
* the template filled with the words, or the words after the template where it
|
|
17
|
+
* has no `{key}`.
|
|
18
|
+
*
|
|
19
|
+
* The shape of every "Remove {label}" a page can override: written either way,
|
|
20
|
+
* "Remove" alone still names which one, as "Remove Draft".
|
|
21
|
+
*/
|
|
22
|
+
export declare const labelWith: (template: string, key: string, words: string) => string;
|
|
@@ -1 +1,4 @@
|
|
|
1
1
|
export const fillTemplate = (template, values) => Object.entries(values).reduce((out, [key, value]) => out.replaceAll(`{${key}}`, () => String(value)), template);
|
|
2
|
+
export const labelWith = (template, key, words) => template.includes(`{${key}}`)
|
|
3
|
+
? fillTemplate(template, { [key]: words })
|
|
4
|
+
: `${template} ${words}`.trim();
|