@mcp-b/web-components 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 +21 -0
- package/README.md +49 -0
- package/dist/accordion-B1Q3kuP_.d.ts +373 -0
- package/dist/accordion-item-DvPfhpm8.js +307 -0
- package/dist/accordion-item-bPRIahNn.d.ts +63 -0
- package/dist/accordion-zDr-Br4V.js +483 -0
- package/dist/action-bar-CYsjmhwP.d.ts +29 -0
- package/dist/action-bar-CjN_UcnP.js +56 -0
- package/dist/alert-dialog-4CnO3Nb5.d.ts +60 -0
- package/dist/alert-dialog-D25Oi_TS.js +126 -0
- package/dist/avatar-Bje_KpZo.d.ts +141 -0
- package/dist/avatar-CRP0kW3x.js +224 -0
- package/dist/badge-Ct95U4UO.js +301 -0
- package/dist/badge-D1DNQrWn.d.ts +106 -0
- package/dist/breadcrumb-BxZ-nQE5.d.ts +365 -0
- package/dist/breadcrumb-item-BC454oQe.d.ts +59 -0
- package/dist/breadcrumb-item-P5pdq_gE.js +151 -0
- package/dist/breadcrumb-uURhiqWJ.js +384 -0
- package/dist/button-5k_aL_gD.js +802 -0
- package/dist/button-BQofnUt4.d.ts +354 -0
- package/dist/button-group-BydvJTQy.js +197 -0
- package/dist/button-group-COodHeuB.d.ts +155 -0
- package/dist/callout-B8zTf8Go.js +188 -0
- package/dist/callout-DFwPao36.d.ts +103 -0
- package/dist/card-BYDzdMAU.d.ts +177 -0
- package/dist/card-DIg1-X2G.js +332 -0
- package/dist/carousel-Bktu7wrD.js +843 -0
- package/dist/carousel-DQITCtEY.d.ts +423 -0
- package/dist/carousel-item-B5-X31Ha.js +79 -0
- package/dist/carousel-item-BB3jL2tk.d.ts +34 -0
- package/dist/cdn/loader.js +530 -0
- package/dist/checkbox-D6r7PVPj.js +641 -0
- package/dist/checkbox-DoFcDEKB.d.ts +354 -0
- package/dist/checkbox-group-CLvNAO_F.js +201 -0
- package/dist/checkbox-group-Cnh8rAn4.d.ts +152 -0
- package/dist/color-input-Bky89xg_.d.ts +470 -0
- package/dist/color-input-DPIxi9wR.js +894 -0
- package/dist/color-picker-adwOmtRl.js +1240 -0
- package/dist/color-picker-wQw8bPsq.d.ts +360 -0
- package/dist/combobox-B6al50UG.js +1693 -0
- package/dist/combobox-item-D2H1CMxC.d.ts +714 -0
- package/dist/combobox-item-yM6tDrGG.js +225 -0
- package/dist/comparison-B1-nMwmp.d.ts +134 -0
- package/dist/comparison-CyqKrCN-.js +435 -0
- package/dist/components/accordion/accordion.d.ts +2 -0
- package/dist/components/accordion/accordion.js +2 -0
- package/dist/components/accordion-item/accordion-item.d.ts +2 -0
- package/dist/components/accordion-item/accordion-item.js +2 -0
- package/dist/components/action-bar/action-bar.d.ts +2 -0
- package/dist/components/action-bar/action-bar.js +2 -0
- package/dist/components/alert-dialog/alert-dialog.d.ts +2 -0
- package/dist/components/alert-dialog/alert-dialog.js +2 -0
- package/dist/components/avatar/avatar.d.ts +2 -0
- package/dist/components/avatar/avatar.js +2 -0
- package/dist/components/badge/badge.d.ts +2 -0
- package/dist/components/badge/badge.js +2 -0
- package/dist/components/breadcrumb/breadcrumb.d.ts +2 -0
- package/dist/components/breadcrumb/breadcrumb.js +2 -0
- package/dist/components/breadcrumb-item/breadcrumb-item.d.ts +2 -0
- package/dist/components/breadcrumb-item/breadcrumb-item.js +2 -0
- package/dist/components/button/button.d.ts +2 -0
- package/dist/components/button/button.js +2 -0
- package/dist/components/button-group/button-group.d.ts +2 -0
- package/dist/components/button-group/button-group.js +2 -0
- package/dist/components/callout/callout.d.ts +2 -0
- package/dist/components/callout/callout.js +2 -0
- package/dist/components/card/card.d.ts +2 -0
- package/dist/components/card/card.js +2 -0
- package/dist/components/carousel/carousel.d.ts +2 -0
- package/dist/components/carousel/carousel.js +2 -0
- package/dist/components/carousel-item/carousel-item.d.ts +2 -0
- package/dist/components/carousel-item/carousel-item.js +2 -0
- package/dist/components/checkbox/checkbox.d.ts +2 -0
- package/dist/components/checkbox/checkbox.js +2 -0
- package/dist/components/checkbox-group/checkbox-group.d.ts +2 -0
- package/dist/components/checkbox-group/checkbox-group.js +2 -0
- package/dist/components/color-input/color-input.d.ts +2 -0
- package/dist/components/color-input/color-input.js +2 -0
- package/dist/components/color-picker/color-picker.d.ts +2 -0
- package/dist/components/color-picker/color-picker.js +2 -0
- package/dist/components/combobox/combobox.d.ts +2 -0
- package/dist/components/combobox/combobox.js +2 -0
- package/dist/components/combobox-item/combobox-item.d.ts +2 -0
- package/dist/components/combobox-item/combobox-item.js +2 -0
- package/dist/components/comparison/comparison.d.ts +2 -0
- package/dist/components/comparison/comparison.js +2 -0
- package/dist/components/copy/copy.d.ts +2 -0
- package/dist/components/copy/copy.js +291 -0
- package/dist/components/data-table/data-table.d.ts +2 -0
- package/dist/components/data-table/data-table.js +2 -0
- package/dist/components/date/date.d.ts +2 -0
- package/dist/components/date/date.js +2 -0
- package/dist/components/dialog/dialog.d.ts +2 -0
- package/dist/components/dialog/dialog.js +2 -0
- package/dist/components/divider/divider.d.ts +2 -0
- package/dist/components/divider/divider.js +2 -0
- package/dist/components/dropdown/dropdown.d.ts +2 -0
- package/dist/components/dropdown/dropdown.js +2 -0
- package/dist/components/dropdown-item/dropdown-item.d.ts +2 -0
- package/dist/components/dropdown-item/dropdown-item.js +2 -0
- package/dist/components/empty-result/empty-result.d.ts +2 -0
- package/dist/components/empty-result/empty-result.js +2 -0
- package/dist/components/empty-state/empty-state.d.ts +2 -0
- package/dist/components/empty-state/empty-state.js +2 -0
- package/dist/components/expander/expander.d.ts +2 -0
- package/dist/components/expander/expander.js +2 -0
- package/dist/components/field/field.d.ts +2 -0
- package/dist/components/field/field.js +2 -0
- package/dist/components/file-input/file-input.d.ts +2 -0
- package/dist/components/file-input/file-input.js +2 -0
- package/dist/components/filter-bar/filter-bar.d.ts +2 -0
- package/dist/components/filter-bar/filter-bar.js +2 -0
- package/dist/components/form-section/form-section.d.ts +2 -0
- package/dist/components/form-section/form-section.js +2 -0
- package/dist/components/icon/icon.d.ts +2 -0
- package/dist/components/icon/icon.js +2 -0
- package/dist/components/include/include.d.ts +2 -0
- package/dist/components/include/include.js +2 -0
- package/dist/components/index.d.ts +85 -0
- package/dist/components/index.js +86 -0
- package/dist/components/infinite-scroller/infinite-scroller.d.ts +2 -0
- package/dist/components/infinite-scroller/infinite-scroller.js +2 -0
- package/dist/components/intersection-observer/intersection-observer.d.ts +2 -0
- package/dist/components/intersection-observer/intersection-observer.js +2 -0
- package/dist/components/listbox/listbox.d.ts +2 -0
- package/dist/components/listbox/listbox.js +2 -0
- package/dist/components/listbox-item/listbox-item.d.ts +2 -0
- package/dist/components/listbox-item/listbox-item.js +2 -0
- package/dist/components/lorem-ipsum/lorem-ipsum.d.ts +2 -0
- package/dist/components/lorem-ipsum/lorem-ipsum.js +2 -0
- package/dist/components/meter/meter.d.ts +2 -0
- package/dist/components/meter/meter.js +2 -0
- package/dist/components/metric/metric.d.ts +2 -0
- package/dist/components/metric/metric.js +2 -0
- package/dist/components/metric-grid/metric-grid.d.ts +2 -0
- package/dist/components/metric-grid/metric-grid.js +2 -0
- package/dist/components/mutation-observer/mutation-observer.d.ts +2 -0
- package/dist/components/mutation-observer/mutation-observer.js +2 -0
- package/dist/components/navicon/navicon.d.ts +2 -0
- package/dist/components/navicon/navicon.js +2 -0
- package/dist/components/number/number.d.ts +2 -0
- package/dist/components/number/number.js +2 -0
- package/dist/components/number-field/number-field.d.ts +2 -0
- package/dist/components/number-field/number-field.js +2 -0
- package/dist/components/pagination/pagination.d.ts +2 -0
- package/dist/components/pagination/pagination.js +2 -0
- package/dist/components/popover/popover.d.ts +2 -0
- package/dist/components/popover/popover.js +2 -0
- package/dist/components/preview-card/preview-card.d.ts +2 -0
- package/dist/components/preview-card/preview-card.js +2 -0
- package/dist/components/progress/progress.d.ts +2 -0
- package/dist/components/progress/progress.js +2 -0
- package/dist/components/radio/radio.d.ts +2 -0
- package/dist/components/radio/radio.js +2 -0
- package/dist/components/radio-item/radio-item.d.ts +2 -0
- package/dist/components/radio-item/radio-item.js +2 -0
- package/dist/components/random-content/random-content.d.ts +2 -0
- package/dist/components/random-content/random-content.js +2 -0
- package/dist/components/rating/rating.d.ts +2 -0
- package/dist/components/rating/rating.js +2 -0
- package/dist/components/resize-observer/resize-observer.d.ts +2 -0
- package/dist/components/resize-observer/resize-observer.js +2 -0
- package/dist/components/scroll-area/scroll-area.d.ts +2 -0
- package/dist/components/scroll-area/scroll-area.js +2 -0
- package/dist/components/scroller/scroller.d.ts +2 -0
- package/dist/components/scroller/scroller.js +2 -0
- package/dist/components/search-list/search-list.d.ts +2 -0
- package/dist/components/search-list/search-list.js +2 -0
- package/dist/components/select/select.d.ts +2 -0
- package/dist/components/select/select.js +2 -0
- package/dist/components/selection-summary/selection-summary.d.ts +2 -0
- package/dist/components/selection-summary/selection-summary.js +2 -0
- package/dist/components/share/share.d.ts +2 -0
- package/dist/components/share/share.js +2 -0
- package/dist/components/slide-activator/slide-activator.d.ts +2 -0
- package/dist/components/slide-activator/slide-activator.js +2 -0
- package/dist/components/slider/slider.d.ts +2 -0
- package/dist/components/slider/slider.js +2 -0
- package/dist/components/sparkline/sparkline.d.ts +2 -0
- package/dist/components/sparkline/sparkline.js +2 -0
- package/dist/components/spinner/spinner.d.ts +2 -0
- package/dist/components/spinner/spinner.js +2 -0
- package/dist/components/splitter/splitter.d.ts +2 -0
- package/dist/components/splitter/splitter.js +2 -0
- package/dist/components/switch/switch.d.ts +2 -0
- package/dist/components/switch/switch.js +2 -0
- package/dist/components/tab/tab.d.ts +2 -0
- package/dist/components/tab/tab.js +2 -0
- package/dist/components/tab-list/tab-list.d.ts +2 -0
- package/dist/components/tab-list/tab-list.js +2 -0
- package/dist/components/tab-panel/tab-panel.d.ts +2 -0
- package/dist/components/tab-panel/tab-panel.js +2 -0
- package/dist/components/text-area/text-area.d.ts +2 -0
- package/dist/components/text-area/text-area.js +2 -0
- package/dist/components/text-field/text-field.d.ts +2 -0
- package/dist/components/text-field/text-field.js +2 -0
- package/dist/components/text-mask/text-mask.d.ts +2 -0
- package/dist/components/text-mask/text-mask.js +2 -0
- package/dist/components/timed-content/timed-content.d.ts +2 -0
- package/dist/components/timed-content/timed-content.js +2 -0
- package/dist/components/toast/toast.d.ts +2 -0
- package/dist/components/toast/toast.js +2 -0
- package/dist/components/toast-item/toast-item.d.ts +2 -0
- package/dist/components/toast-item/toast-item.js +2 -0
- package/dist/components/toggle-icon/toggle-icon.d.ts +2 -0
- package/dist/components/toggle-icon/toggle-icon.js +2 -0
- package/dist/components/toggle-tag/toggle-tag.d.ts +2 -0
- package/dist/components/toggle-tag/toggle-tag.js +2 -0
- package/dist/components/toolbar/toolbar.d.ts +2 -0
- package/dist/components/toolbar/toolbar.js +2 -0
- package/dist/components/tooltip/tooltip.d.ts +2 -0
- package/dist/components/tooltip/tooltip.js +2 -0
- package/dist/components/transition-group/transition-group.d.ts +2 -0
- package/dist/components/transition-group/transition-group.js +2 -0
- package/dist/components/zoomable-frame/zoomable-frame.d.ts +2 -0
- package/dist/components/zoomable-frame/zoomable-frame.js +2 -0
- package/dist/copy-CvC9vaGw.d.ts +206 -0
- package/dist/copy.styles-DWGvGNTP.js +100 -0
- package/dist/data-table-CITa8DSn.js +247 -0
- package/dist/data-table-DL5RhE0d.d.ts +89 -0
- package/dist/date-CJPmOdi9.js +146 -0
- package/dist/date-DtaTBM71.d.ts +142 -0
- package/dist/decorate-DcF3lt7P.js +9 -0
- package/dist/dialog-Cx46HMaZ.js +983 -0
- package/dist/dialog-N-v0woIy.d.ts +414 -0
- package/dist/divider-9vNsfHW8.js +169 -0
- package/dist/divider-DWuAxcXv.d.ts +79 -0
- package/dist/docs/custom-elements.json +29301 -0
- package/dist/dropdown-BXSKpVX9.js +1123 -0
- package/dist/dropdown-Bo00Vlr5.d.ts +537 -0
- package/dist/dropdown-item-_lIs-Tfd.d.ts +111 -0
- package/dist/dropdown-item-i77cRuN6.js +504 -0
- package/dist/empty-result-B2ln1yFL.js +65 -0
- package/dist/empty-result-B54x_Ab2.d.ts +31 -0
- package/dist/empty-state-BLWjtKUo.js +186 -0
- package/dist/empty-state-SGKjpwp3.d.ts +117 -0
- package/dist/expander-BUev0BmM.d.ts +174 -0
- package/dist/expander-Bwvxj6Oa.js +342 -0
- package/dist/field-BEyS909F.js +163 -0
- package/dist/field-ITx0jVw-.d.ts +69 -0
- package/dist/file-input-BEumLJjg.js +841 -0
- package/dist/file-input-D2D6YC0B.d.ts +378 -0
- package/dist/filter-bar-Bj2QzEn9.d.ts +35 -0
- package/dist/filter-bar-Dcs67aXo.js +66 -0
- package/dist/form-section-BchPetkj.js +83 -0
- package/dist/form-section-xFBTBULQ.d.ts +34 -0
- package/dist/icon-BPVkNsY4.js +165 -0
- package/dist/icon-Ci9CPZJV.d.ts +72 -0
- package/dist/icon-library-D_if7p2h.d.ts +2 -0
- package/dist/include-CQHVVtNs.d.ts +103 -0
- package/dist/include-qNUh_6kT.js +155 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.js +92 -0
- package/dist/infinite-scroller-BmmtnWNt.js +285 -0
- package/dist/infinite-scroller-CuUEAlB9.d.ts +174 -0
- package/dist/intersection-observer-B6TciOAQ.js +503 -0
- package/dist/intersection-observer-B7nmP7Zz.d.ts +418 -0
- package/dist/listbox-C3XXRWGX.js +1257 -0
- package/dist/listbox-DD4ujIJe.d.ts +682 -0
- package/dist/listbox-item-CwD9s3VY.js +135 -0
- package/dist/listbox-item-DQEJWp4Z.d.ts +53 -0
- package/dist/localize-322EtXNX.d.ts +66 -0
- package/dist/lorem-ipsum-B2x3V-v8.js +198 -0
- package/dist/lorem-ipsum-CR82CSuJ.d.ts +130 -0
- package/dist/meter-BC7uaJWf.d.ts +73 -0
- package/dist/meter-BIDyjwFp.js +155 -0
- package/dist/metric-CjlLq_VA.d.ts +36 -0
- package/dist/metric-DbuOcDp_.js +86 -0
- package/dist/metric-grid-C2Pb0Zl3.js +37 -0
- package/dist/metric-grid-C5Xbb1_0.d.ts +27 -0
- package/dist/mutation-observer-BmrZ-GER.d.ts +326 -0
- package/dist/mutation-observer-DS8EBuOp.js +388 -0
- package/dist/navicon-Dic5Qjzb.d.ts +159 -0
- package/dist/navicon-_yMHY27-.js +486 -0
- package/dist/number-BNtNXNF3.js +162 -0
- package/dist/number-BwbnErlB.d.ts +143 -0
- package/dist/number-field-BQHB7UYo.js +726 -0
- package/dist/number-field-odk4lKXM.d.ts +422 -0
- package/dist/pagination-6z2qcf3U.d.ts +322 -0
- package/dist/pagination-DuKPuzdb.js +679 -0
- package/dist/popover-D0sxTU6o.d.ts +259 -0
- package/dist/popover-DJBrJ0za.js +556 -0
- package/dist/preview-card-C7H1FPfd.js +287 -0
- package/dist/preview-card-DitOCZTD.d.ts +86 -0
- package/dist/progress-Db0_axHQ.d.ts +181 -0
- package/dist/progress-DzVk260j.js +494 -0
- package/dist/radio-BtDG9xJM.js +658 -0
- package/dist/radio-CieMa4zU.d.ts +460 -0
- package/dist/radio-item-DIrUStAX.js +264 -0
- package/dist/radio-item-Xq2U3cMu.d.ts +69 -0
- package/dist/random-content-BhSeJFKz.d.ts +380 -0
- package/dist/random-content-BwiirXdG.js +450 -0
- package/dist/rating-4xNsWumY.d.ts +369 -0
- package/dist/rating-C1BcJDIO.js +722 -0
- package/dist/resize-observer-BseSbVWP.d.ts +187 -0
- package/dist/resize-observer-DcrLhddo.js +236 -0
- package/dist/scroll-area-COc1857S.js +127 -0
- package/dist/scroll-area-CVYDf5qY.d.ts +61 -0
- package/dist/scroller-LYgBVyfY.js +590 -0
- package/dist/scroller-bB2rGs7b.d.ts +374 -0
- package/dist/search-list-Clmrg8EV.js +884 -0
- package/dist/search-list-n0GYO7rh.d.ts +777 -0
- package/dist/select-CkZK2jJn.d.ts +506 -0
- package/dist/select-DLIaRnA4.js +690 -0
- package/dist/selection-summary-BVnNJ8Lw.js +48 -0
- package/dist/selection-summary-DmFkGyZI.d.ts +34 -0
- package/dist/share-DPlqP2dc.d.ts +162 -0
- package/dist/share-bsgXZCl7.js +250 -0
- package/dist/sigvelo.d.ts +5 -0
- package/dist/sigvelo.js +5 -0
- package/dist/sigvelo.loader.d.ts +3 -0
- package/dist/sigvelo.loader.js +102 -0
- package/dist/slide-activator-D7bBz69E.d.ts +429 -0
- package/dist/slide-activator-DlxQt9R9.js +798 -0
- package/dist/slider-B0FVsV1o.d.ts +921 -0
- package/dist/slider-B90Il7x3.js +1744 -0
- package/dist/sparkline-CcpTaJ_Z.js +358 -0
- package/dist/sparkline-DlCIt81-.d.ts +235 -0
- package/dist/spinner-C04Dmc0H.js +188 -0
- package/dist/spinner-CZ19x_dC.d.ts +99 -0
- package/dist/splitter-DBDJAzsp.d.ts +325 -0
- package/dist/splitter-MnD4In9H.js +638 -0
- package/dist/switch-CPaEKbog.js +581 -0
- package/dist/switch-Cief9M59.d.ts +248 -0
- package/dist/tab-BcqYGsuW.d.ts +44 -0
- package/dist/tab-C-FtuNmh.js +102 -0
- package/dist/tab-list-B_Ye_Oj9.js +691 -0
- package/dist/tab-list-DDvS8qHr.d.ts +450 -0
- package/dist/tab-panel-BaBl6eep.js +60 -0
- package/dist/tab-panel-BzSJlSfd.d.ts +38 -0
- package/dist/text-area-B_mjCE9W.d.ts +327 -0
- package/dist/text-area-Czixaz-_.js +556 -0
- package/dist/text-field-BClWMp6q.d.ts +424 -0
- package/dist/text-field-inpJfp0A.js +687 -0
- package/dist/text-mask-CNKVKSFp.d.ts +336 -0
- package/dist/text-mask-DDEurj90.js +370 -0
- package/dist/themes/sigvelo.css +10 -0
- package/dist/themes/utilities.css +9 -0
- package/dist/timed-content-D2mGFamc.d.ts +181 -0
- package/dist/timed-content-pvEP4l5V.js +226 -0
- package/dist/toast-BnZaIg6Z.js +636 -0
- package/dist/toast-cEBVK9NQ.d.ts +487 -0
- package/dist/toast-item-BPpJT6vD.d.ts +159 -0
- package/dist/toast-item-IS8IFUEg.js +372 -0
- package/dist/toggle-icon-4oLDeEt4.js +752 -0
- package/dist/toggle-icon-DlwMMWZL.d.ts +359 -0
- package/dist/toggle-tag-1sfTFJtg.js +434 -0
- package/dist/toggle-tag-IVvMGT4R.d.ts +245 -0
- package/dist/toolbar-CABq0ZL1.d.ts +122 -0
- package/dist/toolbar-CEZ0-F-X.js +196 -0
- package/dist/tooltip-DbyoPFNe.js +521 -0
- package/dist/tooltip-ahFthek8.d.ts +192 -0
- package/dist/transition-group-3hnAnwSd.js +801 -0
- package/dist/transition-group-DD_CjSNC.d.ts +608 -0
- package/dist/translations/en.d.ts +6 -0
- package/dist/translations/en.js +75 -0
- package/dist/translations/es.d.ts +6 -0
- package/dist/translations/es.js +75 -0
- package/dist/types/custom-element-jsx.d.ts +13723 -0
- package/dist/utilities/icon-library.d.ts +3 -0
- package/dist/utilities/icon-library.js +93 -0
- package/dist/utilities/localize.d.ts +2 -0
- package/dist/utilities/localize.js +6 -0
- package/dist/zoomable-frame-Cldvj5sE.js +398 -0
- package/dist/zoomable-frame-r6S6587z.d.ts +162 -0
- package/package.json +83 -0
|
@@ -0,0 +1,841 @@
|
|
|
1
|
+
import { Localize } from "./utilities/localize.js";
|
|
2
|
+
import "./icon-BPVkNsY4.js";
|
|
3
|
+
import { t as __decorate } from "./decorate-DcF3lt7P.js";
|
|
4
|
+
import "./button-5k_aL_gD.js";
|
|
5
|
+
import { css, html, nothing } from "lit";
|
|
6
|
+
import { property, query, state } from "lit/decorators.js";
|
|
7
|
+
import hostStyles from "@mcp-b/wc-support/styles/host.styles";
|
|
8
|
+
import { SigveloFormControlElement } from "@mcp-b/wc-support/base/sigvelo-element";
|
|
9
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
10
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
11
|
+
import { SigveloBlurEvent, SigveloChangeEvent, SigveloFocusEvent, SigveloInputEvent } from "@mcp-b/wc-support/events/form";
|
|
12
|
+
import formControlStyles from "@mcp-b/wc-support/styles/form-control.styles";
|
|
13
|
+
//#region src/components/file-input/file-input.styles.ts
|
|
14
|
+
var file_input_styles_default = css`
|
|
15
|
+
:host(:state(disabled)) {
|
|
16
|
+
cursor: not-allowed;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
:host(:state(disabled)) #label {
|
|
20
|
+
color: var(--sigvelo-color-text-muted);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:host(:state(disabled)) #dropzone {
|
|
24
|
+
opacity: 0.5;
|
|
25
|
+
pointer-events: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#dropzone {
|
|
29
|
+
position: relative;
|
|
30
|
+
padding: 3em 2em;
|
|
31
|
+
border: dashed var(--sigvelo-border-width) var(--sigvelo-color-neutral-border-muted);
|
|
32
|
+
border-radius: var(--sigvelo-radius-md);
|
|
33
|
+
background-color: var(--sigvelo-color-surface);
|
|
34
|
+
color: var(--sigvelo-color-neutral-text);
|
|
35
|
+
font-weight: var(--sigvelo-font-weight-semibold);
|
|
36
|
+
text-align: center;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
transition:
|
|
39
|
+
var(--sigvelo-motion-duration-interaction) background-color ease,
|
|
40
|
+
var(--sigvelo-motion-duration-interaction) border-color ease,
|
|
41
|
+
var(--sigvelo-motion-duration-interaction) color ease;
|
|
42
|
+
|
|
43
|
+
&:focus {
|
|
44
|
+
outline: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&:has(input:focus-visible) {
|
|
48
|
+
border-color: transparent;
|
|
49
|
+
outline: var(--sigvelo-focus-ring);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&.dragging {
|
|
53
|
+
border-style: solid;
|
|
54
|
+
border-color: var(--sigvelo-color-primary-border);
|
|
55
|
+
background-color: var(--sigvelo-color-primary-bg-subtle);
|
|
56
|
+
color: var(--sigvelo-color-primary-text);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
sigvelo-icon {
|
|
60
|
+
color: var(--sigvelo-color-neutral-text);
|
|
61
|
+
font-size: 2em;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Position the file input to stretch the entire dropzone so validation errors are positioned properly. */
|
|
65
|
+
#file-input {
|
|
66
|
+
position: absolute;
|
|
67
|
+
top: 0;
|
|
68
|
+
right: 0;
|
|
69
|
+
bottom: 0;
|
|
70
|
+
left: 0;
|
|
71
|
+
opacity: 0;
|
|
72
|
+
pointer-events: none;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Create an invisible overlay to prevent dragleave from firing on child elements */
|
|
76
|
+
&::after {
|
|
77
|
+
position: absolute;
|
|
78
|
+
top: 0;
|
|
79
|
+
right: 0;
|
|
80
|
+
bottom: 0;
|
|
81
|
+
left: 0;
|
|
82
|
+
content: "";
|
|
83
|
+
opacity: 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* File list */
|
|
88
|
+
#file-list {
|
|
89
|
+
margin-block-start: 0.5em;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
:host(:state(empty)) #file-list {
|
|
93
|
+
display: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.file {
|
|
97
|
+
display: flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
padding: 0.5em;
|
|
100
|
+
gap: 1em;
|
|
101
|
+
border: var(--sigvelo-border-style) var(--sigvelo-border-width)
|
|
102
|
+
var(--sigvelo-color-neutral-border-subtle);
|
|
103
|
+
border-radius: var(--sigvelo-radius-md);
|
|
104
|
+
background-color: var(--sigvelo-color-surface);
|
|
105
|
+
box-shadow: var(--sigvelo-elevation-hairline);
|
|
106
|
+
|
|
107
|
+
.file-thumbnail {
|
|
108
|
+
display: flex;
|
|
109
|
+
position: relative;
|
|
110
|
+
flex: 0 0 4em;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
aspect-ratio: 1;
|
|
114
|
+
width: 100%;
|
|
115
|
+
border-radius: var(--sigvelo-radius-sm);
|
|
116
|
+
background: var(--sigvelo-color-neutral-bg-subtle);
|
|
117
|
+
|
|
118
|
+
img {
|
|
119
|
+
display: block;
|
|
120
|
+
width: 100%;
|
|
121
|
+
height: 100%;
|
|
122
|
+
object-fit: cover;
|
|
123
|
+
border-radius: inherit;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
sigvelo-icon {
|
|
127
|
+
color: var(--sigvelo-color-text-muted);
|
|
128
|
+
font-size: 1.5em;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.file-details {
|
|
133
|
+
display: flex;
|
|
134
|
+
flex: 1 1 auto;
|
|
135
|
+
flex-direction: column;
|
|
136
|
+
|
|
137
|
+
.file-name {
|
|
138
|
+
white-space: normal;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.file-size {
|
|
142
|
+
color: var(--sigvelo-color-text-muted);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.file-actions {
|
|
147
|
+
display: flex;
|
|
148
|
+
flex: 0 0 auto;
|
|
149
|
+
align-items: center;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
+ .file {
|
|
153
|
+
margin-block-start: 0.5em;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* Sizes */
|
|
158
|
+
#dropzone.xs,
|
|
159
|
+
#file-list.xs {
|
|
160
|
+
font-size: calc(var(--sigvelo-control-text-xs) * 0.8375);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#dropzone.sm,
|
|
164
|
+
#file-list.sm {
|
|
165
|
+
font-size: calc(var(--sigvelo-control-text-sm) * 0.8375);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#dropzone.md,
|
|
169
|
+
#file-list.md {
|
|
170
|
+
font-size: calc(var(--sigvelo-control-text-md) * 0.8375);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#dropzone.lg,
|
|
174
|
+
#file-list.lg {
|
|
175
|
+
font-size: calc(var(--sigvelo-control-text-lg) * 0.8375);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#dropzone.xl,
|
|
179
|
+
#file-list.xl {
|
|
180
|
+
font-size: calc(var(--sigvelo-control-text-xl) * 0.8375);
|
|
181
|
+
}
|
|
182
|
+
`;
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/components/file-input/file-input.ts
|
|
185
|
+
const nativeFileInput = document.createElement("input");
|
|
186
|
+
nativeFileInput.name = "sigvelo-faux-input";
|
|
187
|
+
nativeFileInput.type = "file";
|
|
188
|
+
nativeFileInput.required = true;
|
|
189
|
+
const VALIDATION_MESSAGE = nativeFileInput.validationMessage;
|
|
190
|
+
/**
|
|
191
|
+
* <sigvelo-file-input>
|
|
192
|
+
*
|
|
193
|
+
* @summary Allows the user to select files to upload to the server.
|
|
194
|
+
* @tag sigvelo-file-input
|
|
195
|
+
* @documentation https://design-system.sigvelo.com/docs/components/file
|
|
196
|
+
* @status stable
|
|
197
|
+
* @since 1.0
|
|
198
|
+
*
|
|
199
|
+
* @dependency sigvelo-button
|
|
200
|
+
* @dependency sigvelo-icon
|
|
201
|
+
*
|
|
202
|
+
* @slot label - The file input's label. For plain-text labels, you can use the `label` attribute instead.
|
|
203
|
+
* @slot description - The file input's description. For plain-text descriptions, you can use the `description`
|
|
204
|
+
* attribute instead.
|
|
205
|
+
* @slot dropzone - Custom content to show in the dropzone.
|
|
206
|
+
*
|
|
207
|
+
* @event sigvelo-blur - Emitted when the file input loses focus. This event does not bubble.
|
|
208
|
+
* @event sigvelo-change - Emitted when the user selects or removes a file.
|
|
209
|
+
* @event sigvelo-focus - Emitted when the file input receives focus. This event does not bubble.
|
|
210
|
+
* @event sigvelo-input - Emitted when the file input receives input.
|
|
211
|
+
*
|
|
212
|
+
* @csspart label - The element that contains the text field's label, a `<label>` element.
|
|
213
|
+
* @csspart description - The element that contains the text field's description.
|
|
214
|
+
* @csspart dropzone - The bordered region where files can be dropped.
|
|
215
|
+
* @csspart file-list - The list of files shown when at least one file is selected.
|
|
216
|
+
* @csspart file - A selected file will be drawn in this container.
|
|
217
|
+
* @csspart file-thumbnail - The container that hold's the file's image or icon.
|
|
218
|
+
* @csspart file-image - The file's image preview (if it's an image).
|
|
219
|
+
* @csspart file-icon - The file's icon (if it's not an image).
|
|
220
|
+
* @csspart file-icon__svg - The `<svg>` part of the file icon.
|
|
221
|
+
* @csspart file-details - The container that holds the filename and size.
|
|
222
|
+
* @csspart file-name - The container that holds the file's name, a `<span>` element.
|
|
223
|
+
* @csspart file-size - The container that holds the file's size, a `<small>` element.
|
|
224
|
+
* @csspart file-actions - The container that holds the file's remove button.
|
|
225
|
+
* @csspart file-remove-button - The file's remove button.
|
|
226
|
+
* @csspart file-remove-button__button - The `button` part of the file's remove button.
|
|
227
|
+
*
|
|
228
|
+
* @cssstate disabled - Applied when the file input is disabled.
|
|
229
|
+
* @cssstate blank - Applied when the file input has a blank value.
|
|
230
|
+
* @cssstate focused - Applied when the file input has focus.
|
|
231
|
+
* @cssstate user-valid - Applied when the file input is valid and the user has sufficiently interacted with it.
|
|
232
|
+
* @cssstate user-invalid - Applied when the file input is invalid and the user has sufficiently interacted with it.
|
|
233
|
+
*
|
|
234
|
+
* @example Default
|
|
235
|
+
* ```html
|
|
236
|
+
* <sigvelo-file-input
|
|
237
|
+
* name="files"
|
|
238
|
+
* label="Select a file"
|
|
239
|
+
* description="Files must be 20MB or less"
|
|
240
|
+
* multiple
|
|
241
|
+
* ></sigvelo-file-input>
|
|
242
|
+
* ```
|
|
243
|
+
*
|
|
244
|
+
* **Note:** This component works like a [native file input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file). Files can be posted to your server as multipart form data or you can access them via JavaScript for processing.
|
|
245
|
+
*
|
|
246
|
+
* @example Labels and descriptions
|
|
247
|
+
* You can use the `label` and `description` attributes to provide plain text labels and descriptions for the file input. If you want to provide HTML, use the `label` and `description` slots instead.
|
|
248
|
+
*
|
|
249
|
+
* ```html
|
|
250
|
+
* <sigvelo-file-input name="file" label="Select a file">
|
|
251
|
+
* <span slot="description">
|
|
252
|
+
* For more information, <a href="https://example.com/" target="_blank">visit our website</a>.
|
|
253
|
+
* </span>
|
|
254
|
+
* </sigvelo-file-input>
|
|
255
|
+
* ```
|
|
256
|
+
*
|
|
257
|
+
* @example Uploading with forms
|
|
258
|
+
* When uploading a file from a form, you'll probably want to add `method="post"` and `enctype="multipart/form-data"` to the form so the files will be sent to the server correctly.
|
|
259
|
+
*
|
|
260
|
+
* ```html
|
|
261
|
+
* <form
|
|
262
|
+
* id="file-input__uploading"
|
|
263
|
+
* enctype="multipart/form-data"
|
|
264
|
+
* method="post"
|
|
265
|
+
* action="about:blank"
|
|
266
|
+
* target="_blank"
|
|
267
|
+
* >
|
|
268
|
+
* <sigvelo-file-input name="files" label="Select a file"></sigvelo-file-input>
|
|
269
|
+
* <br>
|
|
270
|
+
* <sigvelo-button type="submit" color="primary">Upload</sigvelo-button>
|
|
271
|
+
* </form>
|
|
272
|
+
*
|
|
273
|
+
* <script>
|
|
274
|
+
* const form = document.getElementById('file-input__uploading');
|
|
275
|
+
*
|
|
276
|
+
* form.addEventListener('submit', event => {
|
|
277
|
+
* event.preventDefault();
|
|
278
|
+
*
|
|
279
|
+
* const formData = new FormData(form);
|
|
280
|
+
* console.log(...formData.values());
|
|
281
|
+
* });
|
|
282
|
+
* <\/script>
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
* @example Working with files
|
|
286
|
+
* Use the `files` property to get an array of selected files. Note the use of an array instead of a `FileList`, which allows you to add, modify, and remove files more easily than a native file input.
|
|
287
|
+
*
|
|
288
|
+
* Try selecting a few files and then clicking each button.
|
|
289
|
+
*
|
|
290
|
+
* ```html
|
|
291
|
+
* <sigvelo-file-input
|
|
292
|
+
* id="file-input__accessing"
|
|
293
|
+
* name="files"
|
|
294
|
+
* label="Select some files"
|
|
295
|
+
* description="Files must be 20MB or less"
|
|
296
|
+
* multiple
|
|
297
|
+
* ></sigvelo-file-input>
|
|
298
|
+
* <br>
|
|
299
|
+
* <sigvelo-button type="submit">Reverse</sigvelo-button>
|
|
300
|
+
* <sigvelo-button type="submit">Clear</sigvelo-button>
|
|
301
|
+
*
|
|
302
|
+
* <script>
|
|
303
|
+
* const fileInput = document.getElementById('file-input__accessing');
|
|
304
|
+
* const reverseButton = fileInput.nextElementSibling.nextElementSibling;
|
|
305
|
+
* const clearButton = reverseButton.nextElementSibling;
|
|
306
|
+
*
|
|
307
|
+
* // Reverse
|
|
308
|
+
* reverseButton.addEventListener('click', event => {
|
|
309
|
+
* fileInput.files = fileInput.files.toReversed();
|
|
310
|
+
* });
|
|
311
|
+
*
|
|
312
|
+
* // Clear
|
|
313
|
+
* clearButton.addEventListener('click', event => {
|
|
314
|
+
* fileInput.files = [];
|
|
315
|
+
* });
|
|
316
|
+
* <\/script>
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* **Warning:** The `files` property must be reassigned, not mutated! Avoid using functions that mutate the array, such as [`reverse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) and [`sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), because they won't trigger an update.
|
|
320
|
+
*
|
|
321
|
+
* @example Accepting multiple files
|
|
322
|
+
* Add the `multiple` attribute to allow the file input to accept more than one file. If the user drops a folder, all files within it will be added to the file input.
|
|
323
|
+
*
|
|
324
|
+
* ```html
|
|
325
|
+
* <sigvelo-file-input
|
|
326
|
+
* name="files"
|
|
327
|
+
* label="Select the files you want to upload"
|
|
328
|
+
* multiple
|
|
329
|
+
* >
|
|
330
|
+
* </sigvelo-file-input>
|
|
331
|
+
* ```
|
|
332
|
+
*
|
|
333
|
+
* @example Accepting file types
|
|
334
|
+
* To limit the file input to certain file types, set the `accept` attribute to a comma-separated string of unique file type specifiers.
|
|
335
|
+
*
|
|
336
|
+
* ```html
|
|
337
|
+
* <sigvelo-file-input
|
|
338
|
+
* name="file"
|
|
339
|
+
* label="Upload a picture of your cat"
|
|
340
|
+
* accept="image/jpeg, image/png, image/gif, image/webp"
|
|
341
|
+
* >
|
|
342
|
+
* </sigvelo-file-input>
|
|
343
|
+
* ```
|
|
344
|
+
*
|
|
345
|
+
* @example Changing the size
|
|
346
|
+
* ```html
|
|
347
|
+
* <sigvelo-file-input size="xs" name="xs" label="Extra small"></sigvelo-file-input><br>
|
|
348
|
+
* <sigvelo-file-input size="sm" name="sm" label="Small"></sigvelo-file-input><br>
|
|
349
|
+
* <sigvelo-file-input size="md" name="md" label="Medium"></sigvelo-file-input><br>
|
|
350
|
+
* <sigvelo-file-input size="lg" name="lg" label="Large"></sigvelo-file-input><br>
|
|
351
|
+
* <sigvelo-file-input size="xl" name="xl" label="Extra large"></sigvelo-file-input>
|
|
352
|
+
* ```
|
|
353
|
+
*
|
|
354
|
+
* @example Custom dropzone content
|
|
355
|
+
* Use the `dropzone` slot to customize what appears inside the dropzone.
|
|
356
|
+
*
|
|
357
|
+
* ```html
|
|
358
|
+
* <sigvelo-file-input name="files" label="Upload a file" multiple>
|
|
359
|
+
* <div slot="dropzone">
|
|
360
|
+
* <sigvelo-icon name="cloud-upload" style="font-size: 2rem;"></sigvelo-icon>
|
|
361
|
+
* <br>
|
|
362
|
+
* Choose some files to send to the cloud
|
|
363
|
+
* </div>
|
|
364
|
+
* </sigvelo-file-input>
|
|
365
|
+
* ```
|
|
366
|
+
*
|
|
367
|
+
* @example Button-only file inputs
|
|
368
|
+
* Button-only file inputs aren't supported, but you can achieve this pattern with a button, a native `<input type="file">`, and a bit of JavaScript. You can use the `sigvelo-vh` utility class to hide the input.
|
|
369
|
+
*
|
|
370
|
+
* ```html
|
|
371
|
+
* <sigvelo-button id="file-input__button-only">Select files</sigvelo-button>
|
|
372
|
+
* <input class="sigvelo-vh" type="file" name="file">
|
|
373
|
+
*
|
|
374
|
+
* <script>
|
|
375
|
+
* const button = document.getElementById('file-input__button-only');
|
|
376
|
+
* const fileInput = button.nextElementSibling;
|
|
377
|
+
*
|
|
378
|
+
* // Open the system file browser when the button is clicked
|
|
379
|
+
* button.addEventListener('click', () => {
|
|
380
|
+
* fileInput.click();
|
|
381
|
+
* });
|
|
382
|
+
*
|
|
383
|
+
* // Listen for files to be selected
|
|
384
|
+
* fileInput.addEventListener('change', () => {
|
|
385
|
+
* // Do something with the files
|
|
386
|
+
* console.log(...fileInput.files);
|
|
387
|
+
*
|
|
388
|
+
* // Reset the input
|
|
389
|
+
* fileInput.value = '';
|
|
390
|
+
* });
|
|
391
|
+
* <\/script>
|
|
392
|
+
* ```
|
|
393
|
+
*
|
|
394
|
+
* @example Validation
|
|
395
|
+
* The `required` attribute can be applied to enable validation using the Constraint Validation API. This will prevent form submission until the user has selected a file.
|
|
396
|
+
*
|
|
397
|
+
* ```html
|
|
398
|
+
* <form action="about:blank" method="get" target="_blank">
|
|
399
|
+
* <sigvelo-file-input name="file" label="Select a file" required></sigvelo-file-input>
|
|
400
|
+
* <br>
|
|
401
|
+
* <sigvelo-button type="submit" color="primary">Submit</sigvelo-button>
|
|
402
|
+
* <sigvelo-button type="reset">Reset</sigvelo-button>
|
|
403
|
+
* </form>
|
|
404
|
+
* ```
|
|
405
|
+
*
|
|
406
|
+
* @example Using custom validation
|
|
407
|
+
* Use the `setCustomValidity()` method to make the file input invalid and show a custom error message on submit. This will override all other validation parameters. To clear the error, remove the attribute or set it to an empty string.
|
|
408
|
+
*
|
|
409
|
+
* ```html
|
|
410
|
+
* <form action="about:blank" method="get" target="_blank" id="file-input__custom-validation">
|
|
411
|
+
* <sigvelo-file-input
|
|
412
|
+
* name="file"
|
|
413
|
+
* label="Select a file"
|
|
414
|
+
* required
|
|
415
|
+
* ></sigvelo-file-input>
|
|
416
|
+
* <br>
|
|
417
|
+
* <sigvelo-button type="submit" color="primary">Submit</sigvelo-button>
|
|
418
|
+
* <sigvelo-button type="reset">Reset</sigvelo-button>
|
|
419
|
+
* </form>
|
|
420
|
+
*
|
|
421
|
+
* <script type="module">
|
|
422
|
+
* import { allDefined } from '/dist/sigvelo.js';
|
|
423
|
+
*
|
|
424
|
+
* await allDefined();
|
|
425
|
+
*
|
|
426
|
+
* const form = document.getElementById('file-input__custom-validation');
|
|
427
|
+
* const fileInput = form.querySelector('sigvelo-file-input');
|
|
428
|
+
*
|
|
429
|
+
* fileInput.setCustomValidity('Not so fast, bubba!');
|
|
430
|
+
* <\/script>
|
|
431
|
+
* ```
|
|
432
|
+
*
|
|
433
|
+
* @example Styling validation
|
|
434
|
+
* You can style valid and invalid file inputs using the `:valid` and `:invalid` pseudo classes.
|
|
435
|
+
*
|
|
436
|
+
* ```html
|
|
437
|
+
* <form action="about:blank" method="get" target="_blank" class="file-input__validation-pseudo">
|
|
438
|
+
* <sigvelo-file-input name="file" label="Select a file" required></sigvelo-file-input>
|
|
439
|
+
* <br>
|
|
440
|
+
* <sigvelo-button type="submit" color="primary">Submit</sigvelo-button>
|
|
441
|
+
* <sigvelo-button type="reset">Reset</sigvelo-button>
|
|
442
|
+
* </form>
|
|
443
|
+
*
|
|
444
|
+
* <style>
|
|
445
|
+
* .file-input__validation-pseudo {
|
|
446
|
+
* sigvelo-file-input:valid {
|
|
447
|
+
* outline: solid 2px var(--sigvelo-color-success-border);
|
|
448
|
+
* outline-offset: .5rem;
|
|
449
|
+
* }
|
|
450
|
+
*
|
|
451
|
+
* sigvelo-file-input:invalid {
|
|
452
|
+
* outline: solid 2px var(--sigvelo-color-danger-border);
|
|
453
|
+
* outline-offset: .5rem;
|
|
454
|
+
* }
|
|
455
|
+
* }
|
|
456
|
+
* </style>
|
|
457
|
+
* ```
|
|
458
|
+
*
|
|
459
|
+
* However, these selectors will match even before the user has had a chance to fill out the form. More often than not, you'll want to use the `user-valid` and `user-invalid` custom states instead. This way, validation styles are only shown _after_ the user interacts with the form control or when the form is submitted.
|
|
460
|
+
*
|
|
461
|
+
* ```html
|
|
462
|
+
* <form action="about:blank" method="get" target="_blank" class="file-input__validation-custom">
|
|
463
|
+
* <sigvelo-file-input name="file" label="Select a file" required></sigvelo-file-input>
|
|
464
|
+
* <br>
|
|
465
|
+
* <sigvelo-button type="submit" color="primary">Submit</sigvelo-button>
|
|
466
|
+
* <sigvelo-button type="reset">Reset</sigvelo-button>
|
|
467
|
+
* </form>
|
|
468
|
+
*
|
|
469
|
+
* <style>
|
|
470
|
+
* .file-input__validation-custom {
|
|
471
|
+
* sigvelo-file-input:state(user-valid) {
|
|
472
|
+
* outline: solid 2px var(--sigvelo-color-success-border);
|
|
473
|
+
* outline-offset: .5rem;
|
|
474
|
+
* }
|
|
475
|
+
*
|
|
476
|
+
* sigvelo-file-input:state(user-invalid) {
|
|
477
|
+
* outline: solid 2px var(--sigvelo-color-danger-border);
|
|
478
|
+
* outline-offset: .5rem;
|
|
479
|
+
* }
|
|
480
|
+
* }
|
|
481
|
+
* </style>
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
var SigveloFileInput = class extends SigveloFormControlElement {
|
|
485
|
+
constructor(..._args) {
|
|
486
|
+
super(..._args);
|
|
487
|
+
this.localize = new Localize(this);
|
|
488
|
+
this.isDragging = false;
|
|
489
|
+
this.isInvalid = false;
|
|
490
|
+
this.hadUserInteraction = false;
|
|
491
|
+
this.wasSubmitted = false;
|
|
492
|
+
this.files = [];
|
|
493
|
+
this.disabled = false;
|
|
494
|
+
this.accept = false;
|
|
495
|
+
this.multiple = false;
|
|
496
|
+
this.size = "md";
|
|
497
|
+
this.required = false;
|
|
498
|
+
}
|
|
499
|
+
static {
|
|
500
|
+
this.formAssociated = true;
|
|
501
|
+
}
|
|
502
|
+
static {
|
|
503
|
+
this.observeSlots = true;
|
|
504
|
+
}
|
|
505
|
+
static {
|
|
506
|
+
this.styles = [
|
|
507
|
+
hostStyles,
|
|
508
|
+
formControlStyles,
|
|
509
|
+
file_input_styles_default
|
|
510
|
+
];
|
|
511
|
+
}
|
|
512
|
+
get focusableAnchor() {
|
|
513
|
+
return this.fileInput;
|
|
514
|
+
}
|
|
515
|
+
connectedCallback() {
|
|
516
|
+
super.connectedCallback();
|
|
517
|
+
this.addEventListener("invalid", this.handleHostInvalid);
|
|
518
|
+
}
|
|
519
|
+
disconnectedCallback() {
|
|
520
|
+
super.disconnectedCallback();
|
|
521
|
+
this.removeEventListener("invalid", this.handleHostInvalid);
|
|
522
|
+
}
|
|
523
|
+
updated(changedProperties) {
|
|
524
|
+
this.updateValidity();
|
|
525
|
+
if (changedProperties.has("files")) {
|
|
526
|
+
this.customStates.set("blank", this.files.length === 0);
|
|
527
|
+
this.fileInput.files = this.getFileList();
|
|
528
|
+
this.fileInput.setAttribute("aria-hidden", "true");
|
|
529
|
+
this.fileInput.removeAttribute("aria-hidden");
|
|
530
|
+
this.updateFormValue();
|
|
531
|
+
}
|
|
532
|
+
if (changedProperties.has("disabled")) this.customStates.set("disabled", this.disabled);
|
|
533
|
+
if (this.hadUserInteraction || this.wasSubmitted) {
|
|
534
|
+
this.customStates.set("user-invalid", this.isInvalid);
|
|
535
|
+
this.customStates.set("user-valid", !this.isInvalid);
|
|
536
|
+
} else {
|
|
537
|
+
this.customStates.set("user-invalid", false);
|
|
538
|
+
this.customStates.set("user-valid", false);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
/** @internal Called when a containing fieldset is disabled. */
|
|
542
|
+
formDisabledCallback(isDisabled) {
|
|
543
|
+
this.disabled = isDisabled;
|
|
544
|
+
}
|
|
545
|
+
/** @internal Called when the form is reset. */
|
|
546
|
+
formResetCallback() {
|
|
547
|
+
this.isInvalid = false;
|
|
548
|
+
this.hadUserInteraction = false;
|
|
549
|
+
this.wasSubmitted = false;
|
|
550
|
+
this.files = [];
|
|
551
|
+
}
|
|
552
|
+
/** Converts the `this.files` array into a `FileList` object so the `<input type="file">` can be updated. */
|
|
553
|
+
getFileList() {
|
|
554
|
+
const dt = new DataTransfer();
|
|
555
|
+
for (const file of this.files) dt.items.add(file);
|
|
556
|
+
return dt.files;
|
|
557
|
+
}
|
|
558
|
+
handleBlur() {
|
|
559
|
+
this.customStates.set("focused", false);
|
|
560
|
+
this.dispatchEvent(new SigveloBlurEvent());
|
|
561
|
+
}
|
|
562
|
+
handleDragEnter(event) {
|
|
563
|
+
event.preventDefault();
|
|
564
|
+
this.isDragging = true;
|
|
565
|
+
}
|
|
566
|
+
handleDragLeave(event) {
|
|
567
|
+
if (event.relatedTarget === this.dropzone) {
|
|
568
|
+
event.stopPropagation();
|
|
569
|
+
event.preventDefault();
|
|
570
|
+
}
|
|
571
|
+
event.preventDefault();
|
|
572
|
+
this.isDragging = false;
|
|
573
|
+
}
|
|
574
|
+
handleDragOver(event) {
|
|
575
|
+
event.preventDefault();
|
|
576
|
+
event.dataTransfer.dropEffect = "copy";
|
|
577
|
+
}
|
|
578
|
+
handleDrop(event) {
|
|
579
|
+
event.preventDefault();
|
|
580
|
+
this.isDragging = false;
|
|
581
|
+
this.hadUserInteraction = true;
|
|
582
|
+
const entryQueue = [];
|
|
583
|
+
const filesToAdd = [];
|
|
584
|
+
const items = event.dataTransfer?.items;
|
|
585
|
+
if (!items) return;
|
|
586
|
+
for (let i = 0; i < items.length; i++) if (items[i].kind === "file") {
|
|
587
|
+
const entry = items[i].webkitGetAsEntry();
|
|
588
|
+
if (entry) entryQueue.push(entry);
|
|
589
|
+
}
|
|
590
|
+
const processQueue = async () => {
|
|
591
|
+
while (entryQueue.length > 0) {
|
|
592
|
+
if (!this.multiple && filesToAdd.length > 0) break;
|
|
593
|
+
const currentEntry = entryQueue.shift();
|
|
594
|
+
if (currentEntry.isFile) await new Promise((resolve) => {
|
|
595
|
+
currentEntry.file((file) => {
|
|
596
|
+
filesToAdd.push(file);
|
|
597
|
+
resolve();
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
else if (currentEntry.isDirectory) {
|
|
601
|
+
const reader = currentEntry.createReader();
|
|
602
|
+
let entries = [];
|
|
603
|
+
do {
|
|
604
|
+
entries = await new Promise((resolve) => {
|
|
605
|
+
reader.readEntries((results) => resolve(results));
|
|
606
|
+
});
|
|
607
|
+
entryQueue.unshift(...entries);
|
|
608
|
+
} while (entries.length > 0);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (this.multiple) this.files = this.files.concat(filesToAdd);
|
|
612
|
+
else if (filesToAdd.length > 0) this.files = [filesToAdd[0]];
|
|
613
|
+
this.dispatchEvent(new SigveloInputEvent());
|
|
614
|
+
this.dispatchEvent(new SigveloChangeEvent());
|
|
615
|
+
};
|
|
616
|
+
processQueue();
|
|
617
|
+
}
|
|
618
|
+
handleFileInput() {
|
|
619
|
+
this.hadUserInteraction = true;
|
|
620
|
+
if (this.fileInput.files) if (this.multiple) this.files = this.files.concat([...this.fileInput.files]);
|
|
621
|
+
else this.files = [this.fileInput.files[0]];
|
|
622
|
+
this.dispatchEvent(new SigveloInputEvent());
|
|
623
|
+
this.dispatchEvent(new SigveloChangeEvent());
|
|
624
|
+
}
|
|
625
|
+
handleFocus() {
|
|
626
|
+
this.customStates.set("focused", true);
|
|
627
|
+
this.dispatchEvent(new SigveloFocusEvent());
|
|
628
|
+
}
|
|
629
|
+
handleHostInvalid() {
|
|
630
|
+
this.wasSubmitted = true;
|
|
631
|
+
}
|
|
632
|
+
handleRemoveClick(_, indexToRemove) {
|
|
633
|
+
this.files = this.files.filter((__, index) => index !== indexToRemove);
|
|
634
|
+
this.dispatchEvent(new SigveloInputEvent());
|
|
635
|
+
this.dispatchEvent(new SigveloChangeEvent());
|
|
636
|
+
}
|
|
637
|
+
/** Determines if a File object is an image type the browser can render. */
|
|
638
|
+
isImage(file) {
|
|
639
|
+
return [
|
|
640
|
+
"image/apng",
|
|
641
|
+
"image/avif",
|
|
642
|
+
"image/gif",
|
|
643
|
+
"image/jpeg",
|
|
644
|
+
"image/png",
|
|
645
|
+
"image/svg+xml",
|
|
646
|
+
"image/webp"
|
|
647
|
+
].includes(file.type);
|
|
648
|
+
}
|
|
649
|
+
/** Returns a system icon name based on the provided mime type. */
|
|
650
|
+
mimeTypeToIconName(mimeType) {
|
|
651
|
+
if ([
|
|
652
|
+
"application/x-freearc",
|
|
653
|
+
"application/x-bzip",
|
|
654
|
+
"application/x-bzip2",
|
|
655
|
+
"application/gzip",
|
|
656
|
+
"application/java-archive",
|
|
657
|
+
"application/vnd.rar",
|
|
658
|
+
"application/x-tar",
|
|
659
|
+
"application/zip",
|
|
660
|
+
"application/x-zip-compressed",
|
|
661
|
+
"application/x-7z-compressed"
|
|
662
|
+
].includes(mimeType)) return "file-zip";
|
|
663
|
+
if (mimeType.startsWith("audio")) return "music";
|
|
664
|
+
if (mimeType.startsWith("image")) return "photo";
|
|
665
|
+
if (mimeType.startsWith("video")) return "video";
|
|
666
|
+
return "file";
|
|
667
|
+
}
|
|
668
|
+
/** Formats a byte value into a human-readable string (e.g. "1.2 MB"). */
|
|
669
|
+
#formatBytes(bytes) {
|
|
670
|
+
const units = [
|
|
671
|
+
"B",
|
|
672
|
+
"KB",
|
|
673
|
+
"MB",
|
|
674
|
+
"GB",
|
|
675
|
+
"TB"
|
|
676
|
+
];
|
|
677
|
+
let i = 0;
|
|
678
|
+
let value = bytes;
|
|
679
|
+
while (value >= 1e3 && i < units.length - 1) {
|
|
680
|
+
value /= 1e3;
|
|
681
|
+
i++;
|
|
682
|
+
}
|
|
683
|
+
return `${i === 0 ? value : value.toFixed(1)} ${units[i]}`;
|
|
684
|
+
}
|
|
685
|
+
/** Updates the form value based on this.files. Call this after adding or removing files to/from this.files. */
|
|
686
|
+
updateFormValue() {
|
|
687
|
+
const formData = new FormData();
|
|
688
|
+
this.files.forEach((file) => formData.append(this.name, file));
|
|
689
|
+
this.internals.setFormValue(formData);
|
|
690
|
+
}
|
|
691
|
+
/** Sets the form control's validity */
|
|
692
|
+
async updateValidity() {
|
|
693
|
+
await this.updateComplete;
|
|
694
|
+
const hasCustomValidity = this.getCustomValidity().length > 0;
|
|
695
|
+
const hasMissingValue = this.required && this.files.length === 0;
|
|
696
|
+
const validationMessage = hasCustomValidity ? this.getCustomValidity() : VALIDATION_MESSAGE;
|
|
697
|
+
const flags = {
|
|
698
|
+
customError: hasCustomValidity,
|
|
699
|
+
valueMissing: hasMissingValue
|
|
700
|
+
};
|
|
701
|
+
this.isInvalid = hasCustomValidity ? true : hasMissingValue;
|
|
702
|
+
this.internals.setValidity(flags, validationMessage, this.focusableAnchor);
|
|
703
|
+
}
|
|
704
|
+
render() {
|
|
705
|
+
const hasLabel = this.label || this.slotsWithContent.has("label");
|
|
706
|
+
const hasDescription = this.description || this.slotsWithContent.has("description");
|
|
707
|
+
return html`
|
|
708
|
+
${hasLabel ? html`
|
|
709
|
+
<label id="label" part="label" for="file-input">
|
|
710
|
+
<slot name="label">${this.label}</slot>
|
|
711
|
+
</label>
|
|
712
|
+
` : nothing}
|
|
713
|
+
${hasDescription ? html`
|
|
714
|
+
<div id="description" part="description">
|
|
715
|
+
<slot name="description">${this.description}</slot>
|
|
716
|
+
</div>
|
|
717
|
+
` : nothing}
|
|
718
|
+
|
|
719
|
+
<label
|
|
720
|
+
id="dropzone"
|
|
721
|
+
part="dropzone"
|
|
722
|
+
class="${classMap({
|
|
723
|
+
xs: this.size === "xs",
|
|
724
|
+
sm: this.size === "sm",
|
|
725
|
+
md: this.size === "md",
|
|
726
|
+
lg: this.size === "lg",
|
|
727
|
+
xl: this.size === "xl",
|
|
728
|
+
disabled: this.disabled,
|
|
729
|
+
dragging: this.isDragging
|
|
730
|
+
})}"
|
|
731
|
+
@focus=${this.handleFocus}
|
|
732
|
+
@blur=${this.handleBlur}
|
|
733
|
+
@dragenter=${this.handleDragEnter}
|
|
734
|
+
@dragleave=${this.handleDragLeave}
|
|
735
|
+
@dragover=${this.handleDragOver}
|
|
736
|
+
@drop=${this.handleDrop}
|
|
737
|
+
>
|
|
738
|
+
<slot name="dropzone">
|
|
739
|
+
<sigvelo-icon library="system" name="upload"></sigvelo-icon>
|
|
740
|
+
<br />
|
|
741
|
+
${this.multiple ? this.localize.term("dragFilesHereOrChooseFromFolder") : this.localize.term("dragFileHereOrChooseFromFolder")}
|
|
742
|
+
</slot>
|
|
743
|
+
|
|
744
|
+
<input
|
|
745
|
+
id="file-input"
|
|
746
|
+
type="file"
|
|
747
|
+
accept=${ifDefined(this.accept)}
|
|
748
|
+
?multiple=${this.multiple}
|
|
749
|
+
?required=${this.required}
|
|
750
|
+
aria-label=${!hasLabel ? this.multiple ? "Choose files" : "Choose file" : nothing}
|
|
751
|
+
aria-describedby=${hasDescription ? "description" : nothing}
|
|
752
|
+
@input=${this.handleFileInput}
|
|
753
|
+
/>
|
|
754
|
+
</label>
|
|
755
|
+
|
|
756
|
+
<div
|
|
757
|
+
part="file-list"
|
|
758
|
+
id="file-list"
|
|
759
|
+
class="${classMap({
|
|
760
|
+
xs: this.size === "xs",
|
|
761
|
+
sm: this.size === "sm",
|
|
762
|
+
md: this.size === "md",
|
|
763
|
+
lg: this.size === "lg",
|
|
764
|
+
xl: this.size === "xl",
|
|
765
|
+
disabled: this.disabled,
|
|
766
|
+
dragging: this.isDragging
|
|
767
|
+
})}"
|
|
768
|
+
>
|
|
769
|
+
${this.files.map((file, index) => {
|
|
770
|
+
const isImage = this.isImage(file);
|
|
771
|
+
const iconName = this.mimeTypeToIconName(file.type);
|
|
772
|
+
return html`
|
|
773
|
+
<div part="file" class="file">
|
|
774
|
+
<span part="file-thumbnail" class="file-thumbnail">
|
|
775
|
+
${isImage ? html`<img
|
|
776
|
+
part="file-image"
|
|
777
|
+
src=${URL.createObjectURL(file)}
|
|
778
|
+
alt=""
|
|
779
|
+
aria-hidden="true"
|
|
780
|
+
/>` : html`
|
|
781
|
+
<sigvelo-icon
|
|
782
|
+
part="file-icon"
|
|
783
|
+
exportparts="svg:file-icon__svg"
|
|
784
|
+
library="system"
|
|
785
|
+
name="${iconName}"
|
|
786
|
+
></sigvelo-icon>
|
|
787
|
+
`}
|
|
788
|
+
</span>
|
|
789
|
+
<div class="file-details">
|
|
790
|
+
<span class="file-name">${file.name}</span>
|
|
791
|
+
<small class="file-size"> ${this.#formatBytes(file.size)} </small>
|
|
792
|
+
</div>
|
|
793
|
+
<div class="file-actions">
|
|
794
|
+
<sigvelo-button
|
|
795
|
+
part="file-remove-button"
|
|
796
|
+
exportparts="button:file-remove-button__button"
|
|
797
|
+
class="file-remove"
|
|
798
|
+
name="x"
|
|
799
|
+
variant="ghost"
|
|
800
|
+
icon-label=${this.localize.term("remove")}
|
|
801
|
+
size=${this.size}
|
|
802
|
+
@click=${(event) => this.handleRemoveClick(event, index)}
|
|
803
|
+
>
|
|
804
|
+
<sigvelo-icon library="system" name="x"></sigvelo-icon>
|
|
805
|
+
</sigvelo-button>
|
|
806
|
+
</div>
|
|
807
|
+
</div>
|
|
808
|
+
`;
|
|
809
|
+
})}
|
|
810
|
+
</div>
|
|
811
|
+
`;
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
__decorate([query("#dropzone")], SigveloFileInput.prototype, "dropzone", void 0);
|
|
815
|
+
__decorate([query("#file-input")], SigveloFileInput.prototype, "fileInput", void 0);
|
|
816
|
+
__decorate([state()], SigveloFileInput.prototype, "isDragging", void 0);
|
|
817
|
+
__decorate([state()], SigveloFileInput.prototype, "isInvalid", void 0);
|
|
818
|
+
__decorate([state()], SigveloFileInput.prototype, "hadUserInteraction", void 0);
|
|
819
|
+
__decorate([state()], SigveloFileInput.prototype, "wasSubmitted", void 0);
|
|
820
|
+
__decorate([state()], SigveloFileInput.prototype, "files", void 0);
|
|
821
|
+
__decorate([property()], SigveloFileInput.prototype, "label", void 0);
|
|
822
|
+
__decorate([property()], SigveloFileInput.prototype, "description", void 0);
|
|
823
|
+
__decorate([property({ reflect: true })], SigveloFileInput.prototype, "name", void 0);
|
|
824
|
+
__decorate([property({
|
|
825
|
+
type: Boolean,
|
|
826
|
+
reflect: true
|
|
827
|
+
})], SigveloFileInput.prototype, "disabled", void 0);
|
|
828
|
+
__decorate([property({ type: Boolean })], SigveloFileInput.prototype, "accept", void 0);
|
|
829
|
+
__decorate([property({ type: Boolean })], SigveloFileInput.prototype, "multiple", void 0);
|
|
830
|
+
__decorate([property({ reflect: true })], SigveloFileInput.prototype, "size", void 0);
|
|
831
|
+
__decorate([property()], SigveloFileInput.prototype, "form", void 0);
|
|
832
|
+
__decorate([property({
|
|
833
|
+
type: Boolean,
|
|
834
|
+
reflect: true
|
|
835
|
+
})], SigveloFileInput.prototype, "required", void 0);
|
|
836
|
+
document.addEventListener("dragover", (event) => event.preventDefault());
|
|
837
|
+
document.addEventListener("dragleave", (event) => event.preventDefault());
|
|
838
|
+
document.addEventListener("drop", (event) => event.preventDefault());
|
|
839
|
+
customElements.define("sigvelo-file-input", SigveloFileInput);
|
|
840
|
+
//#endregion
|
|
841
|
+
export { SigveloFileInput as t };
|