@fusion.dev/helix-headless 0.0.0-dev
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/LICENSE +21 -0
- package/custom-elements.json +75202 -0
- package/dist/accordion/index.d.ts +2 -0
- package/dist/accordion/index.js +2 -0
- package/dist/accordion/item/accordion-item.d.ts +141 -0
- package/dist/accordion/item/accordion-item.js +214 -0
- package/dist/accordion/root/accordion-root.d.ts +57 -0
- package/dist/accordion/root/accordion-root.js +96 -0
- package/dist/announcement/index.d.ts +1 -0
- package/dist/announcement/index.js +1 -0
- package/dist/announcement/root/announcement-root.d.ts +106 -0
- package/dist/announcement/root/announcement-root.js +144 -0
- package/dist/app-header/index.d.ts +1 -0
- package/dist/app-header/index.js +1 -0
- package/dist/app-header/root/app-header-root.d.ts +113 -0
- package/dist/app-header/root/app-header-root.js +147 -0
- package/dist/avatar/group/avatar-group.d.ts +116 -0
- package/dist/avatar/group/avatar-group.js +136 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +2 -0
- package/dist/avatar/root/avatar-root.d.ts +71 -0
- package/dist/avatar/root/avatar-root.js +147 -0
- package/dist/badge/index.d.ts +1 -0
- package/dist/badge/index.js +1 -0
- package/dist/badge/root/badge-root.d.ts +61 -0
- package/dist/badge/root/badge-root.js +121 -0
- package/dist/bar-chart/index.d.ts +1 -0
- package/dist/bar-chart/index.js +1 -0
- package/dist/bar-chart/root/bar-chart-root.d.ts +266 -0
- package/dist/bar-chart/root/bar-chart-root.js +515 -0
- package/dist/blockquote/index.d.ts +1 -0
- package/dist/blockquote/index.js +1 -0
- package/dist/blockquote/root/blockquote-root.d.ts +51 -0
- package/dist/blockquote/root/blockquote-root.js +84 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +104 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +137 -0
- package/dist/breadcrumbs/index.d.ts +2 -0
- package/dist/breadcrumbs/index.js +2 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +77 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.js +94 -0
- package/dist/button/index.d.ts +1 -0
- package/dist/button/index.js +1 -0
- package/dist/button/root/button-root.d.ts +251 -0
- package/dist/button/root/button-root.js +401 -0
- package/dist/button-group/index.d.ts +1 -0
- package/dist/button-group/index.js +1 -0
- package/dist/button-group/root/button-group-root.d.ts +62 -0
- package/dist/button-group/root/button-group-root.js +62 -0
- package/dist/callout/index.d.ts +1 -0
- package/dist/callout/index.js +1 -0
- package/dist/callout/root/callout-root.d.ts +72 -0
- package/dist/callout/root/callout-root.js +90 -0
- package/dist/card/index.d.ts +1 -0
- package/dist/card/index.js +1 -0
- package/dist/card/root/card-root.d.ts +54 -0
- package/dist/card/root/card-root.js +71 -0
- package/dist/carousel/index.d.ts +1 -0
- package/dist/carousel/index.js +1 -0
- package/dist/carousel/root/carousel-root.d.ts +399 -0
- package/dist/carousel/root/carousel-root.js +723 -0
- package/dist/chat/composer/chat-composer.d.ts +160 -0
- package/dist/chat/composer/chat-composer.js +273 -0
- package/dist/chat/index.d.ts +3 -0
- package/dist/chat/index.js +3 -0
- package/dist/chat/message/chat-message.d.ts +170 -0
- package/dist/chat/message/chat-message.js +271 -0
- package/dist/chat/root/chat-root.d.ts +216 -0
- package/dist/chat/root/chat-root.js +389 -0
- package/dist/checkbox/index.d.ts +1 -0
- package/dist/checkbox/index.js +1 -0
- package/dist/checkbox/root/checkbox-root.d.ts +108 -0
- package/dist/checkbox/root/checkbox-root.js +207 -0
- package/dist/checkbox-group/index.d.ts +1 -0
- package/dist/checkbox-group/index.js +1 -0
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +155 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +293 -0
- package/dist/code/index.d.ts +1 -0
- package/dist/code/index.js +1 -0
- package/dist/code/root/code-root.d.ts +36 -0
- package/dist/code/root/code-root.js +43 -0
- package/dist/code-block/index.d.ts +1 -0
- package/dist/code-block/index.js +1 -0
- package/dist/code-block/root/code-block-root.d.ts +112 -0
- package/dist/code-block/root/code-block-root.js +155 -0
- package/dist/color-input/index.d.ts +1 -0
- package/dist/color-input/index.js +1 -0
- package/dist/color-input/root/color-input-root.d.ts +227 -0
- package/dist/color-input/root/color-input-root.js +456 -0
- package/dist/color-picker/color.d.ts +74 -0
- package/dist/color-picker/color.js +238 -0
- package/dist/color-picker/index.d.ts +2 -0
- package/dist/color-picker/index.js +2 -0
- package/dist/color-picker/root/color-picker-root.d.ts +303 -0
- package/dist/color-picker/root/color-picker-root.js +576 -0
- package/dist/combobox/index.d.ts +1 -0
- package/dist/combobox/index.js +1 -0
- package/dist/combobox/root/combobox-root.d.ts +396 -0
- package/dist/combobox/root/combobox-root.js +808 -0
- package/dist/command/index.d.ts +1 -0
- package/dist/command/index.js +1 -0
- package/dist/command/root/command-root.d.ts +166 -0
- package/dist/command/root/command-root.js +353 -0
- package/dist/copy-button/index.d.ts +1 -0
- package/dist/copy-button/index.js +1 -0
- package/dist/copy-button/root/copy-button-root.d.ts +154 -0
- package/dist/copy-button/root/copy-button-root.js +225 -0
- package/dist/data-table/index.d.ts +2 -0
- package/dist/data-table/index.js +2 -0
- package/dist/data-table/root/data-table-root.d.ts +392 -0
- package/dist/data-table/root/data-table-root.js +729 -0
- package/dist/data-table/root/order.d.ts +116 -0
- package/dist/data-table/root/order.js +175 -0
- package/dist/date-input/index.d.ts +1 -0
- package/dist/date-input/index.js +1 -0
- package/dist/date-input/root/date-input-root.d.ts +361 -0
- package/dist/date-input/root/date-input-root.js +791 -0
- package/dist/date-picker/index.d.ts +1 -0
- package/dist/date-picker/index.js +1 -0
- package/dist/date-picker/root/date-picker-root.d.ts +361 -0
- package/dist/date-picker/root/date-picker-root.js +837 -0
- package/dist/dialog/index.d.ts +1 -0
- package/dist/dialog/index.js +1 -0
- package/dist/dialog/root/dialog-root.d.ts +185 -0
- package/dist/dialog/root/dialog-root.js +319 -0
- package/dist/divider/index.d.ts +1 -0
- package/dist/divider/index.js +1 -0
- package/dist/divider/root/divider-root.d.ts +68 -0
- package/dist/divider/root/divider-root.js +116 -0
- package/dist/donut-chart/index.d.ts +1 -0
- package/dist/donut-chart/index.js +1 -0
- package/dist/donut-chart/root/donut-chart-root.d.ts +209 -0
- package/dist/donut-chart/root/donut-chart-root.js +395 -0
- package/dist/drawer/index.d.ts +1 -0
- package/dist/drawer/index.js +1 -0
- package/dist/drawer/root/drawer-root.d.ts +144 -0
- package/dist/drawer/root/drawer-root.js +222 -0
- package/dist/drilldown/index.d.ts +2 -0
- package/dist/drilldown/index.js +2 -0
- package/dist/drilldown/item/drilldown-item.d.ts +87 -0
- package/dist/drilldown/item/drilldown-item.js +152 -0
- package/dist/drilldown/root/drilldown-root.d.ts +115 -0
- package/dist/drilldown/root/drilldown-root.js +263 -0
- package/dist/element-events.generated.d.ts +1 -0
- package/dist/element-events.generated.js +125 -0
- package/dist/empty/index.d.ts +1 -0
- package/dist/empty/index.js +1 -0
- package/dist/empty/root/empty-root.d.ts +47 -0
- package/dist/empty/root/empty-root.js +68 -0
- package/dist/file-input/index.d.ts +1 -0
- package/dist/file-input/index.js +1 -0
- package/dist/file-input/root/file-input-root.d.ts +196 -0
- package/dist/file-input/root/file-input-root.js +488 -0
- package/dist/format-date/index.d.ts +1 -0
- package/dist/format-date/index.js +1 -0
- package/dist/format-date/root/format-date-root.d.ts +151 -0
- package/dist/format-date/root/format-date-root.js +266 -0
- package/dist/heatmap/index.d.ts +2 -0
- package/dist/heatmap/index.js +2 -0
- package/dist/heatmap/root/buckets.d.ts +62 -0
- package/dist/heatmap/root/buckets.js +85 -0
- package/dist/heatmap/root/heatmap-root.d.ts +330 -0
- package/dist/heatmap/root/heatmap-root.js +526 -0
- package/dist/icon/index.d.ts +1 -0
- package/dist/icon/index.js +1 -0
- package/dist/icon/root/icon-root.d.ts +53 -0
- package/dist/icon/root/icon-root.js +93 -0
- package/dist/icon-button/index.d.ts +1 -0
- package/dist/icon-button/index.js +1 -0
- package/dist/icon-button/root/icon-button-root.d.ts +40 -0
- package/dist/icon-button/root/icon-button-root.js +46 -0
- package/dist/image/index.d.ts +1 -0
- package/dist/image/index.js +1 -0
- package/dist/image/root/image-root.d.ts +213 -0
- package/dist/image/root/image-root.js +335 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.js +99 -0
- package/dist/input/index.d.ts +1 -0
- package/dist/input/index.js +1 -0
- package/dist/input/root/input-root.d.ts +281 -0
- package/dist/input/root/input-root.js +472 -0
- package/dist/kbd/index.d.ts +1 -0
- package/dist/kbd/index.js +1 -0
- package/dist/kbd/root/kbd-root.d.ts +98 -0
- package/dist/kbd/root/kbd-root.js +230 -0
- package/dist/legend/index.d.ts +1 -0
- package/dist/legend/index.js +1 -0
- package/dist/legend/root/legend-root.d.ts +83 -0
- package/dist/legend/root/legend-root.js +125 -0
- package/dist/line-chart/index.d.ts +1 -0
- package/dist/line-chart/index.js +1 -0
- package/dist/line-chart/root/line-chart-root.d.ts +238 -0
- package/dist/line-chart/root/line-chart-root.js +365 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/list/index.js +2 -0
- package/dist/list/item/list-item.d.ts +95 -0
- package/dist/list/item/list-item.js +148 -0
- package/dist/list/root/list-root.d.ts +72 -0
- package/dist/list/root/list-root.js +61 -0
- package/dist/listbox/index.d.ts +1 -0
- package/dist/listbox/index.js +1 -0
- package/dist/listbox/root/listbox-root.d.ts +357 -0
- package/dist/listbox/root/listbox-root.js +890 -0
- package/dist/loader/index.d.ts +1 -0
- package/dist/loader/index.js +1 -0
- package/dist/loader/root/loader-root.d.ts +52 -0
- package/dist/loader/root/loader-root.js +74 -0
- package/dist/megamenu/index.d.ts +1 -0
- package/dist/megamenu/index.js +1 -0
- package/dist/megamenu/root/megamenu-root.d.ts +254 -0
- package/dist/megamenu/root/megamenu-root.js +526 -0
- package/dist/menu/index.d.ts +2 -0
- package/dist/menu/index.js +2 -0
- package/dist/menu/item/menu-item.d.ts +231 -0
- package/dist/menu/item/menu-item.js +405 -0
- package/dist/menu/root/menu-root.d.ts +158 -0
- package/dist/menu/root/menu-root.js +422 -0
- package/dist/meter/index.d.ts +1 -0
- package/dist/meter/index.js +1 -0
- package/dist/meter/root/meter-root.d.ts +234 -0
- package/dist/meter/root/meter-root.js +316 -0
- package/dist/navigation/index.d.ts +1 -0
- package/dist/navigation/index.js +1 -0
- package/dist/navigation/root/navigation-root.d.ts +55 -0
- package/dist/navigation/root/navigation-root.js +130 -0
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.js +2 -0
- package/dist/notifications/notification/notification.d.ts +181 -0
- package/dist/notifications/notification/notification.js +305 -0
- package/dist/notifications/root/notifications-root.d.ts +168 -0
- package/dist/notifications/root/notifications-root.js +291 -0
- package/dist/number-input/index.d.ts +1 -0
- package/dist/number-input/index.js +1 -0
- package/dist/number-input/root/number-input-root.d.ts +282 -0
- package/dist/number-input/root/number-input-root.js +592 -0
- package/dist/option/group/option-group.d.ts +38 -0
- package/dist/option/group/option-group.js +58 -0
- package/dist/option/index.d.ts +2 -0
- package/dist/option/index.js +2 -0
- package/dist/option/root/option-root.d.ts +194 -0
- package/dist/option/root/option-root.js +247 -0
- package/dist/outline/index.d.ts +1 -0
- package/dist/outline/index.js +1 -0
- package/dist/outline/root/outline-root.d.ts +237 -0
- package/dist/outline/root/outline-root.js +519 -0
- package/dist/pagination/index.d.ts +3 -0
- package/dist/pagination/index.js +3 -0
- package/dist/pagination/root/pagination-root.d.ts +390 -0
- package/dist/pagination/root/pagination-root.js +695 -0
- package/dist/pagination/size/pagination-size.d.ts +127 -0
- package/dist/pagination/size/pagination-size.js +232 -0
- package/dist/pagination/summary/pagination-summary.d.ts +90 -0
- package/dist/pagination/summary/pagination-summary.js +145 -0
- package/dist/pin-input/index.d.ts +1 -0
- package/dist/pin-input/index.js +1 -0
- package/dist/pin-input/root/pin-input-root.d.ts +292 -0
- package/dist/pin-input/root/pin-input-root.js +553 -0
- package/dist/popover/index.d.ts +1 -0
- package/dist/popover/index.js +1 -0
- package/dist/popover/root/popover-root.d.ts +108 -0
- package/dist/popover/root/popover-root.js +231 -0
- package/dist/progress/index.d.ts +1 -0
- package/dist/progress/index.js +1 -0
- package/dist/progress/root/progress-root.d.ts +125 -0
- package/dist/progress/root/progress-root.js +212 -0
- package/dist/qr-code/index.d.ts +1 -0
- package/dist/qr-code/index.js +1 -0
- package/dist/qr-code/root/qr-code-root.d.ts +93 -0
- package/dist/qr-code/root/qr-code-root.js +233 -0
- package/dist/quote/index.d.ts +1 -0
- package/dist/quote/index.js +1 -0
- package/dist/quote/root/quote-root.d.ts +36 -0
- package/dist/quote/root/quote-root.js +50 -0
- package/dist/radio/group/radio-group.d.ts +84 -0
- package/dist/radio/group/radio-group.js +170 -0
- package/dist/radio/index.d.ts +2 -0
- package/dist/radio/index.js +2 -0
- package/dist/radio/root/radio-root.d.ts +102 -0
- package/dist/radio/root/radio-root.js +151 -0
- package/dist/rating/index.d.ts +1 -0
- package/dist/rating/index.js +1 -0
- package/dist/rating/root/rating-root.d.ts +242 -0
- package/dist/rating/root/rating-root.js +484 -0
- package/dist/scroll-area/index.d.ts +1 -0
- package/dist/scroll-area/index.js +1 -0
- package/dist/scroll-area/root/scroll-area-root.d.ts +96 -0
- package/dist/scroll-area/root/scroll-area-root.js +215 -0
- package/dist/select/index.d.ts +1 -0
- package/dist/select/index.js +1 -0
- package/dist/select/root/select-root.d.ts +170 -0
- package/dist/select/root/select-root.js +419 -0
- package/dist/skeleton/index.d.ts +1 -0
- package/dist/skeleton/index.js +1 -0
- package/dist/skeleton/root/skeleton-root.d.ts +31 -0
- package/dist/skeleton/root/skeleton-root.js +42 -0
- package/dist/slider/index.d.ts +1 -0
- package/dist/slider/index.js +1 -0
- package/dist/slider/root/slider-root.d.ts +235 -0
- package/dist/slider/root/slider-root.js +488 -0
- package/dist/sparkline/index.d.ts +1 -0
- package/dist/sparkline/index.js +1 -0
- package/dist/sparkline/root/sparkline-root.d.ts +147 -0
- package/dist/sparkline/root/sparkline-root.js +278 -0
- package/dist/speed-dial/index.d.ts +2 -0
- package/dist/speed-dial/index.js +2 -0
- package/dist/speed-dial/item/speed-dial-item.d.ts +71 -0
- package/dist/speed-dial/item/speed-dial-item.js +113 -0
- package/dist/speed-dial/root/speed-dial-root.d.ts +122 -0
- package/dist/speed-dial/root/speed-dial-root.js +251 -0
- package/dist/splitter/index.d.ts +1 -0
- package/dist/splitter/index.js +1 -0
- package/dist/splitter/root/splitter-root.d.ts +491 -0
- package/dist/splitter/root/splitter-root.js +1030 -0
- package/dist/stat/group/stat-group.d.ts +30 -0
- package/dist/stat/group/stat-group.js +47 -0
- package/dist/stat/index.d.ts +2 -0
- package/dist/stat/index.js +2 -0
- package/dist/stat/root/stat-root.d.ts +62 -0
- package/dist/stat/root/stat-root.js +51 -0
- package/dist/steps/index.d.ts +2 -0
- package/dist/steps/index.js +2 -0
- package/dist/steps/root/steps-root.d.ts +110 -0
- package/dist/steps/root/steps-root.js +130 -0
- package/dist/steps/step/step.d.ts +139 -0
- package/dist/steps/step/step.js +215 -0
- package/dist/switch/index.d.ts +1 -0
- package/dist/switch/index.js +1 -0
- package/dist/switch/root/switch-root.d.ts +74 -0
- package/dist/switch/root/switch-root.js +153 -0
- package/dist/table/cell/table-cell.d.ts +34 -0
- package/dist/table/cell/table-cell.js +52 -0
- package/dist/table/column/table-column.d.ts +165 -0
- package/dist/table/column/table-column.js +222 -0
- package/dist/table/index.d.ts +4 -0
- package/dist/table/index.js +4 -0
- package/dist/table/root/table-root.d.ts +98 -0
- package/dist/table/root/table-root.js +161 -0
- package/dist/table/row/table-row.d.ts +27 -0
- package/dist/table/row/table-row.js +42 -0
- package/dist/tabs/index.d.ts +3 -0
- package/dist/tabs/index.js +3 -0
- package/dist/tabs/panel/tab-panel.d.ts +67 -0
- package/dist/tabs/panel/tab-panel.js +98 -0
- package/dist/tabs/root/tabs-root.d.ts +123 -0
- package/dist/tabs/root/tabs-root.js +217 -0
- package/dist/tabs/tab/tab.d.ts +64 -0
- package/dist/tabs/tab/tab.js +116 -0
- package/dist/tag/index.d.ts +1 -0
- package/dist/tag/index.js +1 -0
- package/dist/tag/root/tag-root.d.ts +41 -0
- package/dist/tag/root/tag-root.js +67 -0
- package/dist/textarea/index.d.ts +1 -0
- package/dist/textarea/index.js +1 -0
- package/dist/textarea/root/textarea-root.d.ts +215 -0
- package/dist/textarea/root/textarea-root.js +380 -0
- package/dist/time-input/index.d.ts +1 -0
- package/dist/time-input/index.js +1 -0
- package/dist/time-input/root/time-input-root.d.ts +322 -0
- package/dist/time-input/root/time-input-root.js +661 -0
- package/dist/time-picker/index.d.ts +1 -0
- package/dist/time-picker/index.js +1 -0
- package/dist/time-picker/root/time-picker-root.d.ts +380 -0
- package/dist/time-picker/root/time-picker-root.js +669 -0
- package/dist/timeline/index.d.ts +2 -0
- package/dist/timeline/index.js +2 -0
- package/dist/timeline/item/timeline-item.d.ts +81 -0
- package/dist/timeline/item/timeline-item.js +128 -0
- package/dist/timeline/root/timeline-root.d.ts +52 -0
- package/dist/timeline/root/timeline-root.js +72 -0
- package/dist/toast/index.d.ts +2 -0
- package/dist/toast/index.js +2 -0
- package/dist/toast/item/toast-item.d.ts +183 -0
- package/dist/toast/item/toast-item.js +345 -0
- package/dist/toast/root/toast-root.d.ts +72 -0
- package/dist/toast/root/toast-root.js +87 -0
- package/dist/toggle/group/toggle-group.d.ts +140 -0
- package/dist/toggle/group/toggle-group.js +278 -0
- package/dist/toggle/index.d.ts +2 -0
- package/dist/toggle/index.js +2 -0
- package/dist/toggle/root/toggle-root.d.ts +99 -0
- package/dist/toggle/root/toggle-root.js +146 -0
- package/dist/toolbar/index.d.ts +1 -0
- package/dist/toolbar/index.js +1 -0
- package/dist/toolbar/root/toolbar-root.d.ts +105 -0
- package/dist/toolbar/root/toolbar-root.js +260 -0
- package/dist/tooltip/index.d.ts +1 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/root/tooltip-root.d.ts +388 -0
- package/dist/tooltip/root/tooltip-root.js +707 -0
- package/dist/tour/index.d.ts +2 -0
- package/dist/tour/index.js +2 -0
- package/dist/tour/root/tour-root.d.ts +161 -0
- package/dist/tour/root/tour-root.js +351 -0
- package/dist/tour/stop/tour-stop.d.ts +131 -0
- package/dist/tour/stop/tour-stop.js +249 -0
- package/dist/tree/index.d.ts +2 -0
- package/dist/tree/index.js +2 -0
- package/dist/tree/item/tree-item.d.ts +208 -0
- package/dist/tree/item/tree-item.js +381 -0
- package/dist/tree/root/tree-root.d.ts +88 -0
- package/dist/tree/root/tree-root.js +287 -0
- package/dist/trend/index.d.ts +1 -0
- package/dist/trend/index.js +1 -0
- package/dist/trend/root/trend-root.d.ts +67 -0
- package/dist/trend/root/trend-root.js +106 -0
- package/dist/video/index.d.ts +1 -0
- package/dist/video/index.js +1 -0
- package/dist/video/root/video-root.d.ts +711 -0
- package/dist/video/root/video-root.js +1821 -0
- package/dist/video-playlist/index.d.ts +3 -0
- package/dist/video-playlist/index.js +3 -0
- package/dist/video-playlist/item/video-playlist-item.d.ts +101 -0
- package/dist/video-playlist/item/video-playlist-item.js +162 -0
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +121 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +237 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +108 -0
- package/dist/video-playlist/root/video-playlist-root.js +218 -0
- package/dist/virtual-list/index.d.ts +1 -0
- package/dist/virtual-list/index.js +1 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +121 -0
- package/dist/virtual-list/root/virtual-list-root.js +221 -0
- package/jsx.d.ts +49767 -0
- package/package.json +77 -0
- package/svelte.d.ts +129 -0
- package/vue.d.ts +9242 -0
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var HelixHeadlessDataTable_1;
|
|
8
|
+
import { customElement, HelixElement, HelixFilterEvent, HelixNavigateEvent, HelixSortEvent, hostAria, MixinCollection, requestChange, slotFilled, } from '@fusion.dev/helix-core';
|
|
9
|
+
import { nothing } from 'lit';
|
|
10
|
+
import { property, state } from 'lit/decorators.js';
|
|
11
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
12
|
+
/* `static-html`'s `html`, because the pagination's tag is interpolated: a
|
|
13
|
+
template naming a literal `helix-pagination` renders the styled element from
|
|
14
|
+
the headless tier, and `lit`'s own `html` treats `${tag}` in tag position as
|
|
15
|
+
text, which renders an element called `lit$…$` that lays out as nothing.
|
|
16
|
+
Measured: the styled spec read `localName` as `lit$640177303$`. */
|
|
17
|
+
import { html } from 'lit/static-html.js';
|
|
18
|
+
import '../../pagination/index.js';
|
|
19
|
+
import { cycle, format, ordered, parse } from './order.js';
|
|
20
|
+
/**
|
|
21
|
+
* @summary A table that owns a result: rows as data, with sort, filter and paging.
|
|
22
|
+
*
|
|
23
|
+
* @description
|
|
24
|
+
* **The schema is markup and the data is a property.** Columns are declared as
|
|
25
|
+
* `helix-table-column` children, because a schema is small, declarative, and
|
|
26
|
+
* something a reader should be able to see in the HTML; rows are handed over as
|
|
27
|
+
* an array, because data is large and a table that draws ten thousand elements
|
|
28
|
+
* cannot window them.
|
|
29
|
+
*
|
|
30
|
+
* ```html
|
|
31
|
+
* <helix-data-table .rows=${rows} sort="name:asc" page-size="20">
|
|
32
|
+
* <helix-table-column field="name" sortable>Name</helix-table-column>
|
|
33
|
+
* <helix-table-column field="size" align="end" sortable .cell=${bytes}>Size</helix-table-column>
|
|
34
|
+
* </helix-data-table>
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* This is the resolution of a deferral rather than a new idea. `helix-table`
|
|
38
|
+
* takes rows as markup and is the right component for a table of twelve things
|
|
39
|
+
* a person wrote out; the repeated `page`, `page-size` and `total` attributes on
|
|
40
|
+
* the three pagination elements are placeholders whose own comments name the fix
|
|
41
|
+
* as "a data table composing a pagination inside itself", and `helix-table`
|
|
42
|
+
* already carried `@aliases DataTable`: a name claimed and not kept.
|
|
43
|
+
*
|
|
44
|
+
* **Sort and filter apply to the whole set, never the page.** Sorting the drawn
|
|
45
|
+
* window is correct on the first screen and wrong on every other one, which is
|
|
46
|
+
* how it survives being looked at. The arithmetic lives in `order.ts` where
|
|
47
|
+
* nothing can see a window, and its spec asserts the composition rather than the
|
|
48
|
+
* three steps, because each step alone passes either way.
|
|
49
|
+
*
|
|
50
|
+
* **What it does not do, stated where a consumer will read it: the cell values
|
|
51
|
+
* do not server-render.** The headings do, because a column renders its own, and
|
|
52
|
+
* the row elements do, because their count comes from `rows`. Reading a cell
|
|
53
|
+
* needs the columns, and the columns are markup children that Lit SSR does not
|
|
54
|
+
* hand this element: `children` is undefined there. So a crawler and a reader on
|
|
55
|
+
* a slow connection see a table of the right shape with nothing in it, which is
|
|
56
|
+
* strictly less than `helix-table` serves for a table whose rows are markup.
|
|
57
|
+
*
|
|
58
|
+
* That is the cost of "the schema is markup and the data is a property". Use
|
|
59
|
+
* `helix-table` where the content has to be in the served HTML and the result is
|
|
60
|
+
* small enough to write out; use this where the result is large, and accept that
|
|
61
|
+
* the first paint is a shell. The obvious workaround, a `columns` property
|
|
62
|
+
* beside the markup columns, is deliberately not offered: this family has
|
|
63
|
+
* already shipped one source of truth for columns splitting into two, nothing
|
|
64
|
+
* checked that they agreed, and a table rendering one way on the server and
|
|
65
|
+
* another in the browser is that failure with a hydration mismatch on top.
|
|
66
|
+
*
|
|
67
|
+
* **Every axis is controlled or uncontrolled, and that is what makes a server
|
|
68
|
+
* mode fall out rather than be bolted on.** `sort`, `filter`, `page` and
|
|
69
|
+
* `page-size` each defer to the consumer when set and seed themselves from a
|
|
70
|
+
* `default-*` when not. A consumer who answers all four holds the data flow:
|
|
71
|
+
* they hear the reader's request, fetch, and hand back a new `rows` with a
|
|
72
|
+
* `total`. Retrofitting that inverts the flow and is a rewrite, so it is here
|
|
73
|
+
* from the start.
|
|
74
|
+
*
|
|
75
|
+
* @since 0.1.0
|
|
76
|
+
* @status experimental
|
|
77
|
+
* @category data
|
|
78
|
+
* @aliases Grid, Result table, Data grid
|
|
79
|
+
* @documentation https://helix.fusion.dev/components/data-table
|
|
80
|
+
*
|
|
81
|
+
* @slot - The columns, declared as `helix-table-column` children.
|
|
82
|
+
* @slot footer - Below the grid, replacing the pagination this would otherwise draw.
|
|
83
|
+
* @slot toolbar - Above the grid, for a search field or actions.
|
|
84
|
+
*
|
|
85
|
+
* @event {HelixFilterEvent} helix-filter - Fired when the query changes, and cancelable.
|
|
86
|
+
* @event {HelixNavigateEvent} helix-navigate - Fired when a reader asks for another page, and cancelable.
|
|
87
|
+
* @event {HelixSortEvent} helix-sort - Fired when a reader asks for a different order, and cancelable.
|
|
88
|
+
*
|
|
89
|
+
* @csspart cell - One cell.
|
|
90
|
+
* @csspart empty - Shown when no rows match.
|
|
91
|
+
* @csspart footer - The region below the grid.
|
|
92
|
+
* @csspart head - The row the column headings sit in. `display: contents`, so it takes no space.
|
|
93
|
+
* @csspart loading - Shown while the rows are still on their way.
|
|
94
|
+
* @csspart pagination - The pagination, where this draws one.
|
|
95
|
+
* @csspart row - One row of data.
|
|
96
|
+
* @csspart table - The grid.
|
|
97
|
+
* @csspart toolbar - The region above the grid.
|
|
98
|
+
*
|
|
99
|
+
* @cssproperty --data-table-template - The column track list this element worked out from the columns declared in it. Written by the component, read by the sheet that paints: a stylesheet takes it to lay the grid out, and setting it does nothing, because the component writes it inline on the very element that reads it and an inline declaration beats any sheet. `--data-table-columns` is the one to set.
|
|
100
|
+
*/
|
|
101
|
+
let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollection(HelixElement) {
|
|
102
|
+
constructor() {
|
|
103
|
+
super(...arguments);
|
|
104
|
+
/**
|
|
105
|
+
* The whole result, in the order it arrived.
|
|
106
|
+
*
|
|
107
|
+
* A property and not an attribute: it is an array. Left alone this element
|
|
108
|
+
* filters, sorts and pages it; in `server` mode it is the page the consumer
|
|
109
|
+
* already fetched and none of the three is applied.
|
|
110
|
+
*
|
|
111
|
+
* **Read, never written.** Sorting produces a new array rather than reordering
|
|
112
|
+
* this one, because a consumer's array may be the same object their own state
|
|
113
|
+
* holds and reordering it under them is a mutation they did not ask for.
|
|
114
|
+
*/
|
|
115
|
+
this.rows = [];
|
|
116
|
+
/**
|
|
117
|
+
* The field naming a row's stable identity.
|
|
118
|
+
*
|
|
119
|
+
* **Needed before selection exists, not after.** Lit keys the rendered rows by
|
|
120
|
+
* it, so a sort moves a row's element rather than rewriting every cell in
|
|
121
|
+
* place, which is what keeps focus inside a cell and keeps a CSS transition
|
|
122
|
+
* attached to the row it belongs to. Left unset the index is the key, which is
|
|
123
|
+
* correct only while nothing reorders: it is why this defaults to something
|
|
124
|
+
* that works and is worth setting anyway.
|
|
125
|
+
*/
|
|
126
|
+
this.key = '';
|
|
127
|
+
/**
|
|
128
|
+
* Whether this element does the work or asks the consumer to.
|
|
129
|
+
*
|
|
130
|
+
* `client` filters, sorts and pages `rows` itself. `server` applies none of
|
|
131
|
+
* them: `rows` is the page, `total` is the size of the whole result, and the
|
|
132
|
+
* three events are requests the consumer answers by fetching. Past some size
|
|
133
|
+
* the client cannot hold the data, so this is not an optimization, it is the
|
|
134
|
+
* only mode that works, and it is here from the start because adding it later
|
|
135
|
+
* inverts the data flow.
|
|
136
|
+
*/
|
|
137
|
+
this.mode = 'client';
|
|
138
|
+
/**
|
|
139
|
+
* How many rows the whole result has, where this element cannot count them.
|
|
140
|
+
*
|
|
141
|
+
* Only read in `server` mode, where `rows` is one page and its length says
|
|
142
|
+
* nothing about the result. Ignored in `client` mode rather than trusted,
|
|
143
|
+
* because two sources for one count is the mistake, and here the array is the
|
|
144
|
+
* one that cannot be stale.
|
|
145
|
+
*/
|
|
146
|
+
this.total = 0;
|
|
147
|
+
/**
|
|
148
|
+
* Accessible name for the grid.
|
|
149
|
+
*/
|
|
150
|
+
this.label = '';
|
|
151
|
+
/**
|
|
152
|
+
* Order to open on, where nothing declared one.
|
|
153
|
+
*/
|
|
154
|
+
this.defaultSort = '';
|
|
155
|
+
/**
|
|
156
|
+
* Query to open with, where nothing declared one.
|
|
157
|
+
*/
|
|
158
|
+
this.defaultFilter = '';
|
|
159
|
+
/**
|
|
160
|
+
* Page to open on, where nothing declared one.
|
|
161
|
+
*/
|
|
162
|
+
this.defaultPage = 1;
|
|
163
|
+
/**
|
|
164
|
+
* Page size to open with, where nothing declared one.
|
|
165
|
+
*/
|
|
166
|
+
this.defaultPageSize = 0;
|
|
167
|
+
this.sortState = undefined;
|
|
168
|
+
this.filterState = undefined;
|
|
169
|
+
this.pageState = undefined;
|
|
170
|
+
this.pageSizeState = undefined;
|
|
171
|
+
this.paginatedState = undefined;
|
|
172
|
+
/** Said once per element, so a table that re-renders does not repeat it. */
|
|
173
|
+
this.warnedAboutSize = false;
|
|
174
|
+
/** Columns arrive from the light DOM, which changes no property here. */
|
|
175
|
+
this.handleSlotChange = () => {
|
|
176
|
+
this.requestUpdate();
|
|
177
|
+
};
|
|
178
|
+
/** A click on a sortable heading. */
|
|
179
|
+
this.handleHeadClick = (event) => {
|
|
180
|
+
const column = this.columnFrom(event);
|
|
181
|
+
if (column?.canSort) {
|
|
182
|
+
this.toggleSort(column.field);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
/** The same on Enter and Space, since a heading that sorts is a control. */
|
|
186
|
+
this.handleHeadKey = (event) => {
|
|
187
|
+
if (event.key !== 'Enter' && event.key !== ' ') {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const column = this.columnFrom(event);
|
|
191
|
+
if (column?.canSort) {
|
|
192
|
+
event.preventDefault();
|
|
193
|
+
this.toggleSort(column.field);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* The composed pagination's request, relayed as this element's own.
|
|
198
|
+
*
|
|
199
|
+
* Stopped rather than allowed to bubble, because two `helix-navigate` events
|
|
200
|
+
* for one click would reach a consumer's handler twice: the pagination's, and
|
|
201
|
+
* this element's after it. The one that leaves carries this element's page
|
|
202
|
+
* bounds rather than the inner component's.
|
|
203
|
+
*/
|
|
204
|
+
this.handleNavigate = (event) => {
|
|
205
|
+
event.stopPropagation();
|
|
206
|
+
const wanted = Number(event.detail.value);
|
|
207
|
+
if (!Number.isFinite(wanted) || !this.requestPage(wanted)) {
|
|
208
|
+
event.preventDefault();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
static { HelixHeadlessDataTable_1 = this; }
|
|
213
|
+
/**
|
|
214
|
+
* Nothing is assigned by name, so the columns can be put in a header row.
|
|
215
|
+
*
|
|
216
|
+
* `role="columnheader"` under `role="grid"` with no owning row is invalid, and
|
|
217
|
+
* the columns are ordinary children a consumer writes with no `slot`. Manual
|
|
218
|
+
* assignment is the only way to wrap them without editing the consumer's
|
|
219
|
+
* markup, which is a change a React consumer's hydration reports and does not
|
|
220
|
+
* patch up. The same arrangement `helix-table` arrived at, for the same reason.
|
|
221
|
+
*/
|
|
222
|
+
static { this.shadowRootOptions = {
|
|
223
|
+
...HelixElement.shadowRootOptions,
|
|
224
|
+
slotAssignment: 'manual',
|
|
225
|
+
}; }
|
|
226
|
+
/**
|
|
227
|
+
* The order, as `field:direction`.
|
|
228
|
+
*
|
|
229
|
+
* Set it and this element defers: a reader's click fires `helix-sort` and
|
|
230
|
+
* changes nothing until a new value arrives. `default-sort` seeds an order this
|
|
231
|
+
* element then owns.
|
|
232
|
+
*
|
|
233
|
+
*
|
|
234
|
+
*/
|
|
235
|
+
get sort() {
|
|
236
|
+
return this.sortState ?? this.defaultSort;
|
|
237
|
+
}
|
|
238
|
+
set sort(next) {
|
|
239
|
+
const previous = this.sort;
|
|
240
|
+
this.sortState = next;
|
|
241
|
+
this.requestUpdate('sort', previous);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* What the rows are narrowed to, as one query across every column.
|
|
245
|
+
*
|
|
246
|
+
* One query rather than a predicate per column, which is what a reader means
|
|
247
|
+
* by a search box above a table. It matches on each column's ordering value,
|
|
248
|
+
* so search and sort cannot disagree about what a column holds.
|
|
249
|
+
*
|
|
250
|
+
*
|
|
251
|
+
*/
|
|
252
|
+
get filter() {
|
|
253
|
+
return this.filterState ?? this.defaultFilter;
|
|
254
|
+
}
|
|
255
|
+
set filter(next) {
|
|
256
|
+
const previous = this.filter;
|
|
257
|
+
this.filterState = next;
|
|
258
|
+
this.requestUpdate('filter', previous);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The page on show, from 1.
|
|
262
|
+
*
|
|
263
|
+
* Clamped on the way out, so what this reports is the page it drew: a
|
|
264
|
+
* bookmarked link to page 99 of a result that has since shrunk reads back as
|
|
265
|
+
* the last page rather than as 99.
|
|
266
|
+
*
|
|
267
|
+
*
|
|
268
|
+
*/
|
|
269
|
+
get page() {
|
|
270
|
+
const asked = this.pageState ?? this.defaultPage;
|
|
271
|
+
return Math.min(this.pages, Math.max(1, Math.floor(asked) || 1));
|
|
272
|
+
}
|
|
273
|
+
set page(next) {
|
|
274
|
+
const previous = this.page;
|
|
275
|
+
this.pageState = next;
|
|
276
|
+
this.requestUpdate('page', previous);
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* How many rows a page holds. Zero is every row, which is what "no paging" means.
|
|
280
|
+
*
|
|
281
|
+
* **It announces nothing, and that is not an omission.** Nothing in this
|
|
282
|
+
* element ever asks for a different page size: a size selector is
|
|
283
|
+
* `helix-pagination-size`, which a consumer puts in the `footer` slot and
|
|
284
|
+
* answers themselves. Routing this through `requestChange` would announce an
|
|
285
|
+
* event the element never has cause to fire.
|
|
286
|
+
*/
|
|
287
|
+
get pageSize() {
|
|
288
|
+
return Math.max(0, Math.floor(this.pageSizeState ?? this.defaultPageSize) || 0);
|
|
289
|
+
}
|
|
290
|
+
set pageSize(next) {
|
|
291
|
+
const previous = this.pageSize;
|
|
292
|
+
this.pageSizeState = next;
|
|
293
|
+
this.requestUpdate('pageSize', previous);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Whether to draw a pagination under the grid.
|
|
297
|
+
*
|
|
298
|
+
* On by default once a page size is set, because a paged table with no way to
|
|
299
|
+
* change pages shows a reader the first twenty rows and no way to know there
|
|
300
|
+
* are more. Off for a consumer supplying their own through the `footer` slot,
|
|
301
|
+
* which is why the slot replaces this rather than sitting beside it.
|
|
302
|
+
*/
|
|
303
|
+
get paginated() {
|
|
304
|
+
return this.paginatedState ?? this.pageSize > 0;
|
|
305
|
+
}
|
|
306
|
+
set paginated(next) {
|
|
307
|
+
const previous = this.paginated;
|
|
308
|
+
this.paginatedState = next;
|
|
309
|
+
this.requestUpdate('paginated', previous);
|
|
310
|
+
}
|
|
311
|
+
/** The columns declared as children, in the order they are written. */
|
|
312
|
+
get tableColumns() {
|
|
313
|
+
/* `?? []` is the server. Lit's element shim carries attributes and not a
|
|
314
|
+
tree, so `children` is undefined there, and this getter is read during
|
|
315
|
+
`render`: spreading it threw and took the whole SSR suite with it in this
|
|
316
|
+
family once already. */
|
|
317
|
+
return [...(this.children ?? [])].filter((child) => 'isTableColumn' in child && child.isTableColumn === true);
|
|
318
|
+
}
|
|
319
|
+
/** The columns reduced to what the ordering needs. */
|
|
320
|
+
get axes() {
|
|
321
|
+
return this.tableColumns
|
|
322
|
+
.filter((column) => column.field !== '')
|
|
323
|
+
.map((column) => ({ field: column.field, order: (row) => column.order(row) }));
|
|
324
|
+
}
|
|
325
|
+
/** The track list, from the columns if there are any. */
|
|
326
|
+
get template() {
|
|
327
|
+
const declared = this.tableColumns;
|
|
328
|
+
return declared.length > 0 ? declared.map((column) => column.track).join(' ') : '';
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* How many rows this draws before it is worth saying something, and why 2,000.
|
|
332
|
+
*
|
|
333
|
+
* Measured 28 Aug 2026 on a four-column grid, mounting and painting: 100 rows
|
|
334
|
+
* in 10.9ms, 500 in 30.2ms, 2,000 in 83.2ms and **5,000 rows as 20,000 cells
|
|
335
|
+
* in 186ms**. It is linear at roughly 37 microseconds a row, so the 100ms an
|
|
336
|
+
* interaction has to stay inside lands near 2,700 and this sits under it.
|
|
337
|
+
* Sorting stays cheap throughout, 23.7ms at five thousand, so the cost is the
|
|
338
|
+
* cells rather than the work over them.
|
|
339
|
+
*/
|
|
340
|
+
static { this.COMFORTABLE = 2_000; }
|
|
341
|
+
/**
|
|
342
|
+
* Says so when a table is asked to draw more than it comfortably can.
|
|
343
|
+
*
|
|
344
|
+
* **The component renders every row it is given and defaults to doing so.**
|
|
345
|
+
* `defaultPageSize` is `0`, so `paginated` is false unless a consumer asks,
|
|
346
|
+
* which means the out-of-the-box arrangement is the unbounded one and nothing
|
|
347
|
+
* about it says that a result of any size will simply be drawn.
|
|
348
|
+
*
|
|
349
|
+
* **Windowing was considered and refused**, which is worth recording because
|
|
350
|
+
* it is the obvious answer. This element already has two: `paginated` with a
|
|
351
|
+
* `page-size`, and `mode="server"` where `rows` is one page, `total` is the
|
|
352
|
+
* whole result and `aria-rowcount` already reports the result rather than the
|
|
353
|
+
* window, which is the hard half of virtualization done correctly. A third
|
|
354
|
+
* mechanism would fight the first two, and virtualizing a grid means variable
|
|
355
|
+
* row heights, a sticky header and keeping `aria-rowindex` honest against a
|
|
356
|
+
* result the element is no longer holding. `VirtualizeController` exists for
|
|
357
|
+
* the case where the rows are a flat list and this is not that. See #326.
|
|
358
|
+
*
|
|
359
|
+
* So the gap was never the capability, it was that nothing said which of the
|
|
360
|
+
* two to reach for. Once per element, in a browser only: a warning during a
|
|
361
|
+
* server render is one nobody can act on and one that would print per request.
|
|
362
|
+
*/
|
|
363
|
+
warnIfCrowded(drawn) {
|
|
364
|
+
if (this.warnedAboutSize ||
|
|
365
|
+
drawn <= HelixHeadlessDataTable_1.COMFORTABLE ||
|
|
366
|
+
typeof window === 'undefined') {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
this.warnedAboutSize = true;
|
|
370
|
+
console.warn(`<${this.localName}> is drawing ${drawn} rows at once, which is past the ${HelixHeadlessDataTable_1.COMFORTABLE} ` +
|
|
371
|
+
'it stays responsive to: every row is rendered, so this costs roughly 37 microseconds each and ' +
|
|
372
|
+
'crosses an interaction budget around 2,700. Set `page-size` to paginate, or `mode="server"` ' +
|
|
373
|
+
'to hand it one page at a time with `total` describing the whole result.');
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The rows to draw, and the counts around them.
|
|
377
|
+
*
|
|
378
|
+
* In `server` mode this element applies nothing: `rows` is already the page,
|
|
379
|
+
* `total` is the result, and both counts come from the consumer. Anything else
|
|
380
|
+
* would be this element filtering a page it was handed, which narrows one
|
|
381
|
+
* screen and calls it a search.
|
|
382
|
+
*/
|
|
383
|
+
get view() {
|
|
384
|
+
if (this.mode === 'server') {
|
|
385
|
+
const total = Math.max(this.total, this.rows.length);
|
|
386
|
+
return { matched: total, rows: [...this.rows], total };
|
|
387
|
+
}
|
|
388
|
+
const view = ordered(this.rows, this.axes, {
|
|
389
|
+
page: this.page,
|
|
390
|
+
query: this.filter,
|
|
391
|
+
size: this.pageSize,
|
|
392
|
+
spec: this.sort,
|
|
393
|
+
});
|
|
394
|
+
this.warnIfCrowded(view.rows.length);
|
|
395
|
+
return view;
|
|
396
|
+
}
|
|
397
|
+
/** How many pages the result makes, which is at least one even when empty. */
|
|
398
|
+
get pages() {
|
|
399
|
+
const size = this.pageSize;
|
|
400
|
+
if (size <= 0) {
|
|
401
|
+
return 1;
|
|
402
|
+
}
|
|
403
|
+
const count = this.mode === 'server' ? Math.max(this.total, this.rows.length) : this.matched;
|
|
404
|
+
return Math.max(1, Math.ceil(count / size));
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Rows after filtering, computed without paging.
|
|
408
|
+
*
|
|
409
|
+
* Separate from `view` because `pages` needs it and `page` needs `pages`:
|
|
410
|
+
* asking `view` for it would recurse through the clamp in `page`.
|
|
411
|
+
*/
|
|
412
|
+
get matched() {
|
|
413
|
+
const query = this.filter.trim();
|
|
414
|
+
if (query === '') {
|
|
415
|
+
return this.rows.length;
|
|
416
|
+
}
|
|
417
|
+
const axes = this.axes;
|
|
418
|
+
const needle = query.toLocaleLowerCase();
|
|
419
|
+
return this.rows.filter((row) => axes.some((axis) => {
|
|
420
|
+
const value = axis.order(row);
|
|
421
|
+
return value === null || value === undefined
|
|
422
|
+
? false
|
|
423
|
+
: String(value).toLocaleLowerCase().includes(needle);
|
|
424
|
+
})).length;
|
|
425
|
+
}
|
|
426
|
+
/** Emptiness is a fact about the data here, not about slotted children. */
|
|
427
|
+
get hasRows() {
|
|
428
|
+
return this.view.rows.length > 0;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Asks for a different order, and reports whether the request stood.
|
|
432
|
+
*
|
|
433
|
+
* Announced before it is applied, so `preventDefault()` is a refusal and the
|
|
434
|
+
* order does not move, which is what makes a server-side sort expressible: the
|
|
435
|
+
* consumer refuses the local reorder, fetches, and hands back a new set.
|
|
436
|
+
*/
|
|
437
|
+
requestSort(next) {
|
|
438
|
+
return requestChange({
|
|
439
|
+
apply: (value) => {
|
|
440
|
+
const previous = this.sort;
|
|
441
|
+
this.sortState = value;
|
|
442
|
+
this.requestUpdate('sort', previous);
|
|
443
|
+
},
|
|
444
|
+
event: (value) => new HelixSortEvent({ value }),
|
|
445
|
+
host: this,
|
|
446
|
+
next,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
/** Asks for a different query. */
|
|
450
|
+
requestFilter(next) {
|
|
451
|
+
return requestChange({
|
|
452
|
+
apply: (value) => {
|
|
453
|
+
const previous = this.filter;
|
|
454
|
+
this.filterState = value;
|
|
455
|
+
this.requestUpdate('filter', previous);
|
|
456
|
+
},
|
|
457
|
+
event: (value) => new HelixFilterEvent({ value }),
|
|
458
|
+
host: this,
|
|
459
|
+
next,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/** Asks for a different page. */
|
|
463
|
+
requestPage(next) {
|
|
464
|
+
if (next === this.page || next < 1 || next > this.pages) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
return requestChange({
|
|
468
|
+
apply: (value) => {
|
|
469
|
+
const previous = this.page;
|
|
470
|
+
this.pageState = value;
|
|
471
|
+
this.requestUpdate('page', previous);
|
|
472
|
+
},
|
|
473
|
+
event: (value) => new HelixNavigateEvent({ value: String(value) }),
|
|
474
|
+
host: this,
|
|
475
|
+
next,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Narrows the rows, from a consumer's own search field.
|
|
480
|
+
*
|
|
481
|
+
* Public because the query lives above the table in every design that has one,
|
|
482
|
+
* and a consumer wiring their own input needs somewhere to send it. Returns
|
|
483
|
+
* whether the change stood, the same as every other request here.
|
|
484
|
+
*/
|
|
485
|
+
search(query) {
|
|
486
|
+
return this.requestFilter(query);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Cycles the order by one column, which is what a click on its heading means.
|
|
490
|
+
*
|
|
491
|
+
* Ascending, descending, then the order the rows arrived in. Public for the
|
|
492
|
+
* same reason `search` is: a consumer's own heading UI needs a way to ask.
|
|
493
|
+
*/
|
|
494
|
+
toggleSort(field) {
|
|
495
|
+
return this.requestSort(format(cycle(parse(this.sort), field)));
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* The columns into the header row, everything else into the toolbar and footer.
|
|
499
|
+
*
|
|
500
|
+
* Manual assignment, so a consumer's own markup is never written to.
|
|
501
|
+
*/
|
|
502
|
+
assign() {
|
|
503
|
+
const root = this.renderRoot;
|
|
504
|
+
if (!root?.querySelector) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const head = root.querySelector('slot[name="columns"]');
|
|
508
|
+
if (!head?.assign) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const columns = this.tableColumns;
|
|
512
|
+
head.assign(...columns);
|
|
513
|
+
const rest = [...this.children].filter((child) => !columns.includes(child));
|
|
514
|
+
for (const [name, wanted] of [
|
|
515
|
+
['toolbar', true],
|
|
516
|
+
['footer', true],
|
|
517
|
+
]) {
|
|
518
|
+
const slot = root.querySelector(`slot[name="${name}"]`);
|
|
519
|
+
if (slot?.assign && wanted) {
|
|
520
|
+
slot.assign(...rest.filter((child) => child.getAttribute('slot') === name));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
willUpdate(changed) {
|
|
525
|
+
super.willUpdate(changed);
|
|
526
|
+
hostAria(this.internals, { label: this.label || 'Table', role: 'grid' });
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Says on the toolbar and the footer whether anything is in them.
|
|
530
|
+
*
|
|
531
|
+
* **The stylesheet used to ask, and could not.** It read
|
|
532
|
+
* `[part="toolbar"]:has(> slot:not(:has(*)))`, which is two faults at once:
|
|
533
|
+
* `:has()` may not be nested inside `:has()`, so the selector failed to parse
|
|
534
|
+
* and the whole rule was discarded; and `slot:not(:has(*))` is as true of a
|
|
535
|
+
* filled slot as of an empty one, because assigned nodes are not a slot's DOM
|
|
536
|
+
* children. Both verified in a browser. A table with no toolbar paid the gap
|
|
537
|
+
* above the grid for one that was not there.
|
|
538
|
+
*/
|
|
539
|
+
markEmpty() {
|
|
540
|
+
this.markRegion('toolbar', ['toolbar']);
|
|
541
|
+
/* The footer is not empty while this element is drawing its own pagination
|
|
542
|
+
into it, which is the case the old selector spelled with a second `:not`. */
|
|
543
|
+
this.markRegion('footer', ['footer'], '[part="pagination"]');
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* One region, hidden when its slot holds nothing and nothing of ours fills it.
|
|
547
|
+
*
|
|
548
|
+
* `hidden` beside the `data-empty` mirror: `data-empty` is the hook the styled
|
|
549
|
+
* sheet reads, and this tier ships no sheet, so an empty region left in the box
|
|
550
|
+
* tree would be a gap a headless consumer cannot close without knowing to look
|
|
551
|
+
* for it. The styled rule stays too, because that sheet sets `display` on these
|
|
552
|
+
* parts and therefore outranks the UA's `[hidden]` one.
|
|
553
|
+
*/
|
|
554
|
+
markRegion(part, slots, occupied) {
|
|
555
|
+
const region = this.renderRoot?.querySelector(`[part="${part}"]`);
|
|
556
|
+
const empty = !slots.some((name) => slotFilled(this.renderRoot?.querySelector(`slot[name="${name}"]`))) && !(occupied && this.renderRoot?.querySelector(occupied));
|
|
557
|
+
region?.toggleAttribute('data-empty', empty);
|
|
558
|
+
region?.toggleAttribute('hidden', empty);
|
|
559
|
+
}
|
|
560
|
+
updated(changed) {
|
|
561
|
+
super.updated(changed);
|
|
562
|
+
this.markEmpty();
|
|
563
|
+
this.assign();
|
|
564
|
+
}
|
|
565
|
+
renderCell(column, row) {
|
|
566
|
+
return html `<span
|
|
567
|
+
part="cell"
|
|
568
|
+
role="gridcell"
|
|
569
|
+
style=${column.align ? `text-align: ${column.align}` : nothing}
|
|
570
|
+
>${column.read(row)}</span
|
|
571
|
+
>`;
|
|
572
|
+
}
|
|
573
|
+
renderRows(rows) {
|
|
574
|
+
const columns = this.tableColumns;
|
|
575
|
+
const field = this.key;
|
|
576
|
+
/* Keyed, so a sort moves a row's element rather than rewriting every cell
|
|
577
|
+
in place: focus inside a cell survives and a transition stays attached to
|
|
578
|
+
the row it belongs to. The index is the fallback and is correct only
|
|
579
|
+
while nothing reorders, which is why `key` is worth setting. */
|
|
580
|
+
return html `${repeat(rows, (row, index) => (field ? String(row[field] ?? index) : index), (row, index) => html `<div
|
|
581
|
+
part="row"
|
|
582
|
+
role="row"
|
|
583
|
+
aria-rowindex=${this.rowIndex(index)}
|
|
584
|
+
>
|
|
585
|
+
${columns.map((column) => this.renderCell(column, row))}
|
|
586
|
+
</div>`)}`;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* A row's place in the whole result, counting the header as row 1.
|
|
590
|
+
*
|
|
591
|
+
* **The number describes the result and not the window**, which is the whole
|
|
592
|
+
* reason a virtualized or paged grid needs `aria-rowindex` at all: a screen
|
|
593
|
+
* reader on page three should hear row 41, and a grid whose indices restart at
|
|
594
|
+
* every page tells a reader the result is twenty rows long however many it has.
|
|
595
|
+
*/
|
|
596
|
+
rowIndex(within) {
|
|
597
|
+
const size = this.pageSize;
|
|
598
|
+
const offset = size > 0 ? (this.page - 1) * size : 0;
|
|
599
|
+
return offset + within + 2;
|
|
600
|
+
}
|
|
601
|
+
render() {
|
|
602
|
+
const { matched, rows } = this.view;
|
|
603
|
+
const template = this.template;
|
|
604
|
+
const columns = this.tableColumns;
|
|
605
|
+
const pagination = this.tag('pagination');
|
|
606
|
+
return html `<div part="toolbar"><slot name="toolbar"></slot></div>
|
|
607
|
+
<div
|
|
608
|
+
part="table"
|
|
609
|
+
role="rowgroup"
|
|
610
|
+
aria-busy=${this.loading ? 'true' : nothing}
|
|
611
|
+
aria-rowcount=${this.mode === 'server' ? Math.max(this.total, rows.length) + 1 : matched + 1}
|
|
612
|
+
aria-colcount=${columns.length || nothing}
|
|
613
|
+
style=${template ? `--data-table-template: ${template}` : nothing}
|
|
614
|
+
>
|
|
615
|
+
<div part="head" role="row">
|
|
616
|
+
<slot name="columns" @slotchange=${this.handleSlotChange}></slot>
|
|
617
|
+
</div>
|
|
618
|
+
${this.renderRows(rows)} ${this.renderStatus(rows.length > 0)}
|
|
619
|
+
</div>
|
|
620
|
+
<div part="footer">
|
|
621
|
+
<slot name="footer"></slot>
|
|
622
|
+
${this.paginated
|
|
623
|
+
? html `<${pagination}
|
|
624
|
+
part="pagination"
|
|
625
|
+
page=${this.page}
|
|
626
|
+
page-size=${this.pageSize || 1}
|
|
627
|
+
total=${matched}
|
|
628
|
+
@helix-navigate=${this.handleNavigate}
|
|
629
|
+
></${pagination}>`
|
|
630
|
+
: nothing}
|
|
631
|
+
</div>`;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Listens on the host, not on the slot the columns are assigned to.
|
|
635
|
+
*
|
|
636
|
+
* The columns are light-DOM children of this element, so their events bubble
|
|
637
|
+
* to it directly and the shadow tree is not involved at all. Bound on the
|
|
638
|
+
* `<slot>` instead, this works in a browser, because an event from a slotted
|
|
639
|
+
* node passes through the slot in the flattened tree, and does not work in
|
|
640
|
+
* happy-dom, which does not implement that propagation: measured, the host
|
|
641
|
+
* hears the click and the slot does not. A spec written against the slot fails
|
|
642
|
+
* in the suite while the component is correct, and the same trust in the
|
|
643
|
+
* flattened tree could as easily have gone the other way.
|
|
644
|
+
*
|
|
645
|
+
* Added here rather than in the template because there is nothing in the
|
|
646
|
+
* shadow tree to attach it to, and removed on disconnect because this element
|
|
647
|
+
* is the listener's owner rather than its subject.
|
|
648
|
+
*/
|
|
649
|
+
connectedCallback() {
|
|
650
|
+
super.connectedCallback();
|
|
651
|
+
this.addEventListener('click', this.handleHeadClick);
|
|
652
|
+
this.addEventListener('keydown', this.handleHeadKey);
|
|
653
|
+
}
|
|
654
|
+
disconnectedCallback() {
|
|
655
|
+
super.disconnectedCallback();
|
|
656
|
+
this.removeEventListener('click', this.handleHeadClick);
|
|
657
|
+
this.removeEventListener('keydown', this.handleHeadKey);
|
|
658
|
+
}
|
|
659
|
+
columnFrom(event) {
|
|
660
|
+
const columns = this.tableColumns;
|
|
661
|
+
for (const node of event.composedPath()) {
|
|
662
|
+
if (columns.includes(node)) {
|
|
663
|
+
return node;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return undefined;
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
__decorate([
|
|
670
|
+
property({ attribute: false })
|
|
671
|
+
], HelixHeadlessDataTable.prototype, "rows", void 0);
|
|
672
|
+
__decorate([
|
|
673
|
+
property()
|
|
674
|
+
], HelixHeadlessDataTable.prototype, "key", void 0);
|
|
675
|
+
__decorate([
|
|
676
|
+
property()
|
|
677
|
+
], HelixHeadlessDataTable.prototype, "mode", void 0);
|
|
678
|
+
__decorate([
|
|
679
|
+
property({ type: Number })
|
|
680
|
+
], HelixHeadlessDataTable.prototype, "total", void 0);
|
|
681
|
+
__decorate([
|
|
682
|
+
property()
|
|
683
|
+
], HelixHeadlessDataTable.prototype, "label", void 0);
|
|
684
|
+
__decorate([
|
|
685
|
+
property()
|
|
686
|
+
], HelixHeadlessDataTable.prototype, "sort", null);
|
|
687
|
+
__decorate([
|
|
688
|
+
property({ attribute: 'default-sort' })
|
|
689
|
+
], HelixHeadlessDataTable.prototype, "defaultSort", void 0);
|
|
690
|
+
__decorate([
|
|
691
|
+
property()
|
|
692
|
+
], HelixHeadlessDataTable.prototype, "filter", null);
|
|
693
|
+
__decorate([
|
|
694
|
+
property({ attribute: 'default-filter' })
|
|
695
|
+
], HelixHeadlessDataTable.prototype, "defaultFilter", void 0);
|
|
696
|
+
__decorate([
|
|
697
|
+
property({ type: Number })
|
|
698
|
+
], HelixHeadlessDataTable.prototype, "page", null);
|
|
699
|
+
__decorate([
|
|
700
|
+
property({ attribute: 'default-page', type: Number })
|
|
701
|
+
], HelixHeadlessDataTable.prototype, "defaultPage", void 0);
|
|
702
|
+
__decorate([
|
|
703
|
+
property({ attribute: 'page-size', type: Number })
|
|
704
|
+
], HelixHeadlessDataTable.prototype, "pageSize", null);
|
|
705
|
+
__decorate([
|
|
706
|
+
property({ attribute: 'default-page-size', type: Number })
|
|
707
|
+
], HelixHeadlessDataTable.prototype, "defaultPageSize", void 0);
|
|
708
|
+
__decorate([
|
|
709
|
+
property({ type: Boolean })
|
|
710
|
+
], HelixHeadlessDataTable.prototype, "paginated", null);
|
|
711
|
+
__decorate([
|
|
712
|
+
state()
|
|
713
|
+
], HelixHeadlessDataTable.prototype, "sortState", void 0);
|
|
714
|
+
__decorate([
|
|
715
|
+
state()
|
|
716
|
+
], HelixHeadlessDataTable.prototype, "filterState", void 0);
|
|
717
|
+
__decorate([
|
|
718
|
+
state()
|
|
719
|
+
], HelixHeadlessDataTable.prototype, "pageState", void 0);
|
|
720
|
+
__decorate([
|
|
721
|
+
state()
|
|
722
|
+
], HelixHeadlessDataTable.prototype, "pageSizeState", void 0);
|
|
723
|
+
__decorate([
|
|
724
|
+
state()
|
|
725
|
+
], HelixHeadlessDataTable.prototype, "paginatedState", void 0);
|
|
726
|
+
HelixHeadlessDataTable = HelixHeadlessDataTable_1 = __decorate([
|
|
727
|
+
customElement('helix-headless-data-table')
|
|
728
|
+
], HelixHeadlessDataTable);
|
|
729
|
+
export { HelixHeadlessDataTable };
|