@fusion.dev/helix-headless 0.142.1 → 0.144.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 +25381 -1202
- package/dist/accordion/item/accordion-item.d.ts +38 -2
- package/dist/accordion/item/accordion-item.js +38 -6
- package/dist/accordion/root/accordion-root.d.ts +23 -1
- package/dist/accordion/root/accordion-root.js +39 -3
- package/dist/announcement/root/announcement-root.d.ts +11 -7
- package/dist/announcement/root/announcement-root.js +1 -1
- package/dist/app-header/root/app-header-root.d.ts +21 -0
- package/dist/app-header/root/app-header-root.js +31 -5
- package/dist/area-chart/root/area-chart-root.d.ts +12 -4
- package/dist/area-chart/root/area-chart-root.js +39 -11
- package/dist/avatar/group/avatar-group.d.ts +24 -3
- package/dist/avatar/group/avatar-group.js +34 -2
- package/dist/avatar/root/avatar-root.d.ts +17 -1
- package/dist/avatar/root/avatar-root.js +31 -10
- package/dist/badge/root/badge-root.d.ts +12 -0
- package/dist/badge/root/badge-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +30 -5
- package/dist/bar-chart/root/bar-chart-root.js +58 -21
- package/dist/blockquote/root/blockquote-root.d.ts +12 -7
- package/dist/blockquote/root/blockquote-root.js +6 -4
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
- package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
- package/dist/button/root/button-root.d.ts +84 -1
- package/dist/button/root/button-root.js +81 -3
- package/dist/callout/root/callout-root.d.ts +32 -6
- package/dist/callout/root/callout-root.js +26 -7
- package/dist/canvas/root/canvas-root.d.ts +1 -0
- package/dist/canvas/root/canvas-root.js +10 -1
- package/dist/card/root/card-root.d.ts +30 -1
- package/dist/card/root/card-root.js +38 -5
- package/dist/carousel/root/carousel-root.d.ts +47 -5
- package/dist/carousel/root/carousel-root.js +53 -21
- package/dist/chat/composer/chat-composer.d.ts +13 -11
- package/dist/chat/composer/chat-composer.js +6 -12
- package/dist/chat/message/chat-message.js +8 -1
- package/dist/chat/root/chat-root.d.ts +1 -0
- package/dist/chat/root/chat-root.js +2 -1
- package/dist/checkbox/root/checkbox-root.d.ts +7 -0
- package/dist/checkbox/root/checkbox-root.js +9 -3
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +116 -33
- package/dist/checkbox-group/root/checkbox-group-root.js +141 -44
- package/dist/code/root/code-root.d.ts +1 -1
- package/dist/code-block/lines.d.ts +13 -0
- package/dist/code-block/lines.js +2 -0
- package/dist/code-block/root/code-block-root.d.ts +49 -0
- package/dist/code-block/root/code-block-root.js +44 -3
- package/dist/color-input/root/color-input-root.d.ts +60 -2
- package/dist/color-input/root/color-input-root.js +55 -7
- package/dist/color-picker/channels.d.ts +26 -0
- package/dist/color-picker/channels.js +84 -0
- package/dist/color-picker/root/color-picker-root.d.ts +118 -12
- package/dist/color-picker/root/color-picker-root.js +183 -13
- package/dist/combobox/root/combobox-root.d.ts +126 -3
- package/dist/combobox/root/combobox-root.js +224 -21
- package/dist/command/root/command-root.d.ts +47 -10
- package/dist/command/root/command-root.js +45 -4
- package/dist/copy-button/from.d.ts +22 -0
- package/dist/copy-button/from.js +28 -0
- package/dist/copy-button/root/copy-button-root.d.ts +48 -7
- package/dist/copy-button/root/copy-button-root.js +54 -8
- package/dist/data-table/root/data-table-root.d.ts +164 -10
- package/dist/data-table/root/data-table-root.js +488 -57
- package/dist/date-input/root/date-input-root.d.ts +123 -9
- package/dist/date-input/root/date-input-root.js +147 -45
- package/dist/date-picker/root/date-picker-root.d.ts +229 -18
- package/dist/date-picker/root/date-picker-root.js +342 -46
- package/dist/dialog/description.d.ts +9 -0
- package/dist/dialog/description.js +14 -0
- package/dist/dialog/root/dialog-root.d.ts +101 -10
- package/dist/dialog/root/dialog-root.js +83 -4
- package/dist/donut-chart/root/donut-chart-root.d.ts +61 -16
- package/dist/donut-chart/root/donut-chart-root.js +48 -13
- package/dist/drawer/root/drawer-root.d.ts +93 -7
- package/dist/drawer/root/drawer-root.js +126 -5
- package/dist/drawer/swipe-start.d.ts +9 -0
- package/dist/drawer/swipe-start.js +12 -0
- package/dist/drilldown/item/drilldown-item.d.ts +16 -13
- package/dist/drilldown/item/drilldown-item.js +6 -2
- package/dist/drilldown/root/drilldown-root.d.ts +21 -5
- package/dist/drilldown/root/drilldown-root.js +26 -10
- package/dist/element-events.generated.js +42 -13
- package/dist/empty/root/empty-root.d.ts +1 -1
- package/dist/file-input/root/file-input-root.d.ts +65 -1
- package/dist/file-input/root/file-input-root.js +76 -12
- package/dist/file-input/screen.d.ts +35 -0
- package/dist/file-input/screen.js +49 -0
- package/dist/filter-input/menu/filter-menu.d.ts +9 -0
- package/dist/filter-input/menu/filter-menu.js +8 -0
- package/dist/filter-input/root/filter-input-root.d.ts +43 -6
- package/dist/filter-input/root/filter-input-root.js +89 -10
- package/dist/filter-input/suggest.d.ts +17 -0
- package/dist/filter-input/suggest.js +23 -0
- package/dist/format-date/options.d.ts +33 -0
- package/dist/format-date/options.js +42 -0
- package/dist/format-date/root/format-date-root.d.ts +62 -3
- package/dist/format-date/root/format-date-root.js +78 -37
- package/dist/graph/root/graph-root.d.ts +24 -3
- package/dist/graph/root/graph-root.js +66 -12
- package/dist/heatmap/root/buckets.d.ts +2 -1
- package/dist/heatmap/root/buckets.js +5 -1
- package/dist/heatmap/root/heatmap-root.d.ts +47 -9
- package/dist/heatmap/root/heatmap-root.js +46 -18
- package/dist/icon/index.d.ts +2 -0
- package/dist/icon/index.js +2 -0
- package/dist/icon/registry.d.ts +37 -0
- package/dist/icon/registry.js +83 -0
- package/dist/icon/root/icon-root.d.ts +53 -6
- package/dist/icon/root/icon-root.js +72 -4
- package/dist/icon/root/index.d.ts +2 -0
- package/dist/icon/root/index.js +2 -0
- package/dist/icon/set.d.ts +1 -0
- package/dist/icon/set.js +3 -0
- package/dist/icon-button/root/icon-button-root.d.ts +1 -1
- package/dist/image/root/image-root.d.ts +23 -2
- package/dist/image/root/image-root.js +23 -4
- package/dist/input/root/input-root.d.ts +62 -9
- package/dist/input/root/input-root.js +61 -5
- package/dist/kbd/root/kbd-root.d.ts +26 -11
- package/dist/kbd/root/kbd-root.js +35 -38
- package/dist/kbd/shortcut.d.ts +18 -0
- package/dist/kbd/shortcut.js +35 -0
- package/dist/legend/hidden-series.d.ts +8 -0
- package/dist/legend/hidden-series.js +13 -0
- package/dist/legend/root/legend-root.d.ts +63 -0
- package/dist/legend/root/legend-root.js +61 -7
- package/dist/lightbox/item/lightbox-item.d.ts +17 -1
- package/dist/lightbox/item/lightbox-item.js +10 -1
- package/dist/lightbox/root/lightbox-root.d.ts +77 -6
- package/dist/lightbox/root/lightbox-root.js +116 -5
- package/dist/line-chart/root/line-chart-root.d.ts +29 -4
- package/dist/line-chart/root/line-chart-root.js +58 -17
- package/dist/list/item/list-item.d.ts +11 -5
- package/dist/list/item/list-item.js +5 -6
- package/dist/listbox/range.d.ts +17 -0
- package/dist/listbox/range.js +5 -0
- package/dist/listbox/root/listbox-root.d.ts +184 -4
- package/dist/listbox/root/listbox-root.js +229 -23
- package/dist/loader/busy.d.ts +17 -0
- package/dist/loader/busy.js +24 -0
- package/dist/loader/root/loader-root.d.ts +37 -0
- package/dist/loader/root/loader-root.js +52 -3
- package/dist/map/root/map-root.d.ts +19 -4
- package/dist/map/root/map-root.js +36 -7
- package/dist/megamenu/root/megamenu-root.d.ts +10 -1
- package/dist/megamenu/root/megamenu-root.js +10 -1
- package/dist/menu/item/menu-item.d.ts +41 -12
- package/dist/menu/item/menu-item.js +46 -3
- package/dist/menu/root/menu-root.d.ts +32 -2
- package/dist/menu/root/menu-root.js +48 -8
- package/dist/meter/root/meter-root.d.ts +13 -0
- package/dist/meter/root/meter-root.js +24 -5
- package/dist/navigation/root/navigation-root.d.ts +10 -2
- package/dist/navigation/root/navigation-root.js +13 -2
- package/dist/notifications/feed-keys.d.ts +10 -0
- package/dist/notifications/feed-keys.js +14 -0
- package/dist/notifications/group/notification-group.d.ts +1 -0
- package/dist/notifications/notification/notification.d.ts +29 -0
- package/dist/notifications/notification/notification.js +51 -3
- package/dist/notifications/root/notifications-root.d.ts +49 -0
- package/dist/notifications/root/notifications-root.js +76 -2
- package/dist/number-input/root/number-input-root.d.ts +109 -7
- package/dist/number-input/root/number-input-root.js +109 -21
- package/dist/object-inspector/root/object-inspector-root.d.ts +49 -5
- package/dist/object-inspector/root/object-inspector-root.js +92 -12
- package/dist/option/root/option-root.d.ts +58 -6
- package/dist/option/root/option-root.js +35 -5
- package/dist/outline/root/outline-root.d.ts +13 -2
- package/dist/outline/root/outline-root.js +4 -2
- package/dist/pagination/root/pagination-root.d.ts +19 -1
- package/dist/pagination/root/pagination-root.js +49 -9
- package/dist/pagination/size/pagination-size.d.ts +13 -3
- package/dist/pagination/size/pagination-size.js +7 -0
- package/dist/pin-input/format.d.ts +7 -0
- package/dist/pin-input/format.js +16 -0
- package/dist/pin-input/root/pin-input-root.d.ts +37 -0
- package/dist/pin-input/root/pin-input-root.js +48 -7
- package/dist/popover/root/popover-root.d.ts +78 -3
- package/dist/popover/root/popover-root.js +74 -5
- package/dist/progress/root/progress-root.d.ts +23 -1
- package/dist/progress/root/progress-root.js +40 -10
- package/dist/qr-code/export.d.ts +31 -0
- package/dist/qr-code/export.js +10 -0
- package/dist/qr-code/root/qr-code-root.d.ts +45 -0
- package/dist/qr-code/root/qr-code-root.js +78 -3
- package/dist/radio/group/radio-group.d.ts +64 -0
- package/dist/radio/group/radio-group.js +66 -12
- package/dist/radio/root/radio-root.d.ts +8 -5
- package/dist/radio/root/radio-root.js +1 -2
- package/dist/rating/root/rating-root.d.ts +49 -1
- package/dist/rating/root/rating-root.js +69 -10
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
- package/dist/scatter-chart/root/scatter-chart-root.js +40 -14
- package/dist/select/root/select-root.d.ts +93 -3
- package/dist/select/root/select-root.js +111 -13
- package/dist/skeleton/root/skeleton-root.d.ts +39 -3
- package/dist/skeleton/root/skeleton-root.js +33 -4
- package/dist/skip-link/root/skip-link-root.d.ts +10 -0
- package/dist/skip-link/root/skip-link-root.js +15 -1
- package/dist/slider/root/slider-root.d.ts +59 -2
- package/dist/slider/root/slider-root.js +82 -8
- package/dist/sparkline/root/sparkline-root.d.ts +9 -10
- package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
- package/dist/speed-dial/item/speed-dial-item.js +7 -2
- package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
- package/dist/speed-dial/root/speed-dial-root.js +19 -5
- package/dist/splitter/root/splitter-root.d.ts +28 -6
- package/dist/splitter/root/splitter-root.js +35 -1
- package/dist/stat/root/stat-root.d.ts +9 -1
- package/dist/stat/root/stat-root.js +15 -2
- package/dist/steps/root/steps-root.js +1 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/switch/root/switch-root.d.ts +14 -2
- package/dist/switch/root/switch-root.js +7 -1
- package/dist/table/cell/table-cell.d.ts +24 -4
- package/dist/table/cell/table-cell.js +21 -1
- package/dist/table/column/table-column.d.ts +32 -6
- package/dist/table/column/table-column.js +36 -6
- package/dist/table/root/table-root.d.ts +94 -3
- package/dist/table/root/table-root.js +128 -5
- package/dist/table/row/table-row.d.ts +7 -0
- package/dist/table/row/table-row.js +9 -1
- package/dist/tabs/root/tabs-root.d.ts +6 -1
- package/dist/tabs/root/tabs-root.js +6 -2
- package/dist/tag/group/tag-group.d.ts +107 -0
- package/dist/tag/group/tag-group.js +157 -0
- package/dist/tag/index.d.ts +1 -0
- package/dist/tag/index.js +1 -0
- package/dist/tag/root/tag-root.d.ts +83 -1
- package/dist/tag/root/tag-root.js +87 -17
- package/dist/tag/selection.d.ts +10 -0
- package/dist/tag/selection.js +12 -0
- package/dist/textarea/grow.d.ts +22 -0
- package/dist/textarea/grow.js +20 -0
- package/dist/textarea/root/textarea-root.d.ts +13 -0
- package/dist/textarea/root/textarea-root.js +10 -2
- package/dist/time-input/root/time-input-root.d.ts +71 -6
- package/dist/time-input/root/time-input-root.js +110 -44
- package/dist/time-picker/root/time-picker-root.d.ts +155 -26
- package/dist/time-picker/root/time-picker-root.js +192 -63
- package/dist/toast/hotkey.d.ts +22 -0
- package/dist/toast/hotkey.js +23 -0
- package/dist/toast/item/toast-item.d.ts +16 -1
- package/dist/toast/item/toast-item.js +41 -13
- package/dist/toast/root/toast-root.d.ts +105 -8
- package/dist/toast/root/toast-root.js +209 -4
- package/dist/toggle/group/toggle-group.d.ts +95 -16
- package/dist/toggle/group/toggle-group.js +99 -13
- package/dist/toggle/root/toggle-root.d.ts +26 -11
- package/dist/toggle/root/toggle-root.js +14 -6
- package/dist/toolbar/root/toolbar-root.d.ts +55 -15
- package/dist/toolbar/root/toolbar-root.js +99 -16
- package/dist/tooltip/focus-target.d.ts +6 -0
- package/dist/tooltip/focus-target.js +9 -0
- package/dist/tooltip/root/tooltip-root.d.ts +73 -15
- package/dist/tooltip/root/tooltip-root.js +96 -7
- package/dist/tour/naming.d.ts +30 -0
- package/dist/tour/naming.js +10 -0
- package/dist/tour/root/tour-root.d.ts +67 -3
- package/dist/tour/root/tour-root.js +105 -17
- package/dist/tour/stop/tour-stop.d.ts +65 -3
- package/dist/tour/stop/tour-stop.js +61 -11
- package/dist/tour/wait.d.ts +11 -0
- package/dist/tour/wait.js +19 -0
- package/dist/tree/item/tree-item.d.ts +21 -5
- package/dist/tree/item/tree-item.js +14 -4
- package/dist/tree/root/tree-root.d.ts +29 -5
- package/dist/tree/root/tree-root.js +64 -8
- package/dist/trend/root/trend-root.d.ts +36 -1
- package/dist/trend/root/trend-root.js +41 -15
- package/dist/video/root/keys.d.ts +5 -0
- package/dist/video/root/keys.js +13 -1
- package/dist/video/root/video-root.d.ts +19 -0
- package/dist/video/root/video-root.js +48 -4
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
- package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
- package/dist/video-playlist/root/video-playlist-root.js +6 -3
- package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
- package/dist/virtual-list/root/virtual-list-root.js +103 -21
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +9140 -1149
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +2089 -267
|
@@ -4,6 +4,7 @@ registerElementEvents({
|
|
|
4
4
|
'helix-headless-announcement': ['helix-dismiss'],
|
|
5
5
|
'helix-headless-app-header': ['helix-scrolled'],
|
|
6
6
|
'helix-headless-avatar': ['error', 'load'],
|
|
7
|
+
'helix-headless-callout': ['helix-dismiss'],
|
|
7
8
|
'helix-headless-canvas': [
|
|
8
9
|
'helix-before-move',
|
|
9
10
|
'helix-before-reconnect',
|
|
@@ -19,9 +20,9 @@ registerElementEvents({
|
|
|
19
20
|
'helix-remove',
|
|
20
21
|
'helix-select',
|
|
21
22
|
],
|
|
22
|
-
'helix-headless-carousel': ['helix-select'],
|
|
23
|
-
'helix-headless-chat': ['helix-before-pin', 'helix-history', 'helix-send'],
|
|
24
|
-
'helix-headless-chat-composer': ['helix-send'],
|
|
23
|
+
'helix-headless-carousel': ['helix-activate', 'helix-select'],
|
|
24
|
+
'helix-headless-chat': ['helix-before-pin', 'helix-history', 'helix-pin', 'helix-send'],
|
|
25
|
+
'helix-headless-chat-composer': ['helix-send', 'input'],
|
|
25
26
|
'helix-headless-chat-message': ['helix-send'],
|
|
26
27
|
'helix-headless-checkbox': ['change', 'helix-before-toggle', 'input'],
|
|
27
28
|
'helix-headless-checkbox-group': ['change', 'helix-before-change', 'input'],
|
|
@@ -51,14 +52,25 @@ registerElementEvents({
|
|
|
51
52
|
'input',
|
|
52
53
|
'toggle',
|
|
53
54
|
],
|
|
54
|
-
'helix-headless-command': [
|
|
55
|
-
|
|
55
|
+
'helix-headless-command': [
|
|
56
|
+
'helix-before-close',
|
|
57
|
+
'helix-before-open',
|
|
58
|
+
'helix-filter',
|
|
59
|
+
'helix-select',
|
|
60
|
+
'toggle',
|
|
61
|
+
],
|
|
62
|
+
'helix-headless-copy-button': ['helix-copy', 'helix-copy-error'],
|
|
56
63
|
'helix-headless-data-table': [
|
|
64
|
+
'helix-activate',
|
|
57
65
|
'helix-filter',
|
|
66
|
+
'helix-filtered',
|
|
58
67
|
'helix-navigate',
|
|
59
68
|
'helix-reorder',
|
|
69
|
+
'helix-reordered',
|
|
60
70
|
'helix-select',
|
|
71
|
+
'helix-selected',
|
|
61
72
|
'helix-sort',
|
|
73
|
+
'helix-sorted',
|
|
62
74
|
],
|
|
63
75
|
'helix-headless-date-input': [
|
|
64
76
|
'change',
|
|
@@ -73,7 +85,7 @@ registerElementEvents({
|
|
|
73
85
|
'helix-headless-drawer': ['close', 'helix-before-close', 'helix-before-open', 'toggle'],
|
|
74
86
|
'helix-headless-drilldown': ['helix-select'],
|
|
75
87
|
'helix-headless-drilldown-item': ['helix-select'],
|
|
76
|
-
'helix-headless-file-input': ['change', 'helix-before-change', 'input'],
|
|
88
|
+
'helix-headless-file-input': ['change', 'helix-before-change', 'helix-reject', 'input'],
|
|
77
89
|
'helix-headless-filter-chip': ['helix-dismiss'],
|
|
78
90
|
'helix-headless-filter-input': [
|
|
79
91
|
'change',
|
|
@@ -99,9 +111,11 @@ registerElementEvents({
|
|
|
99
111
|
'helix-graph-zoom',
|
|
100
112
|
],
|
|
101
113
|
'helix-headless-heatmap': ['helix-resize'],
|
|
114
|
+
'helix-headless-icon': ['error', 'load'],
|
|
102
115
|
'helix-headless-image': ['error', 'load'],
|
|
103
|
-
'helix-headless-input': ['change', 'helix-before-change', 'input'],
|
|
116
|
+
'helix-headless-input': ['change', 'helix-before-change', 'helix-clear', 'input'],
|
|
104
117
|
'helix-headless-kbd': ['helix-shortcut'],
|
|
118
|
+
'helix-headless-legend': ['change', 'helix-before-change'],
|
|
105
119
|
'helix-headless-lightbox': [
|
|
106
120
|
'close',
|
|
107
121
|
'helix-activate',
|
|
@@ -112,7 +126,10 @@ registerElementEvents({
|
|
|
112
126
|
],
|
|
113
127
|
'helix-headless-listbox': ['change', 'helix-before-change', 'helix-filter', 'input'],
|
|
114
128
|
'helix-headless-map': [
|
|
129
|
+
'change',
|
|
115
130
|
'helix-activate',
|
|
131
|
+
'helix-before-change',
|
|
132
|
+
'helix-before-toggle',
|
|
116
133
|
'helix-map-cluster',
|
|
117
134
|
'helix-map-pan',
|
|
118
135
|
'helix-map-part-change',
|
|
@@ -133,26 +150,28 @@ registerElementEvents({
|
|
|
133
150
|
'helix-headless-map-terrain': ['helix-map-part-change'],
|
|
134
151
|
'helix-headless-megamenu': ['helix-before-close', 'helix-before-open', 'toggle'],
|
|
135
152
|
'helix-headless-menu': ['helix-before-close', 'helix-before-open', 'helix-select', 'toggle'],
|
|
136
|
-
'helix-headless-menu-item': ['helix-select'],
|
|
153
|
+
'helix-headless-menu-item': ['helix-before-toggle', 'helix-select'],
|
|
137
154
|
'helix-headless-notification': ['helix-dismiss', 'helix-read'],
|
|
138
|
-
'helix-headless-notification-group': ['helix-before-close', 'helix-before-open'],
|
|
155
|
+
'helix-headless-notification-group': ['helix-before-close', 'helix-before-open', 'toggle'],
|
|
139
156
|
'helix-headless-notifications': ['helix-dismiss', 'helix-read'],
|
|
140
157
|
'helix-headless-number-input': ['change', 'helix-before-change', 'input'],
|
|
141
158
|
'helix-headless-object-inspector': ['helix-copy'],
|
|
142
159
|
'helix-headless-option': ['helix-select'],
|
|
143
160
|
'helix-headless-outline': ['helix-activate'],
|
|
144
|
-
'helix-headless-pagination': ['helix-navigate'],
|
|
145
|
-
'helix-headless-pagination-size': ['helix-before-change'],
|
|
161
|
+
'helix-headless-pagination': ['helix-activate', 'helix-navigate'],
|
|
162
|
+
'helix-headless-pagination-size': ['change', 'helix-before-change', 'input'],
|
|
146
163
|
'helix-headless-pin-input': ['change', 'helix-before-change', 'helix-complete', 'input'],
|
|
147
164
|
'helix-headless-popover': ['helix-before-close', 'helix-before-open', 'toggle'],
|
|
165
|
+
'helix-headless-qr-code': ['error'],
|
|
148
166
|
'helix-headless-radio': ['helix-select'],
|
|
149
167
|
'helix-headless-radio-group': ['change', 'helix-before-change', 'helix-select', 'input'],
|
|
150
|
-
'helix-headless-rating': ['change', 'helix-before-change', 'input'],
|
|
168
|
+
'helix-headless-rating': ['change', 'helix-before-change', 'helix-clear', 'input'],
|
|
151
169
|
'helix-headless-select': [
|
|
152
170
|
'change',
|
|
153
171
|
'helix-before-change',
|
|
154
172
|
'helix-before-close',
|
|
155
173
|
'helix-before-open',
|
|
174
|
+
'helix-filter',
|
|
156
175
|
'input',
|
|
157
176
|
'toggle',
|
|
158
177
|
],
|
|
@@ -164,14 +183,21 @@ registerElementEvents({
|
|
|
164
183
|
'toggle',
|
|
165
184
|
],
|
|
166
185
|
'helix-headless-speed-dial-item': ['helix-select'],
|
|
167
|
-
'helix-headless-splitter': [
|
|
186
|
+
'helix-headless-splitter': [
|
|
187
|
+
'helix-before-collapse',
|
|
188
|
+
'helix-before-resize',
|
|
189
|
+
'helix-collapse',
|
|
190
|
+
'helix-resized',
|
|
191
|
+
],
|
|
168
192
|
'helix-headless-step': ['helix-select'],
|
|
169
193
|
'helix-headless-steps': ['helix-activate', 'helix-before-activate', 'helix-select'],
|
|
170
194
|
'helix-headless-switch': ['change', 'helix-before-toggle', 'input'],
|
|
171
195
|
'helix-headless-tab': ['helix-select'],
|
|
196
|
+
'helix-headless-table': ['helix-sort'],
|
|
172
197
|
'helix-headless-table-column': ['helix-before-resize'],
|
|
173
198
|
'helix-headless-tabs': ['helix-activate', 'helix-before-activate', 'helix-select'],
|
|
174
199
|
'helix-headless-tag': ['helix-dismiss'],
|
|
200
|
+
'helix-headless-tag-group': ['change', 'helix-before-change', 'helix-dismiss'],
|
|
175
201
|
'helix-headless-textarea': ['change', 'helix-before-change', 'input'],
|
|
176
202
|
'helix-headless-time-input': [
|
|
177
203
|
'change',
|
|
@@ -188,10 +214,13 @@ registerElementEvents({
|
|
|
188
214
|
'helix-headless-toggle-group': ['change', 'helix-before-change', 'helix-select', 'input'],
|
|
189
215
|
'helix-headless-tooltip': ['helix-before-close', 'helix-before-open', 'toggle'],
|
|
190
216
|
'helix-headless-tour': [
|
|
217
|
+
'helix-activate',
|
|
191
218
|
'helix-before-activate',
|
|
192
219
|
'helix-before-close',
|
|
220
|
+
'helix-before-open',
|
|
193
221
|
'helix-complete',
|
|
194
222
|
'helix-tour-ask',
|
|
223
|
+
'toggle',
|
|
195
224
|
],
|
|
196
225
|
'helix-headless-tour-stop': ['helix-tour-ask'],
|
|
197
226
|
'helix-headless-tree': ['helix-activate', 'helix-before-activate', 'helix-select'],
|
|
@@ -25,7 +25,7 @@ import { type TemplateResult } from 'lit';
|
|
|
25
25
|
*
|
|
26
26
|
* @slot - The message: why the region is empty, and what to do about it.
|
|
27
27
|
* @slot actions - The action that would put something in the region.
|
|
28
|
-
* @slot heading - The heading, which names what is missing.
|
|
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.
|
|
29
29
|
* @slot icon - An icon above the heading.
|
|
30
30
|
*
|
|
31
31
|
* @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.
|
|
@@ -16,6 +16,12 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
16
16
|
* visible trigger is a `<label for>`. The label is not focusable. The input is,
|
|
17
17
|
* and Enter and Space on it open the picker.
|
|
18
18
|
*
|
|
19
|
+
* Files arrive from the picker, a drop, or a paste onto the field, and each one
|
|
20
|
+
* is screened: `accept`, `max-file-size`, `max-files` and your own `validate`
|
|
21
|
+
* can refuse it. A refused file is left out, `helix-reject` lists each one with
|
|
22
|
+
* its reason, and a reader hears `rejected-text` with the names filled in.
|
|
23
|
+
* `directory` asks the picker for a folder.
|
|
24
|
+
*
|
|
19
25
|
* @since 0.1.0
|
|
20
26
|
* @status stable
|
|
21
27
|
* @category forms
|
|
@@ -24,10 +30,12 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
24
30
|
*
|
|
25
31
|
* @slot feedback - The message that says what is wrong with the chosen files.
|
|
26
32
|
* @slot hint - Help under the field.
|
|
33
|
+
* @slot label - The label, for content richer than the `label` text.
|
|
27
34
|
* @slot trigger - The content that opens the picker when pressed.
|
|
28
35
|
*
|
|
29
36
|
* @event {Event} change - Fired after the value changes.
|
|
30
37
|
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the chosen files change, with their names, and cancelable. Canceling it keeps the files the field had, even when the browser has already written a new pick.
|
|
38
|
+
* @event {HelixRejectEvent} helix-reject - Fired when files arrive and some are left out. `detail.files` lists each with its `reason`: `type`, `size`, `count` or `invalid`, and your `validate` message.
|
|
31
39
|
* @event {Event} input - Fired after the value changes.
|
|
32
40
|
*
|
|
33
41
|
* @csspart control - The file input itself, which carries the label and validity.
|
|
@@ -37,19 +45,24 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
37
45
|
* @csspart file - One chosen file.
|
|
38
46
|
* @csspart hint - Help under the field, while nothing is wrong.
|
|
39
47
|
* @csspart kind - A file's type.
|
|
48
|
+
* @csspart kind-cell - The grid cell around the tag, rendered only when the tag sits in a `Tag.Group`.
|
|
40
49
|
* @csspart kind-dismiss - The remove button, when `dismissible`.
|
|
41
50
|
* @csspart kind-dismiss-mark - The glyph on the dismiss control, where none is slotted.
|
|
42
51
|
* @csspart kind-label - The label, trimmed to its capitals and baseline.
|
|
52
|
+
* @csspart kind-link - The link around the label, when the tag has an `href`.
|
|
43
53
|
* @csspart kind-start - The category before the label.
|
|
44
54
|
* @csspart label - The label above the field.
|
|
45
55
|
* @csspart list - The chosen files.
|
|
56
|
+
* @csspart live - The live region that says `rejected-text` when files are refused. It is rendered from the first refusal.
|
|
46
57
|
* @csspart meta - The row that holds a file's size and type.
|
|
47
58
|
* @csspart name - A file's name.
|
|
48
59
|
* @csspart remove - The control that removes a file.
|
|
49
60
|
* @csspart size - A file's size.
|
|
61
|
+
* @csspart size-cell - The grid cell around the tag, rendered only when the tag sits in a `Tag.Group`.
|
|
50
62
|
* @csspart size-dismiss - The remove button, when `dismissible`.
|
|
51
63
|
* @csspart size-dismiss-mark - The glyph on the dismiss control, where none is slotted.
|
|
52
64
|
* @csspart size-label - The label, trimmed to its capitals and baseline.
|
|
65
|
+
* @csspart size-link - The link around the label, when the tag has an `href`.
|
|
53
66
|
* @csspart size-start - The category before the label.
|
|
54
67
|
* @csspart trigger - The label that opens the picker.
|
|
55
68
|
*
|
|
@@ -58,23 +71,45 @@ declare const HelixHeadlessFileInput_base: (new (...args: any[]) => import("@fus
|
|
|
58
71
|
export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base {
|
|
59
72
|
protected readonly aria: AriaForwardController;
|
|
60
73
|
/**
|
|
61
|
-
* Which files the picker offers, as a native `accept` list.
|
|
74
|
+
* Which files the picker offers and a drop takes, as a native `accept` list.
|
|
75
|
+
*
|
|
76
|
+
* A dropped file the list does not name is left out, because the picker's
|
|
77
|
+
* filter is the only check the platform makes and a drop never meets it.
|
|
62
78
|
*/
|
|
63
79
|
accept: string;
|
|
64
80
|
/**
|
|
65
81
|
* Which camera or microphone a mobile picker should offer, if any.
|
|
66
82
|
*/
|
|
67
83
|
capture?: 'environment' | 'user';
|
|
84
|
+
/**
|
|
85
|
+
* Whether the picker chooses a folder, and the field takes every file in
|
|
86
|
+
* it. The platform's `webkitdirectory`.
|
|
87
|
+
*/
|
|
88
|
+
directory: boolean;
|
|
68
89
|
/**
|
|
69
90
|
* Language tag the sizes are written in.
|
|
70
91
|
*
|
|
71
92
|
* Absent uses the runtime's own.
|
|
72
93
|
*/
|
|
73
94
|
locale: string;
|
|
95
|
+
/**
|
|
96
|
+
* The most files the field holds, under `multiple`. Files past it are
|
|
97
|
+
* refused.
|
|
98
|
+
*/
|
|
99
|
+
maxFiles?: number;
|
|
100
|
+
/**
|
|
101
|
+
* The most bytes one file may have. A larger one is refused.
|
|
102
|
+
*/
|
|
103
|
+
maxFileSize?: number;
|
|
74
104
|
/**
|
|
75
105
|
* Whether more than one file can be chosen.
|
|
76
106
|
*/
|
|
77
107
|
multiple: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* What a reader hears when files are refused, with `{count}` and `{names}`
|
|
110
|
+
* filled in.
|
|
111
|
+
*/
|
|
112
|
+
rejectedText: string;
|
|
78
113
|
/**
|
|
79
114
|
* The accessible name of the control that removes a file. `{name}` is
|
|
80
115
|
* replaced with the file's name.
|
|
@@ -88,6 +123,22 @@ export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base
|
|
|
88
123
|
* The trigger's text when nothing is slotted into it.
|
|
89
124
|
*/
|
|
90
125
|
triggerLabel: string;
|
|
126
|
+
/**
|
|
127
|
+
* Your own check on each arriving file, which returns why it is refused, or
|
|
128
|
+
* nothing to take it. A property, since a function cannot be an attribute.
|
|
129
|
+
*/
|
|
130
|
+
validate?: (file: File) => string | null | undefined;
|
|
131
|
+
/** The live region, rendered from the first refusal. */
|
|
132
|
+
private readonly status;
|
|
133
|
+
/**
|
|
134
|
+
* Screens arriving files and commits what is taken, after the files the
|
|
135
|
+
* field keeps. Refused files are announced and said.
|
|
136
|
+
*/
|
|
137
|
+
private take;
|
|
138
|
+
/** Sends `helix-reject` and says which files were left out. */
|
|
139
|
+
private refuse;
|
|
140
|
+
/** Takes files pasted onto the field, as a drop takes them. */
|
|
141
|
+
private readonly handlePaste;
|
|
91
142
|
/**
|
|
92
143
|
* Whether something is being dragged over the field.
|
|
93
144
|
*
|
|
@@ -185,8 +236,21 @@ export declare class HelixHeadlessFileInput extends HelixHeadlessFileInput_base
|
|
|
185
236
|
private readonly handleDragOver;
|
|
186
237
|
private readonly handleDragLeave;
|
|
187
238
|
private readonly handleDrop;
|
|
239
|
+
/**
|
|
240
|
+
* Removes a file and keeps focus in the field.
|
|
241
|
+
*
|
|
242
|
+
* The pressed button goes with its file, so focus moves to the file that took
|
|
243
|
+
* its place, or to the one before it, or to the input once the list is empty:
|
|
244
|
+
* left alone, it fell to the page's body.
|
|
245
|
+
*/
|
|
188
246
|
private readonly handleRemove;
|
|
189
247
|
protected firstUpdated(changed: PropertyValues): void;
|
|
248
|
+
/**
|
|
249
|
+
* Reports again on every update, so a new `name` or `required` reaches the
|
|
250
|
+
* form. Only a pick and the first render reported, so the form kept the old
|
|
251
|
+
* name and the old verdict.
|
|
252
|
+
*/
|
|
253
|
+
protected updated(changed: PropertyValues): void;
|
|
190
254
|
/** Moves focus to the native file input, as a label pointing at it would. */
|
|
191
255
|
focus(options?: FocusOptions): void;
|
|
192
256
|
/**
|
|
@@ -4,11 +4,12 @@ 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, fillTemplate, HelixBeforeChangeEvent, HelixFormElement, MixinField, requestChange, restoreValue, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, customElement, drawIcon, drawStatus, fillTemplate, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, HelixRejectEvent, MixinField, requestChange, restoreValue, 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
|
+
import { screenFiles } from '../screen.js';
|
|
12
13
|
import '../../tag/index.js';
|
|
13
14
|
const named = (label, name) => label.includes('{name}') ? fillTemplate(label, { name }) : `${label} ${name}`;
|
|
14
15
|
const size = (bytes, locale) => {
|
|
@@ -26,29 +27,41 @@ const size = (bytes, locale) => {
|
|
|
26
27
|
return `${written} ${unit}`;
|
|
27
28
|
};
|
|
28
29
|
const kind = (file) => {
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
31
|
-
return
|
|
30
|
+
const extension = /\.([a-z0-9]{1,6})$/i.exec(file.name)?.[1];
|
|
31
|
+
if (extension) {
|
|
32
|
+
return extension.toUpperCase();
|
|
32
33
|
}
|
|
33
|
-
const
|
|
34
|
-
return
|
|
34
|
+
const subtype = file.type.split('/')[1]?.replace(/^x-/, '').split('+')[0] ?? '';
|
|
35
|
+
return /^[a-z0-9]{1,6}$/i.test(subtype) ? subtype.toUpperCase() : 'File';
|
|
35
36
|
};
|
|
36
37
|
let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(HelixFormElement) {
|
|
37
38
|
constructor() {
|
|
38
39
|
super(...arguments);
|
|
39
40
|
this.aria = new AriaForwardController(this, {
|
|
41
|
+
named: () => this.labeled,
|
|
40
42
|
target: () => this.partNamed('control'),
|
|
41
43
|
});
|
|
42
44
|
this.accept = '';
|
|
45
|
+
this.directory = false;
|
|
43
46
|
this.locale = '';
|
|
44
47
|
this.multiple = false;
|
|
48
|
+
this.rejectedText = 'Not added: {names}';
|
|
45
49
|
this.removeLabel = 'Remove {name}';
|
|
46
50
|
this.triggerLabel = 'Choose files';
|
|
51
|
+
this.status = new StatusController(this);
|
|
52
|
+
this.handlePaste = (event) => {
|
|
53
|
+
const pasted = [...(event.clipboardData?.files ?? [])];
|
|
54
|
+
if (this.isDisabled || pasted.length === 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
this.take(pasted, this.multiple ? this.files : []);
|
|
59
|
+
};
|
|
47
60
|
this.dropping = false;
|
|
48
61
|
this.committed = [];
|
|
49
62
|
this.handleChange = (event) => {
|
|
50
63
|
event.stopPropagation();
|
|
51
|
-
this.
|
|
64
|
+
this.take(this.files, [], true);
|
|
52
65
|
};
|
|
53
66
|
this.handleDragOver = (event) => {
|
|
54
67
|
if (this.isDisabled) {
|
|
@@ -71,15 +84,44 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
71
84
|
if (dropped.length === 0) {
|
|
72
85
|
return;
|
|
73
86
|
}
|
|
74
|
-
this.
|
|
87
|
+
this.take(dropped, this.multiple ? this.files : []);
|
|
75
88
|
};
|
|
76
89
|
this.handleRemove = (event) => {
|
|
77
90
|
const at = Number(event.currentTarget.dataset.at);
|
|
78
|
-
if (Number.isFinite(at)) {
|
|
79
|
-
|
|
91
|
+
if (!Number.isFinite(at)) {
|
|
92
|
+
return;
|
|
80
93
|
}
|
|
94
|
+
this.removeAt(at);
|
|
95
|
+
this.updateComplete.then(() => {
|
|
96
|
+
const buttons = [...this.renderRoot.querySelectorAll('[part="remove"]')];
|
|
97
|
+
(buttons[Math.min(at, buttons.length - 1)] ?? this.control)?.focus();
|
|
98
|
+
});
|
|
81
99
|
};
|
|
82
100
|
}
|
|
101
|
+
take(arriving, keeping, picked = false) {
|
|
102
|
+
const { kept, refused } = screenFiles(arriving, keeping, {
|
|
103
|
+
accept: this.accept,
|
|
104
|
+
maxFileSize: this.maxFileSize,
|
|
105
|
+
maxFiles: this.maxFiles,
|
|
106
|
+
multiple: this.multiple || picked,
|
|
107
|
+
validate: this.validate,
|
|
108
|
+
});
|
|
109
|
+
const same = (one, two) => one.length === two.length && one.every((file, at) => file === two[at]);
|
|
110
|
+
if (picked || !(same(kept, this.committed) && same(kept, this.files))) {
|
|
111
|
+
this.commit(kept);
|
|
112
|
+
}
|
|
113
|
+
if (refused.length > 0) {
|
|
114
|
+
this.refuse(refused);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
refuse(refused) {
|
|
118
|
+
this.dispatchEvent(new HelixRejectEvent({ files: refused }));
|
|
119
|
+
const words = fillTemplate(this.rejectedText, {
|
|
120
|
+
count: formatNumbers(this.lang)(refused.length),
|
|
121
|
+
names: new Intl.ListFormat(this.lang || undefined, { style: 'short', type: 'unit' }).format(refused.map((one) => one.file.name)),
|
|
122
|
+
});
|
|
123
|
+
this.status.say(words);
|
|
124
|
+
}
|
|
83
125
|
get files() {
|
|
84
126
|
return [...(this.control?.files ?? [])];
|
|
85
127
|
}
|
|
@@ -152,6 +194,10 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
152
194
|
this.committed = this.files;
|
|
153
195
|
this.sync();
|
|
154
196
|
}
|
|
197
|
+
updated(changed) {
|
|
198
|
+
super.updated(changed);
|
|
199
|
+
this.sync();
|
|
200
|
+
}
|
|
155
201
|
focus(options) {
|
|
156
202
|
this.control?.focus(options);
|
|
157
203
|
}
|
|
@@ -164,10 +210,10 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
164
210
|
}
|
|
165
211
|
renderMeta(file) {
|
|
166
212
|
return html `<${this.tag('tag')} part="size"
|
|
167
|
-
exportparts="dismiss: size-dismiss, dismiss-mark: size-dismiss-mark, label: size-label, start: size-start">${size(file.size, this.locale)}</${this.tag('tag')}>
|
|
213
|
+
exportparts="cell: size-cell, dismiss: size-dismiss, dismiss-mark: size-dismiss-mark, label: size-label, link: size-link, start: size-start">${size(file.size, this.locale)}</${this.tag('tag')}>
|
|
168
214
|
<${this.tag('tag')}
|
|
169
215
|
part="kind"
|
|
170
|
-
exportparts="dismiss: kind-dismiss, dismiss-mark: kind-dismiss-mark, label: kind-label, start: kind-start">${kind(file)}</${this.tag('tag')}>`;
|
|
216
|
+
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')}>`;
|
|
171
217
|
}
|
|
172
218
|
render() {
|
|
173
219
|
const files = this.files;
|
|
@@ -178,6 +224,7 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
178
224
|
@dragleave=${this.handleDragLeave}
|
|
179
225
|
@dragover=${this.handleDragOver}
|
|
180
226
|
@drop=${this.handleDrop}
|
|
227
|
+
@paste=${this.handlePaste}
|
|
181
228
|
>
|
|
182
229
|
<input
|
|
183
230
|
part="control"
|
|
@@ -191,6 +238,7 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
191
238
|
?disabled=${this.isDisabled}
|
|
192
239
|
?multiple=${this.multiple}
|
|
193
240
|
?required=${this.required}
|
|
241
|
+
?webkitdirectory=${this.directory}
|
|
194
242
|
@change=${this.handleChange}
|
|
195
243
|
@input=${this.stopInner}
|
|
196
244
|
/>
|
|
@@ -202,6 +250,7 @@ let HelixHeadlessFileInput = class HelixHeadlessFileInput extends MixinField(Hel
|
|
|
202
250
|
one ordering decision this component makes differently from the way it
|
|
203
251
|
reads. Reasoning above renderMeta. -->
|
|
204
252
|
${this.renderHint()}${this.renderFeedback()}
|
|
253
|
+
${drawStatus(this.status)}
|
|
205
254
|
${files.length === 0
|
|
206
255
|
? nothing
|
|
207
256
|
: html `<ul part="list">
|
|
@@ -232,18 +281,33 @@ __decorate([
|
|
|
232
281
|
__decorate([
|
|
233
282
|
property()
|
|
234
283
|
], HelixHeadlessFileInput.prototype, "capture", void 0);
|
|
284
|
+
__decorate([
|
|
285
|
+
property({ type: Boolean })
|
|
286
|
+
], HelixHeadlessFileInput.prototype, "directory", void 0);
|
|
235
287
|
__decorate([
|
|
236
288
|
property()
|
|
237
289
|
], HelixHeadlessFileInput.prototype, "locale", void 0);
|
|
290
|
+
__decorate([
|
|
291
|
+
property({ attribute: 'max-files', type: Number })
|
|
292
|
+
], HelixHeadlessFileInput.prototype, "maxFiles", void 0);
|
|
293
|
+
__decorate([
|
|
294
|
+
property({ attribute: 'max-file-size', type: Number })
|
|
295
|
+
], HelixHeadlessFileInput.prototype, "maxFileSize", void 0);
|
|
238
296
|
__decorate([
|
|
239
297
|
property({ reflect: true, type: Boolean })
|
|
240
298
|
], HelixHeadlessFileInput.prototype, "multiple", void 0);
|
|
299
|
+
__decorate([
|
|
300
|
+
property({ attribute: 'rejected-text' })
|
|
301
|
+
], HelixHeadlessFileInput.prototype, "rejectedText", void 0);
|
|
241
302
|
__decorate([
|
|
242
303
|
property({ attribute: 'remove-label' })
|
|
243
304
|
], HelixHeadlessFileInput.prototype, "removeLabel", void 0);
|
|
244
305
|
__decorate([
|
|
245
306
|
property({ attribute: 'trigger-label' })
|
|
246
307
|
], HelixHeadlessFileInput.prototype, "triggerLabel", void 0);
|
|
308
|
+
__decorate([
|
|
309
|
+
property({ attribute: false })
|
|
310
|
+
], HelixHeadlessFileInput.prototype, "validate", void 0);
|
|
247
311
|
__decorate([
|
|
248
312
|
state()
|
|
249
313
|
], HelixHeadlessFileInput.prototype, "dropping", void 0);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type RefusedFile } from '@fusion.dev/helix-core';
|
|
2
|
+
/**
|
|
3
|
+
* Which of the files arriving at a file field it takes, and why it refuses the
|
|
4
|
+
* rest: the rules `accept`, `max-file-size`, `max-files` and `validate` set.
|
|
5
|
+
* Zag's file upload screens a drop the same way and reports each refused file
|
|
6
|
+
* with its reason.
|
|
7
|
+
*/
|
|
8
|
+
export type { Refusal, RefusedFile } from '@fusion.dev/helix-core';
|
|
9
|
+
/** The rules a field screens arriving files by. */
|
|
10
|
+
export interface ScreenRules {
|
|
11
|
+
/** A native `accept` list. Empty takes every type. */
|
|
12
|
+
readonly accept: string;
|
|
13
|
+
/** The most bytes one file may have. */
|
|
14
|
+
readonly maxFileSize?: number | undefined;
|
|
15
|
+
/** The most files the field holds, counting the ones it has. */
|
|
16
|
+
readonly maxFiles?: number | undefined;
|
|
17
|
+
/** Whether the field holds more than one file. */
|
|
18
|
+
readonly multiple: boolean;
|
|
19
|
+
/** Your own check, which returns why a file is refused, or nothing. */
|
|
20
|
+
readonly validate?: ((file: File) => string | null | undefined) | undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Whether a file is one `accept` lists: an extension, a type, or a family
|
|
24
|
+
* such as `image/*`, as the platform reads it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const accepts: (file: File, accept: string) => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Screens arriving files against the rules, given the files the field keeps.
|
|
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.
|
|
31
|
+
*/
|
|
32
|
+
export declare const screenFiles: (arriving: File[], keeping: File[], rules: ScreenRules) => {
|
|
33
|
+
kept: File[];
|
|
34
|
+
refused: RefusedFile[];
|
|
35
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { commaList } from '@fusion.dev/helix-core';
|
|
2
|
+
export const accepts = (file, accept) => {
|
|
3
|
+
const tokens = commaList(accept).map((token) => token.toLowerCase());
|
|
4
|
+
if (tokens.length === 0) {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
const name = file.name.toLowerCase();
|
|
8
|
+
const type = file.type.toLowerCase();
|
|
9
|
+
return tokens.some((token) => token.startsWith('.')
|
|
10
|
+
? name.endsWith(token)
|
|
11
|
+
: token.endsWith('/*')
|
|
12
|
+
? type.startsWith(token.slice(0, -1))
|
|
13
|
+
: type === token);
|
|
14
|
+
};
|
|
15
|
+
const refusal = (file, rules) => {
|
|
16
|
+
if (!accepts(file, rules.accept)) {
|
|
17
|
+
return { file, reason: 'type' };
|
|
18
|
+
}
|
|
19
|
+
if (rules.maxFileSize !== undefined && file.size > rules.maxFileSize) {
|
|
20
|
+
return { file, reason: 'size' };
|
|
21
|
+
}
|
|
22
|
+
const message = rules.validate?.(file);
|
|
23
|
+
return message ? { file, message, reason: 'invalid' } : undefined;
|
|
24
|
+
};
|
|
25
|
+
export const screenFiles = (arriving, keeping, rules) => {
|
|
26
|
+
const refused = [];
|
|
27
|
+
const taken = [];
|
|
28
|
+
for (const file of arriving) {
|
|
29
|
+
const refusedFor = refusal(file, rules);
|
|
30
|
+
if (refusedFor) {
|
|
31
|
+
refused.push(refusedFor);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
taken.push(file);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!rules.multiple) {
|
|
38
|
+
const last = taken.at(-1);
|
|
39
|
+
for (const file of taken.slice(0, -1)) {
|
|
40
|
+
refused.push({ file, reason: 'count' });
|
|
41
|
+
}
|
|
42
|
+
return { kept: last ? [last] : keeping.slice(0, 1), refused };
|
|
43
|
+
}
|
|
44
|
+
const room = rules.maxFiles === undefined ? taken.length : Math.max(0, rules.maxFiles - keeping.length);
|
|
45
|
+
for (const file of taken.slice(room)) {
|
|
46
|
+
refused.push({ file, reason: 'count' });
|
|
47
|
+
}
|
|
48
|
+
return { kept: [...keeping, ...taken.slice(0, room)], refused };
|
|
49
|
+
};
|
|
@@ -151,6 +151,15 @@ export declare class HelixHeadlessFilterMenu extends HelixElement {
|
|
|
151
151
|
* a filter is never left looking at a menu that says it took.
|
|
152
152
|
*/
|
|
153
153
|
apply(field: string, values: readonly string[], operator?: string): boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Keeps each choice row's tick where this element puts it.
|
|
156
|
+
*
|
|
157
|
+
* A choice row checks itself after `helix-before-toggle`, and this element
|
|
158
|
+
* already sets `checked` on every row from its own state. The request is
|
|
159
|
+
* refused, so a tick moves only when the choice is applied, and stopped, so
|
|
160
|
+
* it does not reach a page that never placed the row.
|
|
161
|
+
*/
|
|
162
|
+
private readonly keepTick;
|
|
154
163
|
/**
|
|
155
164
|
* A row was chosen: a value to tick, or a comparison to use.
|
|
156
165
|
*
|
|
@@ -17,6 +17,12 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
|
|
|
17
17
|
this.label = 'Filter';
|
|
18
18
|
this.picked = new Map();
|
|
19
19
|
this.comparisons = new Map();
|
|
20
|
+
this.keepTick = (event) => {
|
|
21
|
+
if (event.target === event.currentTarget) {
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
20
26
|
this.handleSelect = (event) => {
|
|
21
27
|
const row = event.composedPath()[0];
|
|
22
28
|
if (!(row instanceof HTMLElement)) {
|
|
@@ -152,6 +158,7 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
|
|
|
152
158
|
checkable
|
|
153
159
|
exclusive
|
|
154
160
|
?checked=${operator.name === using?.name}
|
|
161
|
+
@helix-before-toggle=${this.keepTick}
|
|
155
162
|
data-facet="operator"
|
|
156
163
|
data-field=${name}
|
|
157
164
|
data-value=${operator.name}
|
|
@@ -173,6 +180,7 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
|
|
|
173
180
|
checkable
|
|
174
181
|
?exclusive=${using?.arity === 'one'}
|
|
175
182
|
?checked=${ticked.has(option.value)}
|
|
183
|
+
@helix-before-toggle=${this.keepTick}
|
|
176
184
|
data-facet="value"
|
|
177
185
|
data-field=${name}
|
|
178
186
|
data-value=${option.value}
|