@nizivo/react 0.0.0-stage → 0.2.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/LICENSE +202 -0
- package/README.md +120 -2
- package/THIRD_PARTY_NOTICES +68 -0
- package/dist/_engines/react-aria/dialog.client.js +126 -0
- package/dist/_engines/react-aria/dom-allowlist.js +19 -0
- package/dist/_engines/react-aria/dom.js +31 -0
- package/dist/_engines/react-aria/drawer.client.js +8 -0
- package/dist/_engines/react-aria/file-upload.client.js +50 -0
- package/dist/_engines/react-aria/locale.client.js +13 -0
- package/dist/_engines/react-aria/menu.client.js +229 -0
- package/dist/_engines/react-aria/open-state.client.js +53 -0
- package/dist/_engines/react-aria/outside-press.client.js +61 -0
- package/dist/_engines/react-aria/overlay.client.js +46 -0
- package/dist/_engines/react-aria/popover.client.js +148 -0
- package/dist/_engines/react-aria/popup.client.js +153 -0
- package/dist/_engines/react-aria/select.client.js +180 -0
- package/dist/_engines/react-aria/tabs.client.js +95 -0
- package/dist/_engines/react-aria/toast.client.js +38 -0
- package/dist/_engines/react-aria/tooltip.client.js +72 -0
- package/dist/_internal/cx.js +11 -0
- package/dist/_internal/data-status.d.ts +3 -0
- package/dist/_internal/data-status.js +13 -0
- package/dist/_internal/engine-part.d.ts +1 -0
- package/dist/_internal/field.js +20 -0
- package/dist/_internal/glyphs.js +87 -0
- package/dist/_internal/keys.js +62 -0
- package/dist/_internal/modal.client.js +54 -0
- package/dist/_internal/nested-focus.js +33 -0
- package/dist/_internal/overlay.d.ts +9 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/alert/alert-dismiss.client.d.ts +32 -0
- package/dist/alert/alert-dismiss.client.js +38 -0
- package/dist/alert/alert.d.ts +28 -0
- package/dist/alert/alert.js +44 -0
- package/dist/alert/index.d.ts +3 -0
- package/dist/alert/index.js +3 -0
- package/dist/app-shell/app-shell.d.ts +24 -0
- package/dist/app-shell/app-shell.js +56 -0
- package/dist/app-shell/index.d.ts +2 -0
- package/dist/app-shell/index.js +1 -0
- package/dist/augment.d.ts +13 -0
- package/dist/augment.js +0 -0
- package/dist/avatar/avatar.d.ts +96 -0
- package/dist/avatar/avatar.js +94 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +1 -0
- package/dist/badge/badge.d.ts +19 -0
- package/dist/badge/badge.js +22 -0
- package/dist/badge/index.d.ts +2 -0
- package/dist/badge/index.js +1 -0
- package/dist/banner/banner-dismiss.client.d.ts +32 -0
- package/dist/banner/banner-dismiss.client.js +38 -0
- package/dist/banner/banner.d.ts +34 -0
- package/dist/banner/banner.js +47 -0
- package/dist/banner/index.d.ts +3 -0
- package/dist/banner/index.js +3 -0
- package/dist/breadcrumb/breadcrumb.d.ts +46 -0
- package/dist/breadcrumb/breadcrumb.js +46 -0
- package/dist/breadcrumb/breadcrumb.parts.d.ts +6 -0
- package/dist/breadcrumb/breadcrumb.parts.js +9 -0
- package/dist/breadcrumb/index.d.ts +3 -0
- package/dist/breadcrumb/index.js +3 -0
- package/dist/button/button.d.ts +55 -0
- package/dist/button/button.js +62 -0
- package/dist/button/index.d.ts +2 -0
- package/dist/button/index.js +1 -0
- package/dist/card/card.d.ts +64 -0
- package/dist/card/card.js +62 -0
- package/dist/card/card.parts.d.ts +6 -0
- package/dist/card/card.parts.js +14 -0
- package/dist/card/index.d.ts +3 -0
- package/dist/card/index.js +3 -0
- package/dist/checkbox/checkbox.client.d.ts +37 -0
- package/dist/checkbox/checkbox.client.js +81 -0
- package/dist/checkbox/index.d.ts +2 -0
- package/dist/checkbox/index.js +1 -0
- package/dist/chip-group/chip-group.client.d.ts +88 -0
- package/dist/chip-group/chip-group.client.js +157 -0
- package/dist/chip-group/index.d.ts +2 -0
- package/dist/chip-group/index.js +1 -0
- package/dist/choice-card/choice-card.client.d.ts +66 -0
- package/dist/choice-card/choice-card.client.js +138 -0
- package/dist/choice-card/index.d.ts +2 -0
- package/dist/choice-card/index.js +1 -0
- package/dist/config/config.client.d.ts +24 -0
- package/dist/config/config.client.js +33 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +1 -0
- package/dist/container/container.d.ts +13 -0
- package/dist/container/container.js +16 -0
- package/dist/container/index.d.ts +2 -0
- package/dist/container/index.js +1 -0
- package/dist/contracts/details.d.ts +13 -0
- package/dist/contracts/details.js +9 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +5 -0
- package/dist/contracts/merge-props.d.ts +16 -0
- package/dist/contracts/merge-props.js +76 -0
- package/dist/contracts/render.d.ts +17 -0
- package/dist/contracts/render.js +43 -0
- package/dist/contracts/state.d.ts +42 -0
- package/dist/contracts/state.js +42 -0
- package/dist/css/alert.css +2 -0
- package/dist/css/app-shell.css +2 -0
- package/dist/css/avatar.css +2 -0
- package/dist/css/badge.css +2 -0
- package/dist/css/banner.css +2 -0
- package/dist/css/base.css +2 -0
- package/dist/css/breadcrumb.css +2 -0
- package/dist/css/button.css +2 -0
- package/dist/css/card.css +2 -0
- package/dist/css/checkbox.css +2 -0
- package/dist/css/chip-group.css +2 -0
- package/dist/css/choice-card.css +2 -0
- package/dist/css/container.css +2 -0
- package/dist/css/delta.css +2 -0
- package/dist/css/dialog.css +2 -0
- package/dist/css/drawer.css +2 -0
- package/dist/css/empty-state.css +2 -0
- package/dist/css/field.css +2 -0
- package/dist/css/fieldset.css +2 -0
- package/dist/css/file-upload.css +2 -0
- package/dist/css/form.css +2 -0
- package/dist/css/grid.css +2 -0
- package/dist/css/heading.css +2 -0
- package/dist/css/icon-button.css +2 -0
- package/dist/css/image.css +2 -0
- package/dist/css/inline-error.css +2 -0
- package/dist/css/inline.css +2 -0
- package/dist/css/input.css +2 -0
- package/dist/css/kbd.css +2 -0
- package/dist/css/kpi-tile.css +2 -0
- package/dist/css/menu.css +2 -0
- package/dist/css/meter.css +2 -0
- package/dist/css/metric.css +2 -0
- package/dist/css/mobile-tab-bar.css +2 -0
- package/dist/css/mobile-top-bar.css +2 -0
- package/dist/css/motion.css +2 -0
- package/dist/css/native-select.css +2 -0
- package/dist/css/nav-item.css +2 -0
- package/dist/css/number-value.css +2 -0
- package/dist/css/page-header.css +2 -0
- package/dist/css/pagination.css +2 -0
- package/dist/css/password-input.css +2 -0
- package/dist/css/popover.css +2 -0
- package/dist/css/progress-bar.css +2 -0
- package/dist/css/progress-ring.css +2 -0
- package/dist/css/radio-group.css +2 -0
- package/dist/css/ranked-list.css +2 -0
- package/dist/css/search-field.css +2 -0
- package/dist/css/segmented-control.css +2 -0
- package/dist/css/select.css +2 -0
- package/dist/css/separator.css +2 -0
- package/dist/css/sidebar.css +2 -0
- package/dist/css/skeleton.css +2 -0
- package/dist/css/split.css +2 -0
- package/dist/css/stack.css +2 -0
- package/dist/css/sticky-bar.css +2 -0
- package/dist/css/switch.css +2 -0
- package/dist/css/tab-nav.css +2 -0
- package/dist/css/table-selection.css +2 -0
- package/dist/css/table.css +2 -0
- package/dist/css/tabs.css +2 -0
- package/dist/css/text.css +2 -0
- package/dist/css/textarea.css +2 -0
- package/dist/css/toast.css +2 -0
- package/dist/css/tooltip.css +2 -0
- package/dist/css/top-bar.css +2 -0
- package/dist/css/trend-card.css +2 -0
- package/dist/delta/delta.d.ts +32 -0
- package/dist/delta/delta.js +50 -0
- package/dist/delta/index.d.ts +2 -0
- package/dist/delta/index.js +1 -0
- package/dist/dialog/dialog.client.d.ts +25 -0
- package/dist/dialog/dialog.client.js +145 -0
- package/dist/dialog/dialog.contract.d.ts +97 -0
- package/dist/dialog/dialog.parts.d.ts +6 -0
- package/dist/dialog/dialog.parts.js +15 -0
- package/dist/dialog/index.d.ts +5 -0
- package/dist/dialog/index.js +3 -0
- package/dist/drawer/drawer.client.d.ts +25 -0
- package/dist/drawer/drawer.client.js +154 -0
- package/dist/drawer/drawer.contract.d.ts +98 -0
- package/dist/drawer/drawer.parts.d.ts +6 -0
- package/dist/drawer/drawer.parts.js +16 -0
- package/dist/drawer/index.d.ts +5 -0
- package/dist/drawer/index.js +3 -0
- package/dist/empty-state/empty-state.d.ts +18 -0
- package/dist/empty-state/empty-state.js +32 -0
- package/dist/empty-state/index.d.ts +2 -0
- package/dist/empty-state/index.js +1 -0
- package/dist/field/field-scope.client.d.ts +50 -0
- package/dist/field/field-scope.client.js +212 -0
- package/dist/field/field-static.d.ts +122 -0
- package/dist/field/field-static.js +159 -0
- package/dist/field/field.d.ts +5 -0
- package/dist/field/field.js +53 -0
- package/dist/field/index.d.ts +4 -0
- package/dist/field/index.js +4 -0
- package/dist/fieldset/fieldset.d.ts +36 -0
- package/dist/fieldset/fieldset.js +63 -0
- package/dist/fieldset/index.d.ts +2 -0
- package/dist/fieldset/index.js +1 -0
- package/dist/file-upload/file-upload.client.d.ts +9 -0
- package/dist/file-upload/file-upload.client.js +406 -0
- package/dist/file-upload/file-upload.contract.d.ts +112 -0
- package/dist/file-upload/index.d.ts +3 -0
- package/dist/file-upload/index.js +1 -0
- package/dist/file-upload/seam.d.ts +1 -0
- package/dist/form/form.client.d.ts +38 -0
- package/dist/form/form.client.js +127 -0
- package/dist/form/form.d.ts +36 -0
- package/dist/form/form.js +29 -0
- package/dist/form/index.d.ts +4 -0
- package/dist/form/index.js +4 -0
- package/dist/form/submit-button.client.d.ts +20 -0
- package/dist/form/submit-button.client.js +19 -0
- package/dist/grid/grid.d.ts +38 -0
- package/dist/grid/grid.js +28 -0
- package/dist/grid/index.d.ts +2 -0
- package/dist/grid/index.js +1 -0
- package/dist/heading/heading.d.ts +30 -0
- package/dist/heading/heading.js +26 -0
- package/dist/heading/index.d.ts +2 -0
- package/dist/heading/index.js +1 -0
- package/dist/i18n/format-label.d.ts +24 -0
- package/dist/i18n/format-label.js +19 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +1 -0
- package/dist/icon-button/icon-button-static.d.ts +23 -0
- package/dist/icon-button/icon-button-static.js +83 -0
- package/dist/icon-button/icon-button.client.js +29 -0
- package/dist/icon-button/icon-button.contract.d.ts +89 -0
- package/dist/icon-button/icon-button.d.ts +5 -0
- package/dist/icon-button/icon-button.js +21 -0
- package/dist/icon-button/index.d.ts +4 -0
- package/dist/icon-button/index.js +3 -0
- package/dist/image/image.d.ts +28 -0
- package/dist/image/image.js +24 -0
- package/dist/image/index.d.ts +2 -0
- package/dist/image/index.js +1 -0
- package/dist/index.d.ts +174 -0
- package/dist/index.js +96 -0
- package/dist/inline/index.d.ts +2 -0
- package/dist/inline/index.js +1 -0
- package/dist/inline/inline.d.ts +16 -0
- package/dist/inline/inline.js +14 -0
- package/dist/inline-error/index.d.ts +2 -0
- package/dist/inline-error/index.js +1 -0
- package/dist/inline-error/inline-error.d.ts +17 -0
- package/dist/inline-error/inline-error.js +33 -0
- package/dist/input/index.d.ts +2 -0
- package/dist/input/index.js +1 -0
- package/dist/input/input.client.d.ts +39 -0
- package/dist/input/input.client.js +82 -0
- package/dist/kbd/index.d.ts +2 -0
- package/dist/kbd/index.js +1 -0
- package/dist/kbd/kbd.d.ts +19 -0
- package/dist/kbd/kbd.js +68 -0
- package/dist/kpi-tile/index.d.ts +2 -0
- package/dist/kpi-tile/index.js +1 -0
- package/dist/kpi-tile/kpi-tile.d.ts +30 -0
- package/dist/kpi-tile/kpi-tile.js +48 -0
- package/dist/locales/en-US.d.ts +77 -0
- package/dist/locales/en-US.js +83 -0
- package/dist/menu/index.d.ts +5 -0
- package/dist/menu/index.js +3 -0
- package/dist/menu/menu.client.d.ts +14 -0
- package/dist/menu/menu.client.js +152 -0
- package/dist/menu/menu.contract.d.ts +152 -0
- package/dist/menu/menu.parts.d.ts +6 -0
- package/dist/menu/menu.parts.js +17 -0
- package/dist/meter/index.d.ts +2 -0
- package/dist/meter/index.js +1 -0
- package/dist/meter/meter.d.ts +43 -0
- package/dist/meter/meter.js +59 -0
- package/dist/metric/index.d.ts +2 -0
- package/dist/metric/index.js +1 -0
- package/dist/metric/metric.d.ts +72 -0
- package/dist/metric/metric.js +116 -0
- package/dist/mobile-tab-bar/index.d.ts +4 -0
- package/dist/mobile-tab-bar/index.js +4 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-inset.client.js +38 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-more.client.d.ts +26 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-more.client.js +60 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.d.ts +39 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.js +54 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.parts.d.ts +6 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.parts.js +9 -0
- package/dist/mobile-top-bar/index.d.ts +2 -0
- package/dist/mobile-top-bar/index.js +1 -0
- package/dist/mobile-top-bar/mobile-top-bar.d.ts +17 -0
- package/dist/mobile-top-bar/mobile-top-bar.js +31 -0
- package/dist/motion/count-up.client.d.ts +39 -0
- package/dist/motion/count-up.client.js +109 -0
- package/dist/motion/index.d.ts +2 -0
- package/dist/motion/index.js +1 -0
- package/dist/native-select/index.d.ts +2 -0
- package/dist/native-select/index.js +1 -0
- package/dist/native-select/native-select.d.ts +43 -0
- package/dist/native-select/native-select.js +56 -0
- package/dist/nav-item/index.d.ts +2 -0
- package/dist/nav-item/index.js +1 -0
- package/dist/nav-item/nav-item.d.ts +35 -0
- package/dist/nav-item/nav-item.js +50 -0
- package/dist/number-value/index.d.ts +2 -0
- package/dist/number-value/index.js +1 -0
- package/dist/number-value/number-value.d.ts +25 -0
- package/dist/number-value/number-value.js +26 -0
- package/dist/page-header/index.d.ts +2 -0
- package/dist/page-header/index.js +1 -0
- package/dist/page-header/page-header.d.ts +19 -0
- package/dist/page-header/page-header.js +39 -0
- package/dist/pagination/index.d.ts +2 -0
- package/dist/pagination/index.js +1 -0
- package/dist/pagination/pagination.d.ts +74 -0
- package/dist/pagination/pagination.js +136 -0
- package/dist/password-input/index.d.ts +2 -0
- package/dist/password-input/index.js +1 -0
- package/dist/password-input/password-input.client.d.ts +52 -0
- package/dist/password-input/password-input.client.js +106 -0
- package/dist/popover/index.d.ts +5 -0
- package/dist/popover/index.js +3 -0
- package/dist/popover/popover.client.d.ts +20 -0
- package/dist/popover/popover.client.js +113 -0
- package/dist/popover/popover.contract.d.ts +88 -0
- package/dist/popover/popover.parts.d.ts +6 -0
- package/dist/popover/popover.parts.js +13 -0
- package/dist/progress-bar/index.d.ts +2 -0
- package/dist/progress-bar/index.js +1 -0
- package/dist/progress-bar/progress-bar.d.ts +34 -0
- package/dist/progress-bar/progress-bar.js +55 -0
- package/dist/progress-ring/index.d.ts +2 -0
- package/dist/progress-ring/index.js +1 -0
- package/dist/progress-ring/progress-ring.d.ts +38 -0
- package/dist/progress-ring/progress-ring.js +67 -0
- package/dist/radio-group/index.d.ts +3 -0
- package/dist/radio-group/index.js +3 -0
- package/dist/radio-group/radio-group.client.d.ts +22 -0
- package/dist/radio-group/radio-group.client.js +70 -0
- package/dist/radio-group/radio-group.d.ts +28 -0
- package/dist/radio-group/radio-group.js +35 -0
- package/dist/ranked-list/index.d.ts +3 -0
- package/dist/ranked-list/index.js +3 -0
- package/dist/ranked-list/ranked-list.d.ts +85 -0
- package/dist/ranked-list/ranked-list.js +153 -0
- package/dist/ranked-list/ranked-list.parts.d.ts +6 -0
- package/dist/ranked-list/ranked-list.parts.js +10 -0
- package/dist/search-field/index.d.ts +2 -0
- package/dist/search-field/index.js +1 -0
- package/dist/search-field/search-field.client.d.ts +55 -0
- package/dist/search-field/search-field.client.js +136 -0
- package/dist/segmented-control/index.d.ts +3 -0
- package/dist/segmented-control/index.js +3 -0
- package/dist/segmented-control/segmented-control.client.d.ts +61 -0
- package/dist/segmented-control/segmented-control.client.js +156 -0
- package/dist/segmented-control/segmented-control.parts.d.ts +6 -0
- package/dist/segmented-control/segmented-control.parts.js +9 -0
- package/dist/select/index.d.ts +5 -0
- package/dist/select/index.js +3 -0
- package/dist/select/select.client.d.ts +12 -0
- package/dist/select/select.client.js +152 -0
- package/dist/select/select.contract.d.ts +119 -0
- package/dist/select/select.parts.d.ts +6 -0
- package/dist/select/select.parts.js +15 -0
- package/dist/separator/index.d.ts +2 -0
- package/dist/separator/index.js +1 -0
- package/dist/separator/separator.d.ts +26 -0
- package/dist/separator/separator.js +23 -0
- package/dist/sidebar/index.d.ts +4 -0
- package/dist/sidebar/index.js +4 -0
- package/dist/sidebar/sidebar-item.client.d.ts +10 -0
- package/dist/sidebar/sidebar-item.client.js +55 -0
- package/dist/sidebar/sidebar.d.ts +45 -0
- package/dist/sidebar/sidebar.js +62 -0
- package/dist/sidebar/sidebar.parts.d.ts +6 -0
- package/dist/sidebar/sidebar.parts.js +11 -0
- package/dist/skeleton/index.d.ts +2 -0
- package/dist/skeleton/index.js +1 -0
- package/dist/skeleton/skeleton.d.ts +20 -0
- package/dist/skeleton/skeleton.js +19 -0
- package/dist/split/index.d.ts +3 -0
- package/dist/split/index.js +3 -0
- package/dist/split/split.d.ts +28 -0
- package/dist/split/split.js +33 -0
- package/dist/split/split.parts.d.ts +6 -0
- package/dist/split/split.parts.js +10 -0
- package/dist/stack/index.d.ts +2 -0
- package/dist/stack/index.js +1 -0
- package/dist/stack/stack.d.ts +17 -0
- package/dist/stack/stack.js +14 -0
- package/dist/sticky-bar/index.d.ts +2 -0
- package/dist/sticky-bar/index.js +1 -0
- package/dist/sticky-bar/sticky-bar.d.ts +16 -0
- package/dist/sticky-bar/sticky-bar.js +26 -0
- package/dist/styles.css +595 -0
- package/dist/switch/index.d.ts +2 -0
- package/dist/switch/index.js +1 -0
- package/dist/switch/switch.client.d.ts +33 -0
- package/dist/switch/switch.client.js +63 -0
- package/dist/tab-nav/index.d.ts +3 -0
- package/dist/tab-nav/index.js +3 -0
- package/dist/tab-nav/tab-nav.d.ts +36 -0
- package/dist/tab-nav/tab-nav.js +47 -0
- package/dist/tab-nav/tab-nav.parts.d.ts +6 -0
- package/dist/tab-nav/tab-nav.parts.js +9 -0
- package/dist/table/index.d.ts +3 -0
- package/dist/table/index.js +3 -0
- package/dist/table/table.d.ts +101 -0
- package/dist/table/table.js +121 -0
- package/dist/table/table.parts.d.ts +6 -0
- package/dist/table/table.parts.js +18 -0
- package/dist/table-selection/index.d.ts +3 -0
- package/dist/table-selection/index.js +3 -0
- package/dist/table-selection/table-selection.client.d.ts +14 -0
- package/dist/table-selection/table-selection.client.js +84 -0
- package/dist/table-selection/table-selection.d.ts +34 -0
- package/dist/table-selection/table-selection.js +50 -0
- package/dist/tabs/index.d.ts +4 -0
- package/dist/tabs/index.js +3 -0
- package/dist/tabs/tabs.client.d.ts +8 -0
- package/dist/tabs/tabs.client.js +68 -0
- package/dist/tabs/tabs.contract.d.ts +89 -0
- package/dist/tabs/tabs.parts.d.ts +6 -0
- package/dist/tabs/tabs.parts.js +11 -0
- package/dist/text/index.d.ts +2 -0
- package/dist/text/index.js +1 -0
- package/dist/text/text.d.ts +32 -0
- package/dist/text/text.js +17 -0
- package/dist/textarea/index.d.ts +2 -0
- package/dist/textarea/index.js +1 -0
- package/dist/textarea/textarea.client.d.ts +18 -0
- package/dist/textarea/textarea.client.js +31 -0
- package/dist/theme-script/index.d.ts +2 -0
- package/dist/theme-script/index.js +1 -0
- package/dist/theme-script/theme-script.d.ts +43 -0
- package/dist/theme-script/theme-script.js +46 -0
- package/dist/toast/index.d.ts +4 -0
- package/dist/toast/index.js +3 -0
- package/dist/toast/seam.d.ts +2 -0
- package/dist/toast/store.d.ts +19 -0
- package/dist/toast/store.js +136 -0
- package/dist/toast/toast.contract.d.ts +56 -0
- package/dist/toast/toaster.client.d.ts +10 -0
- package/dist/toast/toaster.client.js +305 -0
- package/dist/tooltip/index.d.ts +5 -0
- package/dist/tooltip/index.js +3 -0
- package/dist/tooltip/tooltip.client.d.ts +12 -0
- package/dist/tooltip/tooltip.client.js +51 -0
- package/dist/tooltip/tooltip.contract.d.ts +60 -0
- package/dist/tooltip/tooltip.parts.d.ts +6 -0
- package/dist/tooltip/tooltip.parts.js +10 -0
- package/dist/top-bar/index.d.ts +2 -0
- package/dist/top-bar/index.js +1 -0
- package/dist/top-bar/top-bar.d.ts +17 -0
- package/dist/top-bar/top-bar.js +35 -0
- package/dist/trend-card/index.d.ts +2 -0
- package/dist/trend-card/index.js +1 -0
- package/dist/trend-card/trend-card.d.ts +34 -0
- package/dist/trend-card/trend-card.js +74 -0
- package/package.json +447 -3
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { RenderProp } from "../contracts/render.js";
|
|
2
|
+
import { ComponentPropsWithRef, ReactElement, ReactNode } from "react";
|
|
3
|
+
//#region src/fieldset/fieldset.d.ts
|
|
4
|
+
export interface FieldsetState {
|
|
5
|
+
/** An error message is presented. */
|
|
6
|
+
invalid: boolean;
|
|
7
|
+
disabled: boolean;
|
|
8
|
+
required: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface FieldsetProps extends Omit<ComponentPropsWithRef<"fieldset">, "children"> {
|
|
11
|
+
/** The group's name, a native `<legend>`. */
|
|
12
|
+
legend?: ReactNode;
|
|
13
|
+
/** Help text after the group, announced on entering it through `aria-describedby`. */
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* The group's error, rendered through InlineError and joined to `aria-describedby`; sets
|
|
17
|
+
* `data-invalid`. Not a live region (§16.5). `null`, `false` and `''` present no error.
|
|
18
|
+
*/
|
|
19
|
+
error?: ReactNode;
|
|
20
|
+
/** Replaces the internal error mark (`circle-x`). Decorative. */
|
|
21
|
+
errorIcon?: ReactNode;
|
|
22
|
+
/** Draws an `aria-hidden` mark after the legend; the controls inside carry `required`. @default false */
|
|
23
|
+
required?: boolean;
|
|
24
|
+
/** Native: disables every control inside, with no client code. @default false */
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
/** Ids replacing the generated ones. */
|
|
27
|
+
ids?: {
|
|
28
|
+
description?: string | undefined;
|
|
29
|
+
error?: string | undefined;
|
|
30
|
+
};
|
|
31
|
+
/** Composition of the root; anything but a `<fieldset>` loses native `disabled`. */
|
|
32
|
+
render?: RenderProp<FieldsetState>;
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
export declare function Fieldset({ legend, description, error, errorIcon, required, disabled, ids, render, "aria-describedby": ariaDescribedBy, className, children, ...rest }: FieldsetProps): ReactElement;
|
|
36
|
+
//#endregion
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { cx } from "../_internal/cx.js";
|
|
2
|
+
import { renderElement } from "../contracts/render.js";
|
|
3
|
+
import { CircleXGlyph } from "../_internal/glyphs.js";
|
|
4
|
+
import { stateAttrs } from "../contracts/state.js";
|
|
5
|
+
import { joinIds, presented } from "../_internal/field.js";
|
|
6
|
+
import { InlineError } from "../inline-error/inline-error.js";
|
|
7
|
+
import { useId } from "react";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/fieldset/fieldset.tsx
|
|
10
|
+
function Fieldset({ legend, description, error, errorIcon, required = false, disabled = false, ids, render, "aria-describedby": ariaDescribedBy, className, children, ...rest }) {
|
|
11
|
+
const base = useId();
|
|
12
|
+
const descriptionId = ids?.description ?? `${base}-description`;
|
|
13
|
+
const errorId = ids?.error ?? `${base}-error`;
|
|
14
|
+
const hasDescription = presented(description);
|
|
15
|
+
const invalid = presented(error);
|
|
16
|
+
return renderElement("fieldset", render, {
|
|
17
|
+
invalid,
|
|
18
|
+
disabled,
|
|
19
|
+
required
|
|
20
|
+
}, {
|
|
21
|
+
"data-slot": "fieldset",
|
|
22
|
+
...stateAttrs({
|
|
23
|
+
invalid,
|
|
24
|
+
disabled,
|
|
25
|
+
required
|
|
26
|
+
}),
|
|
27
|
+
...rest,
|
|
28
|
+
className: cx("nz-fieldset", className),
|
|
29
|
+
disabled: render === void 0 && disabled ? true : void 0,
|
|
30
|
+
"aria-describedby": joinIds(hasDescription && descriptionId, invalid && errorId, ariaDescribedBy),
|
|
31
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [presented(legend) && /* @__PURE__ */ jsxs("legend", {
|
|
32
|
+
className: "nz-fieldset-legend",
|
|
33
|
+
"data-slot": "fieldset-legend",
|
|
34
|
+
children: [legend, required && /* @__PURE__ */ jsx("span", {
|
|
35
|
+
className: "nz-fieldset-required",
|
|
36
|
+
"data-slot": "fieldset-required",
|
|
37
|
+
"aria-hidden": "true",
|
|
38
|
+
children: "*"
|
|
39
|
+
})]
|
|
40
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
41
|
+
className: "nz-fieldset-content",
|
|
42
|
+
"data-slot": "fieldset-content",
|
|
43
|
+
children: [
|
|
44
|
+
children,
|
|
45
|
+
hasDescription && /* @__PURE__ */ jsx("div", {
|
|
46
|
+
className: "nz-fieldset-description",
|
|
47
|
+
"data-slot": "fieldset-description",
|
|
48
|
+
id: descriptionId,
|
|
49
|
+
children: description
|
|
50
|
+
}),
|
|
51
|
+
invalid && /* @__PURE__ */ jsx(InlineError, {
|
|
52
|
+
className: "nz-fieldset-error",
|
|
53
|
+
"data-slot": "fieldset-error",
|
|
54
|
+
id: errorId,
|
|
55
|
+
icon: errorIcon ?? /* @__PURE__ */ jsx(CircleXGlyph, {}),
|
|
56
|
+
children: error
|
|
57
|
+
})
|
|
58
|
+
]
|
|
59
|
+
})] })
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { Fieldset };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Fieldset } from "./fieldset.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FileUploadProps } from "./file-upload.contract.js";
|
|
2
|
+
import { JSX } from "react";
|
|
3
|
+
//#region src/file-upload/file-upload.client.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* `className` and `style` go on the root; every other input prop, `ref` included, goes on the
|
|
6
|
+
* native `<input type="file">`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function FileUpload({ id, name, accept, multiple, maxSize, disabled, required, invalid, hint, icon, items, onFilesChange, onReject, onRemove, onRetry, onCancel, labels: labelsProp, locale, className, style, "aria-invalid": ariaInvalid, "aria-describedby": describedByProp, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest }: FileUploadProps): JSX.Element;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "../_internal/cx.js";
|
|
3
|
+
import { mergeProps } from "../contracts/merge-props.js";
|
|
4
|
+
import { useLabels } from "../config/config.client.js";
|
|
5
|
+
import { CircleCheckGlyph, CircleXGlyph, CloseGlyph } from "../_internal/glyphs.js";
|
|
6
|
+
import { Button } from "../button/button.js";
|
|
7
|
+
import { stateAttrs } from "../contracts/state.js";
|
|
8
|
+
import { joinIds } from "../_internal/field.js";
|
|
9
|
+
import { InlineError } from "../inline-error/inline-error.js";
|
|
10
|
+
import { useFieldControl } from "../field/field-scope.client.js";
|
|
11
|
+
import { iconButtonElement } from "../icon-button/icon-button-static.js";
|
|
12
|
+
import { ProgressBar } from "../progress-bar/progress-bar.js";
|
|
13
|
+
import { useDropTarget } from "../_engines/react-aria/file-upload.client.js";
|
|
14
|
+
import { useEffect, useEffectEvent, useId, useLayoutEffect, useRef, useState } from "react";
|
|
15
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
//#region src/file-upload/file-upload.client.tsx
|
|
17
|
+
const LABELS = {
|
|
18
|
+
prompt: "Drop files here or {browse}",
|
|
19
|
+
browse: "browse",
|
|
20
|
+
release: "Release to add files",
|
|
21
|
+
summary: "{complete} of {total} uploaded",
|
|
22
|
+
wrongType: "{name} is not an accepted file type.",
|
|
23
|
+
tooLarge: "{name} is larger than {max}.",
|
|
24
|
+
tooMany: "{name} was not added: choose one file.",
|
|
25
|
+
list: "Chosen files",
|
|
26
|
+
remove: "Remove {name}",
|
|
27
|
+
retry: "Retry",
|
|
28
|
+
cancel: "Cancel",
|
|
29
|
+
uploading: "Uploading {name}",
|
|
30
|
+
complete: "Uploaded",
|
|
31
|
+
failed: "Upload failed"
|
|
32
|
+
};
|
|
33
|
+
/** Ids for held files: unique on the page, and never in the server HTML. */
|
|
34
|
+
let nextId = 0;
|
|
35
|
+
/**
|
|
36
|
+
* `className` and `style` go on the root; every other input prop, `ref` included, goes on the
|
|
37
|
+
* native `<input type="file">`.
|
|
38
|
+
*/
|
|
39
|
+
function FileUpload({ id, name, accept, multiple = false, maxSize, disabled, required, invalid, hint, icon, items, onFilesChange, onReject, onRemove, onRetry, onCancel, labels: labelsProp, locale = "en-US", className, style, "aria-invalid": ariaInvalid, "aria-describedby": describedByProp, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest }) {
|
|
40
|
+
const labels = {
|
|
41
|
+
...LABELS,
|
|
42
|
+
...useLabels("fileUpload", labelsProp)
|
|
43
|
+
};
|
|
44
|
+
const base = useId();
|
|
45
|
+
const hintId = `${base}-hint`;
|
|
46
|
+
const messagesId = `${base}-messages`;
|
|
47
|
+
const [files, setFiles] = useState([]);
|
|
48
|
+
const [rejected, setRejected] = useState([]);
|
|
49
|
+
const zone = useRef(null);
|
|
50
|
+
const list = useRef(null);
|
|
51
|
+
const refocus = useRef(null);
|
|
52
|
+
const showHint = hint != null && hint !== false && hint !== "";
|
|
53
|
+
const field = useFieldControl({
|
|
54
|
+
id,
|
|
55
|
+
name,
|
|
56
|
+
required,
|
|
57
|
+
disabled,
|
|
58
|
+
invalid: invalid ?? (ariaInvalid === true || ariaInvalid === "true" ? true : void 0),
|
|
59
|
+
"aria-describedby": joinIds(describedByProp, showHint && hintId, rejected.length > 0 && messagesId),
|
|
60
|
+
labelBehavior: "focus"
|
|
61
|
+
});
|
|
62
|
+
const rows = listRows(files, items);
|
|
63
|
+
const pending = rows.filter((row) => row.item?.status === "uploading").length > 0;
|
|
64
|
+
const complete = rows.filter((row) => row.item?.status === "complete").length;
|
|
65
|
+
/** Writes the list into the input, then into state, then tells the app. */
|
|
66
|
+
const commit = (element, nextFiles) => {
|
|
67
|
+
write(element, nextFiles);
|
|
68
|
+
setFiles(nextFiles);
|
|
69
|
+
onFilesChange?.(nextFiles);
|
|
70
|
+
};
|
|
71
|
+
/** A pick or a drop: check each file, add the ones that pass, report the others. */
|
|
72
|
+
const add = (incoming, element) => {
|
|
73
|
+
const accepted = [];
|
|
74
|
+
const refused = [];
|
|
75
|
+
for (const file of incoming) {
|
|
76
|
+
const reason = !matches(file, accept) ? "type" : maxSize !== void 0 && file.size > maxSize ? "size" : !multiple && accepted.length > 0 ? "count" : void 0;
|
|
77
|
+
if (reason !== void 0) refused.push({
|
|
78
|
+
file,
|
|
79
|
+
reason
|
|
80
|
+
});
|
|
81
|
+
else if (!files.some((held) => same(held.file, file))) {
|
|
82
|
+
nextId += 1;
|
|
83
|
+
accepted.push({
|
|
84
|
+
id: `${base}-${nextId}`,
|
|
85
|
+
file
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
setRejected(refused);
|
|
90
|
+
if (refused.length > 0) onReject?.(refused);
|
|
91
|
+
if (accepted.length > 0) commit(element, multiple ? [...files, ...accepted] : accepted);
|
|
92
|
+
else write(element, files);
|
|
93
|
+
};
|
|
94
|
+
const { dropProps, isDropTarget } = useDropTarget({
|
|
95
|
+
disabled: field.disabled,
|
|
96
|
+
onDrop: (dropped, target) => add(dropped, inputIn(target))
|
|
97
|
+
}, zone);
|
|
98
|
+
const adopt = useEffectEvent((element) => {
|
|
99
|
+
if (element.files !== null && element.files.length > 0) add([...element.files], element);
|
|
100
|
+
});
|
|
101
|
+
useLayoutEffect(() => {
|
|
102
|
+
const element = fileInputOf(zone.current);
|
|
103
|
+
if (element !== null) adopt(element);
|
|
104
|
+
}, []);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
const form = fileInputOf(zone.current)?.form;
|
|
107
|
+
if (form == null) return void 0;
|
|
108
|
+
const onReset = () => {
|
|
109
|
+
setFiles([]);
|
|
110
|
+
setRejected([]);
|
|
111
|
+
onFilesChange?.([]);
|
|
112
|
+
};
|
|
113
|
+
form.addEventListener("reset", onReset);
|
|
114
|
+
return () => form.removeEventListener("reset", onReset);
|
|
115
|
+
}, [onFilesChange]);
|
|
116
|
+
const count = rows.length;
|
|
117
|
+
useLayoutEffect(() => {
|
|
118
|
+
const removed = refocus.current;
|
|
119
|
+
refocus.current = null;
|
|
120
|
+
if (removed === null || count >= removed.count) return;
|
|
121
|
+
const buttons = [...list.current?.children ?? []].map((row) => row.querySelector("button"));
|
|
122
|
+
(buttons[Math.min(removed.index, buttons.length - 1)] ?? fileInputOf(zone.current))?.focus();
|
|
123
|
+
});
|
|
124
|
+
const drop = (row, index, event) => {
|
|
125
|
+
refocus.current = {
|
|
126
|
+
index,
|
|
127
|
+
count
|
|
128
|
+
};
|
|
129
|
+
if (row.held) commit(inputIn(event.currentTarget), files.filter((entry) => entry.id !== row.id));
|
|
130
|
+
};
|
|
131
|
+
const onChange = (event) => {
|
|
132
|
+
const chosen = [...event.currentTarget.files ?? []];
|
|
133
|
+
if (chosen.length > 0) add(chosen, event.currentTarget);
|
|
134
|
+
else write(event.currentTarget, files);
|
|
135
|
+
};
|
|
136
|
+
const prompt = isDropTarget ? labels.release : pending ? fill(labels.summary, {
|
|
137
|
+
complete: String(complete),
|
|
138
|
+
total: String(rows.length)
|
|
139
|
+
}) : browseLine(labels.prompt, labels.browse);
|
|
140
|
+
const invalidShown = field.invalid || rejected.length > 0;
|
|
141
|
+
const removeLabel = (row) => fill(labels.remove, { name: row.name });
|
|
142
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
143
|
+
className: cx("nz-file-upload", className),
|
|
144
|
+
"data-slot": "file-upload",
|
|
145
|
+
...stateAttrs({
|
|
146
|
+
disabled: field.disabled,
|
|
147
|
+
invalid: invalidShown,
|
|
148
|
+
pending
|
|
149
|
+
}),
|
|
150
|
+
style,
|
|
151
|
+
children: [
|
|
152
|
+
/* @__PURE__ */ jsxs("div", {
|
|
153
|
+
...dropProps,
|
|
154
|
+
ref: zone,
|
|
155
|
+
className: "nz-file-upload-dropzone",
|
|
156
|
+
"data-slot": "file-upload-dropzone",
|
|
157
|
+
"data-drag-over": isDropTarget ? "" : void 0,
|
|
158
|
+
...stateAttrs({
|
|
159
|
+
disabled: field.disabled,
|
|
160
|
+
invalid: invalidShown
|
|
161
|
+
}),
|
|
162
|
+
"aria-disabled": field.disabled ? true : void 0,
|
|
163
|
+
children: [
|
|
164
|
+
/* @__PURE__ */ jsx("input", {
|
|
165
|
+
...mergeProps(field.controlProps, rest),
|
|
166
|
+
onChange,
|
|
167
|
+
type: "file",
|
|
168
|
+
className: "nz-file-upload-input",
|
|
169
|
+
"data-slot": "file-upload-input",
|
|
170
|
+
accept,
|
|
171
|
+
multiple,
|
|
172
|
+
required: field.required && rows.length === 0 ? true : void 0,
|
|
173
|
+
"aria-label": ariaLabel ?? (ariaLabelledBy === void 0 && field.labelledBy === void 0 ? fill(labels.prompt, { browse: labels.browse }) : void 0),
|
|
174
|
+
"aria-labelledby": ariaLabelledBy
|
|
175
|
+
}),
|
|
176
|
+
icon != null && /* @__PURE__ */ jsx("span", {
|
|
177
|
+
className: "nz-file-upload-icon",
|
|
178
|
+
"data-slot": "file-upload-icon",
|
|
179
|
+
"aria-hidden": "true",
|
|
180
|
+
children: icon
|
|
181
|
+
}),
|
|
182
|
+
/* @__PURE__ */ jsx("span", {
|
|
183
|
+
className: "nz-file-upload-prompt",
|
|
184
|
+
"data-slot": "file-upload-prompt",
|
|
185
|
+
children: prompt
|
|
186
|
+
}),
|
|
187
|
+
showHint && /* @__PURE__ */ jsx("span", {
|
|
188
|
+
className: "nz-file-upload-hint",
|
|
189
|
+
"data-slot": "file-upload-hint",
|
|
190
|
+
id: hintId,
|
|
191
|
+
children: hint
|
|
192
|
+
})
|
|
193
|
+
]
|
|
194
|
+
}),
|
|
195
|
+
/* @__PURE__ */ jsx("div", {
|
|
196
|
+
className: "nz-file-upload-messages",
|
|
197
|
+
"data-slot": "file-upload-messages",
|
|
198
|
+
id: messagesId,
|
|
199
|
+
"aria-live": "polite",
|
|
200
|
+
children: rejected.map(({ file, reason }) => /* @__PURE__ */ jsx(InlineError, { children: rejection(labels, reason, file.name, maxSize, locale) }, `${reason}-${file.name}-${file.size}-${file.lastModified}`))
|
|
201
|
+
}),
|
|
202
|
+
rows.length > 0 && /* @__PURE__ */ jsx("ul", {
|
|
203
|
+
ref: list,
|
|
204
|
+
className: "nz-file-upload-list",
|
|
205
|
+
"data-slot": "file-upload-list",
|
|
206
|
+
"aria-label": labels.list,
|
|
207
|
+
children: rows.map((row, index) => {
|
|
208
|
+
const status = row.item?.status;
|
|
209
|
+
const nameId = `${base}-name-${row.id}`;
|
|
210
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
211
|
+
className: "nz-file-upload-item",
|
|
212
|
+
"data-slot": "file-upload-item",
|
|
213
|
+
...stateAttrs({
|
|
214
|
+
pending: status === "uploading",
|
|
215
|
+
error: status === "error"
|
|
216
|
+
}),
|
|
217
|
+
children: [
|
|
218
|
+
/* @__PURE__ */ jsx("span", {
|
|
219
|
+
className: "nz-file-upload-item-name",
|
|
220
|
+
"data-slot": "file-upload-item-name",
|
|
221
|
+
id: nameId,
|
|
222
|
+
children: row.name
|
|
223
|
+
}),
|
|
224
|
+
/* @__PURE__ */ jsxs("span", {
|
|
225
|
+
className: "nz-file-upload-item-status",
|
|
226
|
+
"data-slot": "file-upload-item-status",
|
|
227
|
+
children: [row.size !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
228
|
+
className: "nz-file-upload-item-size",
|
|
229
|
+
"data-slot": "file-upload-item-size",
|
|
230
|
+
children: formatBytes(row.size, locale)
|
|
231
|
+
}), itemStatus(row, labels)]
|
|
232
|
+
}),
|
|
233
|
+
/* @__PURE__ */ jsxs("span", {
|
|
234
|
+
className: "nz-file-upload-item-actions",
|
|
235
|
+
"data-slot": "file-upload-item-actions",
|
|
236
|
+
children: [status === "error" && /* @__PURE__ */ jsx(Button, {
|
|
237
|
+
variant: "tertiary",
|
|
238
|
+
size: "sm",
|
|
239
|
+
"aria-describedby": nameId,
|
|
240
|
+
disabled: field.disabled,
|
|
241
|
+
onClick: () => onRetry?.(row.id),
|
|
242
|
+
children: labels.retry
|
|
243
|
+
}), status === "uploading" ? /* @__PURE__ */ jsx(Button, {
|
|
244
|
+
variant: "tertiary",
|
|
245
|
+
size: "sm",
|
|
246
|
+
"aria-describedby": nameId,
|
|
247
|
+
disabled: field.disabled,
|
|
248
|
+
onClick: (event) => {
|
|
249
|
+
drop(row, index, event);
|
|
250
|
+
onCancel?.(row.id);
|
|
251
|
+
},
|
|
252
|
+
children: labels.cancel
|
|
253
|
+
}) : /* @__PURE__ */ jsx(RemoveButton, {
|
|
254
|
+
label: removeLabel(row),
|
|
255
|
+
disabled: field.disabled,
|
|
256
|
+
onClick: (event) => {
|
|
257
|
+
drop(row, index, event);
|
|
258
|
+
onRemove?.(row.id);
|
|
259
|
+
}
|
|
260
|
+
})]
|
|
261
|
+
})
|
|
262
|
+
]
|
|
263
|
+
}, row.id);
|
|
264
|
+
})
|
|
265
|
+
})
|
|
266
|
+
]
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/** IconButton's element with no tooltip, as Toast's close button: the row's name is visible. */
|
|
270
|
+
function RemoveButton(props) {
|
|
271
|
+
return iconButtonElement({
|
|
272
|
+
label: props.label,
|
|
273
|
+
icon: /* @__PURE__ */ jsx(CloseGlyph, {}),
|
|
274
|
+
variant: "tertiary",
|
|
275
|
+
size: "sm",
|
|
276
|
+
disabled: props.disabled,
|
|
277
|
+
onClick: props.onClick
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/** The file input of the FileUpload that holds `element`. */
|
|
281
|
+
function inputIn(element) {
|
|
282
|
+
return fileInputOf(element.closest("[data-slot=\"file-upload\"]"));
|
|
283
|
+
}
|
|
284
|
+
function fileInputOf(scope) {
|
|
285
|
+
return scope?.querySelector("[data-slot=\"file-upload-input\"]") ?? null;
|
|
286
|
+
}
|
|
287
|
+
/** The held files in order, each with its item, then the items that match no held file. */
|
|
288
|
+
function listRows(files, items) {
|
|
289
|
+
const byId = new Map((items ?? []).map((item) => [item.id, item]));
|
|
290
|
+
const rows = files.map(({ id, file }) => {
|
|
291
|
+
const item = byId.get(id);
|
|
292
|
+
byId.delete(id);
|
|
293
|
+
return {
|
|
294
|
+
id,
|
|
295
|
+
name: item?.name ?? file.name,
|
|
296
|
+
size: item?.size ?? file.size,
|
|
297
|
+
item,
|
|
298
|
+
held: true
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
for (const item of byId.values()) rows.push({
|
|
302
|
+
id: item.id,
|
|
303
|
+
name: item.name ?? item.id,
|
|
304
|
+
size: item.size,
|
|
305
|
+
item,
|
|
306
|
+
held: false
|
|
307
|
+
});
|
|
308
|
+
return rows;
|
|
309
|
+
}
|
|
310
|
+
function itemStatus(row, labels) {
|
|
311
|
+
const item = row.item;
|
|
312
|
+
switch (item?.status) {
|
|
313
|
+
case "uploading": return /* @__PURE__ */ jsx(ProgressBar, {
|
|
314
|
+
value: item.progress ?? 0,
|
|
315
|
+
indeterminate: item.progress === void 0,
|
|
316
|
+
showValue: false,
|
|
317
|
+
"aria-label": fill(labels.uploading, { name: row.name })
|
|
318
|
+
});
|
|
319
|
+
case "complete": return /* @__PURE__ */ jsxs("span", {
|
|
320
|
+
className: "nz-file-upload-item-complete",
|
|
321
|
+
"data-slot": "file-upload-item-complete",
|
|
322
|
+
children: [/* @__PURE__ */ jsx(CircleCheckGlyph, {}), labels.complete]
|
|
323
|
+
});
|
|
324
|
+
case "error": return /* @__PURE__ */ jsxs("span", {
|
|
325
|
+
className: "nz-file-upload-item-error",
|
|
326
|
+
"data-slot": "file-upload-item-error",
|
|
327
|
+
children: [/* @__PURE__ */ jsx(CircleXGlyph, {}), item.error ?? labels.failed]
|
|
328
|
+
});
|
|
329
|
+
default: return null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function rejection(labels, reason, name, maxSize, locale) {
|
|
333
|
+
if (reason === "type") return fill(labels.wrongType, { name });
|
|
334
|
+
if (reason === "count") return fill(labels.tooMany, { name });
|
|
335
|
+
return fill(labels.tooLarge, {
|
|
336
|
+
name,
|
|
337
|
+
max: formatBytes(maxSize ?? 0, locale)
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
/** The prompt with the browse word in its own span, where `{browse}` is (at the end if absent). */
|
|
341
|
+
function browseLine(template, browse) {
|
|
342
|
+
const at = template.indexOf("{browse}");
|
|
343
|
+
const word = /* @__PURE__ */ jsx("span", {
|
|
344
|
+
className: "nz-file-upload-browse",
|
|
345
|
+
"data-slot": "file-upload-browse",
|
|
346
|
+
children: browse
|
|
347
|
+
});
|
|
348
|
+
if (at === -1) return template;
|
|
349
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
350
|
+
template.slice(0, at),
|
|
351
|
+
word,
|
|
352
|
+
template.slice(at + 8)
|
|
353
|
+
] });
|
|
354
|
+
}
|
|
355
|
+
function fill(template, values) {
|
|
356
|
+
let out = template;
|
|
357
|
+
for (const [key, value] of Object.entries(values)) out = out.replaceAll(`{${key}}`, value);
|
|
358
|
+
return out;
|
|
359
|
+
}
|
|
360
|
+
const UNITS = [
|
|
361
|
+
"byte",
|
|
362
|
+
"kilobyte",
|
|
363
|
+
"megabyte",
|
|
364
|
+
"gigabyte",
|
|
365
|
+
"terabyte"
|
|
366
|
+
];
|
|
367
|
+
/** Decimal units (1 MB = 1,000,000 bytes), as macOS and the `maxSize` docs write them. */
|
|
368
|
+
function formatBytes(bytes, locale) {
|
|
369
|
+
let value = Math.max(bytes, 0);
|
|
370
|
+
let unit = 0;
|
|
371
|
+
while (value >= 1e3 && unit < UNITS.length - 1) {
|
|
372
|
+
value /= 1e3;
|
|
373
|
+
unit += 1;
|
|
374
|
+
}
|
|
375
|
+
return new Intl.NumberFormat(locale, {
|
|
376
|
+
style: "unit",
|
|
377
|
+
unit: UNITS[unit],
|
|
378
|
+
unitDisplay: unit === 0 ? "long" : "short",
|
|
379
|
+
maximumFractionDigits: unit > 0 && value < 10 ? 1 : 0
|
|
380
|
+
}).format(value);
|
|
381
|
+
}
|
|
382
|
+
/** The native `accept` rule: a MIME type, a `type/*` wildcard or a `.ext`, any of them. */
|
|
383
|
+
function matches(file, accept) {
|
|
384
|
+
const rules = (accept ?? "").split(",").map((rule) => rule.trim().toLowerCase()).filter((rule) => rule !== "");
|
|
385
|
+
if (rules.length === 0) return true;
|
|
386
|
+
const fileName = file.name.toLowerCase();
|
|
387
|
+
const type = file.type.toLowerCase();
|
|
388
|
+
return rules.some((rule) => rule.startsWith(".") ? fileName.endsWith(rule) : rule.endsWith("/*") ? type.startsWith(rule.slice(0, -1)) : type === rule);
|
|
389
|
+
}
|
|
390
|
+
function same(a, b) {
|
|
391
|
+
return a.name === b.name && a.size === b.size && a.lastModified === b.lastModified;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Puts the held files in the input, as a FileList (the only kind `input.files` takes), and fires
|
|
395
|
+
* `input` so a Field withdraws a "choose a file" message. Not `change`: React's onChange on a file
|
|
396
|
+
* input is the native `change`, which would run the pick handler again.
|
|
397
|
+
*/
|
|
398
|
+
function write(element, files) {
|
|
399
|
+
if (element === null) return;
|
|
400
|
+
const transfer = new DataTransfer();
|
|
401
|
+
for (const { file } of files) transfer.items.add(file);
|
|
402
|
+
element.files = transfer.files;
|
|
403
|
+
element.dispatchEvent(new Event("input", { bubbles: true }));
|
|
404
|
+
}
|
|
405
|
+
//#endregion
|
|
406
|
+
export { FileUpload };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import "./seam.js";
|
|
2
|
+
import { ComponentPropsWithRef, ReactNode, RefObject } from "react";
|
|
3
|
+
//#region src/file-upload/file-upload.contract.d.ts
|
|
4
|
+
/** Where an item's upload is. Absent on an item: chosen, not sent yet. */
|
|
5
|
+
export type FileUploadStatus = "uploading" | "complete" | "error";
|
|
6
|
+
/** A file the component holds (and its input submits), with the id the component gave it. */
|
|
7
|
+
export interface FileUploadFile {
|
|
8
|
+
/** Stays the same while the file is listed. Key your `items` and upload requests by it. */
|
|
9
|
+
id: string;
|
|
10
|
+
file: File;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* An item's upload state, from the app, which does the uploading. Matched to a held file by `id`;
|
|
14
|
+
* an item whose id matches no held file is listed too, after the held files (a file uploaded
|
|
15
|
+
* earlier, shown on an edit form).
|
|
16
|
+
*/
|
|
17
|
+
export interface FileUploadItem {
|
|
18
|
+
id: string;
|
|
19
|
+
/**
|
|
20
|
+
* Shown in the list. Defaults to the held file's name; an item that matches no held file needs
|
|
21
|
+
* one, or its `id` is shown.
|
|
22
|
+
*/
|
|
23
|
+
name?: string;
|
|
24
|
+
/** In bytes, shown beside the name. Defaults to the held file's size. */
|
|
25
|
+
size?: number;
|
|
26
|
+
status?: FileUploadStatus;
|
|
27
|
+
/** 0 to 100 while `uploading`; absent, the bar is indeterminate. */
|
|
28
|
+
progress?: number;
|
|
29
|
+
/** The message while `status` is `error`. @default labels.failed */
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Why a chosen or dropped file was not added. */
|
|
33
|
+
export type FileUploadRejectionReason = "type" | "size" | "count";
|
|
34
|
+
export interface FileUploadRejection {
|
|
35
|
+
file: File;
|
|
36
|
+
reason: FileUploadRejectionReason;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Strings FileUpload renders (§16.4): serialisable, English defaults. `{name}` is a file's name,
|
|
40
|
+
* `{max}` the formatted `maxSize`, `{browse}` where the browse word goes, `{complete}` and `{total}`
|
|
41
|
+
* counts.
|
|
42
|
+
*/
|
|
43
|
+
export interface FileUploadLabels {
|
|
44
|
+
/** The dropzone's line. @default 'Drop files here or {browse}' */
|
|
45
|
+
prompt: string;
|
|
46
|
+
/** The word that reads as the picker's button, in the brand colour. @default 'browse' */
|
|
47
|
+
browse: string;
|
|
48
|
+
/** Replaces the prompt while a drag with files is over the dropzone. @default 'Release to add files' */
|
|
49
|
+
release: string;
|
|
50
|
+
/** Replaces the prompt while an item is uploading. @default '{complete} of {total} uploaded' */
|
|
51
|
+
summary: string;
|
|
52
|
+
/** A file `accept` does not match. @default '{name} is not an accepted file type.' */
|
|
53
|
+
wrongType: string;
|
|
54
|
+
/** A file over `maxSize`. @default '{name} is larger than {max}.' */
|
|
55
|
+
tooLarge: string;
|
|
56
|
+
/** Without `multiple`, every file of a drop after the first. @default '{name} was not added: choose one file.' */
|
|
57
|
+
tooMany: string;
|
|
58
|
+
/** The list's accessible name. @default 'Chosen files' */
|
|
59
|
+
list: string;
|
|
60
|
+
/** Each item's remove button. @default 'Remove {name}' */
|
|
61
|
+
remove: string;
|
|
62
|
+
/** An item in error. @default 'Retry' */
|
|
63
|
+
retry: string;
|
|
64
|
+
/** An item uploading. @default 'Cancel' */
|
|
65
|
+
cancel: string;
|
|
66
|
+
/** An uploading item's progress bar. @default 'Uploading {name}' */
|
|
67
|
+
uploading: string;
|
|
68
|
+
/** A complete item's status. @default 'Uploaded' */
|
|
69
|
+
complete: string;
|
|
70
|
+
/** An item in error with no `error` text. @default 'Upload failed' */
|
|
71
|
+
failed: string;
|
|
72
|
+
}
|
|
73
|
+
export interface FileUploadProps extends Omit<ComponentPropsWithRef<"input">, "type" | "size" | "children" | "value" | "defaultValue" | "onChange" | "accept" | "multiple"> {
|
|
74
|
+
/**
|
|
75
|
+
* The native `accept`: MIME types (`image/png`), wildcards (`image/*`) and extensions (`.pdf`),
|
|
76
|
+
* comma-separated. The picker filters by it, and a dropped or picked file that does not match is
|
|
77
|
+
* not added.
|
|
78
|
+
*/
|
|
79
|
+
accept?: string;
|
|
80
|
+
/** More than one file; each pick or drop adds to the list. Without it, a new file replaces the old. @default false */
|
|
81
|
+
multiple?: boolean;
|
|
82
|
+
/** Bytes. A larger file is not added. 1 MB is 1,000,000 bytes, as `{max}` is written. */
|
|
83
|
+
maxSize?: number;
|
|
84
|
+
/**
|
|
85
|
+
* An error message is presented for this control (§8.3). Inside a Field, the Field sets it; an
|
|
86
|
+
* explicit value here wins.
|
|
87
|
+
*/
|
|
88
|
+
invalid?: boolean;
|
|
89
|
+
/** The line under the prompt, such as "PNG, JPG or WebP, up to 20 MB". */
|
|
90
|
+
hint?: ReactNode;
|
|
91
|
+
/** Decorative mark above the prompt, such as your icon set's `upload` glyph (`aria-hidden`). */
|
|
92
|
+
icon?: ReactNode;
|
|
93
|
+
/**
|
|
94
|
+
* Upload state per file, keyed by the ids `onFilesChange` gives. Leave it out when the form
|
|
95
|
+
* submits the files itself.
|
|
96
|
+
*/
|
|
97
|
+
items?: readonly FileUploadItem[];
|
|
98
|
+
/** The held files changed: a pick, a drop, a remove, a cancel or the form's reset. Every held file, in order. */
|
|
99
|
+
onFilesChange?: (files: FileUploadFile[]) => void;
|
|
100
|
+
/** Files of a pick or drop that were not added; their messages show under the dropzone. */
|
|
101
|
+
onReject?: (rejections: FileUploadRejection[]) => void;
|
|
102
|
+
/** An item's remove button. A held file has already left the list and the input. */
|
|
103
|
+
onRemove?: (id: string) => void;
|
|
104
|
+
/** An item's retry button, on an item in `error`. */
|
|
105
|
+
onRetry?: (id: string) => void;
|
|
106
|
+
/** An item's cancel button, on an item `uploading`. The held file has already left the list. */
|
|
107
|
+
onCancel?: (id: string) => void;
|
|
108
|
+
labels?: Partial<FileUploadLabels>;
|
|
109
|
+
/** BCP 47 tag for sizes. @default 'en-US' */
|
|
110
|
+
locale?: string;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { FileUploadFile, FileUploadItem, FileUploadLabels, FileUploadProps, FileUploadRejection, FileUploadRejectionReason, FileUploadStatus } from "./file-upload.contract.js";
|
|
2
|
+
import { FileUpload } from "./file-upload.client.js";
|
|
3
|
+
export { FileUpload, type FileUploadFile, type FileUploadItem, type FileUploadLabels, type FileUploadProps, type FileUploadRejection, type FileUploadRejectionReason, type FileUploadStatus };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FileUpload } from "./file-upload.client.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "react";
|