@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
|
@@ -11,12 +11,19 @@ import { type TemplateResult } from 'lit';
|
|
|
11
11
|
* was loading, and the announcement tells a screen reader user that the search
|
|
12
12
|
* returned nothing. It is announced from a status region of its own, which is
|
|
13
13
|
* rendered empty and filled a frame after the view appears. Screen readers read
|
|
14
|
-
* a region that arrives with its text already in it inconsistently.
|
|
14
|
+
* a region that arrives with its text already in it inconsistently. For the
|
|
15
|
+
* seven seconds the region holds its copy, the heading and the message are
|
|
16
|
+
* hidden from screen readers, so the words are in the page once.
|
|
15
17
|
*
|
|
16
18
|
* Every region is a bare slot. There is no `empty-state-heading` or
|
|
17
19
|
* `empty-state-actions` element: assign your own heading and actions to the
|
|
18
20
|
* slots.
|
|
19
21
|
*
|
|
22
|
+
* **Or give the heading as words.** `heading` draws them in a `heading` part
|
|
23
|
+
* that is a heading at `heading-level`, 3 where it is not set, so a page
|
|
24
|
+
* rendering from data or on a server gets a heading a reader finds in the
|
|
25
|
+
* outline without writing the element. A heading slotted in replaces it.
|
|
26
|
+
*
|
|
20
27
|
* @since 0.1.0
|
|
21
28
|
* @status stable
|
|
22
29
|
* @category feedback
|
|
@@ -25,12 +32,27 @@ import { type TemplateResult } from 'lit';
|
|
|
25
32
|
*
|
|
26
33
|
* @slot - The message: why the region is empty, and what to do about it.
|
|
27
34
|
* @slot actions - The action that would put something in the region.
|
|
28
|
-
* @slot heading - The heading, which names what is missing. Slot a heading element, such as an `<h3>`, so a reader can find it in the page's outline.
|
|
35
|
+
* @slot heading - The heading, which names what is missing. Slot a heading element, such as an `<h3>`, so a reader can find it in the page's outline. Replaces the one `heading` draws.
|
|
29
36
|
* @slot icon - An icon above the heading.
|
|
30
37
|
*
|
|
38
|
+
* @csspart heading - The heading `heading` draws, a heading at `heading-level`. Drawn only while `heading` holds words and nothing is slotted into `heading`.
|
|
31
39
|
* @csspart live - A copy of the heading and the message, in a live region that screen readers announce when the view appears. Visually hidden in the styled tier.
|
|
32
40
|
*/
|
|
33
41
|
export declare class HelixHeadlessEmpty extends HelixElement {
|
|
42
|
+
/**
|
|
43
|
+
* The heading as words, such as "No results", drawn as a heading when
|
|
44
|
+
* nothing is slotted into `heading`.
|
|
45
|
+
*
|
|
46
|
+
* Absent draws none, and the `heading` slot is the only heading.
|
|
47
|
+
*/
|
|
48
|
+
heading: string;
|
|
49
|
+
/**
|
|
50
|
+
* The level of the heading `heading` draws, from 1 to 6.
|
|
51
|
+
*
|
|
52
|
+
* Absent is 3, the level of a heading inside a page's section. Set it to fit
|
|
53
|
+
* the outline the empty view sits in. A slotted heading keeps its own.
|
|
54
|
+
*/
|
|
55
|
+
headingLevel?: number;
|
|
34
56
|
/**
|
|
35
57
|
* Whether the state is announced when it appears.
|
|
36
58
|
*
|
|
@@ -40,6 +62,16 @@ export declare class HelixHeadlessEmpty extends HelixElement {
|
|
|
40
62
|
*/
|
|
41
63
|
noAnnounce: boolean;
|
|
42
64
|
protected readonly arrival: ArrivalController;
|
|
65
|
+
/**
|
|
66
|
+
* The `heading` slot, with the heading `heading` draws as its fallback, so
|
|
67
|
+
* one slotted in replaces it; no fallback while `heading` holds no words.
|
|
68
|
+
*
|
|
69
|
+
* A method, so a tier above can draw its own, as the slot lets a page.
|
|
70
|
+
*
|
|
71
|
+
* @param hidden Whether the live copy holds the heading's words, which
|
|
72
|
+
* hides them from readers until it empties.
|
|
73
|
+
*/
|
|
74
|
+
protected renderHeading(hidden: boolean): TemplateResult;
|
|
43
75
|
protected render(): TemplateResult;
|
|
44
76
|
}
|
|
45
77
|
declare global {
|
|
@@ -4,29 +4,51 @@ 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 { ArrivalController, customElement, HelixElement, slottedWords, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { ArrivalController, customElement, HelixElement, headingLevel, slottedWords, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessEmpty = class HelixHeadlessEmpty extends HelixElement {
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
|
+
this.heading = '';
|
|
13
14
|
this.noAnnounce = false;
|
|
14
15
|
this.arrival = new ArrivalController(this, {
|
|
15
16
|
arriving: () => !this.serverRendered && document.readyState === 'complete',
|
|
16
|
-
text: () => slottedWords(this, ['heading', ''])
|
|
17
|
+
text: () => [slottedWords(this, ['heading']) || this.heading.trim(), slottedWords(this, [''])]
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.join(' '),
|
|
17
20
|
});
|
|
18
21
|
}
|
|
22
|
+
renderHeading(hidden) {
|
|
23
|
+
return html `<slot
|
|
24
|
+
aria-hidden=${hidden ? 'true' : nothing}
|
|
25
|
+
name="heading"
|
|
26
|
+
@slotchange=${() => this.arrival.say()}
|
|
27
|
+
>${this.heading.trim()
|
|
28
|
+
? html `<div aria-level=${headingLevel(this.headingLevel)} part="heading" role="heading">
|
|
29
|
+
${this.heading}
|
|
30
|
+
</div>`
|
|
31
|
+
: nothing}</slot
|
|
32
|
+
>`;
|
|
33
|
+
}
|
|
19
34
|
render() {
|
|
20
35
|
const say = () => this.arrival.say();
|
|
36
|
+
const held = this.arrival.said !== '' && !this.noAnnounce;
|
|
21
37
|
return html `<slot name="icon"></slot>
|
|
22
|
-
|
|
23
|
-
<slot @slotchange=${say}></slot>
|
|
38
|
+
${this.renderHeading(held)}
|
|
39
|
+
<slot aria-hidden=${held ? 'true' : nothing} @slotchange=${say}></slot>
|
|
24
40
|
<slot name="actions"></slot>
|
|
25
41
|
${this.noAnnounce
|
|
26
42
|
? nothing
|
|
27
43
|
: html `<span part="live" role="status">${this.arrival.said}</span>`}`;
|
|
28
44
|
}
|
|
29
45
|
};
|
|
46
|
+
__decorate([
|
|
47
|
+
property()
|
|
48
|
+
], HelixHeadlessEmpty.prototype, "heading", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
property({ attribute: 'heading-level', type: Number })
|
|
51
|
+
], HelixHeadlessEmpty.prototype, "headingLevel", void 0);
|
|
30
52
|
__decorate([
|
|
31
53
|
property({ attribute: 'no-announce', reflect: true, type: Boolean })
|
|
32
54
|
], HelixHeadlessEmpty.prototype, "noAnnounce", void 0);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { type FileStatus } from '../status.js';
|
|
4
|
+
export type { FileStatus } from '../status.js';
|
|
3
5
|
import '../../tag/index.js';
|
|
4
6
|
declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
5
7
|
/**
|
|
@@ -20,7 +22,22 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
20
22
|
* is screened: `accept`, `max-file-size`, `max-files` and your own `validate`
|
|
21
23
|
* can refuse it. A refused file is left out, `helix-reject` lists each one with
|
|
22
24
|
* its reason, and a reader hears `rejected-text` with the names filled in.
|
|
23
|
-
* `
|
|
25
|
+
* A reader also hears `added-text` for the files a drop or a paste adds, and
|
|
26
|
+
* `removed-text` for a file a remove button takes out, since neither moves
|
|
27
|
+
* focus or says anything on its own. `directory` asks the picker for a folder. `transformFiles` changes the files
|
|
28
|
+
* a field takes before it holds them, such as shrinking an image.
|
|
29
|
+
*
|
|
30
|
+
* Each chosen file is a row: its name, its size and type as tags, and a
|
|
31
|
+
* remove button. `renderFile` draws the row's details your own way, and the
|
|
32
|
+
* `remove-icon` slot replaces the button's icon.
|
|
33
|
+
*
|
|
34
|
+
* **Keyboard.** The input is the tab stop, and each file's remove button is
|
|
35
|
+
* one more.
|
|
36
|
+
*
|
|
37
|
+
* | Key | What it does |
|
|
38
|
+
* |---|---|
|
|
39
|
+
* | Enter, Space | On the input, opens the picker. On a remove button, removes that file and moves focus to the button of the file in its place, or back to the input. |
|
|
40
|
+
* | Control+V, Command+V | Takes files from the clipboard, as a drop does. |
|
|
24
41
|
*
|
|
25
42
|
* @since 0.1.0
|
|
26
43
|
* @status stable
|
|
@@ -31,6 +48,7 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
31
48
|
* @slot feedback - The message that says what is wrong with the chosen files.
|
|
32
49
|
* @slot hint - Help under the field.
|
|
33
50
|
* @slot label - The label, for content richer than the `label` text.
|
|
51
|
+
* @slot remove-icon - The icon on each file's remove button, in place of the bin. Each button shows a copy.
|
|
34
52
|
* @slot trigger - The content that opens the picker when pressed.
|
|
35
53
|
*
|
|
36
54
|
* @event {Event} change - Fired after the value changes.
|
|
@@ -43,6 +61,9 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
43
61
|
* @csspart feedback - The message that says what is wrong.
|
|
44
62
|
* @csspart field - The box you press or drop files on.
|
|
45
63
|
* @csspart file - One chosen file.
|
|
64
|
+
* @csspart file-done - A file whose upload `setFileStatus` says is done. Set together with `file`.
|
|
65
|
+
* @csspart file-error - A file whose upload `setFileStatus` says failed. Set together with `file`.
|
|
66
|
+
* @csspart file-uploading - A file whose upload `setFileStatus` says is under way. Set together with `file`.
|
|
46
67
|
* @csspart hint - Help under the field, while nothing is wrong.
|
|
47
68
|
* @csspart kind - A file's type.
|
|
48
69
|
* @csspart kind-cell - The grid cell around the tag, rendered only when the tag sits in a `Tag.Group`.
|
|
@@ -53,9 +74,10 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
53
74
|
* @csspart kind-start - The category before the label.
|
|
54
75
|
* @csspart label - The label above the field.
|
|
55
76
|
* @csspart list - The chosen files.
|
|
56
|
-
* @csspart live - The live region that says `rejected-text
|
|
77
|
+
* @csspart live - The live region that says `added-text`, `rejected-text`, and `removed-text`. It is rendered from the first time it has something to say.
|
|
57
78
|
* @csspart meta - The row that holds a file's size and type.
|
|
58
79
|
* @csspart name - A file's name.
|
|
80
|
+
* @csspart progress - A file's upload bar, a `<progress>`, while `setFileStatus` gives it a measure or says it is under way.
|
|
59
81
|
* @csspart remove - The control that removes a file.
|
|
60
82
|
* @csspart size - A file's size.
|
|
61
83
|
* @csspart size-cell - The grid cell around the tag, rendered only when the tag sits in a `Tag.Group`.
|
|
@@ -64,8 +86,12 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
64
86
|
* @csspart size-label - The label, trimmed to its capitals and baseline.
|
|
65
87
|
* @csspart size-link - The link around the label, when the tag has an `href`.
|
|
66
88
|
* @csspart size-start - The category before the label.
|
|
89
|
+
* @csspart status - How a file's upload is going, from `setFileStatus`: the bar and the words.
|
|
90
|
+
* @csspart status-text - The words `setFileStatus` gives a file, such as the reason it failed.
|
|
67
91
|
* @csspart trigger - The label that opens the picker.
|
|
68
92
|
*
|
|
93
|
+
* @cssstate dropping - Files are being dragged over the field.
|
|
94
|
+
* @cssstate has-files - The field holds at least one file.
|
|
69
95
|
* @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
|
|
70
96
|
*/
|
|
71
97
|
export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base {
|
|
@@ -77,6 +103,11 @@ export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base
|
|
|
77
103
|
* filter is the only check the platform makes and a drop never meets it.
|
|
78
104
|
*/
|
|
79
105
|
accept: string;
|
|
106
|
+
/**
|
|
107
|
+
* What a reader hears when a drop or a paste adds files, with `{names}` and
|
|
108
|
+
* `{count}` filled in.
|
|
109
|
+
*/
|
|
110
|
+
addedText: string;
|
|
80
111
|
/**
|
|
81
112
|
* Which camera or microphone a mobile picker should offer, if any.
|
|
82
113
|
*/
|
|
@@ -105,11 +136,20 @@ export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base
|
|
|
105
136
|
* Whether more than one file can be chosen.
|
|
106
137
|
*/
|
|
107
138
|
multiple: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* The name of a file's progress bar, read by screen readers, with `{name}`
|
|
141
|
+
* filled in. A label with no `{name}` has it added after it.
|
|
142
|
+
*/
|
|
143
|
+
progressLabel: string;
|
|
108
144
|
/**
|
|
109
145
|
* What a reader hears when files are refused, with `{count}` and `{names}`
|
|
110
146
|
* filled in.
|
|
111
147
|
*/
|
|
112
148
|
rejectedText: string;
|
|
149
|
+
/**
|
|
150
|
+
* What a reader hears when a file is removed, with `{name}` filled in.
|
|
151
|
+
*/
|
|
152
|
+
removedText: string;
|
|
113
153
|
/**
|
|
114
154
|
* The accessible name of the control that removes a file. `{name}` is
|
|
115
155
|
* replaced with the file's name.
|
|
@@ -119,6 +159,19 @@ export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base
|
|
|
119
159
|
* `{name}` has it added after it.
|
|
120
160
|
*/
|
|
121
161
|
removeLabel: string;
|
|
162
|
+
/**
|
|
163
|
+
* Draws a file's row in place of its name, size, and type: a Lit template, a
|
|
164
|
+
* string, or a DOM node, given the file and its place in the list. The
|
|
165
|
+
* remove button stays beside it.
|
|
166
|
+
*/
|
|
167
|
+
renderFile?: (file: File, index: number) => unknown;
|
|
168
|
+
/**
|
|
169
|
+
* Your own step between taking files and holding them, such as shrinking an
|
|
170
|
+
* image, as Zag's file upload `transformFiles`. It is given the files taken
|
|
171
|
+
* from one pick, drop, or paste and returns the files to hold, or a promise
|
|
172
|
+
* of them. A promise that rejects refuses those files, with its message.
|
|
173
|
+
*/
|
|
174
|
+
transformFiles?: (files: File[]) => File[] | Promise<File[]>;
|
|
122
175
|
/**
|
|
123
176
|
* The trigger's text when nothing is slotted into it.
|
|
124
177
|
*/
|
|
@@ -128,15 +181,49 @@ export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base
|
|
|
128
181
|
* nothing to take it. A property, since a function cannot be an attribute.
|
|
129
182
|
*/
|
|
130
183
|
validate?: (file: File) => string | null | undefined;
|
|
131
|
-
/** The live region, rendered from the first
|
|
184
|
+
/** The live region, rendered from the first time it has something to say. */
|
|
132
185
|
private readonly status;
|
|
186
|
+
/** What the page has said of each file's upload, by file. */
|
|
187
|
+
private readonly statuses;
|
|
188
|
+
/**
|
|
189
|
+
* Shows how a file's upload is going, in its row: a bar for `progress`,
|
|
190
|
+
* from 0 to 1, or a bar without a measure while `state` is `uploading`, and
|
|
191
|
+
* `text` beside it. `state` names the row `file-uploading`, `file-done` or
|
|
192
|
+
* `file-error` beside `file`, and a reader hears `text` when the state
|
|
193
|
+
* becomes `done` or `error`. `null` clears it.
|
|
194
|
+
*
|
|
195
|
+
* The field uploads nothing, as Zag's file upload does not: your page sends
|
|
196
|
+
* the file and says here how it is going.
|
|
197
|
+
*/
|
|
198
|
+
setFileStatus(file: File, status: FileStatus | null): void;
|
|
133
199
|
/**
|
|
134
200
|
* Screens arriving files and commits what is taken, after the files the
|
|
135
|
-
* field keeps
|
|
201
|
+
* field keeps, through `transformFiles` where it is set.
|
|
136
202
|
*/
|
|
137
203
|
private take;
|
|
138
|
-
/**
|
|
139
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Commits what an arrival leaves, sends `helix-reject` for what it refused,
|
|
206
|
+
* and says both.
|
|
207
|
+
*
|
|
208
|
+
* Nothing taken and nothing moved, as when every dropped file is refused, is
|
|
209
|
+
* no change to announce. A pick is the platform's own `change`, relayed
|
|
210
|
+
* whatever it holds, and the picker itself tells a reader what was chosen,
|
|
211
|
+
* so `added-text` is said for a drop or a paste only.
|
|
212
|
+
*/
|
|
213
|
+
private finish;
|
|
214
|
+
/**
|
|
215
|
+
* A sentence about some files, with `{count}` and `{names}` filled in.
|
|
216
|
+
*
|
|
217
|
+
* The names as the page's language lists them, which in English is the comma
|
|
218
|
+
* list it always was: `unit` and `short` join with commas and no "and". The
|
|
219
|
+
* count is written as the language writes a number.
|
|
220
|
+
*/
|
|
221
|
+
private listed;
|
|
222
|
+
/** The element slotted into `remove-icon`, one copy per row's remove button. */
|
|
223
|
+
private readonly removeIcon;
|
|
224
|
+
private readonly handleRemoveIcon;
|
|
225
|
+
/** The icon on one row's remove button: a copy of `remove-icon`, or the bin. */
|
|
226
|
+
private removeMark;
|
|
140
227
|
/** Takes files pasted onto the field, as a drop takes them. */
|
|
141
228
|
private readonly handlePaste;
|
|
142
229
|
/**
|
|
@@ -279,6 +366,11 @@ export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base
|
|
|
279
366
|
* renders the styled one from the same template.
|
|
280
367
|
*/
|
|
281
368
|
protected renderMeta(file: File): TemplateResult;
|
|
369
|
+
/**
|
|
370
|
+
* How a file's upload is going, from `setFileStatus`, behind a seam a tier
|
|
371
|
+
* can move: a `<progress>` named by `progress-label` and the status words.
|
|
372
|
+
*/
|
|
373
|
+
protected renderFileStatus(file: File): TemplateResult | typeof nothing;
|
|
282
374
|
protected render(): TemplateResult;
|
|
283
375
|
}
|
|
284
376
|
declare global {
|
|
@@ -286,4 +378,3 @@ declare global {
|
|
|
286
378
|
'helix-headless-file-input': HelixHeadlessFileInput;
|
|
287
379
|
}
|
|
288
380
|
}
|
|
289
|
-
export {};
|
|
@@ -4,12 +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 { AriaForwardController, customElement, drawIcon, drawStatus, fillTemplate, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, HelixRejectEvent, MixinField, requestChange, restoreValue, StatusController, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, customElement, drawIcon, drawStatus, fillTemplate, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, HelixRejectEvent, MixinField, requestChange, restoreValue, SlottedGlyph, StatusController, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { trash } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { html } from 'lit/static-html.js';
|
|
12
12
|
import { screenFiles } from '../screen.js';
|
|
13
|
+
import { barOf, saysStatus } from '../status.js';
|
|
13
14
|
import '../../tag/index.js';
|
|
14
15
|
const named = (label, name) => label.includes('{name}') ? fillTemplate(label, { name }) : `${label} ${name}`;
|
|
15
16
|
const size = (bytes, locale) => {
|
|
@@ -42,20 +43,29 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
42
43
|
target: () => this.partNamed('control'),
|
|
43
44
|
});
|
|
44
45
|
this.accept = '';
|
|
46
|
+
this.addedText = 'Added: {names}';
|
|
45
47
|
this.directory = false;
|
|
46
48
|
this.locale = '';
|
|
47
49
|
this.multiple = false;
|
|
50
|
+
this.progressLabel = 'Uploading {name}';
|
|
48
51
|
this.rejectedText = 'Not added: {names}';
|
|
52
|
+
this.removedText = 'Removed: {name}';
|
|
49
53
|
this.removeLabel = 'Remove {name}';
|
|
50
54
|
this.triggerLabel = 'Choose files';
|
|
51
55
|
this.status = new StatusController(this);
|
|
56
|
+
this.statuses = new WeakMap();
|
|
57
|
+
this.removeIcon = new SlottedGlyph();
|
|
58
|
+
this.handleRemoveIcon = (event) => {
|
|
59
|
+
this.removeIcon.read(event.target);
|
|
60
|
+
this.requestUpdate();
|
|
61
|
+
};
|
|
52
62
|
this.handlePaste = (event) => {
|
|
53
63
|
const pasted = [...(event.clipboardData?.files ?? [])];
|
|
54
64
|
if (this.isDisabled || pasted.length === 0) {
|
|
55
65
|
return;
|
|
56
66
|
}
|
|
57
67
|
event.preventDefault();
|
|
58
|
-
this.take(pasted, this.
|
|
68
|
+
this.take(pasted, this.files);
|
|
59
69
|
};
|
|
60
70
|
this.dropping = false;
|
|
61
71
|
this.committed = [];
|
|
@@ -84,7 +94,7 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
84
94
|
if (dropped.length === 0) {
|
|
85
95
|
return;
|
|
86
96
|
}
|
|
87
|
-
this.take(dropped, this.
|
|
97
|
+
this.take(dropped, this.files);
|
|
88
98
|
};
|
|
89
99
|
this.handleRemove = (event) => {
|
|
90
100
|
const at = Number(event.currentTarget.dataset.at);
|
|
@@ -98,6 +108,19 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
98
108
|
});
|
|
99
109
|
};
|
|
100
110
|
}
|
|
111
|
+
setFileStatus(file, status) {
|
|
112
|
+
const was = this.statuses.get(file);
|
|
113
|
+
if (status) {
|
|
114
|
+
this.statuses.set(file, status);
|
|
115
|
+
if (saysStatus(status, was)) {
|
|
116
|
+
this.status.say(status.text ?? '');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.statuses.delete(file);
|
|
121
|
+
}
|
|
122
|
+
this.requestUpdate();
|
|
123
|
+
}
|
|
101
124
|
take(arriving, keeping, picked = false) {
|
|
102
125
|
const { kept, refused } = screenFiles(arriving, keeping, {
|
|
103
126
|
accept: this.accept,
|
|
@@ -106,21 +129,45 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
106
129
|
multiple: this.multiple || picked,
|
|
107
130
|
validate: this.validate,
|
|
108
131
|
});
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
132
|
+
const taken = kept.filter((file) => !keeping.includes(file));
|
|
133
|
+
const transform = this.transformFiles;
|
|
134
|
+
if (!transform || taken.length === 0) {
|
|
135
|
+
this.finish(kept, taken, refused, picked);
|
|
136
|
+
return;
|
|
112
137
|
}
|
|
138
|
+
const held = kept.filter((file) => keeping.includes(file));
|
|
139
|
+
Promise.resolve()
|
|
140
|
+
.then(() => transform(taken))
|
|
141
|
+
.then((made) => this.finish([...held, ...made], made, refused, picked), (error) => {
|
|
142
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
143
|
+
this.finish(held, [], [...refused, ...taken.map((file) => ({ file, message, reason: 'invalid' }))], picked);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
finish(next, added, refused, picked) {
|
|
147
|
+
const same = (one, two) => one.length === two.length && one.every((file, at) => file === two[at]);
|
|
148
|
+
const moved = picked || !(same(next, this.committed) && same(next, this.files));
|
|
149
|
+
const applied = moved && this.commit(next);
|
|
113
150
|
if (refused.length > 0) {
|
|
114
|
-
this.
|
|
151
|
+
this.dispatchEvent(new HelixRejectEvent({ files: refused }));
|
|
152
|
+
}
|
|
153
|
+
const words = [
|
|
154
|
+
applied && !picked && added.length > 0 ? this.listed(this.addedText, added) : '',
|
|
155
|
+
refused.length > 0
|
|
156
|
+
? this.listed(this.rejectedText, refused.map((one) => one.file))
|
|
157
|
+
: '',
|
|
158
|
+
].filter((one) => one !== '');
|
|
159
|
+
if (words.length > 0) {
|
|
160
|
+
this.status.say(words.join(' '));
|
|
115
161
|
}
|
|
116
162
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
names: new Intl.ListFormat(this.lang || undefined, { style: 'short', type: 'unit' }).format(refused.map((one) => one.file.name)),
|
|
163
|
+
listed(sentence, files) {
|
|
164
|
+
return fillTemplate(sentence, {
|
|
165
|
+
count: formatNumbers(this.lang)(files.length),
|
|
166
|
+
names: new Intl.ListFormat(this.lang || undefined, { style: 'short', type: 'unit' }).format(files.map((file) => file.name)),
|
|
122
167
|
});
|
|
123
|
-
|
|
168
|
+
}
|
|
169
|
+
removeMark(at) {
|
|
170
|
+
return this.removeIcon.copyFor(at) ?? drawIcon(trash);
|
|
124
171
|
}
|
|
125
172
|
get files() {
|
|
126
173
|
return [...(this.control?.files ?? [])];
|
|
@@ -132,12 +179,15 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
132
179
|
this.commit([]);
|
|
133
180
|
}
|
|
134
181
|
removeAt(at) {
|
|
135
|
-
this.
|
|
182
|
+
const gone = this.files[at];
|
|
183
|
+
if (gone && this.commit(this.files.filter((_, index) => index !== at))) {
|
|
184
|
+
this.status.say(fillTemplate(this.removedText, { name: gone.name }));
|
|
185
|
+
}
|
|
136
186
|
}
|
|
137
187
|
commit(next) {
|
|
138
188
|
const control = this.control;
|
|
139
189
|
if (!control) {
|
|
140
|
-
return;
|
|
190
|
+
return false;
|
|
141
191
|
}
|
|
142
192
|
const previous = this.committed;
|
|
143
193
|
const applied = requestChange({
|
|
@@ -152,6 +202,7 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
152
202
|
if (!applied) {
|
|
153
203
|
this.put(control, previous);
|
|
154
204
|
}
|
|
205
|
+
return applied;
|
|
155
206
|
}
|
|
156
207
|
put(control, files) {
|
|
157
208
|
if (files.length === 0) {
|
|
@@ -197,6 +248,8 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
197
248
|
updated(changed) {
|
|
198
249
|
super.updated(changed);
|
|
199
250
|
this.sync();
|
|
251
|
+
this.toggleState('dropping', this.dropping);
|
|
252
|
+
this.toggleState('has-files', this.files.length > 0);
|
|
200
253
|
}
|
|
201
254
|
focus(options) {
|
|
202
255
|
this.control?.focus(options);
|
|
@@ -215,6 +268,23 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
215
268
|
part="kind"
|
|
216
269
|
exportparts="cell: kind-cell, dismiss: kind-dismiss, dismiss-mark: kind-dismiss-mark, label: kind-label, link: kind-link, start: kind-start">${kind(file)}</${this.tag('tag')}>`;
|
|
217
270
|
}
|
|
271
|
+
renderFileStatus(file) {
|
|
272
|
+
const status = this.statuses.get(file);
|
|
273
|
+
if (!status) {
|
|
274
|
+
return nothing;
|
|
275
|
+
}
|
|
276
|
+
const bar = barOf(status);
|
|
277
|
+
return html `<span part="status"
|
|
278
|
+
>${bar === undefined
|
|
279
|
+
? nothing
|
|
280
|
+
: html `<progress
|
|
281
|
+
part="progress"
|
|
282
|
+
max="1"
|
|
283
|
+
value=${bar === 'unmeasured' ? nothing : bar}
|
|
284
|
+
aria-label=${named(this.progressLabel, file.name)}
|
|
285
|
+
></progress>`}${status.text ? html `<span part="status-text">${status.text}</span>` : nothing}</span
|
|
286
|
+
>`;
|
|
287
|
+
}
|
|
218
288
|
render() {
|
|
219
289
|
const files = this.files;
|
|
220
290
|
return html `${this.renderLabel()}
|
|
@@ -246,6 +316,9 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
246
316
|
<slot name="trigger">${this.triggerLabel}</slot>
|
|
247
317
|
</label>
|
|
248
318
|
</div>
|
|
319
|
+
<!-- Hidden, because this is where the icon arrives: each remove button
|
|
320
|
+
shows a copy. -->
|
|
321
|
+
<slot name="remove-icon" hidden @slotchange=${this.handleRemoveIcon}></slot>
|
|
249
322
|
<!-- The hint sits under the field and the list goes last, which is the
|
|
250
323
|
one ordering decision this component makes differently from the way it
|
|
251
324
|
reads. Reasoning above renderMeta. -->
|
|
@@ -254,12 +327,21 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
254
327
|
${files.length === 0
|
|
255
328
|
? nothing
|
|
256
329
|
: html `<ul part="list">
|
|
257
|
-
${files.map((file, at) =>
|
|
330
|
+
${files.map((file, at) => {
|
|
331
|
+
const state = this.statuses.get(file)?.state;
|
|
332
|
+
const done = state === 'done';
|
|
333
|
+
const failed = state === 'error';
|
|
334
|
+
const sending = state === 'uploading';
|
|
335
|
+
return html `<li
|
|
336
|
+
part="file${done ? ' file-done' : ''}${failed ? ' file-error' : ''}${sending ? ' file-uploading' : ''}"
|
|
337
|
+
>
|
|
258
338
|
<span part="detail">
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
339
|
+
${this.renderFile
|
|
340
|
+
? this.renderFile(file, at)
|
|
341
|
+
: html `<span part="name">${file.name}</span>
|
|
342
|
+
<span part="meta">
|
|
343
|
+
${this.renderMeta(file)}
|
|
344
|
+
</span>`}${this.renderFileStatus(file)}
|
|
263
345
|
</span>
|
|
264
346
|
<button
|
|
265
347
|
part="remove"
|
|
@@ -269,15 +351,19 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
269
351
|
?disabled=${this.isDisabled}
|
|
270
352
|
@click=${this.handleRemove}
|
|
271
353
|
>
|
|
272
|
-
${
|
|
354
|
+
${this.removeMark(at)}
|
|
273
355
|
</button>
|
|
274
|
-
</li
|
|
356
|
+
</li>`;
|
|
357
|
+
})}
|
|
275
358
|
</ul>`}`;
|
|
276
359
|
}
|
|
277
360
|
};
|
|
278
361
|
__decorate([
|
|
279
362
|
property()
|
|
280
363
|
], HelixHeadlessFileInput.prototype, "accept", void 0);
|
|
364
|
+
__decorate([
|
|
365
|
+
property({ attribute: 'added-text' })
|
|
366
|
+
], HelixHeadlessFileInput.prototype, "addedText", void 0);
|
|
281
367
|
__decorate([
|
|
282
368
|
property()
|
|
283
369
|
], HelixHeadlessFileInput.prototype, "capture", void 0);
|
|
@@ -296,12 +382,24 @@ __decorate([
|
|
|
296
382
|
__decorate([
|
|
297
383
|
property({ reflect: true, type: Boolean })
|
|
298
384
|
], HelixHeadlessFileInput.prototype, "multiple", void 0);
|
|
385
|
+
__decorate([
|
|
386
|
+
property({ attribute: 'progress-label' })
|
|
387
|
+
], HelixHeadlessFileInput.prototype, "progressLabel", void 0);
|
|
299
388
|
__decorate([
|
|
300
389
|
property({ attribute: 'rejected-text' })
|
|
301
390
|
], HelixHeadlessFileInput.prototype, "rejectedText", void 0);
|
|
391
|
+
__decorate([
|
|
392
|
+
property({ attribute: 'removed-text' })
|
|
393
|
+
], HelixHeadlessFileInput.prototype, "removedText", void 0);
|
|
302
394
|
__decorate([
|
|
303
395
|
property({ attribute: 'remove-label' })
|
|
304
396
|
], HelixHeadlessFileInput.prototype, "removeLabel", void 0);
|
|
397
|
+
__decorate([
|
|
398
|
+
property({ attribute: false })
|
|
399
|
+
], HelixHeadlessFileInput.prototype, "renderFile", void 0);
|
|
400
|
+
__decorate([
|
|
401
|
+
property({ attribute: false })
|
|
402
|
+
], HelixHeadlessFileInput.prototype, "transformFiles", void 0);
|
|
305
403
|
__decorate([
|
|
306
404
|
property({ attribute: 'trigger-label' })
|
|
307
405
|
], HelixHeadlessFileInput.prototype, "triggerLabel", void 0);
|
|
@@ -27,7 +27,8 @@ export declare const accepts: (file: File, accept: string) => boolean;
|
|
|
27
27
|
/**
|
|
28
28
|
* Screens arriving files against the rules, given the files the field keeps.
|
|
29
29
|
* `kept` is what the field holds afterward: the files it keeps and the
|
|
30
|
-
* arrivals it took, or for a single-file field the last arrival it took
|
|
30
|
+
* arrivals it took, or for a single-file field the last arrival it took, and
|
|
31
|
+
* the file it keeps when it took none.
|
|
31
32
|
*/
|
|
32
33
|
export declare const screenFiles: (arriving: File[], keeping: File[], rules: ScreenRules) => {
|
|
33
34
|
kept: File[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How one file's upload is going, as a page reports it to File Input. The
|
|
3
|
+
* field does not upload anything: the page does, and says how it is going.
|
|
4
|
+
*/
|
|
5
|
+
export interface FileStatus {
|
|
6
|
+
/** How much is done, from 0 to 1. Left out, the bar moves without a measure while `state` is `uploading`. */
|
|
7
|
+
readonly progress?: number | undefined;
|
|
8
|
+
/** Where the upload is: under way, finished, or failed. */
|
|
9
|
+
readonly state?: 'done' | 'error' | 'uploading' | undefined;
|
|
10
|
+
/** Words beside the bar, such as "Uploaded" or the reason it failed. */
|
|
11
|
+
readonly text?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The bar's value, held between 0 and 1, or nothing for a bar without a
|
|
15
|
+
* measure, and no bar at all for a status that is neither measured nor under
|
|
16
|
+
* way.
|
|
17
|
+
*/
|
|
18
|
+
export declare const barOf: (status: FileStatus) => number | 'unmeasured' | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a new status is worth saying: a finish or a failure with words, the
|
|
21
|
+
* first time the file reaches it. Progress is shown and not said, since a
|
|
22
|
+
* reader hearing every percent hears nothing else.
|
|
23
|
+
*/
|
|
24
|
+
export declare const saysStatus: (next: FileStatus, was: FileStatus | undefined) => boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const barOf = (status) => {
|
|
2
|
+
const { progress, state } = status;
|
|
3
|
+
if (typeof progress === 'number' && Number.isFinite(progress)) {
|
|
4
|
+
return Math.min(1, Math.max(0, progress));
|
|
5
|
+
}
|
|
6
|
+
return state === 'uploading' ? 'unmeasured' : undefined;
|
|
7
|
+
};
|
|
8
|
+
export const saysStatus = (next, was) => Boolean(next.text) &&
|
|
9
|
+
(next.state === 'done' || next.state === 'error') &&
|
|
10
|
+
next.state !== was?.state;
|