@fusion.dev/helix-headless 0.147.0 → 0.149.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 +11222 -2332
- package/dist/accordion/item/accordion-item.d.ts +5 -2
- package/dist/accordion/item/accordion-item.js +11 -7
- package/dist/accordion/root/accordion-root.js +4 -6
- package/dist/announcement/root/announcement-root.d.ts +61 -5
- package/dist/announcement/root/announcement-root.js +126 -20
- package/dist/area-chart/root/area-chart-root.d.ts +11 -0
- package/dist/area-chart/root/area-chart-root.js +21 -9
- package/dist/avatar/group/avatar-group.d.ts +10 -2
- package/dist/avatar/group/avatar-group.js +10 -5
- package/dist/badge/count.d.ts +19 -0
- package/dist/badge/count.js +20 -0
- package/dist/badge/root/badge-root.d.ts +6 -2
- package/dist/badge/root/badge-root.js +8 -22
- package/dist/bar-chart/root/bar-chart-root.d.ts +13 -1
- package/dist/bar-chart/root/bar-chart-root.js +17 -4
- package/dist/blockquote/root/blockquote-root.d.ts +66 -8
- package/dist/blockquote/root/blockquote-root.js +85 -8
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +2 -2
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +8 -1
- package/dist/breadcrumbs/root/breadcrumbs-root.js +5 -2
- package/dist/button/root/button-root.d.ts +10 -1
- package/dist/button/root/button-root.js +3 -2
- package/dist/button-group/arrows.d.ts +14 -0
- package/dist/button-group/arrows.js +10 -0
- package/dist/button-group/root/button-group-root.d.ts +144 -3
- package/dist/button-group/root/button-group-root.js +142 -2
- package/dist/callout/root/callout-root.d.ts +16 -2
- package/dist/callout/root/callout-root.js +16 -4
- package/dist/canvas/describe.d.ts +10 -0
- package/dist/canvas/describe.js +9 -0
- package/dist/canvas/edge-pan.d.ts +61 -0
- package/dist/canvas/edge-pan.js +63 -0
- package/dist/canvas/neighbor.d.ts +17 -0
- package/dist/canvas/neighbor.js +1 -0
- package/dist/canvas/node/canvas-node.d.ts +12 -2
- package/dist/canvas/node/canvas-node.js +8 -3
- package/dist/canvas/root/canvas-document.d.ts +10 -0
- package/dist/canvas/root/canvas-document.js +1 -0
- package/dist/canvas/root/canvas-root.d.ts +168 -9
- package/dist/canvas/root/canvas-root.js +239 -69
- package/dist/canvas/snap.d.ts +42 -0
- package/dist/canvas/snap.js +32 -0
- package/dist/carousel/root/carousel-root.d.ts +9 -3
- package/dist/carousel/root/carousel-root.js +17 -10
- package/dist/chat/composer/chat-composer.d.ts +5 -0
- package/dist/chat/composer/chat-composer.js +4 -1
- package/dist/chat/message/chat-message.d.ts +9 -5
- package/dist/chat/message/chat-message.js +8 -4
- package/dist/chat/naming.js +2 -2
- package/dist/chat/root/chat-root.d.ts +40 -4
- package/dist/chat/root/chat-root.js +38 -14
- package/dist/checkbox/root/checkbox-root.d.ts +11 -0
- package/dist/checkbox/root/checkbox-root.js +8 -2
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +24 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +28 -12
- package/dist/checkbox-group/select-all.d.ts +11 -0
- package/dist/checkbox-group/select-all.js +5 -0
- package/dist/code-block/root/code-block-root.d.ts +20 -8
- package/dist/code-block/root/code-block-root.js +16 -5
- package/dist/color-input/root/color-input-root.d.ts +13 -0
- package/dist/color-input/root/color-input-root.js +18 -5
- package/dist/color-picker/root/color-picker-root.d.ts +19 -3
- package/dist/color-picker/root/color-picker-root.js +52 -24
- package/dist/color-picker/wheel.d.ts +11 -0
- package/dist/color-picker/wheel.js +9 -0
- package/dist/combobox/root/combobox-root.d.ts +106 -18
- package/dist/combobox/root/combobox-root.js +101 -26
- package/dist/command/root/command-root.d.ts +19 -9
- package/dist/command/root/command-root.js +9 -4
- package/dist/copy-button/root/copy-button-root.d.ts +5 -0
- package/dist/copy-button/root/copy-button-root.js +7 -2
- package/dist/data-table/root/data-table-root.d.ts +171 -29
- package/dist/data-table/root/data-table-root.js +284 -161
- package/dist/date-input/root/date-input-root.d.ts +32 -9
- package/dist/date-input/root/date-input-root.js +66 -44
- package/dist/date-picker/root/date-picker-root.d.ts +38 -15
- package/dist/date-picker/root/date-picker-root.js +52 -33
- package/dist/description-list/item/description-list-item.d.ts +4 -0
- package/dist/description-list/item/description-list-item.js +7 -1
- package/dist/dialog/root/dialog-root.d.ts +12 -1
- package/dist/dialog/root/dialog-root.js +11 -4
- package/dist/divider/root/divider-root.d.ts +45 -16
- package/dist/divider/root/divider-root.js +28 -4
- package/dist/donut-chart/root/donut-chart-root.d.ts +5 -0
- package/dist/donut-chart/root/donut-chart-root.js +8 -5
- package/dist/drawer/root/drawer-root.d.ts +12 -1
- package/dist/drawer/root/drawer-root.js +9 -2
- package/dist/drilldown/item/drilldown-item.js +3 -4
- package/dist/drilldown/root/drilldown-root.d.ts +5 -0
- package/dist/drilldown/root/drilldown-root.js +4 -1
- package/dist/element-events.generated.js +26 -3
- package/dist/empty/root/empty-root.d.ts +17 -3
- package/dist/empty/root/empty-root.js +29 -5
- package/dist/file-input/root/file-input-root.d.ts +18 -3
- package/dist/file-input/root/file-input-root.js +34 -18
- package/dist/file-input/status.js +2 -1
- package/dist/filter-input/chip/filter-chip.d.ts +13 -0
- package/dist/filter-input/chip/filter-chip.js +7 -3
- package/dist/filter-input/menu/filter-menu.d.ts +5 -0
- package/dist/filter-input/menu/filter-menu.js +3 -1
- package/dist/filter-input/root/filter-input-root.d.ts +20 -3
- package/dist/filter-input/root/filter-input-root.js +8 -4
- package/dist/format-date/fields.d.ts +20 -0
- package/dist/format-date/fields.js +14 -0
- package/dist/format-date/options.d.ts +2 -1
- package/dist/format-date/options.js +9 -38
- package/dist/format-date/root/format-date-root.d.ts +55 -5
- package/dist/format-date/root/format-date-root.js +29 -34
- package/dist/graph/root/graph-model.d.ts +11 -0
- package/dist/graph/root/graph-model.js +4 -0
- package/dist/graph/root/graph-root.d.ts +101 -14
- package/dist/graph/root/graph-root.js +140 -46
- package/dist/heatmap/root/heatmap-root.d.ts +37 -4
- package/dist/heatmap/root/heatmap-root.js +51 -16
- package/dist/icon-button/root/icon-button-root.d.ts +5 -0
- package/dist/icon-button/root/icon-button-root.js +1 -0
- package/dist/image/root/image-root.d.ts +11 -0
- package/dist/input/root/input-root.d.ts +5 -0
- package/dist/input/root/input-root.js +4 -1
- package/dist/kbd/root/kbd-root.js +1 -2
- package/dist/legend/root/legend-root.js +4 -17
- package/dist/lightbox/root/lightbox-root.d.ts +14 -4
- package/dist/lightbox/root/lightbox-root.js +25 -7
- package/dist/line-chart/root/line-chart-root.d.ts +5 -0
- package/dist/line-chart/root/line-chart-root.js +4 -2
- package/dist/list/item/list-item.d.ts +32 -0
- package/dist/list/item/list-item.js +34 -7
- package/dist/list/root/list-root.d.ts +87 -0
- package/dist/list/root/list-root.js +119 -23
- package/dist/listbox/reorder/index.d.ts +1 -0
- package/dist/listbox/reorder/index.js +4 -0
- package/dist/listbox/reorder/listbox-reorder.d.ts +83 -0
- package/dist/listbox/reorder/listbox-reorder.js +151 -0
- package/dist/listbox/root/listbox-root.d.ts +185 -33
- package/dist/listbox/root/listbox-root.js +166 -136
- package/dist/loader/root/loader-root.d.ts +5 -0
- package/dist/loader/root/loader-root.js +3 -1
- package/dist/map/area/map-area.d.ts +5 -0
- package/dist/map/area/map-area.js +3 -1
- package/dist/map/buildings/map-buildings.d.ts +5 -0
- package/dist/map/buildings/map-buildings.js +3 -1
- package/dist/map/contours/map-contours.d.ts +5 -0
- package/dist/map/contours/map-contours.js +3 -1
- package/dist/map/landcover/map-landcover.d.ts +5 -0
- package/dist/map/landcover/map-landcover.js +3 -1
- package/dist/map/marker/map-marker.d.ts +18 -2
- package/dist/map/marker/map-marker.js +13 -5
- package/dist/map/points/map-points.d.ts +5 -0
- package/dist/map/points/map-points.js +6 -4
- package/dist/map/position/map-position.d.ts +5 -0
- package/dist/map/position/map-position.js +3 -1
- package/dist/map/raster/map-raster.d.ts +5 -0
- package/dist/map/raster/map-raster.js +3 -1
- package/dist/map/root/map-root.d.ts +73 -16
- package/dist/map/root/map-root.js +122 -44
- package/dist/map/route/map-route.d.ts +5 -0
- package/dist/map/route/map-route.js +3 -1
- package/dist/map/terrain/map-terrain.d.ts +5 -0
- package/dist/map/terrain/map-terrain.js +3 -1
- package/dist/megamenu/root/megamenu-root.js +4 -11
- package/dist/menu/root/menu-root.d.ts +7 -2
- package/dist/menu/root/menu-root.js +3 -1
- package/dist/meter/root/meter-root.d.ts +16 -3
- package/dist/meter/root/meter-root.js +12 -5
- package/dist/navigation/root/navigation-root.d.ts +5 -0
- package/dist/navigation/root/navigation-root.js +7 -8
- package/dist/notifications/group/notification-group.d.ts +8 -1
- package/dist/notifications/group/notification-group.js +12 -6
- package/dist/notifications/notification/notification.d.ts +17 -1
- package/dist/notifications/notification/notification.js +6 -2
- package/dist/notifications/root/notifications-root.d.ts +49 -5
- package/dist/notifications/root/notifications-root.js +36 -8
- package/dist/number-input/root/number-input-root.d.ts +21 -8
- package/dist/number-input/root/number-input-root.js +26 -11
- package/dist/object-inspector/root/object-inspector-root.d.ts +56 -13
- package/dist/object-inspector/root/object-inspector-root.js +41 -30
- package/dist/outline/root/outline-root.d.ts +5 -0
- package/dist/outline/root/outline-root.js +3 -1
- package/dist/pagination/root/pagination-root.d.ts +7 -1
- package/dist/pagination/root/pagination-root.js +16 -7
- package/dist/pagination/size/pagination-size.d.ts +8 -3
- package/dist/pagination/size/pagination-size.js +5 -3
- package/dist/pagination/summary/pagination-summary.d.ts +8 -6
- package/dist/pagination/summary/pagination-summary.js +4 -9
- package/dist/pin-input/code.d.ts +23 -0
- package/dist/pin-input/code.js +21 -0
- package/dist/pin-input/root/pin-input-root.d.ts +9 -3
- package/dist/pin-input/root/pin-input-root.js +13 -23
- package/dist/popover/root/popover-root.d.ts +12 -2
- package/dist/popover/root/popover-root.js +10 -4
- package/dist/progress/root/progress-root.d.ts +7 -2
- package/dist/progress/root/progress-root.js +5 -2
- package/dist/qr-code/name.d.ts +3 -2
- package/dist/qr-code/name.js +2 -2
- package/dist/qr-code/root/qr-code-root.d.ts +26 -5
- package/dist/qr-code/root/qr-code-root.js +27 -6
- package/dist/radio/group/radio-group.d.ts +11 -0
- package/dist/radio/group/radio-group.js +8 -2
- package/dist/rating/root/rating-root.d.ts +12 -1
- package/dist/rating/root/rating-root.js +10 -3
- package/dist/scatter-chart/measures.d.ts +22 -0
- package/dist/scatter-chart/measures.js +11 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +22 -8
- package/dist/scatter-chart/root/scatter-chart-root.js +25 -23
- package/dist/select/root/select-root.d.ts +67 -8
- package/dist/select/root/select-root.js +45 -11
- package/dist/skip-link/root/skip-link-root.d.ts +5 -0
- package/dist/skip-link/root/skip-link-root.js +3 -1
- package/dist/slider/root/slider-root.d.ts +7 -2
- package/dist/slider/root/slider-root.js +11 -5
- package/dist/sparkline/readings.d.ts +15 -5
- package/dist/sparkline/readings.js +3 -3
- package/dist/sparkline/root/sparkline-root.d.ts +9 -4
- package/dist/sparkline/root/sparkline-root.js +9 -3
- package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
- package/dist/speed-dial/group/speed-dial-group.js +43 -0
- package/dist/speed-dial/index.d.ts +1 -0
- package/dist/speed-dial/index.js +1 -0
- package/dist/speed-dial/item/speed-dial-item.d.ts +26 -1
- package/dist/speed-dial/item/speed-dial-item.js +41 -3
- package/dist/speed-dial/long-press.d.ts +50 -0
- package/dist/speed-dial/long-press.js +48 -0
- package/dist/speed-dial/root/speed-dial-root.d.ts +85 -1
- package/dist/speed-dial/root/speed-dial-root.js +117 -5
- package/dist/splitter/root/splitter-root.d.ts +12 -3
- package/dist/splitter/root/splitter-root.js +22 -4
- package/dist/steps/root/steps-root.d.ts +9 -2
- package/dist/steps/root/steps-root.js +6 -3
- package/dist/steps/step/step.d.ts +12 -0
- package/dist/steps/step/step.js +11 -2
- package/dist/switch/root/switch-root.d.ts +11 -0
- package/dist/switch/root/switch-root.js +8 -2
- package/dist/table/cell/table-cell.d.ts +8 -1
- package/dist/table/cell/table-cell.js +6 -2
- package/dist/table/column/table-column.d.ts +11 -4
- package/dist/table/column/table-column.js +15 -10
- package/dist/table/grid-controller.d.ts +122 -0
- package/dist/table/grid-controller.js +299 -0
- package/dist/table/root/table-root.d.ts +154 -8
- package/dist/table/root/table-root.js +197 -38
- package/dist/table/row/table-row.d.ts +55 -1
- package/dist/table/row/table-row.js +60 -7
- package/dist/tabs/root/tabs-root.d.ts +5 -0
- package/dist/tabs/root/tabs-root.js +3 -1
- package/dist/tag/group/tag-group.d.ts +5 -0
- package/dist/tag/group/tag-group.js +8 -15
- package/dist/tag/root/tag-root.d.ts +14 -1
- package/dist/tag/root/tag-root.js +11 -8
- package/dist/textarea/root/textarea-root.d.ts +5 -0
- package/dist/textarea/root/textarea-root.js +3 -1
- package/dist/time-input/root/time-input-root.d.ts +14 -7
- package/dist/time-input/root/time-input-root.js +43 -32
- package/dist/time-picker/root/time-picker-root.d.ts +16 -7
- package/dist/time-picker/root/time-picker-root.js +28 -12
- package/dist/toast/item/toast-item.d.ts +13 -3
- package/dist/toast/item/toast-item.js +2 -0
- package/dist/toast/root/toast-root.d.ts +22 -2
- package/dist/toast/root/toast-root.js +24 -17
- package/dist/toggle/group/toggle-group.js +3 -5
- package/dist/toolbar/root/toolbar-root.d.ts +36 -0
- package/dist/toolbar/root/toolbar-root.js +43 -9
- package/dist/tooltip/root/tooltip-root.d.ts +27 -17
- package/dist/tooltip/root/tooltip-root.js +1 -2
- package/dist/tour/root/tour-root.d.ts +8 -2
- package/dist/tour/root/tour-root.js +4 -2
- package/dist/tour/stop/tour-stop.d.ts +5 -0
- package/dist/tour/stop/tour-stop.js +6 -1
- package/dist/tree/grip.d.ts +5 -0
- package/dist/tree/grip.js +1 -0
- package/dist/tree/item/tree-item.d.ts +24 -0
- package/dist/tree/item/tree-item.js +27 -5
- package/dist/tree/root/tree-root.d.ts +66 -1
- package/dist/tree/root/tree-root.js +77 -5
- package/dist/trend/root/trend-root.d.ts +20 -4
- package/dist/trend/root/trend-root.js +20 -5
- package/dist/video/root/video-root.d.ts +23 -3
- package/dist/video/root/video-root.js +56 -15
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +5 -0
- package/dist/video-playlist/root/video-playlist-root.js +3 -1
- package/dist/virtual-list/root/virtual-list-root.d.ts +19 -3
- package/dist/virtual-list/root/virtual-list-root.js +10 -19
- package/lint.json +1 -1
- package/package.json +7 -6
- package/types/jsx.d.ts +6005 -2114
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +1594 -676
- package/types/words.d.ts +3280 -0
- package/dist/kbd/keys.d.ts +0 -29
- package/dist/kbd/keys.js +0 -52
- package/dist/toast/hotkey.d.ts +0 -22
- package/dist/toast/hotkey.js +0 -23
- package/dist/tooltip/focus-target.d.ts +0 -6
- package/dist/tooltip/focus-target.js +0 -9
|
@@ -9,19 +9,62 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
9
9
|
* controls, and a development build warns once with the kind `missing-name`.
|
|
10
10
|
*
|
|
11
11
|
* The group does not manage focus, so each button keeps its own tab stop. For
|
|
12
|
-
* one tab stop with arrow keys between
|
|
13
|
-
* use Toolbar.
|
|
12
|
+
* one tab stop with arrow keys between a mix of controls, the APG toolbar
|
|
13
|
+
* pattern, use Toolbar.
|
|
14
14
|
*
|
|
15
15
|
* Buttons are slotted, so they stay your own elements and keep their own
|
|
16
16
|
* appearance and size.
|
|
17
17
|
*
|
|
18
|
+
* **Buttons that stay pressed.** With `selection-mode`, each button with a
|
|
19
|
+
* `value` is a toggle button: a press presses or releases it, and it says so
|
|
20
|
+
* with `aria-pressed`. `single` keeps one pressed at a time, and a press on the
|
|
21
|
+
* pressed one releases it. `multiple` lets any number be pressed. `value` is
|
|
22
|
+
* the pressed values, comma separated. A press sends a cancelable
|
|
23
|
+
* `helix-before-change` with the value it would leave, then `change`.
|
|
24
|
+
*
|
|
25
|
+
* The pressed state is written on the control inside each button's shadow
|
|
26
|
+
* root, so the markup you rendered is never changed and a framework hydrating
|
|
27
|
+
* it sees what its server sent. That is also why only Helix buttons are
|
|
28
|
+
* toggles: a native `<button>` or a button without a `value` stays a plain
|
|
29
|
+
* action button in the group, and a native one without its own
|
|
30
|
+
* `aria-pressed` warns once, with the runtime kind `untold-toggle`. The inner
|
|
31
|
+
* control also carries
|
|
32
|
+
* `--button-group-pressed`, `1` or `0`, for a `::part(button)` rule of yours.
|
|
33
|
+
*
|
|
34
|
+
* Use Toggle Group instead for a choice that belongs in a form, or one where
|
|
35
|
+
* the arrow keys choose as they move: it is a `radiogroup` of options with a
|
|
36
|
+
* form value, `required` and validation. A Button Group in a selection mode is
|
|
37
|
+
* a set of actions that stay on, such as bold and italic, or a view that a
|
|
38
|
+
* press switches, and it submits nothing.
|
|
39
|
+
*
|
|
40
|
+
* **Keyboard.** In a selection mode the group is one tab stop: the button
|
|
41
|
+
* focus was last on, then the first pressed one, then the first one.
|
|
42
|
+
*
|
|
43
|
+
* | Key | What it does |
|
|
44
|
+
* |---|---|
|
|
45
|
+
* | Right, Down | Moves to the next button, from the last back to the first. |
|
|
46
|
+
* | Left, Up | Moves to the button before, from the first round to the last. |
|
|
47
|
+
* | Home, End | Moves to the first or the last button. |
|
|
48
|
+
* | Space, Enter | Presses or releases the focused button. |
|
|
49
|
+
*
|
|
50
|
+
* Left and Right swap on a right-to-left page, and a disabled button is
|
|
51
|
+
* passed over. In a selection mode the group is a `toolbar`, with
|
|
52
|
+
* `aria-orientation` under `orientation="vertical"`. Inside a toolbar it stays
|
|
53
|
+
* a named `group`, and the toolbar's own arrow keys walk its buttons, so a
|
|
54
|
+
* reader meets one toolbar.
|
|
55
|
+
*
|
|
18
56
|
* @since 0.1.0
|
|
19
57
|
* @status stable
|
|
20
58
|
* @category actions
|
|
21
|
-
* @aliases Segmented buttons, Split button
|
|
59
|
+
* @aliases Segmented buttons, Split button, Toggle buttons
|
|
22
60
|
* @documentation https://fusion.dev/helix/components/button-group
|
|
23
61
|
*
|
|
24
62
|
* @slot - The buttons in the group.
|
|
63
|
+
*
|
|
64
|
+
* @event {Event} change - Fired after a press changes `value`, in a selection mode.
|
|
65
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before a press changes `value`, with the value it would leave in `detail.value`. Cancelable: call `preventDefault()` to keep the buttons as they are.
|
|
66
|
+
*
|
|
67
|
+
* @cssproperty --button-group-pressed - Written on the control inside each toggle button of a group with `selection-mode`: `1` while it is pressed and `0` while it is not. Read it in a `::part(button)` rule to draw the pressed look.
|
|
25
68
|
*/
|
|
26
69
|
export declare class HelixHeadlessButtonGroup extends HelixElement {
|
|
27
70
|
/**
|
|
@@ -51,8 +94,106 @@ export declare class HelixHeadlessButtonGroup extends HelixElement {
|
|
|
51
94
|
* column.
|
|
52
95
|
*/
|
|
53
96
|
orientation?: 'horizontal' | 'vertical';
|
|
97
|
+
/**
|
|
98
|
+
* Whether the buttons stay pressed: `single` keeps one pressed at a time and
|
|
99
|
+
* `multiple` any number. Unset, they are action buttons, each its own tab
|
|
100
|
+
* stop, as before.
|
|
101
|
+
*
|
|
102
|
+
* Optional, so the attribute is absent until a consumer writes it.
|
|
103
|
+
*/
|
|
104
|
+
selectionMode?: 'multiple' | 'single';
|
|
105
|
+
/**
|
|
106
|
+
* The values of the pressed buttons, comma separated, in a selection mode.
|
|
107
|
+
* A button's own `value` names it, so a value holds no comma.
|
|
108
|
+
*
|
|
109
|
+
* The attribute is the seed, and a press changes the property, which does
|
|
110
|
+
* not reflect, as a native control's `value` does not.
|
|
111
|
+
*/
|
|
112
|
+
value: string;
|
|
113
|
+
/**
|
|
114
|
+
* The Helix buttons of a group in a selection mode, in the order they are
|
|
115
|
+
* written, and none otherwise. Empty on a server, which has no tree.
|
|
116
|
+
*/
|
|
117
|
+
private get buttons();
|
|
118
|
+
/**
|
|
119
|
+
* Whether the group holds the tab stop and the arrow keys: in a selection
|
|
120
|
+
* mode, and not inside a toolbar, whose own keys walk the buttons.
|
|
121
|
+
*
|
|
122
|
+
* Truthiness, as `buttons` reads it: a removed attribute leaves the property
|
|
123
|
+
* null, which is no selection mode.
|
|
124
|
+
*/
|
|
125
|
+
private get roving();
|
|
126
|
+
/** Whether a button is pressed: its value is among the group's. */
|
|
127
|
+
private pressed;
|
|
128
|
+
/** The button focus was last on, which holds the tab stop. */
|
|
129
|
+
private lastFocused;
|
|
130
|
+
/**
|
|
131
|
+
* The buttons this group has told something, each with whether it moved
|
|
132
|
+
* their tab stop, so a button that leaves the group, or a group that leaves
|
|
133
|
+
* its selection mode, is put back as it was.
|
|
134
|
+
*/
|
|
135
|
+
private readonly told;
|
|
136
|
+
private watcher;
|
|
137
|
+
/**
|
|
138
|
+
* Tells every button whether it is pressed and whether it holds the stop,
|
|
139
|
+
* and puts back the ones that left.
|
|
140
|
+
*/
|
|
141
|
+
private sync;
|
|
142
|
+
/** Whether this group has said a native button in it cannot be a toggle, so it says so once. */
|
|
143
|
+
private warned;
|
|
144
|
+
/**
|
|
145
|
+
* Says once that a native `<button>` in a selection mode stays an action
|
|
146
|
+
* button, since its pressed state would be an attribute on the page's markup.
|
|
147
|
+
* One with its own `aria-pressed` is the page's to say, and is not reported.
|
|
148
|
+
*/
|
|
149
|
+
private warn;
|
|
150
|
+
/**
|
|
151
|
+
* Writes a button's pressed state onto its control, once the button has
|
|
152
|
+
* rendered it, and takes it off a button the group no longer holds.
|
|
153
|
+
*
|
|
154
|
+
* **On the control inside the button's shadow root, never on the button.**
|
|
155
|
+
* An attribute written on the consumer's element is a hydration mismatch a
|
|
156
|
+
* React consumer's hydration reports and does not patch up, which is why
|
|
157
|
+
* `tellDisclosure` hands a trigger `expanded` as a property. Inside the
|
|
158
|
+
* button's own shadow root no framework compares the attribute, and the
|
|
159
|
+
* reader is on that control. Read at the moment of the write, so the last
|
|
160
|
+
* press wins whatever order renders finish in.
|
|
161
|
+
*
|
|
162
|
+
* The control is the `<button>` a Helix button renders, which is where its
|
|
163
|
+
* `delegatesFocus` sends focus and what a reader is on.
|
|
164
|
+
*
|
|
165
|
+
* A button that carries `aria-pressed` itself is the consumer's to say, and
|
|
166
|
+
* its own forwarding carries that down instead.
|
|
167
|
+
*/
|
|
168
|
+
private mark;
|
|
169
|
+
/**
|
|
170
|
+
* Says on a button's control whether it is pressed, or that it is no toggle
|
|
171
|
+
* at all where `pressed` is undefined. A styled tier draws the look here.
|
|
172
|
+
*
|
|
173
|
+
* @param control The focusable control inside the button's shadow root.
|
|
174
|
+
* @param pressed Whether the button is pressed, or undefined where it is not a toggle.
|
|
175
|
+
*/
|
|
176
|
+
protected markPressed(control: HTMLElement, pressed: boolean | undefined): void;
|
|
177
|
+
/**
|
|
178
|
+
* Presses or releases the button a press acted on. `helix-press` rather than
|
|
179
|
+
* `click`, since a button sends it only for a press that acted: never while
|
|
180
|
+
* it is disabled or pending.
|
|
181
|
+
*/
|
|
182
|
+
private readonly handlePress;
|
|
183
|
+
/**
|
|
184
|
+
* Moves focus between the buttons without pressing them, a toolbar's
|
|
185
|
+
* reading: a press is its own act, on Space or Enter, which the button
|
|
186
|
+
* answers natively. Both axes, as every set here answers both, and the
|
|
187
|
+
* horizontal pair turns on a right-to-left page.
|
|
188
|
+
*/
|
|
189
|
+
private readonly handleKeydown;
|
|
190
|
+
/** Moves the tab stop to the button focus arrived on. */
|
|
191
|
+
private readonly noteFocus;
|
|
192
|
+
connectedCallback(): void;
|
|
193
|
+
disconnectedCallback(): void;
|
|
54
194
|
protected willUpdate(changed: PropertyValues): void;
|
|
55
195
|
protected firstUpdated(changed: PropertyValues): void;
|
|
196
|
+
protected updated(changed: PropertyValues): void;
|
|
56
197
|
protected render(): TemplateResult;
|
|
57
198
|
}
|
|
58
199
|
declare global {
|
|
@@ -4,22 +4,156 @@ 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 { auditName, customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
7
|
+
import { auditName, commaList, customElement, HelixElement, hostAria, inlineStep, pressedValue, reportRuntime, requestValue, rovingStop, toolbarAround, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { arrowTarget } from '../arrows.js';
|
|
11
|
+
const isGroupButton = (child) => child instanceof HTMLElement && 'focusable' in child && 'value' in child;
|
|
10
12
|
let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixElement {
|
|
11
13
|
constructor() {
|
|
12
14
|
super(...arguments);
|
|
13
15
|
this.label = '';
|
|
16
|
+
this.value = '';
|
|
17
|
+
this.lastFocused = undefined;
|
|
18
|
+
this.told = new Map();
|
|
19
|
+
this.warned = false;
|
|
20
|
+
this.handlePress = (event) => {
|
|
21
|
+
const mode = this.selectionMode;
|
|
22
|
+
const button = this.buttons.find((one) => event.composedPath().includes(one));
|
|
23
|
+
if (mode && button && button.value !== '') {
|
|
24
|
+
requestValue(this, pressedValue(mode, this.value, button.value), (next) => {
|
|
25
|
+
this.value = next;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
this.handleKeydown = (event) => {
|
|
30
|
+
const buttons = this.roving ? this.buttons.filter((one) => one.disabled !== true) : [];
|
|
31
|
+
const from = buttons.findIndex((one) => event.composedPath().includes(one));
|
|
32
|
+
const to = arrowTarget(event.key, inlineStep(this, event.key), from, buttons.length);
|
|
33
|
+
if (to >= 0 && !event.defaultPrevented) {
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
buttons[to]?.focus();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
this.noteFocus = (event) => {
|
|
39
|
+
const button = this.buttons.find((one) => event.composedPath().includes(one));
|
|
40
|
+
if (button && button !== this.lastFocused) {
|
|
41
|
+
this.lastFocused = button;
|
|
42
|
+
this.sync();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
get buttons() {
|
|
47
|
+
return this.selectionMode && this.children ? [...this.children].filter(isGroupButton) : [];
|
|
48
|
+
}
|
|
49
|
+
get roving() {
|
|
50
|
+
return Boolean(this.selectionMode) && toolbarAround(this) === null;
|
|
51
|
+
}
|
|
52
|
+
pressed(button) {
|
|
53
|
+
return button.value !== '' && commaList(this.value).includes(button.value);
|
|
54
|
+
}
|
|
55
|
+
sync() {
|
|
56
|
+
const buttons = this.buttons;
|
|
57
|
+
const roving = this.roving;
|
|
58
|
+
const stop = roving
|
|
59
|
+
? rovingStop(buttons, this.lastFocused, {
|
|
60
|
+
disabled: (button) => button.disabled === true,
|
|
61
|
+
selected: (button) => this.pressed(button),
|
|
62
|
+
})
|
|
63
|
+
: undefined;
|
|
64
|
+
for (const [button, roved] of this.told) {
|
|
65
|
+
if (!buttons.includes(button)) {
|
|
66
|
+
this.told.delete(button);
|
|
67
|
+
this.mark(button);
|
|
68
|
+
if (roved) {
|
|
69
|
+
whenHydrated(button, () => {
|
|
70
|
+
button.focusable = true;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const button of buttons) {
|
|
76
|
+
this.told.set(button, roving);
|
|
77
|
+
this.mark(button);
|
|
78
|
+
if (roving) {
|
|
79
|
+
whenHydrated(button, () => {
|
|
80
|
+
button.focusable = button === stop;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
for (const child of this.selectionMode && this.children ? this.children : []) {
|
|
85
|
+
if (child.localName.includes('-') && !isGroupButton(child)) {
|
|
86
|
+
void customElements.whenDefined(child.localName).then(() => this.sync());
|
|
87
|
+
}
|
|
88
|
+
else if (child.localName === 'button' && !child.hasAttribute('aria-pressed')) {
|
|
89
|
+
this.warn(child);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
warn(button) {
|
|
94
|
+
if (this.warned) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.warned = true;
|
|
98
|
+
reportRuntime({
|
|
99
|
+
kind: 'untold-toggle',
|
|
100
|
+
message: `<${this.localName}> cannot press a native <button>: its state would be written onto your ` +
|
|
101
|
+
'markup. Slot a Helix button with a `value`, or set `aria-pressed` on the button yourself.',
|
|
102
|
+
tag: button.localName,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
mark(button) {
|
|
106
|
+
void button.updateComplete.then(() => {
|
|
107
|
+
const control = button.shadowRoot?.querySelector('button');
|
|
108
|
+
if (control && !button.hasAttribute('aria-pressed')) {
|
|
109
|
+
const toggle = this.told.has(button) && button.value !== '';
|
|
110
|
+
this.markPressed(control, toggle ? this.pressed(button) : undefined);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
markPressed(control, pressed) {
|
|
115
|
+
if (pressed === undefined) {
|
|
116
|
+
control.removeAttribute('aria-pressed');
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
control.setAttribute('aria-pressed', String(pressed));
|
|
120
|
+
}
|
|
121
|
+
control.style.setProperty('--button-group-pressed', pressed === undefined ? '' : pressed ? '1' : '0');
|
|
122
|
+
}
|
|
123
|
+
connectedCallback() {
|
|
124
|
+
super.connectedCallback();
|
|
125
|
+
this.addEventListener('focusin', this.noteFocus);
|
|
126
|
+
this.addEventListener('helix-press', this.handlePress);
|
|
127
|
+
this.addEventListener('keydown', this.handleKeydown);
|
|
128
|
+
this.watcher = new MutationObserver(() => this.sync());
|
|
129
|
+
this.watcher.observe(this, {
|
|
130
|
+
attributeFilter: ['disabled', 'value'],
|
|
131
|
+
childList: true,
|
|
132
|
+
subtree: true,
|
|
133
|
+
});
|
|
134
|
+
this.requestUpdate();
|
|
135
|
+
}
|
|
136
|
+
disconnectedCallback() {
|
|
137
|
+
super.disconnectedCallback();
|
|
138
|
+
this.removeEventListener('focusin', this.noteFocus);
|
|
139
|
+
this.removeEventListener('helix-press', this.handlePress);
|
|
140
|
+
this.removeEventListener('keydown', this.handleKeydown);
|
|
141
|
+
this.watcher?.disconnect();
|
|
14
142
|
}
|
|
15
143
|
willUpdate(changed) {
|
|
16
144
|
super.willUpdate(changed);
|
|
17
|
-
|
|
145
|
+
const toolbar = this.roving;
|
|
146
|
+
hostAria(this.internals, { label: this.label, role: toolbar ? 'toolbar' : 'group' });
|
|
147
|
+
this.internals.ariaOrientation = toolbar ? (this.orientation ?? null) : null;
|
|
18
148
|
}
|
|
19
149
|
firstUpdated(changed) {
|
|
20
150
|
super.firstUpdated(changed);
|
|
21
151
|
auditName(this, () => null, 'Give it a `label`, or an `aria-label` that says what the buttons are for.', () => this.label !== '');
|
|
22
152
|
}
|
|
153
|
+
updated(changed) {
|
|
154
|
+
super.updated(changed);
|
|
155
|
+
this.sync();
|
|
156
|
+
}
|
|
23
157
|
render() {
|
|
24
158
|
return html `<slot></slot>`;
|
|
25
159
|
}
|
|
@@ -30,6 +164,12 @@ __decorate([
|
|
|
30
164
|
__decorate([
|
|
31
165
|
property({ reflect: true })
|
|
32
166
|
], HelixHeadlessButtonGroup.prototype, "orientation", void 0);
|
|
167
|
+
__decorate([
|
|
168
|
+
property({ attribute: 'selection-mode', reflect: true })
|
|
169
|
+
], HelixHeadlessButtonGroup.prototype, "selectionMode", void 0);
|
|
170
|
+
__decorate([
|
|
171
|
+
property()
|
|
172
|
+
], HelixHeadlessButtonGroup.prototype, "value", void 0);
|
|
33
173
|
HelixHeadlessButtonGroup = __decorate([
|
|
34
174
|
customElement('helix-headless-button-group')
|
|
35
175
|
], HelixHeadlessButtonGroup);
|
|
@@ -42,6 +42,11 @@ declare const HelixHeadlessCallout_base: (new (...args: any[]) => import("@fusio
|
|
|
42
42
|
* @csspart icon-mark - The icon for the tone, shown when no icon is slotted.
|
|
43
43
|
*/
|
|
44
44
|
export declare class HelixHeadlessCallout extends HelixHeadlessCallout_base {
|
|
45
|
+
/**
|
|
46
|
+
* The key this family's words are registered under, its styled tag:
|
|
47
|
+
* `registerWords('de', { 'helix-callout': { toneLabels: { danger: 'Fehler' } } })`.
|
|
48
|
+
*/
|
|
49
|
+
static words: string;
|
|
45
50
|
protected willUpdate(changed: PropertyValues): void;
|
|
46
51
|
/**
|
|
47
52
|
* What kind of attention the passage needs.
|
|
@@ -55,10 +60,19 @@ export declare class HelixHeadlessCallout extends HelixHeadlessCallout_base {
|
|
|
55
60
|
/**
|
|
56
61
|
* What a screen reader is told the tone is, such as "Fehler".
|
|
57
62
|
*
|
|
58
|
-
* Absent is the
|
|
59
|
-
* "Success" or "Warning".
|
|
63
|
+
* Absent is the tone's words in `tone-labels`, "Error", "Information",
|
|
64
|
+
* "Note", "Success" or "Warning" in English.
|
|
60
65
|
*/
|
|
61
66
|
toneLabel: string;
|
|
67
|
+
/**
|
|
68
|
+
* What a screen reader is told each tone is, by the tone's name, written as
|
|
69
|
+
* JSON in the attribute: `tone-labels='{"danger":"Fehler"}'`. A tone left
|
|
70
|
+
* out keeps its English, and `tone-label` wins over both.
|
|
71
|
+
*
|
|
72
|
+
* `danger` is said as "Error", the word a reader understands, and
|
|
73
|
+
* `neutral` as "Note", for what the passage is.
|
|
74
|
+
*/
|
|
75
|
+
toneLabels: Partial<Record<'danger' | 'info' | 'neutral' | 'success' | 'warning', string>>;
|
|
62
76
|
/**
|
|
63
77
|
* The mark for the callout's tone, behind a seam.
|
|
64
78
|
*
|
|
@@ -4,16 +4,23 @@ 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, drawDismiss, drawDismissGlyph, HelixElement, hostAria, MixinDismissible, TONE_MARKS, toneMark, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, MixinDismissible, TONE_MARKS, toneMark, words, wordsConverter, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
11
|
-
const NOTE = { icon: TONE_MARKS.info.icon, label: 'Note' };
|
|
12
11
|
let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(HelixElement) {
|
|
13
12
|
constructor() {
|
|
14
13
|
super(...arguments);
|
|
15
14
|
this.toneLabel = '';
|
|
15
|
+
this.toneLabels = {
|
|
16
|
+
danger: 'Error',
|
|
17
|
+
info: 'Information',
|
|
18
|
+
neutral: 'Note',
|
|
19
|
+
success: 'Success',
|
|
20
|
+
warning: 'Warning',
|
|
21
|
+
};
|
|
16
22
|
}
|
|
23
|
+
static { this.words = 'helix-callout'; }
|
|
17
24
|
willUpdate(changed) {
|
|
18
25
|
super.willUpdate(changed);
|
|
19
26
|
hostAria(this.internals, { role: 'note' });
|
|
@@ -31,8 +38,9 @@ let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(H
|
|
|
31
38
|
</slot>`;
|
|
32
39
|
}
|
|
33
40
|
render() {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
41
|
+
const tone = this.tone === 'neutral' ? 'neutral' : toneMark(this.tone) ? (this.tone ?? 'info') : 'info';
|
|
42
|
+
const { icon } = toneMark(tone) ?? TONE_MARKS.info;
|
|
43
|
+
const named = this.toneLabel || (this.toneLabels[tone] ?? '');
|
|
36
44
|
return html `<span part="icon" role="img" aria-label=${named}>${this.renderIcon(icon, named)}</span>
|
|
37
45
|
<div part="content">
|
|
38
46
|
<slot name="heading"></slot>
|
|
@@ -52,6 +60,10 @@ __decorate([
|
|
|
52
60
|
__decorate([
|
|
53
61
|
property({ attribute: 'tone-label' })
|
|
54
62
|
], HelixHeadlessCallout.prototype, "toneLabel", void 0);
|
|
63
|
+
__decorate([
|
|
64
|
+
words,
|
|
65
|
+
property({ attribute: 'tone-labels', converter: wordsConverter })
|
|
66
|
+
], HelixHeadlessCallout.prototype, "toneLabels", void 0);
|
|
55
67
|
HelixHeadlessCallout = __decorate([
|
|
56
68
|
customElement('helix-headless-callout')
|
|
57
69
|
], HelixHeadlessCallout);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words that describe a card or a connection, such as whether it is
|
|
3
|
+
* selected, what its tone means and where its connections go, as one list in
|
|
4
|
+
* the way `locale` writes one: "selected, Blocked" in English, "selected und
|
|
5
|
+
* Blocked" in German. An empty word is left out, and nothing at all is empty.
|
|
6
|
+
*
|
|
7
|
+
* **A narrow conjunction**, which English writes with commas alone, so the
|
|
8
|
+
* English reads as it did when the words were joined with a comma.
|
|
9
|
+
*/
|
|
10
|
+
export declare const descriptionOf: (locale: string, words: readonly (string | undefined)[]) => string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const formatters = new Map();
|
|
2
|
+
export const descriptionOf = (locale, words) => {
|
|
3
|
+
let found = formatters.get(locale);
|
|
4
|
+
if (!found) {
|
|
5
|
+
found = new Intl.ListFormat(locale || undefined, { style: 'narrow', type: 'conjunction' });
|
|
6
|
+
formatters.set(locale, found);
|
|
7
|
+
}
|
|
8
|
+
return found.format(words.filter((one) => Boolean(one)));
|
|
9
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Moving the view while something is carried to its edge: a card, a corner, a
|
|
3
|
+
* connection being drawn, or the box that selects.
|
|
4
|
+
*
|
|
5
|
+
* **A board is larger than its box, and a hand stops at the edge of the box.**
|
|
6
|
+
* Without this, carrying a card to a place off screen took a drop at the edge,
|
|
7
|
+
* a pan, and a second pick-up, and a connection to a card off screen could not
|
|
8
|
+
* be drawn by pointer at all.
|
|
9
|
+
*/
|
|
10
|
+
/** A point on screen, in pixels. */
|
|
11
|
+
export interface EdgePoint {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
}
|
|
15
|
+
/** The box the view is drawn in, on screen. */
|
|
16
|
+
export interface EdgeRect {
|
|
17
|
+
bottom: number;
|
|
18
|
+
left: number;
|
|
19
|
+
right: number;
|
|
20
|
+
top: number;
|
|
21
|
+
}
|
|
22
|
+
/** How near an edge, in pixels, the view starts to move. */
|
|
23
|
+
export declare const EDGE_ZONE = 32;
|
|
24
|
+
/** The most the view moves in one frame, in pixels: at the edge and past it. */
|
|
25
|
+
export declare const EDGE_MOST = 12;
|
|
26
|
+
/**
|
|
27
|
+
* How far the view should move toward each side in one frame, in pixels, for
|
|
28
|
+
* a pointer at `point`: positive toward the right and the bottom, nothing
|
|
29
|
+
* outside the zone, and faster the nearer the edge, up to `most` at it and
|
|
30
|
+
* past it.
|
|
31
|
+
*
|
|
32
|
+
* A box narrower than two zones moves only once the pointer is past its edge,
|
|
33
|
+
* so a small board is not always moving.
|
|
34
|
+
*/
|
|
35
|
+
export declare const edgeSpeed: (point: EdgePoint, rect: EdgeRect, zone?: number, most?: number) => EdgePoint;
|
|
36
|
+
/**
|
|
37
|
+
* The frames that move the view while a pointer holds something near an edge.
|
|
38
|
+
*
|
|
39
|
+
* `follow` with every pointer move keeps it going while the pointer is in the
|
|
40
|
+
* zone, and `stop` ends it, which the board calls when the gesture ends and
|
|
41
|
+
* when it leaves the page. Each frame hands `step` how far to move, and the
|
|
42
|
+
* board moves the view and carries what is in hand with it.
|
|
43
|
+
*/
|
|
44
|
+
export declare class EdgePan {
|
|
45
|
+
private readonly rect;
|
|
46
|
+
private readonly step;
|
|
47
|
+
private readonly ended;
|
|
48
|
+
/** The frame asked for, while the view is moving. */
|
|
49
|
+
private frame;
|
|
50
|
+
/** Where the pointer last was. */
|
|
51
|
+
private point;
|
|
52
|
+
constructor(rect: () => EdgeRect | undefined, step: (by: EdgePoint) => void, ended?: () => void);
|
|
53
|
+
/** Whether the view is moving. */
|
|
54
|
+
get moving(): boolean;
|
|
55
|
+
/** Where the pointer is now, which starts the frames where it is in the zone. */
|
|
56
|
+
follow(point: EdgePoint): void;
|
|
57
|
+
/** Ends the frames. */
|
|
58
|
+
stop(): void;
|
|
59
|
+
private speed;
|
|
60
|
+
private readonly tick;
|
|
61
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const EDGE_ZONE = 32;
|
|
2
|
+
export const EDGE_MOST = 12;
|
|
3
|
+
export const edgeSpeed = (point, rect, zone = EDGE_ZONE, most = EDGE_MOST) => {
|
|
4
|
+
const along = (at, start, end) => {
|
|
5
|
+
if (at >= end) {
|
|
6
|
+
return 1;
|
|
7
|
+
}
|
|
8
|
+
if (at <= start) {
|
|
9
|
+
return -1;
|
|
10
|
+
}
|
|
11
|
+
const reach = end - start < zone * 2 ? 0 : zone;
|
|
12
|
+
if (reach > 0 && at > end - reach) {
|
|
13
|
+
return (at - (end - reach)) / reach;
|
|
14
|
+
}
|
|
15
|
+
if (reach > 0 && at < start + reach) {
|
|
16
|
+
return -(start + reach - at) / reach;
|
|
17
|
+
}
|
|
18
|
+
return 0;
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
x: Math.round(along(point.x, rect.left, rect.right) * most),
|
|
22
|
+
y: Math.round(along(point.y, rect.top, rect.bottom) * most),
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export class EdgePan {
|
|
26
|
+
constructor(rect, step, ended = () => undefined) {
|
|
27
|
+
this.rect = rect;
|
|
28
|
+
this.step = step;
|
|
29
|
+
this.ended = ended;
|
|
30
|
+
this.tick = () => {
|
|
31
|
+
const by = this.speed();
|
|
32
|
+
if (by.x === 0 && by.y === 0) {
|
|
33
|
+
this.frame = undefined;
|
|
34
|
+
this.ended();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.step(by);
|
|
38
|
+
this.frame = requestAnimationFrame(this.tick);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
get moving() {
|
|
42
|
+
return this.frame !== undefined;
|
|
43
|
+
}
|
|
44
|
+
follow(point) {
|
|
45
|
+
this.point = point;
|
|
46
|
+
const by = this.speed();
|
|
47
|
+
if (this.frame === undefined && (by.x !== 0 || by.y !== 0)) {
|
|
48
|
+
this.frame = requestAnimationFrame(this.tick);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
stop() {
|
|
52
|
+
this.point = undefined;
|
|
53
|
+
if (this.frame !== undefined) {
|
|
54
|
+
cancelAnimationFrame(this.frame);
|
|
55
|
+
this.frame = undefined;
|
|
56
|
+
this.ended();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
speed() {
|
|
60
|
+
const rect = this.rect();
|
|
61
|
+
return this.point && rect ? edgeSpeed(this.point, rect) : { x: 0, y: 0 };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where focus goes when a stop on a board leaves: the arithmetic, kept apart
|
|
3
|
+
* from the board that moves focus there.
|
|
4
|
+
*
|
|
5
|
+
* Shared by the two ways a stop leaves, Delete and the page taking it away,
|
|
6
|
+
* so a reader lands in the same place either way.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* The first stop after `at` in `walk` that `kept` keeps, or, with none after
|
|
10
|
+
* it, the nearest one before it. Undefined where none is kept.
|
|
11
|
+
*
|
|
12
|
+
* @param walk Every stop's key, in the order the arrow keys walk them.
|
|
13
|
+
* @param at Where the stop that left was, as an index into `walk`, or `-1`
|
|
14
|
+
* for nowhere, which takes the first stop kept.
|
|
15
|
+
* @param kept Whether a stop is still there.
|
|
16
|
+
*/
|
|
17
|
+
export declare const neighborOf: (walk: readonly string[], at: number, kept: (key: string) => boolean) => string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const neighborOf = (walk, at, kept) => walk.slice(at + 1).find(kept) ?? walk.slice(0, Math.max(at, 0)).reverse().find(kept);
|
|
@@ -150,6 +150,16 @@ export declare class HelixHeadlessCanvasNode extends HelixElement {
|
|
|
150
150
|
* point and one to a circle on its curve without the board knowing which.
|
|
151
151
|
*/
|
|
152
152
|
shape?: 'circle' | 'diamond' | 'pill' | 'square';
|
|
153
|
+
/**
|
|
154
|
+
* @internal What the card's state adds to what it says, in the page's words,
|
|
155
|
+
* written by the board: its `selected-label` while it is selected. Read
|
|
156
|
+
* first, before what the tone means.
|
|
157
|
+
*
|
|
158
|
+
* **A selection a reader cannot see has to be said.** A card is an article,
|
|
159
|
+
* and an article has no selected state for `aria-selected` to carry, so a
|
|
160
|
+
* reader who selected three cards heard nothing on any of them.
|
|
161
|
+
*/
|
|
162
|
+
status: string;
|
|
153
163
|
/**
|
|
154
164
|
* @internal Whether this is the card the reader selected, written by the
|
|
155
165
|
* board. Kept apart from focus, so a reader who clicks a button beside the
|
|
@@ -211,8 +221,8 @@ export declare class HelixHeadlessCanvasNode extends HelixElement {
|
|
|
211
221
|
*/
|
|
212
222
|
focus(options?: FocusOptions): void;
|
|
213
223
|
/**
|
|
214
|
-
* The card, and the sentence that says
|
|
215
|
-
* leads.
|
|
224
|
+
* The card, and the sentence that says whether it is selected, what its
|
|
225
|
+
* tone means and where it leads.
|
|
216
226
|
*
|
|
217
227
|
* **`aria-describedby` at a hidden element, which is allowed and is the
|
|
218
228
|
* point.** A description is computed from its target whether or not the
|
|
@@ -4,9 +4,10 @@ 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, PlacementController } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, PlacementController, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
|
+
import { descriptionOf } from '../describe.js';
|
|
10
11
|
const DRAWN = [
|
|
11
12
|
'group',
|
|
12
13
|
'height',
|
|
@@ -33,6 +34,7 @@ let HelixHeadlessCanvasNode = class HelixHeadlessCanvasNode extends HelixElement
|
|
|
33
34
|
this.links = '';
|
|
34
35
|
this.meaning = '';
|
|
35
36
|
this.readOnly = false;
|
|
37
|
+
this.status = '';
|
|
36
38
|
this.selected = false;
|
|
37
39
|
this.movable = false;
|
|
38
40
|
this.resizable = false;
|
|
@@ -72,7 +74,7 @@ let HelixHeadlessCanvasNode = class HelixHeadlessCanvasNode extends HelixElement
|
|
|
72
74
|
</svg>`
|
|
73
75
|
: nothing}<div
|
|
74
76
|
part="node"
|
|
75
|
-
aria-describedby=${this.meaning || this.links ? 'about' : nothing}
|
|
77
|
+
aria-describedby=${this.status || this.meaning || this.links ? 'about' : nothing}
|
|
76
78
|
aria-label=${this.label || nothing}
|
|
77
79
|
aria-labelledby=${this.label || this.group ? nothing : 'content'}
|
|
78
80
|
aria-keyshortcuts=${this.connectable ? 'Enter F2 Space Shift+ArrowRight Shift+ArrowDown Alt+ArrowRight Alt+ArrowDown C Delete' : nothing}
|
|
@@ -81,7 +83,7 @@ let HelixHeadlessCanvasNode = class HelixHeadlessCanvasNode extends HelixElement
|
|
|
81
83
|
>
|
|
82
84
|
<slot id="content"></slot>
|
|
83
85
|
<slot name="description"></slot>
|
|
84
|
-
<span id="about" hidden>${[this.meaning, this.links]
|
|
86
|
+
<span id="about" hidden>${descriptionOf(wordsLocale(this), [this.status, this.meaning, this.links])}</span>
|
|
85
87
|
</div>
|
|
86
88
|
${this.connectable
|
|
87
89
|
? html `<span part="handle handle-top" aria-hidden="true" data-side="top"></span>
|
|
@@ -131,6 +133,9 @@ __decorate([
|
|
|
131
133
|
__decorate([
|
|
132
134
|
property({ reflect: true })
|
|
133
135
|
], HelixHeadlessCanvasNode.prototype, "shape", void 0);
|
|
136
|
+
__decorate([
|
|
137
|
+
state()
|
|
138
|
+
], HelixHeadlessCanvasNode.prototype, "status", void 0);
|
|
134
139
|
__decorate([
|
|
135
140
|
state()
|
|
136
141
|
], HelixHeadlessCanvasNode.prototype, "selected", void 0);
|