@fusion.dev/helix-headless 0.145.0 → 0.147.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 +12286 -4281
- package/dist/accordion/item/accordion-item.d.ts +51 -18
- package/dist/accordion/item/accordion-item.js +45 -13
- package/dist/accordion/root/accordion-root.d.ts +16 -7
- package/dist/accordion/root/accordion-root.js +3 -3
- package/dist/announcement/root/announcement-root.d.ts +16 -6
- package/dist/announcement/root/announcement-root.js +37 -7
- package/dist/app-header/root/app-header-root.d.ts +7 -2
- package/dist/app-header/root/app-header-root.js +9 -1
- package/dist/app-header/sectioning.d.ts +3 -1
- package/dist/app-header/sectioning.js +3 -2
- package/dist/area-chart/root/area-chart-root.d.ts +18 -1
- package/dist/area-chart/root/area-chart-root.js +11 -3
- package/dist/avatar/group/avatar-group.d.ts +20 -14
- package/dist/avatar/group/avatar-group.js +17 -19
- package/dist/avatar/root/avatar-root.d.ts +31 -1
- package/dist/avatar/root/avatar-root.js +11 -1
- package/dist/badge/root/badge-root.d.ts +60 -7
- package/dist/badge/root/badge-root.js +89 -6
- package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
- package/dist/bar-chart/root/bar-chart-root.js +48 -20
- package/dist/bar-chart/stack.d.ts +25 -0
- package/dist/bar-chart/stack.js +27 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +25 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.js +51 -4
- package/dist/button/root/button-root.d.ts +50 -38
- package/dist/button/root/button-root.js +42 -53
- package/dist/button/submitter.d.ts +27 -0
- package/dist/button/submitter.js +25 -0
- package/dist/button-group/root/button-group-root.d.ts +2 -1
- package/dist/button-group/root/button-group-root.js +5 -1
- package/dist/canvas/node/canvas-node.d.ts +4 -3
- package/dist/canvas/node/canvas-node.js +3 -2
- package/dist/canvas/root/canvas-root.js +2 -2
- package/dist/card/root/card-root.d.ts +36 -4
- package/dist/card/root/card-root.js +29 -10
- package/dist/carousel/root/carousel-root.d.ts +43 -4
- package/dist/carousel/root/carousel-root.js +40 -12
- package/dist/carousel/stops.d.ts +20 -0
- package/dist/carousel/stops.js +30 -0
- package/dist/chat/message/chat-message.js +5 -4
- package/dist/chat/naming.d.ts +5 -1
- package/dist/chat/naming.js +4 -2
- package/dist/chat/root/chat-root.d.ts +40 -4
- package/dist/chat/root/chat-root.js +32 -6
- package/dist/checkbox/root/checkbox-root.d.ts +20 -0
- package/dist/checkbox/root/checkbox-root.js +18 -7
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
- package/dist/checkbox-group/root/checkbox-group-root.js +14 -11
- package/dist/checkbox-group/select-all.d.ts +21 -0
- package/dist/checkbox-group/select-all.js +7 -0
- package/dist/code-block/highlight.d.ts +15 -0
- package/dist/code-block/highlight.js +4 -0
- package/dist/code-block/root/code-block-root.d.ts +79 -10
- package/dist/code-block/root/code-block-root.js +74 -5
- package/dist/color-input/root/color-input-root.d.ts +14 -0
- package/dist/color-input/root/color-input-root.js +17 -7
- package/dist/color-picker/channels.js +1 -2
- package/dist/color-picker/root/color-picker-root.d.ts +53 -16
- package/dist/color-picker/root/color-picker-root.js +155 -46
- package/dist/color-picker/wheel.d.ts +17 -0
- package/dist/color-picker/wheel.js +6 -0
- package/dist/combobox/root/combobox-root.d.ts +56 -0
- package/dist/combobox/root/combobox-root.js +92 -15
- package/dist/command/root/command-root.d.ts +19 -2
- package/dist/command/root/command-root.js +24 -23
- package/dist/copy-button/root/copy-button-root.d.ts +21 -1
- package/dist/copy-button/root/copy-button-root.js +16 -4
- package/dist/data-table/index.d.ts +1 -1
- package/dist/data-table/index.js +1 -1
- package/dist/data-table/keys.d.ts +6 -0
- package/dist/data-table/keys.js +14 -0
- package/dist/data-table/root/data-table-root.d.ts +27 -18
- package/dist/data-table/root/data-table-root.js +31 -57
- package/dist/data-table/tree.d.ts +16 -1
- package/dist/data-table/tree.js +2 -3
- package/dist/date-input/root/date-input-root.d.ts +11 -2
- package/dist/date-input/root/date-input-root.js +26 -12
- package/dist/date-picker/root/date-picker-root.d.ts +14 -9
- package/dist/date-picker/root/date-picker-root.js +33 -22
- package/dist/description-list/item/description-list-item.d.ts +18 -4
- package/dist/description-list/item/description-list-item.js +8 -4
- package/dist/dialog/description.js +15 -1
- package/dist/dialog/root/dialog-root.d.ts +8 -2
- package/dist/dialog/root/dialog-root.js +16 -1
- package/dist/divider/root/divider-root.d.ts +3 -0
- package/dist/divider/root/divider-root.js +2 -1
- package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
- package/dist/donut-chart/root/donut-chart-root.js +55 -1
- package/dist/donut-chart/slice-label.d.ts +35 -0
- package/dist/donut-chart/slice-label.js +11 -0
- package/dist/drawer/reveal.d.ts +8 -0
- package/dist/drawer/reveal.js +1 -0
- package/dist/drawer/root/drawer-root.d.ts +63 -2
- package/dist/drawer/root/drawer-root.js +75 -4
- package/dist/drilldown/item/drilldown-item.d.ts +21 -1
- package/dist/drilldown/item/drilldown-item.js +40 -5
- package/dist/drilldown/root/drilldown-root.d.ts +21 -3
- package/dist/drilldown/root/drilldown-root.js +22 -3
- package/dist/element-events.generated.js +35 -6
- package/dist/empty/root/empty-root.d.ts +34 -2
- package/dist/empty/root/empty-root.js +26 -4
- package/dist/file-input/root/file-input-root.d.ts +99 -8
- package/dist/file-input/root/file-input-root.js +120 -22
- package/dist/file-input/screen.d.ts +2 -1
- package/dist/file-input/status.d.ts +24 -0
- package/dist/file-input/status.js +10 -0
- package/dist/filter-input/chip/filter-chip.d.ts +23 -0
- package/dist/filter-input/chip/filter-chip.js +11 -2
- package/dist/filter-input/menu/filter-menu.d.ts +2 -0
- package/dist/filter-input/menu/filter-menu.js +12 -4
- package/dist/filter-input/root/filter-input-root.d.ts +38 -6
- package/dist/filter-input/root/filter-input-root.js +18 -28
- package/dist/filter-input/suggest.d.ts +28 -3
- package/dist/filter-input/suggest.js +18 -8
- package/dist/format-date/options.d.ts +3 -4
- package/dist/format-date/options.js +2 -2
- package/dist/format-date/root/format-date-root.d.ts +27 -17
- package/dist/format-date/root/format-date-root.js +27 -48
- package/dist/heatmap/root/buckets.d.ts +21 -0
- package/dist/heatmap/root/buckets.js +34 -0
- package/dist/heatmap/root/heatmap-root.d.ts +83 -11
- package/dist/heatmap/root/heatmap-root.js +104 -12
- package/dist/icon/index.d.ts +1 -1
- package/dist/icon/index.js +1 -1
- package/dist/icon/registry.d.ts +26 -1
- package/dist/icon/registry.js +12 -1
- package/dist/icon/root/icon-root.d.ts +25 -1
- package/dist/icon/root/icon-root.js +44 -12
- package/dist/icon/root/index.d.ts +1 -1
- package/dist/icon/root/index.js +1 -1
- package/dist/icon/settle.d.ts +7 -0
- package/dist/icon/settle.js +10 -0
- package/dist/icon-button/root/icon-button-root.d.ts +2 -0
- package/dist/image/root/image-root.d.ts +14 -1
- package/dist/image/root/image-root.js +7 -2
- package/dist/input/root/input-root.d.ts +34 -3
- package/dist/input/root/input-root.js +17 -4
- package/dist/kbd/keys.d.ts +29 -0
- package/dist/kbd/keys.js +52 -0
- package/dist/kbd/root/kbd-root.d.ts +52 -1
- package/dist/kbd/root/kbd-root.js +40 -47
- package/dist/legend/hidden-series.d.ts +10 -2
- package/dist/legend/hidden-series.js +5 -2
- package/dist/legend/root/legend-root.d.ts +77 -12
- package/dist/legend/root/legend-root.js +71 -17
- package/dist/lightbox/root/lightbox-root.d.ts +98 -10
- package/dist/lightbox/root/lightbox-root.js +153 -18
- package/dist/lightbox/zoom-controller.d.ts +59 -0
- package/dist/lightbox/zoom-controller.js +128 -0
- package/dist/lightbox/zoom.d.ts +24 -0
- package/dist/lightbox/zoom.js +18 -0
- package/dist/line-chart/root/line-chart-root.d.ts +38 -1
- package/dist/line-chart/root/line-chart-root.js +31 -3
- package/dist/list/item/list-item.d.ts +2 -0
- package/dist/list/item/list-item.js +11 -2
- package/dist/list/root/list-root.d.ts +70 -13
- package/dist/list/root/list-root.js +91 -13
- package/dist/list/selection.d.ts +54 -7
- package/dist/list/selection.js +32 -7
- package/dist/listbox/root/listbox-root.d.ts +44 -4
- package/dist/listbox/root/listbox-root.js +72 -34
- package/dist/loader/busy.d.ts +10 -0
- package/dist/loader/busy.js +11 -0
- package/dist/loader/root/loader-root.d.ts +9 -2
- package/dist/loader/root/loader-root.js +23 -3
- package/dist/megamenu/hand-over.d.ts +75 -0
- package/dist/megamenu/hand-over.js +67 -0
- package/dist/megamenu/root/megamenu-root.d.ts +80 -15
- package/dist/megamenu/root/megamenu-root.js +76 -19
- package/dist/menu/item/menu-item.d.ts +51 -2
- package/dist/menu/item/menu-item.js +50 -26
- package/dist/menu/root/menu-root.d.ts +17 -0
- package/dist/menu/root/menu-root.js +2 -2
- package/dist/meter/root/meter-root.d.ts +62 -1
- package/dist/meter/root/meter-root.js +38 -16
- package/dist/navigation/root/navigation-root.d.ts +2 -1
- package/dist/navigation/root/navigation-root.js +2 -2
- package/dist/notifications/root/notifications-root.d.ts +20 -4
- package/dist/notifications/root/notifications-root.js +30 -8
- package/dist/number-input/grain.d.ts +28 -0
- package/dist/number-input/grain.js +14 -0
- package/dist/number-input/root/number-input-root.d.ts +34 -9
- package/dist/number-input/root/number-input-root.js +31 -25
- package/dist/object-inspector/root/object-inspector-root.d.ts +88 -33
- package/dist/object-inspector/root/object-inspector-root.js +134 -92
- package/dist/object-inspector/rows.d.ts +18 -0
- package/dist/object-inspector/rows.js +33 -0
- package/dist/option/index.d.ts +1 -0
- package/dist/option/index.js +1 -0
- package/dist/option/root/option-root.d.ts +5 -3
- package/dist/option/separator/option-separator.d.ts +30 -0
- package/dist/option/separator/option-separator.js +21 -0
- package/dist/outline/root/outline-root.d.ts +30 -0
- package/dist/outline/root/outline-root.js +17 -13
- package/dist/pagination/size/pagination-size.d.ts +6 -0
- package/dist/pagination/size/pagination-size.js +5 -3
- package/dist/pin-input/code.d.ts +37 -0
- package/dist/pin-input/code.js +25 -0
- package/dist/pin-input/root/pin-input-root.d.ts +116 -115
- package/dist/pin-input/root/pin-input-root.js +163 -155
- package/dist/popover/hide-outside.d.ts +14 -0
- package/dist/popover/hide-outside.js +34 -0
- package/dist/popover/root/popover-root.d.ts +64 -8
- package/dist/popover/root/popover-root.js +67 -4
- package/dist/progress/root/progress-root.d.ts +47 -0
- package/dist/progress/root/progress-root.js +34 -16
- package/dist/qr-code/export.d.ts +45 -1
- package/dist/qr-code/export.js +28 -0
- package/dist/qr-code/name.d.ts +11 -0
- package/dist/qr-code/name.js +7 -0
- package/dist/qr-code/root/qr-code-root.d.ts +36 -11
- package/dist/qr-code/root/qr-code-root.js +58 -11
- package/dist/quote/marks.d.ts +8 -0
- package/dist/quote/marks.js +5 -0
- package/dist/quote/root/quote-root.d.ts +14 -2
- package/dist/quote/root/quote-root.js +23 -1
- package/dist/radio/group/radio-group.d.ts +15 -0
- package/dist/radio/root/radio-root.d.ts +6 -2
- package/dist/radio/root/radio-root.js +7 -2
- package/dist/rating/root/rating-root.d.ts +30 -12
- package/dist/rating/root/rating-root.js +27 -27
- package/dist/scatter-chart/fit.d.ts +15 -0
- package/dist/scatter-chart/fit.js +35 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +51 -1
- package/dist/scatter-chart/root/scatter-chart-root.js +64 -24
- package/dist/scroll-area/root/scroll-area-root.d.ts +22 -51
- package/dist/scroll-area/root/scroll-area-root.js +57 -173
- package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
- package/dist/scroll-area/scrollbar-controller.js +172 -0
- package/dist/scroll-area/scrollbar.d.ts +27 -8
- package/dist/scroll-area/scrollbar.js +10 -1
- package/dist/select/align.d.ts +47 -0
- package/dist/select/align.js +7 -0
- package/dist/select/root/select-root.d.ts +71 -0
- package/dist/select/root/select-root.js +78 -6
- package/dist/skeleton/root/skeleton-root.d.ts +3 -0
- package/dist/skeleton/root/skeleton-root.js +4 -2
- package/dist/skip-link/root/skip-link-root.js +2 -2
- package/dist/slider/root/slider-root.d.ts +59 -5
- package/dist/slider/root/slider-root.js +45 -3
- package/dist/sparkline/readings.d.ts +36 -0
- package/dist/sparkline/readings.js +36 -0
- package/dist/sparkline/root/sparkline-root.d.ts +121 -7
- package/dist/sparkline/root/sparkline-root.js +160 -26
- package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
- package/dist/speed-dial/item/speed-dial-item.js +2 -2
- package/dist/speed-dial/root/speed-dial-root.d.ts +6 -0
- package/dist/speed-dial/root/speed-dial-root.js +11 -3
- package/dist/splitter/root/splitter-root.d.ts +10 -12
- package/dist/splitter/root/splitter-root.js +211 -204
- package/dist/stat/root/stat-root.d.ts +14 -5
- package/dist/stat/root/stat-root.js +21 -5
- package/dist/steps/reach.d.ts +5 -0
- package/dist/steps/reach.js +3 -0
- package/dist/steps/root/steps-root.d.ts +56 -3
- package/dist/steps/root/steps-root.js +50 -6
- package/dist/steps/step/step.d.ts +8 -0
- package/dist/steps/step/step.js +8 -3
- package/dist/switch/root/switch-root.d.ts +10 -0
- package/dist/table/column/table-column.d.ts +6 -10
- package/dist/table/column/table-column.js +8 -20
- package/dist/table/root/table-root.d.ts +31 -10
- package/dist/table/root/table-root.js +14 -18
- package/dist/table/row/table-row.d.ts +24 -0
- package/dist/table/row/table-row.js +37 -1
- package/dist/tabs/panel/tab-panel.d.ts +16 -3
- package/dist/tabs/panel/tab-panel.js +34 -5
- package/dist/tabs/root/tabs-root.d.ts +17 -3
- package/dist/tabs/root/tabs-root.js +1 -1
- package/dist/tabs/tab/tab.d.ts +5 -0
- package/dist/tabs/tab/tab.js +5 -2
- package/dist/tag/group/tag-group.d.ts +44 -5
- package/dist/tag/group/tag-group.js +60 -9
- package/dist/tag/root/tag-root.js +9 -2
- package/dist/textarea/root/textarea-root.d.ts +41 -2
- package/dist/textarea/root/textarea-root.js +39 -1
- package/dist/time-input/root/time-input-root.d.ts +10 -2
- package/dist/time-input/root/time-input-root.js +24 -13
- package/dist/time-picker/root/time-picker-root.d.ts +28 -17
- package/dist/time-picker/root/time-picker-root.js +18 -29
- package/dist/time-picker/wheel-name.d.ts +9 -0
- package/dist/time-picker/wheel-name.js +15 -0
- package/dist/timeline/group/timeline-group.js +2 -2
- package/dist/toast/item/toast-item.d.ts +16 -3
- package/dist/toast/item/toast-item.js +22 -6
- package/dist/toast/root/toast-root.d.ts +34 -4
- package/dist/toast/root/toast-root.js +74 -13
- package/dist/toast/words.d.ts +12 -0
- package/dist/toast/words.js +25 -0
- package/dist/toggle/group/toggle-group.d.ts +52 -7
- package/dist/toggle/group/toggle-group.js +58 -44
- package/dist/toggle/root/toggle-root.js +2 -4
- package/dist/toolbar/root/toolbar-root.d.ts +21 -5
- package/dist/toolbar/root/toolbar-root.js +52 -8
- package/dist/tooltip/root/tooltip-root.d.ts +20 -3
- package/dist/tooltip/root/tooltip-root.js +18 -1
- package/dist/tour/back.d.ts +10 -0
- package/dist/tour/back.js +8 -0
- package/dist/tour/root/tour-root.d.ts +45 -2
- package/dist/tour/root/tour-root.js +53 -8
- package/dist/tour/stop/tour-stop.d.ts +3 -0
- package/dist/tour/stop/tour-stop.js +3 -3
- package/dist/tree/item/tree-item.d.ts +7 -3
- package/dist/tree/item/tree-item.js +3 -0
- package/dist/tree/root/tree-root.d.ts +24 -3
- package/dist/tree/root/tree-root.js +32 -13
- package/dist/tree/selection.js +2 -15
- package/dist/trend/figure.d.ts +16 -0
- package/dist/trend/figure.js +8 -0
- package/dist/trend/root/trend-root.d.ts +83 -19
- package/dist/trend/root/trend-root.js +59 -8
- package/dist/video/media-events.d.ts +13 -18
- package/dist/video/media-events.js +1 -5
- package/dist/video/root/extra-controls.d.ts +12 -0
- package/dist/video/root/extra-controls.js +6 -2
- package/dist/video/root/video-root.d.ts +23 -6
- package/dist/video/root/video-root.js +19 -10
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +2 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +17 -1
- package/dist/video-playlist/root/video-playlist-root.js +3 -0
- package/dist/virtual-list/fill.d.ts +11 -8
- package/dist/virtual-list/fill.js +10 -17
- package/dist/virtual-list/keys.d.ts +16 -7
- package/dist/virtual-list/keys.js +17 -6
- package/dist/virtual-list/plan.d.ts +65 -0
- package/dist/virtual-list/plan.js +27 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +136 -13
- package/dist/virtual-list/root/virtual-list-root.js +218 -51
- package/lint.json +1 -1
- package/package.json +8 -8
- package/types/jsx.d.ts +7441 -1458
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +1501 -326
- package/dist/chat/relative-clock.d.ts +0 -39
- package/dist/chat/relative-clock.js +0 -31
- package/dist/data-table/root/order.d.ts +0 -141
- package/dist/data-table/root/order.js +0 -76
- package/dist/tag/selection.d.ts +0 -10
- package/dist/tag/selection.js +0 -12
|
@@ -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 { AriaForwardController, anchorElement, arrowReach, CommandController, customElement, deepActiveElement, FocusScopeController, HelixElement, headingIn, MixinControllerOpen, PopoverController, reflectElements, sideOf, tellDisclosure, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, anchorElement, arrowReach, CommandController, customElement, deepActiveElement, FocusScopeController, HelixElement, headingIn, MixinControllerOpen, OpenPhaseController, PopoverController, reflectElements, sideOf, tellDisclosure, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
|
+
import { hideOutside } from '../hide-outside.js';
|
|
10
11
|
let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpen(HelixElement) {
|
|
11
12
|
constructor() {
|
|
12
13
|
super(...arguments);
|
|
@@ -18,6 +19,14 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
|
|
|
18
19
|
});
|
|
19
20
|
this.offset = 4;
|
|
20
21
|
this.placement = 'bottom-start';
|
|
22
|
+
this.phases = new OpenPhaseController(this, {
|
|
23
|
+
mark: {
|
|
24
|
+
entering: (on) => this.toggleState('entering', on),
|
|
25
|
+
exiting: (on) => this.toggleState('exiting', on),
|
|
26
|
+
},
|
|
27
|
+
open: () => this.open,
|
|
28
|
+
surface: () => this.partNamed('popover'),
|
|
29
|
+
});
|
|
21
30
|
this.panel = new PopoverController(this, {
|
|
22
31
|
anchor: () => this.trigger,
|
|
23
32
|
arrow: () => this.partNamed('arrow'),
|
|
@@ -60,6 +69,7 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
|
|
|
60
69
|
},
|
|
61
70
|
},
|
|
62
71
|
});
|
|
72
|
+
this.closingFromInside = false;
|
|
63
73
|
this.handleFocusOut = (event) => {
|
|
64
74
|
const next = event.relatedTarget;
|
|
65
75
|
if (!this.open || !(next instanceof Node)) {
|
|
@@ -68,7 +78,15 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
|
|
|
68
78
|
if (this.contains(next) || this.renderRoot.contains(next) || this.invoker?.contains(next)) {
|
|
69
79
|
return;
|
|
70
80
|
}
|
|
71
|
-
this.
|
|
81
|
+
this.close(false);
|
|
82
|
+
};
|
|
83
|
+
this.notePress = (event) => {
|
|
84
|
+
const trigger = this.renderRoot
|
|
85
|
+
?.querySelector('slot[name="trigger"]')
|
|
86
|
+
?.assignedElements({ flatten: false })[0];
|
|
87
|
+
if (trigger && event.composedPath().includes(trigger)) {
|
|
88
|
+
this.pressed = true;
|
|
89
|
+
}
|
|
72
90
|
};
|
|
73
91
|
this.handleTriggerClick = () => {
|
|
74
92
|
if (this.open) {
|
|
@@ -78,6 +96,8 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
|
|
|
78
96
|
this.show();
|
|
79
97
|
}
|
|
80
98
|
};
|
|
99
|
+
this.pressed = false;
|
|
100
|
+
this.settled = false;
|
|
81
101
|
}
|
|
82
102
|
get slotted() {
|
|
83
103
|
return (this.renderRoot
|
|
@@ -99,33 +119,76 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
|
|
|
99
119
|
}
|
|
100
120
|
}
|
|
101
121
|
hide() {
|
|
122
|
+
this.close(true);
|
|
123
|
+
}
|
|
124
|
+
close(giveBack) {
|
|
102
125
|
if (!this.open || !this.requestOpen(false)) {
|
|
103
126
|
return;
|
|
104
127
|
}
|
|
105
128
|
this.panel.hide();
|
|
106
|
-
if (this.
|
|
129
|
+
if (giveBack && this.focusInside) {
|
|
107
130
|
this.trigger.focus();
|
|
108
131
|
}
|
|
109
132
|
}
|
|
133
|
+
get focusInside() {
|
|
134
|
+
return this.scope.holdsFocus || this.contains(deepActiveElement());
|
|
135
|
+
}
|
|
136
|
+
willUpdate(changed) {
|
|
137
|
+
super.willUpdate(changed);
|
|
138
|
+
this.closingFromInside =
|
|
139
|
+
changed.has('open') && !this.open && changed.get('open') === true && this.focusInside;
|
|
140
|
+
}
|
|
110
141
|
connectedCallback() {
|
|
111
142
|
super.connectedCallback();
|
|
112
143
|
this.addEventListener('focusout', this.handleFocusOut);
|
|
144
|
+
this.addEventListener('click', this.notePress, { capture: true });
|
|
113
145
|
}
|
|
114
146
|
disconnectedCallback() {
|
|
115
147
|
super.disconnectedCallback();
|
|
116
148
|
this.removeEventListener('focusout', this.handleFocusOut);
|
|
149
|
+
this.removeEventListener('click', this.notePress, { capture: true });
|
|
150
|
+
this.hideAround();
|
|
117
151
|
}
|
|
118
152
|
tellTrigger() {
|
|
119
153
|
const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
|
|
120
|
-
|
|
154
|
+
const trigger = slot?.assignedElements({ flatten: false })[0];
|
|
155
|
+
if (!trigger || trigger.localName.includes('-')) {
|
|
156
|
+
tellDisclosure(trigger, this.open);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (trigger !== this.told) {
|
|
160
|
+
if (!this.pressed || trigger.hasAttribute('aria-expanded')) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
this.told = trigger;
|
|
164
|
+
}
|
|
165
|
+
trigger.setAttribute('aria-expanded', String(this.open));
|
|
166
|
+
}
|
|
167
|
+
hideAround() {
|
|
168
|
+
const hide = this.open && this.modal && this.isConnected;
|
|
169
|
+
if (hide && !this.showOutside) {
|
|
170
|
+
this.showOutside = hideOutside([this, ...(this.invoker ? [this.invoker] : [])]);
|
|
171
|
+
}
|
|
172
|
+
else if (!hide && this.showOutside) {
|
|
173
|
+
this.showOutside();
|
|
174
|
+
this.showOutside = undefined;
|
|
175
|
+
}
|
|
121
176
|
}
|
|
122
177
|
updated(changed) {
|
|
123
178
|
super.updated(changed);
|
|
124
179
|
this.tellTrigger();
|
|
125
180
|
this.nameByHeading();
|
|
181
|
+
if (this.settled) {
|
|
182
|
+
this.hideAround();
|
|
183
|
+
}
|
|
184
|
+
this.settled = true;
|
|
126
185
|
if (changed.has('open') && this.open && changed.get('open') === false) {
|
|
127
186
|
this.scope.enter();
|
|
128
187
|
}
|
|
188
|
+
if (this.closingFromInside) {
|
|
189
|
+
this.closingFromInside = false;
|
|
190
|
+
this.trigger.focus();
|
|
191
|
+
}
|
|
129
192
|
}
|
|
130
193
|
render() {
|
|
131
194
|
return html `<slot name="trigger" @click=${this.handleTriggerClick}></slot>
|
|
@@ -15,6 +15,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
15
15
|
*
|
|
16
16
|
* The fill is a fraction of the track, written as a custom property.
|
|
17
17
|
*
|
|
18
|
+
* **Reaching `max` is said and sent.** When the value arrives at `max` from
|
|
19
|
+
* below, the bar says `complete-label`, "Complete" by default, in a polite
|
|
20
|
+
* `live` region and sends `helix-complete`, so a reader hears that the work is
|
|
21
|
+
* done and a page can move on. A bar that starts full says nothing, and an
|
|
22
|
+
* empty `complete-label` keeps it quiet. The `complete` custom state is set
|
|
23
|
+
* while the bar is full.
|
|
24
|
+
*
|
|
18
25
|
* @since 0.1.0
|
|
19
26
|
* @status stable
|
|
20
27
|
* @category feedback
|
|
@@ -23,14 +30,41 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
23
30
|
*
|
|
24
31
|
* @slot label - A visible label. Its words name the progress bar in place of `label`.
|
|
25
32
|
*
|
|
33
|
+
* @event {HelixCompleteEvent} helix-complete - The value reached `max` from below. Its `value` is `max`. Not sent for a bar that starts full.
|
|
34
|
+
*
|
|
26
35
|
* @csspart groove - The unfilled circle under the ring's filled arc.
|
|
27
36
|
* @csspart indicator - The filled part that shows the work done.
|
|
37
|
+
* @csspart live - A polite region that says `complete-label` when the work is done, rendered from that moment. Hide it visually.
|
|
28
38
|
* @csspart track - The full length the work is measured against.
|
|
29
39
|
* @csspart value - The value shown beside the bar when `show-value` is set.
|
|
30
40
|
*
|
|
31
41
|
* @cssproperty --progress-fraction - The value as a fraction of the range, 0 to 1. Pinned to 1 while indeterminate.
|
|
42
|
+
*
|
|
43
|
+
* @cssstate complete - The value is at `max` and the bar is not indeterminate.
|
|
32
44
|
*/
|
|
33
45
|
export declare class HelixHeadlessProgress extends HelixElement {
|
|
46
|
+
/**
|
|
47
|
+
* The words a screen reader hears when the value reaches `max`, such as
|
|
48
|
+
* "Upload complete".
|
|
49
|
+
*
|
|
50
|
+
* Said once, politely, as the work finishes. Empty says nothing, for a bar
|
|
51
|
+
* whose page announces the result itself.
|
|
52
|
+
*/
|
|
53
|
+
completeLabel: string;
|
|
54
|
+
/**
|
|
55
|
+
* `Intl.NumberFormat` options the reading is written with, as React Aria's
|
|
56
|
+
* Meter and ProgressBar take them: a unit, a currency, or a number of
|
|
57
|
+
* decimals. Written as JSON in the attribute.
|
|
58
|
+
*
|
|
59
|
+
* ```html
|
|
60
|
+
* <helix-progress value="18" max="32" format-options='{"style":"unit","unit":"gigabyte"}'></helix-progress>
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* A `percent` style writes the share of the range, and any other the value
|
|
64
|
+
* itself, so the example says "18 GB". Absent is a whole percentage. The
|
|
65
|
+
* words are announced as well as shown. `value-text` still wins.
|
|
66
|
+
*/
|
|
67
|
+
formatOptions?: Intl.NumberFormatOptions;
|
|
34
68
|
/**
|
|
35
69
|
* Whether the length of the task is unknown. The bar then shows activity
|
|
36
70
|
* without a value.
|
|
@@ -114,11 +148,24 @@ export declare class HelixHeadlessProgress extends HelixElement {
|
|
|
114
148
|
* report progress.
|
|
115
149
|
*/
|
|
116
150
|
valueText: string;
|
|
151
|
+
/** The region the bar says `complete-label` in, rendered from the first time it does. */
|
|
152
|
+
private readonly status;
|
|
153
|
+
/** Whether the bar was full at the last update, or unknown before the first. */
|
|
154
|
+
private wasComplete;
|
|
155
|
+
/** Whether the work is done: determinate and at `max`. */
|
|
156
|
+
private get complete();
|
|
117
157
|
/** The range the value is measured in, with a top above its bottom. */
|
|
118
158
|
private get range();
|
|
119
159
|
/** What is done, as a fraction of the whole, between 0 and 1. */
|
|
120
160
|
get fraction(): number;
|
|
121
161
|
protected willUpdate(changed: PropertyValues): void;
|
|
162
|
+
protected updated(changed: PropertyValues): void;
|
|
163
|
+
/**
|
|
164
|
+
* What the bar says: the consumer's words, or the reading in
|
|
165
|
+
* `format-options`, a share of the range for a percent and the value for
|
|
166
|
+
* anything else.
|
|
167
|
+
*/
|
|
168
|
+
private get text();
|
|
122
169
|
/** A label's words changed, so the name is written again. */
|
|
123
170
|
private readonly renamed;
|
|
124
171
|
protected render(): TemplateResult;
|
|
@@ -4,24 +4,13 @@ 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, hostAria, slottedWords } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, drawStatus, HelixCompleteEvent, HelixElement, hostAria, readingText, StatusController, slottedWords, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
-
const percents = new Map();
|
|
11
|
-
const percent = (share, locale) => {
|
|
12
|
-
let format = percents.get(locale);
|
|
13
|
-
if (!format) {
|
|
14
|
-
format = new Intl.NumberFormat(locale || undefined, {
|
|
15
|
-
maximumFractionDigits: 0,
|
|
16
|
-
style: 'percent',
|
|
17
|
-
});
|
|
18
|
-
percents.set(locale, format);
|
|
19
|
-
}
|
|
20
|
-
return format.format(share);
|
|
21
|
-
};
|
|
22
10
|
let HelixHeadlessProgress = class HelixHeadlessProgress extends HelixElement {
|
|
23
11
|
constructor() {
|
|
24
12
|
super(...arguments);
|
|
13
|
+
this.completeLabel = 'Complete';
|
|
25
14
|
this.indeterminate = false;
|
|
26
15
|
this.label = 'Progress';
|
|
27
16
|
this.locale = '';
|
|
@@ -30,10 +19,14 @@ let HelixHeadlessProgress = class HelixHeadlessProgress extends HelixElement {
|
|
|
30
19
|
this.showValue = false;
|
|
31
20
|
this.value = 0;
|
|
32
21
|
this.valueText = '';
|
|
22
|
+
this.status = new StatusController(this);
|
|
33
23
|
this.renamed = () => {
|
|
34
24
|
this.requestUpdate();
|
|
35
25
|
};
|
|
36
26
|
}
|
|
27
|
+
get complete() {
|
|
28
|
+
return !this.indeterminate && this.fraction >= 1;
|
|
29
|
+
}
|
|
37
30
|
get range() {
|
|
38
31
|
const min = Number.isFinite(this.min) ? this.min : 0;
|
|
39
32
|
return { max: this.max > min ? this.max : min + 100, min };
|
|
@@ -54,7 +47,26 @@ let HelixHeadlessProgress = class HelixHeadlessProgress extends HelixElement {
|
|
|
54
47
|
this.internals.ariaValueNow = this.indeterminate
|
|
55
48
|
? null
|
|
56
49
|
: String(Math.min(Math.max(this.value || min, min), max));
|
|
57
|
-
this.internals.ariaValueText =
|
|
50
|
+
this.internals.ariaValueText =
|
|
51
|
+
this.valueText || (this.formatOptions !== undefined && !this.indeterminate ? this.text : null);
|
|
52
|
+
this.toggleState('complete', this.complete);
|
|
53
|
+
}
|
|
54
|
+
updated(changed) {
|
|
55
|
+
super.updated(changed);
|
|
56
|
+
const complete = this.complete;
|
|
57
|
+
const arrived = complete && this.wasComplete === false;
|
|
58
|
+
this.wasComplete = complete;
|
|
59
|
+
if (!arrived) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (this.completeLabel !== '') {
|
|
63
|
+
this.status.say(this.completeLabel);
|
|
64
|
+
}
|
|
65
|
+
this.dispatchEvent(new HelixCompleteEvent({ value: String(this.range.max) }));
|
|
66
|
+
}
|
|
67
|
+
get text() {
|
|
68
|
+
return (this.valueText ||
|
|
69
|
+
readingText(Math.min(Math.max(this.value, this.range.min), this.range.max), this.fraction, this.locale, this.formatOptions));
|
|
58
70
|
}
|
|
59
71
|
render() {
|
|
60
72
|
const fraction = this.indeterminate ? 1 : this.fraction;
|
|
@@ -69,11 +81,17 @@ let HelixHeadlessProgress = class HelixHeadlessProgress extends HelixElement {
|
|
|
69
81
|
</div>`}
|
|
70
82
|
${this.showValue && !this.indeterminate
|
|
71
83
|
? html `<span part="value" aria-hidden="true"
|
|
72
|
-
>${this.
|
|
84
|
+
>${this.text}</span
|
|
73
85
|
>`
|
|
74
|
-
: ''}`;
|
|
86
|
+
: ''}${drawStatus(this.status)}`;
|
|
75
87
|
}
|
|
76
88
|
};
|
|
89
|
+
__decorate([
|
|
90
|
+
property({ attribute: 'complete-label' })
|
|
91
|
+
], HelixHeadlessProgress.prototype, "completeLabel", void 0);
|
|
92
|
+
__decorate([
|
|
93
|
+
property({ attribute: 'format-options', type: Object })
|
|
94
|
+
], HelixHeadlessProgress.prototype, "formatOptions", void 0);
|
|
77
95
|
__decorate([
|
|
78
96
|
property({ reflect: true, type: Boolean })
|
|
79
97
|
], HelixHeadlessProgress.prototype, "indeterminate", void 0);
|
package/dist/qr-code/export.d.ts
CHANGED
|
@@ -21,11 +21,55 @@ export interface QrDrawing {
|
|
|
21
21
|
modules: string;
|
|
22
22
|
/** The quiet zone, in modules, that both paths are moved in by. */
|
|
23
23
|
quiet: number;
|
|
24
|
+
/** The logo in the middle, where one is slotted and can be written into a file. */
|
|
25
|
+
logo?: QrLogo;
|
|
24
26
|
}
|
|
27
|
+
/** A place in the drawing, in `viewBox` units: x, y, width and height. */
|
|
28
|
+
export type QrBox = readonly [number, number, number, number];
|
|
29
|
+
/** The slotted logo, read from the element, as a file can carry it. */
|
|
30
|
+
export interface QrLogo {
|
|
31
|
+
/** The box around the mark, which clears the modules under it. */
|
|
32
|
+
frame: QrBox;
|
|
33
|
+
/** The fill of that box. */
|
|
34
|
+
ground: string;
|
|
35
|
+
/** An image's address, written as an `<image>`. */
|
|
36
|
+
href?: string;
|
|
37
|
+
/** Where the mark sits inside the box. */
|
|
38
|
+
mark: QrBox;
|
|
39
|
+
/** An inline SVG's markup, written as a nested `<svg>` at the mark's place. */
|
|
40
|
+
svg?: string;
|
|
41
|
+
}
|
|
42
|
+
/** A rectangle the page measured, as `getBoundingClientRect` gives one. */
|
|
43
|
+
export interface QrRect {
|
|
44
|
+
readonly height: number;
|
|
45
|
+
readonly left: number;
|
|
46
|
+
readonly top: number;
|
|
47
|
+
readonly width: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A rectangle measured on the page as a place in the drawing: `area` is the
|
|
51
|
+
* drawn code's own rectangle and `box` the side of its `viewBox`, so a logo
|
|
52
|
+
* set over the code by a stylesheet lands where it was drawn.
|
|
53
|
+
*/
|
|
54
|
+
export declare const boxIn: (rect: QrRect, area: QrRect, box: number) => QrBox;
|
|
55
|
+
/**
|
|
56
|
+
* The logo's box in the drawing, or nothing where any of it falls outside the
|
|
57
|
+
* code, such as a logo the headless tier sets beside the code rather than
|
|
58
|
+
* over it, which a file of the code alone has no place for.
|
|
59
|
+
*/
|
|
60
|
+
export declare const logoBox: (rect: QrRect, area: QrRect, box: number) => QrBox | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* The logo as the file writes it: its box, then the mark, as an `<image>` or as
|
|
63
|
+
* the slotted SVG moved to the mark's place. Nothing for a mark that is
|
|
64
|
+
* neither, such as text, which a file of its own cannot carry in the page's
|
|
65
|
+
* fonts.
|
|
66
|
+
*/
|
|
67
|
+
export declare const qrLogo: (logo: QrLogo) => string;
|
|
25
68
|
/**
|
|
26
69
|
* The code as standalone SVG markup, sized `size` pixels square.
|
|
27
70
|
*
|
|
28
71
|
* The background is a rectangle under the code, since a scanner needs the
|
|
29
|
-
* light quiet zone and a transparent file put on a dark page has none.
|
|
72
|
+
* light quiet zone and a transparent file put on a dark page has none. A
|
|
73
|
+
* logo goes over the code, as it is drawn on the page.
|
|
30
74
|
*/
|
|
31
75
|
export declare const qrSvg: (drawing: QrDrawing, size: number) => string;
|
package/dist/qr-code/export.js
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
|
+
export const boxIn = (rect, area, box) => {
|
|
2
|
+
const scale = box / area.width;
|
|
3
|
+
return [
|
|
4
|
+
(rect.left - area.left) * scale,
|
|
5
|
+
(rect.top - area.top) * scale,
|
|
6
|
+
rect.width * scale,
|
|
7
|
+
rect.height * scale,
|
|
8
|
+
];
|
|
9
|
+
};
|
|
10
|
+
export const logoBox = (rect, area, box) => {
|
|
11
|
+
const frame = boxIn(rect, area, box);
|
|
12
|
+
const [x, y, width, height] = frame;
|
|
13
|
+
return x < 0 || y < 0 || x + width > box || y + height > box ? undefined : frame;
|
|
14
|
+
};
|
|
1
15
|
const attribute = (value) => value.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
|
16
|
+
const unit = (value) => String(Math.round(value * 100) / 100);
|
|
17
|
+
const placed = ([x, y, width, height]) => `x="${unit(x)}" y="${unit(y)}" width="${unit(width)}" height="${unit(height)}"`;
|
|
18
|
+
export const qrLogo = (logo) => {
|
|
19
|
+
const ground = `<rect ${placed(logo.frame)} fill="${attribute(logo.ground)}"/>`;
|
|
20
|
+
if (logo.href) {
|
|
21
|
+
return `${ground}<image ${placed(logo.mark)} href="${attribute(logo.href)}" preserveAspectRatio="xMidYMid meet"/>`;
|
|
22
|
+
}
|
|
23
|
+
if (logo.svg) {
|
|
24
|
+
const mark = logo.svg.replace(/^\s*<svg\b([^>]*)>/, (_, rest) => `<svg${rest.replace(/\s(?:x|y|width|height|slot)="[^"]*"/g, '')} ${placed(logo.mark)}>`);
|
|
25
|
+
return `${ground}${mark}`;
|
|
26
|
+
}
|
|
27
|
+
return '';
|
|
28
|
+
};
|
|
2
29
|
export const qrSvg = (drawing, size) => {
|
|
3
30
|
const shift = `translate(${drawing.quiet} ${drawing.quiet})`;
|
|
4
31
|
return (`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${drawing.box} ${drawing.box}"` +
|
|
@@ -6,5 +33,6 @@ export const qrSvg = (drawing, size) => {
|
|
|
6
33
|
`<rect width="${drawing.box}" height="${drawing.box}" fill="${attribute(drawing.background)}"/>` +
|
|
7
34
|
`<path d="${attribute(drawing.modules)}" transform="${shift}" fill="${attribute(drawing.moduleColor)}"/>` +
|
|
8
35
|
`<path d="${attribute(drawing.finders)}" transform="${shift}" fill="${attribute(drawing.finderColor)}"/>` +
|
|
36
|
+
(drawing.logo ? qrLogo(drawing.logo) : '') +
|
|
9
37
|
'</svg>');
|
|
10
38
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The name a code is read by: its `label`, or with none, the word for a code,
|
|
3
|
+
* followed by the value where the value is a web address.
|
|
4
|
+
*
|
|
5
|
+
* **A value that is no web address is never read out.** A code that sets up
|
|
6
|
+
* an authenticator (`otpauth://…?secret=…`) or joins a network
|
|
7
|
+
* (`WIFI:…;P:…;;`) carries a secret in its value, and the value as the name
|
|
8
|
+
* read that secret aloud to anyone in earshot. A web address is what a
|
|
9
|
+
* sighted reader gets by scanning, so it is said after the word.
|
|
10
|
+
*/
|
|
11
|
+
export declare const qrName: (label: string, value: string, word: string) => string;
|
|
@@ -13,9 +13,12 @@ export type QrStyle = 'dots' | 'rounded' | 'square';
|
|
|
13
13
|
* thousand modules, and an element for each would be a thousand nodes for one
|
|
14
14
|
* image.
|
|
15
15
|
*
|
|
16
|
-
* The element has `role="img"` and an accessible name. Set
|
|
17
|
-
* code is for
|
|
18
|
-
*
|
|
16
|
+
* The element has `role="img"` and an accessible name. Set `label` to what
|
|
17
|
+
* the code is for, such as "Open the menu". With no `label`, a code is named
|
|
18
|
+
* by `code-label`, "QR code", followed by its value where the value is a web
|
|
19
|
+
* address, which a URL read aloud makes a destination. Any other value is
|
|
20
|
+
* never read out: a code that sets up an authenticator or joins a network
|
|
21
|
+
* carries a secret in it.
|
|
19
22
|
*
|
|
20
23
|
* The quiet zone of four modules is required by the specification, and a
|
|
21
24
|
* scanner rejects a code cropped to its edge. It is drawn inside the `viewBox`,
|
|
@@ -28,11 +31,13 @@ export type QrStyle = 'dots' | 'rounded' | 'square';
|
|
|
28
31
|
*
|
|
29
32
|
* A higher level holds fewer characters, so a value that fits at `M` can be too
|
|
30
33
|
* long once a logo raises the level to `H`. A value too long for the level
|
|
31
|
-
* draws no code
|
|
34
|
+
* draws no code: the element fires `error`, carries `:state(overflow)`, and
|
|
35
|
+
* shows what is in the `fallback` slot, such as the link written out.
|
|
32
36
|
*
|
|
33
37
|
* `toSvg()`, `toPng()` and `download()` give the drawn code as a file of its
|
|
34
|
-
* own, in the colors it is drawn in,
|
|
35
|
-
* print, as Zag's download
|
|
38
|
+
* own, in the colors it is drawn in, with a slotted image or SVG logo where
|
|
39
|
+
* it sits, for a page that offers it to save or print, as Zag's download
|
|
40
|
+
* trigger does.
|
|
36
41
|
*
|
|
37
42
|
* @since 0.1.0
|
|
38
43
|
* @status stable
|
|
@@ -40,16 +45,25 @@ export type QrStyle = 'dots' | 'rounded' | 'square';
|
|
|
40
45
|
* @aliases QR, Barcode, Scan code
|
|
41
46
|
* @documentation https://fusion.dev/helix/components/qr-code
|
|
42
47
|
*
|
|
48
|
+
* @slot fallback - Shown in place of the code when the value is too long for it, such as the link as text.
|
|
43
49
|
* @slot logo - A logo for the center. A code with a logo scans only at a high correction level.
|
|
44
50
|
*
|
|
45
51
|
* @event {Event} error - The value is too long for a code at the correction level, so no code is drawn.
|
|
46
52
|
*
|
|
47
53
|
* @csspart code - The square code image.
|
|
54
|
+
* @csspart fallback - The box around the `fallback` slot, drawn only when the value is too long for a code.
|
|
48
55
|
* @csspart finders - The three corner squares, which can take their own color.
|
|
49
56
|
* @csspart logo - The box that holds the center logo.
|
|
50
57
|
* @csspart modules - Every module except the three corner squares.
|
|
58
|
+
*
|
|
59
|
+
* @cssstate overflow - The value is too long for a code at the correction level, so the fallback shows.
|
|
51
60
|
*/
|
|
52
61
|
export declare class HelixHeadlessQrCode extends HelixElement {
|
|
62
|
+
/**
|
|
63
|
+
* The words a code with no `label` is named by, followed by its value where
|
|
64
|
+
* the value is a web address.
|
|
65
|
+
*/
|
|
66
|
+
codeLabel: string;
|
|
53
67
|
/**
|
|
54
68
|
* The error correction level, which sets how much of the code can be lost
|
|
55
69
|
* and still scan.
|
|
@@ -62,10 +76,13 @@ export declare class HelixHeadlessQrCode extends HelixElement {
|
|
|
62
76
|
*/
|
|
63
77
|
correction?: QrCorrection;
|
|
64
78
|
/**
|
|
65
|
-
* The image's accessible name
|
|
79
|
+
* The image's accessible name: what the code is for, such as "Open the
|
|
80
|
+
* menu".
|
|
66
81
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
82
|
+
* Absent names it by `code-label` and, for a web address, the address,
|
|
83
|
+
* which is what a reader who cannot scan it needs. Any other value is left
|
|
84
|
+
* out of the name, since it may hold a secret, such as an authenticator's
|
|
85
|
+
* key or a network's password.
|
|
69
86
|
*/
|
|
70
87
|
label: string;
|
|
71
88
|
/**
|
|
@@ -112,10 +129,18 @@ export declare class HelixHeadlessQrCode extends HelixElement {
|
|
|
112
129
|
* is drawn in, with its background under the quiet zone.
|
|
113
130
|
*
|
|
114
131
|
* `''` where no code is drawn, before the first render or for a value too
|
|
115
|
-
* long for the level. A slotted logo is
|
|
116
|
-
*
|
|
132
|
+
* long for the level. A slotted `<img>` or `<svg>` logo is written in where
|
|
133
|
+
* it is drawn: an image as its address, or as its pixels where the page may
|
|
134
|
+
* read them, which a PNG needs. A logo of text is left out, a file having
|
|
135
|
+
* none of the page's fonts; the code still scans without it.
|
|
117
136
|
*/
|
|
118
137
|
toSvg(size?: number): string;
|
|
138
|
+
/**
|
|
139
|
+
* The slotted logo as the file draws it, measured against the drawn code, or
|
|
140
|
+
* nothing where none is slotted, where it is not over the code (the headless
|
|
141
|
+
* tier sets it beside it), or where it is neither an image nor an SVG.
|
|
142
|
+
*/
|
|
143
|
+
private logoDrawing;
|
|
119
144
|
/**
|
|
120
145
|
* The code as a PNG, `size` pixels square, drawn from `toSvg()`.
|
|
121
146
|
*
|
|
@@ -8,8 +8,21 @@ import { customElement, HelixElement, rgbOf } from '@fusion.dev/helix-core';
|
|
|
8
8
|
import { html, nothing, svg, } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { encode } from 'uqr';
|
|
11
|
-
import { qrSvg } from '../export.js';
|
|
11
|
+
import { boxIn, logoBox, qrSvg } from '../export.js';
|
|
12
|
+
import { qrName } from '../name.js';
|
|
12
13
|
const QUIET = 4;
|
|
14
|
+
const pixelsOf = (image) => {
|
|
15
|
+
try {
|
|
16
|
+
const canvas = document.createElement('canvas');
|
|
17
|
+
canvas.width = image.naturalWidth;
|
|
18
|
+
canvas.height = image.naturalHeight;
|
|
19
|
+
canvas.getContext('2d')?.drawImage(image, 0, 0);
|
|
20
|
+
return canvas.toDataURL('image/png');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return image.currentSrc || image.src;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
13
26
|
const isFinder = (x, y, size) => {
|
|
14
27
|
const near = (a, b) => a < 8 && b < 8;
|
|
15
28
|
return near(x, y) || near(size - 1 - x, y) || near(x, size - 1 - y);
|
|
@@ -64,6 +77,7 @@ const pathFor = (matrix, style, only = 'all') => {
|
|
|
64
77
|
let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
65
78
|
constructor() {
|
|
66
79
|
super(...arguments);
|
|
80
|
+
this.codeLabel = 'QR code';
|
|
67
81
|
this.label = '';
|
|
68
82
|
this.value = '';
|
|
69
83
|
this.logo = false;
|
|
@@ -96,7 +110,9 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
96
110
|
updated(changed) {
|
|
97
111
|
super.updated(changed);
|
|
98
112
|
const key = `${this.level}:${this.value}`;
|
|
99
|
-
|
|
113
|
+
const overflow = this.value !== '' && this.encoded() === undefined;
|
|
114
|
+
this.toggleState('overflow', overflow);
|
|
115
|
+
if (overflow) {
|
|
100
116
|
if (this.overflowed !== key) {
|
|
101
117
|
this.overflowed = key;
|
|
102
118
|
this.dispatchEvent(new Event('error', { bubbles: false, cancelable: false, composed: false }));
|
|
@@ -115,16 +131,46 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
115
131
|
}
|
|
116
132
|
const ground = getComputedStyle(this).backgroundColor;
|
|
117
133
|
const clear = ground === '' || ground === 'transparent' || /^rgba\(.*,\s*0\)$/.test(ground);
|
|
134
|
+
const background = clear ? '#ffffff' : rgbOf(ground);
|
|
135
|
+
const box = Number(code.getAttribute('viewBox')?.split(' ')[2] ?? 0);
|
|
136
|
+
const logo = this.logoDrawing(code, box, background);
|
|
118
137
|
return qrSvg({
|
|
119
|
-
background
|
|
120
|
-
box
|
|
138
|
+
background,
|
|
139
|
+
box,
|
|
121
140
|
finderColor: rgbOf(getComputedStyle(finders).fill || '#000000'),
|
|
122
141
|
finders: finders.getAttribute('d') ?? '',
|
|
123
142
|
moduleColor: rgbOf(getComputedStyle(modules).fill || '#000000'),
|
|
124
143
|
modules: modules.getAttribute('d') ?? '',
|
|
125
144
|
quiet: QUIET,
|
|
145
|
+
...(logo ? { logo } : {}),
|
|
126
146
|
}, size);
|
|
127
147
|
}
|
|
148
|
+
logoDrawing(code, box, background) {
|
|
149
|
+
const holder = this.renderRoot.querySelector('[part="logo"]');
|
|
150
|
+
const mark = this.knownChildren.find((child) => child.slot === 'logo');
|
|
151
|
+
const area = code.getBoundingClientRect();
|
|
152
|
+
if (!holder || holder.hidden || !mark || area.width === 0) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
const frame = logoBox(holder.getBoundingClientRect(), area, box);
|
|
156
|
+
if (!frame) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
const fill = getComputedStyle(holder).backgroundColor;
|
|
160
|
+
const ground = fill === '' || fill === 'transparent' || /^rgba\(.*,\s*0\)$/.test(fill);
|
|
161
|
+
const logo = {
|
|
162
|
+
frame,
|
|
163
|
+
ground: ground ? background : rgbOf(fill),
|
|
164
|
+
mark: boxIn(mark.getBoundingClientRect(), area, box),
|
|
165
|
+
};
|
|
166
|
+
if (mark instanceof HTMLImageElement) {
|
|
167
|
+
return { ...logo, href: pixelsOf(mark) };
|
|
168
|
+
}
|
|
169
|
+
if (mark instanceof SVGSVGElement) {
|
|
170
|
+
return { ...logo, svg: new XMLSerializer().serializeToString(mark) };
|
|
171
|
+
}
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
128
174
|
async toPng(size = 512) {
|
|
129
175
|
const markup = this.toSvg(size);
|
|
130
176
|
if (markup === '') {
|
|
@@ -151,11 +197,7 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
151
197
|
link.click();
|
|
152
198
|
setTimeout(() => URL.revokeObjectURL(url));
|
|
153
199
|
}
|
|
154
|
-
renderCode() {
|
|
155
|
-
if (this.value === '') {
|
|
156
|
-
return nothing;
|
|
157
|
-
}
|
|
158
|
-
const result = this.encoded();
|
|
200
|
+
renderCode(result) {
|
|
159
201
|
if (result === undefined) {
|
|
160
202
|
return nothing;
|
|
161
203
|
}
|
|
@@ -168,7 +210,7 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
168
210
|
viewBox="0 0 ${box} ${box}"
|
|
169
211
|
xmlns="http://www.w3.org/2000/svg"
|
|
170
212
|
role="img"
|
|
171
|
-
aria-label=${this.label
|
|
213
|
+
aria-label=${qrName(this.label, this.value, this.codeLabel)}
|
|
172
214
|
shape-rendering="crispEdges"
|
|
173
215
|
>
|
|
174
216
|
<path
|
|
@@ -186,7 +228,9 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
186
228
|
</svg>`;
|
|
187
229
|
}
|
|
188
230
|
render() {
|
|
189
|
-
|
|
231
|
+
const result = this.value === '' ? undefined : this.encoded();
|
|
232
|
+
const overflow = this.value !== '' && result === undefined;
|
|
233
|
+
return html `${this.renderCode(result)}${overflow ? html `<span part="fallback"><slot name="fallback"></slot></span>` : nothing}
|
|
190
234
|
<span ?hidden=${!this.logo} part="logo">
|
|
191
235
|
<slot
|
|
192
236
|
name="logo"
|
|
@@ -201,6 +245,9 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
201
245
|
</span>`;
|
|
202
246
|
}
|
|
203
247
|
};
|
|
248
|
+
__decorate([
|
|
249
|
+
property({ attribute: 'code-label' })
|
|
250
|
+
], HelixHeadlessQrCode.prototype, "codeLabel", void 0);
|
|
204
251
|
__decorate([
|
|
205
252
|
property({ attribute: 'correction' })
|
|
206
253
|
], HelixHeadlessQrCode.prototype, "correction", void 0);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether quoted text starts or ends with a quotation mark someone typed.
|
|
3
|
+
*
|
|
4
|
+
* A Quote renders a `<q>`, which sets the marks itself, so typed ones show
|
|
5
|
+
* twice: “"like this"”. Only the ends are read, since a mark inside the text
|
|
6
|
+
* is a quotation within it, which a nested Quote should set.
|
|
7
|
+
*/
|
|
8
|
+
export declare const typedMarks: (text: string) => boolean;
|