@empathyco/x-components 6.0.0-alpha.184 → 6.0.0-alpha.186
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/CHANGELOG.md +17 -0
- package/docs/API-reference/api/x-components.aioverview.md +22 -8
- package/docs/API-reference/api/x-components.allfilter.md +6 -4
- package/docs/API-reference/api/x-components.animatewidth.md +1 -1
- package/docs/API-reference/api/x-components.autoprogressbar.md +5 -5
- package/docs/API-reference/api/x-components.banner.md +5 -5
- package/docs/API-reference/api/x-components.bannerslist.md +5 -5
- package/docs/API-reference/api/x-components.baseaddtocart.md +6 -4
- package/docs/API-reference/api/x-components.basecolumnpickerdropdown.md +8 -6
- package/docs/API-reference/api/x-components.basecolumnpickerlist.md +7 -5
- package/docs/API-reference/api/x-components.basecurrency.md +4 -4
- package/docs/API-reference/api/x-components.basedropdown.md +12 -12
- package/docs/API-reference/api/x-components.baseeventbutton.md +5 -5
- package/docs/API-reference/api/x-components.baseeventsmodal.md +10 -8
- package/docs/API-reference/api/x-components.baseeventsmodalclose.md +7 -5
- package/docs/API-reference/api/x-components.baseeventsmodalopen.md +7 -5
- package/docs/API-reference/api/x-components.basegrid.md +9 -7
- package/docs/API-reference/api/x-components.baseheadertogglepanel.md +9 -7
- package/docs/API-reference/api/x-components.baseidmodal.md +8 -6
- package/docs/API-reference/api/x-components.baseidmodalclose.md +4 -4
- package/docs/API-reference/api/x-components.baseidmodalopen.md +4 -4
- package/docs/API-reference/api/x-components.baseidtogglepanel.md +8 -6
- package/docs/API-reference/api/x-components.baseidtogglepanelbutton.md +7 -5
- package/docs/API-reference/api/x-components.basekeyboardnavigation.md +6 -6
- package/docs/API-reference/api/x-components.basemodal.md +9 -9
- package/docs/API-reference/api/x-components.basepricefilterlabel.md +6 -4
- package/docs/API-reference/api/x-components.baserating.md +7 -5
- package/docs/API-reference/api/x-components.baseratingfilterlabel.md +7 -5
- package/docs/API-reference/api/x-components.baseresultcurrentprice.md +6 -4
- package/docs/API-reference/api/x-components.baseresultimage.md +9 -9
- package/docs/API-reference/api/x-components.baseresultlink.md +5 -5
- package/docs/API-reference/api/x-components.baseresultpreviousprice.md +5 -3
- package/docs/API-reference/api/x-components.baseresultrating.md +7 -5
- package/docs/API-reference/api/x-components.basescroll.md +7 -7
- package/docs/API-reference/api/x-components.baseslider.md +7 -7
- package/docs/API-reference/api/x-components.basesuggestion.md +8 -6
- package/docs/API-reference/api/x-components.basesuggestions.md +5 -5
- package/docs/API-reference/api/x-components.baseswitch.md +6 -6
- package/docs/API-reference/api/x-components.basetabspanel.md +6 -6
- package/docs/API-reference/api/x-components.baseteleport.md +6 -6
- package/docs/API-reference/api/x-components.basetogglepanel.md +4 -4
- package/docs/API-reference/api/x-components.basevariablecolumngrid.md +7 -5
- package/docs/API-reference/api/x-components.changeheight.md +2 -2
- package/docs/API-reference/api/x-components.clearfilters.md +7 -5
- package/docs/API-reference/api/x-components.clearhistoryqueries.md +3 -1
- package/docs/API-reference/api/x-components.clearsearchinput.md +7 -1
- package/docs/API-reference/api/x-components.closemainmodal.md +3 -1
- package/docs/API-reference/api/x-components.collapseheight.md +5 -5
- package/docs/API-reference/api/x-components.collapsewidth.md +5 -5
- package/docs/API-reference/api/x-components.crossfade.md +4 -4
- package/docs/API-reference/api/x-components.devicedetector.md +9 -5
- package/docs/API-reference/api/x-components.displayclickprovider.md +5 -5
- package/docs/API-reference/api/x-components.displayemitter.md +4 -4
- package/docs/API-reference/api/x-components.editablenumberrangefilter.md +7 -7
- package/docs/API-reference/api/x-components.empathize.md +6 -6
- package/docs/API-reference/api/x-components.excludefilterswithnoresults.md +4 -4
- package/docs/API-reference/api/x-components.experiencecontrols.md +1 -1
- package/docs/API-reference/api/x-components.extraparams.md +3 -3
- package/docs/API-reference/api/x-components.facets.md +5 -5
- package/docs/API-reference/api/x-components.facetsprovider.md +4 -4
- package/docs/API-reference/api/x-components.fade.md +4 -4
- package/docs/API-reference/api/x-components.fadeandslide.md +5 -5
- package/docs/API-reference/api/x-components.fallbackdisclaimer.md +1 -1
- package/docs/API-reference/api/x-components.filterslist.md +5 -5
- package/docs/API-reference/api/x-components.filterssearch.md +6 -6
- package/docs/API-reference/api/x-components.fixedheaderandasideslayout.md +9 -5
- package/docs/API-reference/api/x-components.globalxbus.md +3 -3
- package/docs/API-reference/api/x-components.hierarchicalfilter.md +8 -5
- package/docs/API-reference/api/x-components.highlight_2.md +5 -5
- package/docs/API-reference/api/x-components.historyqueries.md +4 -1
- package/docs/API-reference/api/x-components.historyqueriesswitch.md +3 -1
- package/docs/API-reference/api/x-components.historyquery.md +8 -5
- package/docs/API-reference/api/x-components.identifierresult.md +4 -4
- package/docs/API-reference/api/x-components.identifierresults.md +5 -5
- package/docs/API-reference/api/x-components.itemslist.md +5 -5
- package/docs/API-reference/api/x-components.locationprovider.md +4 -4
- package/docs/API-reference/api/x-components.mainmodal.md +6 -4
- package/docs/API-reference/api/x-components.mainscroll.md +5 -5
- package/docs/API-reference/api/x-components.mainscrollitem.md +6 -6
- package/docs/API-reference/api/x-components.md +1 -0
- package/docs/API-reference/api/x-components.multicolumnmaxwidthlayout.md +9 -5
- package/docs/API-reference/api/x-components.myhistory.md +8 -5
- package/docs/API-reference/api/x-components.nextqueries.md +8 -5
- package/docs/API-reference/api/x-components.nextquerieslist.md +5 -5
- package/docs/API-reference/api/x-components.nextquery.md +7 -5
- package/docs/API-reference/api/x-components.nextquerypreview.md +4 -4
- package/docs/API-reference/api/x-components.noanimation.md +2 -2
- package/docs/API-reference/api/x-components.numberrangefilter.md +7 -5
- package/docs/API-reference/api/x-components.openmainmodal.md +3 -1
- package/docs/API-reference/api/x-components.pageloaderbutton.md +7 -5
- package/docs/API-reference/api/x-components.pageselector.md +5 -5
- package/docs/API-reference/api/x-components.partialquerybutton.md +5 -5
- package/docs/API-reference/api/x-components.partialresultslist.md +5 -5
- package/docs/API-reference/api/x-components.popularsearch.md +6 -4
- package/docs/API-reference/api/x-components.popularsearches.md +4 -1
- package/docs/API-reference/api/x-components.preselectedfilters.md +5 -5
- package/docs/API-reference/api/x-components.promoted.md +4 -4
- package/docs/API-reference/api/x-components.promotedslist.md +5 -5
- package/docs/API-reference/api/x-components.querypreview.md +6 -6
- package/docs/API-reference/api/x-components.querypreviewbutton.md +6 -4
- package/docs/API-reference/api/x-components.querypreviewlist.md +8 -6
- package/docs/API-reference/api/x-components.querysuggestion.md +6 -4
- package/docs/API-reference/api/x-components.querysuggestions.md +4 -1
- package/docs/API-reference/api/x-components.recommendations.md +5 -5
- package/docs/API-reference/api/x-components.redirection.md +6 -6
- package/docs/API-reference/api/x-components.relatedprompt.md +9 -4
- package/docs/API-reference/api/x-components.relatedpromptslist.md +5 -5
- package/docs/API-reference/api/x-components.relatedpromptstaglist.md +11 -7
- package/docs/API-reference/api/x-components.relatedtag.md +6 -6
- package/docs/API-reference/api/x-components.relatedtags.md +7 -5
- package/docs/API-reference/api/x-components.removehistoryquery.md +6 -4
- package/docs/API-reference/api/x-components.renderlessextraparams.md +4 -4
- package/docs/API-reference/api/x-components.renderlessfilter.md +5 -5
- package/docs/API-reference/api/x-components.resultslist.md +6 -6
- package/docs/API-reference/api/x-components.resultvariantselector.md +6 -6
- package/docs/API-reference/api/x-components.resultvariantsprovider.md +5 -5
- package/docs/API-reference/api/x-components.scroll.md +8 -6
- package/docs/API-reference/api/x-components.scrolltotop.md +7 -5
- package/docs/API-reference/api/x-components.searchbutton.md +2 -2
- package/docs/API-reference/api/x-components.searchinput.md +6 -6
- package/docs/API-reference/api/x-components.searchinputplaceholder.md +6 -6
- package/docs/API-reference/api/x-components.selectedfilters.md +5 -5
- package/docs/API-reference/api/x-components.selectedfilterslist.md +7 -5
- package/docs/API-reference/api/x-components.semanticqueries.md +4 -1
- package/docs/API-reference/api/x-components.semanticquery.md +6 -4
- package/docs/API-reference/api/x-components.simplefilter.md +7 -5
- package/docs/API-reference/api/x-components.singlecolumnlayout.md +10 -5
- package/docs/API-reference/api/x-components.slicedfilters.md +6 -6
- package/docs/API-reference/api/x-components.slidingpanel.md +8 -8
- package/docs/API-reference/api/x-components.snippetcallbacks.md +3 -1
- package/docs/API-reference/api/x-components.snippetconfigextraparams.md +8 -6
- package/docs/API-reference/api/x-components.sortdropdown.md +8 -6
- package/docs/API-reference/api/x-components.sortedfilters.md +4 -4
- package/docs/API-reference/api/x-components.sortlist.md +7 -5
- package/docs/API-reference/api/x-components.sortpickerlist.md +7 -5
- package/docs/API-reference/api/x-components.spellcheck.md +1 -1
- package/docs/API-reference/api/x-components.spellcheckbutton.md +2 -2
- package/docs/API-reference/api/x-components.staggeredfadeandslide.md +5 -5
- package/docs/API-reference/api/x-components.tagging.md +4 -4
- package/docs/API-reference/api/x-components.typinghtmlelement.__timeoutid.md +11 -0
- package/docs/API-reference/api/x-components.typinghtmlelement.md +19 -0
- package/docs/API-reference/api/x-components.urlhandler.md +5 -1
- package/js/components/animations/animate-scale/animate-scale.style.scss.js +1 -1
- package/js/components/animations/animate-width.vue.js.map +1 -1
- package/js/components/animations/collapse-height.vue.js.map +1 -1
- package/js/components/animations/collapse-width.vue.js.map +1 -1
- package/js/components/animations/cross-fade.vue.js.map +1 -1
- package/js/components/animations/fade-and-slide.vue.js.map +1 -1
- package/js/components/animations/fade.vue.js.map +1 -1
- package/js/components/animations/staggered-fade-and-slide.vue.js.map +1 -1
- package/js/components/auto-progress-bar.vue.js.map +1 -1
- package/js/components/base-dropdown.vue.js.map +1 -1
- package/js/components/base-grid.vue.js.map +1 -1
- package/js/components/base-keyboard-navigation.vue.js.map +1 -1
- package/js/components/base-rating.vue.js.map +1 -1
- package/js/components/base-rating.vue3.js +1 -1
- package/js/components/base-slider.vue.js +16 -18
- package/js/components/base-slider.vue.js.map +1 -1
- package/js/components/base-switch.vue.js +10 -13
- package/js/components/base-switch.vue.js.map +1 -1
- package/js/components/base-teleport.vue.js.map +1 -1
- package/js/components/base-variable-column-grid.vue.js.map +1 -1
- package/js/components/column-picker/base-column-picker-dropdown.vue.js.map +1 -1
- package/js/components/column-picker/base-column-picker-list.vue.js.map +1 -1
- package/js/components/currency/base-currency.vue.js.map +1 -1
- package/js/components/filters/labels/base-rating-filter-label.vue.js.map +1 -1
- package/js/components/highlight.vue.js.map +1 -1
- package/js/components/icons/ai-star.vue.js +19 -22
- package/js/components/icons/ai-star.vue.js.map +1 -1
- package/js/components/icons/arrow-down.vue.js +16 -19
- package/js/components/icons/arrow-down.vue.js.map +1 -1
- package/js/components/icons/arrow-left.vue.js +16 -19
- package/js/components/icons/arrow-left.vue.js.map +1 -1
- package/js/components/icons/arrow-right.vue.js +16 -19
- package/js/components/icons/arrow-right.vue.js.map +1 -1
- package/js/components/icons/arrow-up.vue.js +16 -19
- package/js/components/icons/arrow-up.vue.js.map +1 -1
- package/js/components/icons/bag.vue.js +16 -19
- package/js/components/icons/bag.vue.js.map +1 -1
- package/js/components/icons/bar-code.vue.js +8 -10
- package/js/components/icons/bar-code.vue.js.map +1 -1
- package/js/components/icons/barcode-tiny.vue.js +8 -10
- package/js/components/icons/barcode-tiny.vue.js.map +1 -1
- package/js/components/icons/cart-filled.vue.js +21 -25
- package/js/components/icons/cart-filled.vue.js.map +1 -1
- package/js/components/icons/cart.vue.js +16 -19
- package/js/components/icons/cart.vue.js.map +1 -1
- package/js/components/icons/check-tiny.vue.js +9 -11
- package/js/components/icons/check-tiny.vue.js.map +1 -1
- package/js/components/icons/check.vue.js +9 -11
- package/js/components/icons/check.vue.js.map +1 -1
- package/js/components/icons/checkbox-selected-filled.vue.js +20 -23
- package/js/components/icons/checkbox-selected-filled.vue.js.map +1 -1
- package/js/components/icons/checkbox-selected.vue.js +19 -22
- package/js/components/icons/checkbox-selected.vue.js.map +1 -1
- package/js/components/icons/checkbox-unselected-filled.vue.js +13 -15
- package/js/components/icons/checkbox-unselected-filled.vue.js.map +1 -1
- package/js/components/icons/checkbox-unselected.vue.js +12 -14
- package/js/components/icons/checkbox-unselected.vue.js.map +1 -1
- package/js/components/icons/chevron-down.vue.js +9 -11
- package/js/components/icons/chevron-down.vue.js.map +1 -1
- package/js/components/icons/chevron-left.vue.js +9 -11
- package/js/components/icons/chevron-left.vue.js.map +1 -1
- package/js/components/icons/chevron-right.vue.js +9 -11
- package/js/components/icons/chevron-right.vue.js.map +1 -1
- package/js/components/icons/chevron-tiny-down.vue.js +9 -11
- package/js/components/icons/chevron-tiny-down.vue.js.map +1 -1
- package/js/components/icons/chevron-tiny-left.vue.js +9 -11
- package/js/components/icons/chevron-tiny-left.vue.js.map +1 -1
- package/js/components/icons/chevron-tiny-right.vue.js +9 -11
- package/js/components/icons/chevron-tiny-right.vue.js.map +1 -1
- package/js/components/icons/chevron-tiny-up.vue.js +9 -11
- package/js/components/icons/chevron-tiny-up.vue.js.map +1 -1
- package/js/components/icons/chevron-up.vue.js +9 -11
- package/js/components/icons/chevron-up.vue.js.map +1 -1
- package/js/components/icons/corner-arrow-left.vue.js +9 -11
- package/js/components/icons/corner-arrow-left.vue.js.map +1 -1
- package/js/components/icons/corner-arrow-right.vue.js +9 -11
- package/js/components/icons/corner-arrow-right.vue.js.map +1 -1
- package/js/components/icons/cross-tiny.vue.js +9 -11
- package/js/components/icons/cross-tiny.vue.js.map +1 -1
- package/js/components/icons/cross.vue.js +9 -11
- package/js/components/icons/cross.vue.js.map +1 -1
- package/js/components/icons/curated-check-filled.vue.js +19 -22
- package/js/components/icons/curated-check-filled.vue.js.map +1 -1
- package/js/components/icons/curated-check-tiny-filled.vue.js +19 -22
- package/js/components/icons/curated-check-tiny-filled.vue.js.map +1 -1
- package/js/components/icons/curated-check-tiny.vue.js +18 -21
- package/js/components/icons/curated-check-tiny.vue.js.map +1 -1
- package/js/components/icons/curated-check.vue.js +18 -21
- package/js/components/icons/curated-check.vue.js.map +1 -1
- package/js/components/icons/diagonal-arrow-left-down.vue.js +9 -11
- package/js/components/icons/diagonal-arrow-left-down.vue.js.map +1 -1
- package/js/components/icons/diagonal-arrow-left-top.vue.js +9 -11
- package/js/components/icons/diagonal-arrow-left-top.vue.js.map +1 -1
- package/js/components/icons/diagonal-arrow-right-down.vue.js +9 -11
- package/js/components/icons/diagonal-arrow-right-down.vue.js.map +1 -1
- package/js/components/icons/diagonal-arrow-right-top.vue.js +9 -11
- package/js/components/icons/diagonal-arrow-right-top.vue.js.map +1 -1
- package/js/components/icons/filters.vue.js +8 -10
- package/js/components/icons/filters.vue.js.map +1 -1
- package/js/components/icons/grid-1-col.vue.js +8 -10
- package/js/components/icons/grid-1-col.vue.js.map +1 -1
- package/js/components/icons/grid-2-col.vue.js +8 -10
- package/js/components/icons/grid-2-col.vue.js.map +1 -1
- package/js/components/icons/grid-2-rows.vue.js +19 -22
- package/js/components/icons/grid-2-rows.vue.js.map +1 -1
- package/js/components/icons/grid-4-col.vue.js +8 -10
- package/js/components/icons/grid-4-col.vue.js.map +1 -1
- package/js/components/icons/heart-filled.vue.js +10 -12
- package/js/components/icons/heart-filled.vue.js.map +1 -1
- package/js/components/icons/heart.vue.js +9 -11
- package/js/components/icons/heart.vue.js.map +1 -1
- package/js/components/icons/hide.vue.js +9 -11
- package/js/components/icons/hide.vue.js.map +1 -1
- package/js/components/icons/history-tiny.vue.js +16 -19
- package/js/components/icons/history-tiny.vue.js.map +1 -1
- package/js/components/icons/history.vue.js +16 -19
- package/js/components/icons/history.vue.js.map +1 -1
- package/js/components/icons/light-bulb-off.vue.js +14 -17
- package/js/components/icons/light-bulb-off.vue.js.map +1 -1
- package/js/components/icons/light-bulb-on.vue.js +20 -24
- package/js/components/icons/light-bulb-on.vue.js.map +1 -1
- package/js/components/icons/menu.vue.js +9 -11
- package/js/components/icons/menu.vue.js.map +1 -1
- package/js/components/icons/minus-tiny.vue.js +9 -11
- package/js/components/icons/minus-tiny.vue.js.map +1 -1
- package/js/components/icons/minus.vue.js +9 -11
- package/js/components/icons/minus.vue.js.map +1 -1
- package/js/components/icons/plus-tiny.vue.js +9 -11
- package/js/components/icons/plus-tiny.vue.js.map +1 -1
- package/js/components/icons/plus.vue.js +9 -11
- package/js/components/icons/plus.vue.js.map +1 -1
- package/js/components/icons/radiobutton-selected.vue.js +3 -5
- package/js/components/icons/radiobutton-selected.vue.js.map +1 -1
- package/js/components/icons/radiobutton-unselected.vue.js +20 -23
- package/js/components/icons/radiobutton-unselected.vue.js.map +1 -1
- package/js/components/icons/search-tiny.vue.js +9 -11
- package/js/components/icons/search-tiny.vue.js.map +1 -1
- package/js/components/icons/search.vue.js +9 -11
- package/js/components/icons/search.vue.js.map +1 -1
- package/js/components/icons/settings.vue.js +3 -5
- package/js/components/icons/settings.vue.js.map +1 -1
- package/js/components/icons/show.vue.js +18 -21
- package/js/components/icons/show.vue.js.map +1 -1
- package/js/components/icons/sort-az.vue.js +31 -36
- package/js/components/icons/sort-az.vue.js.map +1 -1
- package/js/components/icons/sort-price-down.vue.js +3 -5
- package/js/components/icons/sort-price-down.vue.js.map +1 -1
- package/js/components/icons/sort-price-up.vue.js +3 -5
- package/js/components/icons/sort-price-up.vue.js.map +1 -1
- package/js/components/icons/sort-relevancy.vue.js +23 -27
- package/js/components/icons/sort-relevancy.vue.js.map +1 -1
- package/js/components/icons/sort-za.vue.js +31 -36
- package/js/components/icons/sort-za.vue.js.map +1 -1
- package/js/components/icons/spinner.vue.js +3 -5
- package/js/components/icons/spinner.vue.js.map +1 -1
- package/js/components/icons/star-filled.vue.js +23 -26
- package/js/components/icons/star-filled.vue.js.map +1 -1
- package/js/components/icons/star.vue.js +11 -13
- package/js/components/icons/star.vue.js.map +1 -1
- package/js/components/icons/tag-filled.vue.js +17 -20
- package/js/components/icons/tag-filled.vue.js.map +1 -1
- package/js/components/icons/tag.vue.js +16 -19
- package/js/components/icons/tag.vue.js.map +1 -1
- package/js/components/icons/trash-open.vue.js +3 -5
- package/js/components/icons/trash-open.vue.js.map +1 -1
- package/js/components/icons/trash.vue.js +3 -5
- package/js/components/icons/trash.vue.js.map +1 -1
- package/js/components/icons/trending-tiny.vue.js +16 -19
- package/js/components/icons/trending-tiny.vue.js.map +1 -1
- package/js/components/icons/trending.vue.js +16 -19
- package/js/components/icons/trending.vue.js.map +1 -1
- package/js/components/icons/user-filled.vue.js +13 -16
- package/js/components/icons/user-filled.vue.js.map +1 -1
- package/js/components/icons/user.vue.js +9 -11
- package/js/components/icons/user.vue.js.map +1 -1
- package/js/components/items-list.vue.js.map +1 -1
- package/js/components/layouts/fixed-header-and-asides-layout.vue.js.map +1 -1
- package/js/components/layouts/multi-column-max-width-layout.vue.js.map +1 -1
- package/js/components/layouts/single-column-layout.vue.js.map +1 -1
- package/js/components/modals/base-events-modal-close.vue.js.map +1 -1
- package/js/components/modals/base-events-modal-open.vue.js.map +1 -1
- package/js/components/modals/base-events-modal.vue.js.map +1 -1
- package/js/components/modals/base-id-modal.vue.js.map +1 -1
- package/js/components/modals/base-modal.vue.js.map +1 -1
- package/js/components/modals/close-main-modal.vue.js.map +1 -1
- package/js/components/modals/main-modal.vue.js.map +1 -1
- package/js/components/modals/open-main-modal.vue.js.map +1 -1
- package/js/components/page-loader-button.vue.js +5 -1
- package/js/components/page-loader-button.vue.js.map +1 -1
- package/js/components/page-selector.vue.js +10 -2
- package/js/components/page-selector.vue.js.map +1 -1
- package/js/components/panels/base-header-toggle-panel.vue.js.map +1 -1
- package/js/components/panels/base-id-toggle-panel-button.vue.js.map +1 -1
- package/js/components/panels/base-id-toggle-panel.vue.js.map +1 -1
- package/js/components/panels/base-tabs-panel.vue.js.map +1 -1
- package/js/components/panels/base-toggle-panel.vue.js.map +1 -1
- package/js/components/result/base-result-add-to-cart.vue.js.map +1 -1
- package/js/components/result/base-result-current-price.vue.js.map +1 -1
- package/js/components/result/base-result-fallback-image.vue.js +15 -18
- package/js/components/result/base-result-fallback-image.vue.js.map +1 -1
- package/js/components/result/base-result-image.vue.js.map +1 -1
- package/js/components/result/base-result-link.vue.js.map +1 -1
- package/js/components/result/base-result-placeholder-image.vue.js +14 -17
- package/js/components/result/base-result-placeholder-image.vue.js.map +1 -1
- package/js/components/result/base-result-previous-price.vue.js.map +1 -1
- package/js/components/result/base-result-rating.vue.js.map +1 -1
- package/js/components/result/result-variant-selector.vue.js.map +1 -1
- package/js/components/sliding-panel.vue.js +10 -2
- package/js/components/sliding-panel.vue.js.map +1 -1
- package/js/components/sliding-panel.vue3.js +1 -1
- package/js/components/suggestions/base-suggestion.vue.js.map +1 -1
- package/js/components/suggestions/base-suggestions.vue.js.map +1 -1
- package/js/composables/use-on-display.js +1 -1
- package/js/composables/use-on-display.js.map +1 -1
- package/js/directives/infinite-scroll.js +1 -1
- package/js/directives/infinite-scroll.js.map +1 -1
- package/js/directives/typing.js.map +1 -1
- package/js/x-modules/ai/components/ai-overview.vue.js +25 -26
- package/js/x-modules/ai/components/ai-overview.vue.js.map +1 -1
- package/js/x-modules/device/components/device-detector.vue.js.map +1 -1
- package/js/x-modules/empathize/components/empathize.vue.js.map +1 -1
- package/js/x-modules/facets/components/clear-filters.vue.js.map +1 -1
- package/js/x-modules/facets/components/facets/facets.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/all-filter.vue.js +5 -1
- package/js/x-modules/facets/components/filters/all-filter.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/editable-number-range-filter.vue.js +10 -2
- package/js/x-modules/facets/components/filters/editable-number-range-filter.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/hierarchical-filter.vue.js +3 -3
- package/js/x-modules/facets/components/filters/hierarchical-filter.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/number-range-filter.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/simple-filter.vue.js.map +1 -1
- package/js/x-modules/facets/components/lists/filters-list.vue.js.map +1 -1
- package/js/x-modules/facets/components/lists/filters-search.vue.js.map +1 -1
- package/js/x-modules/facets/components/lists/filters-search.vue3.js +1 -1
- package/js/x-modules/facets/components/lists/selected-filters-list.vue.js.map +1 -1
- package/js/x-modules/facets/components/lists/sliced-filters.vue.js +20 -4
- package/js/x-modules/facets/components/lists/sliced-filters.vue.js.map +1 -1
- package/js/x-modules/history-queries/components/clear-history-queries.vue.js +5 -1
- package/js/x-modules/history-queries/components/clear-history-queries.vue.js.map +1 -1
- package/js/x-modules/history-queries/components/history-queries.vue.js.map +1 -1
- package/js/x-modules/history-queries/components/history-query.vue.js +5 -1
- package/js/x-modules/history-queries/components/history-query.vue.js.map +1 -1
- package/js/x-modules/history-queries/components/my-history.vue.js +3 -3
- package/js/x-modules/history-queries/components/my-history.vue.js.map +1 -1
- package/js/x-modules/history-queries/components/remove-history-query.vue.js.map +1 -1
- package/js/x-modules/identifier-results/components/identifier-result.vue.js.map +1 -1
- package/js/x-modules/identifier-results/components/identifier-results.vue.js.map +1 -1
- package/js/x-modules/next-queries/components/next-queries.vue.js.map +1 -1
- package/js/x-modules/next-queries/components/next-query-preview.vue.js.map +1 -1
- package/js/x-modules/next-queries/components/next-query.vue.js.map +1 -1
- package/js/x-modules/popular-searches/components/popular-search.vue.js.map +1 -1
- package/js/x-modules/popular-searches/components/popular-searches.vue.js.map +1 -1
- package/js/x-modules/queries-preview/components/query-preview-button.vue.js.map +1 -1
- package/js/x-modules/queries-preview/components/query-preview-list.vue.js.map +1 -1
- package/js/x-modules/queries-preview/components/query-preview.vue.js.map +1 -1
- package/js/x-modules/query-suggestions/components/query-suggestion.vue.js.map +1 -1
- package/js/x-modules/query-suggestions/components/query-suggestions.vue.js.map +1 -1
- package/js/x-modules/recommendations/components/recommendations.vue.js.map +1 -1
- package/js/x-modules/related-prompts/components/related-prompt.vue.js.map +1 -1
- package/js/x-modules/related-prompts/components/related-prompts-tag-list.vue.js.map +1 -1
- package/js/x-modules/related-tags/components/related-tag.vue.js.map +1 -1
- package/js/x-modules/related-tags/components/related-tags.vue.js +3 -3
- package/js/x-modules/related-tags/components/related-tags.vue.js.map +1 -1
- package/js/x-modules/scroll/components/main-scroll-item.vue.js.map +1 -1
- package/js/x-modules/scroll/components/scroll-to-top.vue.js.map +1 -1
- package/js/x-modules/scroll/components/scroll.vue.js.map +1 -1
- package/js/x-modules/search/components/banner.vue.js.map +1 -1
- package/js/x-modules/search/components/fallback-disclaimer.vue.js.map +1 -1
- package/js/x-modules/search/components/partial-query-button.vue.js.map +1 -1
- package/js/x-modules/search/components/partial-results-list.vue.js.map +1 -1
- package/js/x-modules/search/components/promoted.vue.js.map +1 -1
- package/js/x-modules/search/components/redirection.vue.js.map +1 -1
- package/js/x-modules/search/components/sort-dropdown.vue.js.map +1 -1
- package/js/x-modules/search/components/sort-list.vue.js.map +1 -1
- package/js/x-modules/search/components/sort-picker-list.vue.js.map +1 -1
- package/js/x-modules/search/components/spellcheck-button.vue.js.map +1 -1
- package/js/x-modules/search/components/spellcheck.vue.js.map +1 -1
- package/js/x-modules/search-box/components/clear-search-input.vue.js +5 -1
- package/js/x-modules/search-box/components/clear-search-input.vue.js.map +1 -1
- package/js/x-modules/search-box/components/search-button.vue.js +7 -8
- package/js/x-modules/search-box/components/search-button.vue.js.map +1 -1
- package/js/x-modules/search-box/components/search-input-placeholder.vue.js.map +1 -1
- package/js/x-modules/search-box/components/search-input.vue.js.map +1 -1
- package/js/x-modules/semantic-queries/components/semantic-queries.vue.js +3 -3
- package/js/x-modules/semantic-queries/components/semantic-queries.vue.js.map +1 -1
- package/js/x-modules/semantic-queries/components/semantic-query.vue.js.map +1 -1
- package/package.json +11 -11
- package/report/x-components.api.json +6216 -1603
- package/report/x-components.api.md +819 -647
- package/types/components/animations/animate-width.vue.d.ts +1 -1
- package/types/components/animations/change-height.vue.d.ts +2 -2
- package/types/components/animations/collapse-height.vue.d.ts +5 -5
- package/types/components/animations/collapse-width.vue.d.ts +5 -5
- package/types/components/animations/cross-fade.vue.d.ts +4 -4
- package/types/components/animations/fade-and-slide.vue.d.ts +5 -5
- package/types/components/animations/fade.vue.d.ts +4 -4
- package/types/components/animations/no-animation.vue.d.ts +2 -2
- package/types/components/animations/staggered-fade-and-slide.vue.d.ts +5 -5
- package/types/components/animations/staggered-fade-and-slide.vue.d.ts.map +1 -1
- package/types/components/auto-progress-bar.vue.d.ts +5 -5
- package/types/components/base-dropdown.vue.d.ts +12 -12
- package/types/components/base-event-button.vue.d.ts +5 -5
- package/types/components/base-grid.vue.d.ts +9 -7
- package/types/components/base-grid.vue.d.ts.map +1 -1
- package/types/components/base-keyboard-navigation.vue.d.ts +6 -6
- package/types/components/base-rating.vue.d.ts +7 -5
- package/types/components/base-rating.vue.d.ts.map +1 -1
- package/types/components/base-slider.vue.d.ts +7 -7
- package/types/components/base-switch.vue.d.ts +6 -6
- package/types/components/base-teleport.vue.d.ts +6 -6
- package/types/components/base-variable-column-grid.vue.d.ts +7 -5
- package/types/components/base-variable-column-grid.vue.d.ts.map +1 -1
- package/types/components/column-picker/base-column-picker-dropdown.vue.d.ts +8 -6
- package/types/components/column-picker/base-column-picker-dropdown.vue.d.ts.map +1 -1
- package/types/components/column-picker/base-column-picker-list.vue.d.ts +7 -5
- package/types/components/column-picker/base-column-picker-list.vue.d.ts.map +1 -1
- package/types/components/currency/base-currency.vue.d.ts +4 -4
- package/types/components/display-click-provider.vue.d.ts +5 -5
- package/types/components/display-emitter.vue.d.ts +4 -4
- package/types/components/filters/labels/base-price-filter-label.vue.d.ts +6 -4
- package/types/components/filters/labels/base-price-filter-label.vue.d.ts.map +1 -1
- package/types/components/filters/labels/base-rating-filter-label.vue.d.ts +7 -5
- package/types/components/filters/labels/base-rating-filter-label.vue.d.ts.map +1 -1
- package/types/components/global-x-bus.vue.d.ts +3 -3
- package/types/components/highlight.vue.d.ts +5 -5
- package/types/components/items-list.vue.d.ts +5 -5
- package/types/components/layouts/fixed-header-and-asides-layout.vue.d.ts +9 -5
- package/types/components/layouts/fixed-header-and-asides-layout.vue.d.ts.map +1 -1
- package/types/components/layouts/multi-column-max-width-layout.vue.d.ts +9 -5
- package/types/components/layouts/multi-column-max-width-layout.vue.d.ts.map +1 -1
- package/types/components/layouts/single-column-layout.vue.d.ts +10 -5
- package/types/components/layouts/single-column-layout.vue.d.ts.map +1 -1
- package/types/components/location-provider.vue.d.ts +4 -4
- package/types/components/modals/base-events-modal-close.vue.d.ts +7 -5
- package/types/components/modals/base-events-modal-close.vue.d.ts.map +1 -1
- package/types/components/modals/base-events-modal-open.vue.d.ts +7 -5
- package/types/components/modals/base-events-modal-open.vue.d.ts.map +1 -1
- package/types/components/modals/base-events-modal.vue.d.ts +10 -8
- package/types/components/modals/base-events-modal.vue.d.ts.map +1 -1
- package/types/components/modals/base-id-modal-close.vue.d.ts +4 -4
- package/types/components/modals/base-id-modal-open.vue.d.ts +4 -4
- package/types/components/modals/base-id-modal.vue.d.ts +8 -6
- package/types/components/modals/base-id-modal.vue.d.ts.map +1 -1
- package/types/components/modals/base-modal.vue.d.ts +9 -9
- package/types/components/modals/close-main-modal.vue.d.ts +3 -1
- package/types/components/modals/close-main-modal.vue.d.ts.map +1 -1
- package/types/components/modals/main-modal.vue.d.ts +6 -4
- package/types/components/modals/main-modal.vue.d.ts.map +1 -1
- package/types/components/modals/open-main-modal.vue.d.ts +3 -1
- package/types/components/modals/open-main-modal.vue.d.ts.map +1 -1
- package/types/components/page-loader-button.vue.d.ts +7 -5
- package/types/components/page-loader-button.vue.d.ts.map +1 -1
- package/types/components/page-selector.vue.d.ts +5 -5
- package/types/components/panels/base-header-toggle-panel.vue.d.ts +9 -7
- package/types/components/panels/base-header-toggle-panel.vue.d.ts.map +1 -1
- package/types/components/panels/base-id-toggle-panel-button.vue.d.ts +7 -5
- package/types/components/panels/base-id-toggle-panel-button.vue.d.ts.map +1 -1
- package/types/components/panels/base-id-toggle-panel.vue.d.ts +8 -6
- package/types/components/panels/base-id-toggle-panel.vue.d.ts.map +1 -1
- package/types/components/panels/base-tabs-panel.vue.d.ts +6 -6
- package/types/components/panels/base-toggle-panel.vue.d.ts +4 -4
- package/types/components/result/base-result-add-to-cart.vue.d.ts +6 -4
- package/types/components/result/base-result-add-to-cart.vue.d.ts.map +1 -1
- package/types/components/result/base-result-current-price.vue.d.ts +6 -4
- package/types/components/result/base-result-current-price.vue.d.ts.map +1 -1
- package/types/components/result/base-result-image.vue.d.ts +9 -9
- package/types/components/result/base-result-link.vue.d.ts +5 -5
- package/types/components/result/base-result-previous-price.vue.d.ts +5 -3
- package/types/components/result/base-result-previous-price.vue.d.ts.map +1 -1
- package/types/components/result/base-result-rating.vue.d.ts +7 -5
- package/types/components/result/base-result-rating.vue.d.ts.map +1 -1
- package/types/components/result/result-variant-selector.vue.d.ts +6 -6
- package/types/components/result/result-variants-provider.vue.d.ts +5 -5
- package/types/components/scroll/base-scroll.vue.d.ts +7 -7
- package/types/components/sliding-panel.vue.d.ts +8 -8
- package/types/components/snippet-callbacks.vue.d.ts +3 -1
- package/types/components/snippet-callbacks.vue.d.ts.map +1 -1
- package/types/components/suggestions/base-suggestion.vue.d.ts +8 -6
- package/types/components/suggestions/base-suggestion.vue.d.ts.map +1 -1
- package/types/components/suggestions/base-suggestions.vue.d.ts +5 -5
- package/types/directives/infinite-scroll.d.ts.map +1 -1
- package/types/directives/typing.d.ts +1 -2
- package/types/directives/typing.d.ts.map +1 -1
- package/types/x-modules/ai/components/ai-overview.vue.d.ts +22 -8
- package/types/x-modules/ai/components/ai-overview.vue.d.ts.map +1 -1
- package/types/x-modules/device/components/device-detector.vue.d.ts +9 -5
- package/types/x-modules/device/components/device-detector.vue.d.ts.map +1 -1
- package/types/x-modules/empathize/components/empathize.vue.d.ts +6 -6
- package/types/x-modules/experience-controls/components/experience-controls.vue.d.ts +1 -1
- package/types/x-modules/extra-params/components/extra-params.vue.d.ts +3 -3
- package/types/x-modules/extra-params/components/renderless-extra-param.vue.d.ts +4 -4
- package/types/x-modules/extra-params/components/snippet-config-extra-params.vue.d.ts +8 -6
- package/types/x-modules/extra-params/components/snippet-config-extra-params.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/clear-filters.vue.d.ts +7 -5
- package/types/x-modules/facets/components/clear-filters.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/facets/facets-provider.vue.d.ts +4 -4
- package/types/x-modules/facets/components/facets/facets.vue.d.ts +5 -5
- package/types/x-modules/facets/components/filters/all-filter.vue.d.ts +6 -4
- package/types/x-modules/facets/components/filters/all-filter.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/filters/editable-number-range-filter.vue.d.ts +7 -7
- package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts +8 -5
- package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/filters/number-range-filter.vue.d.ts +7 -5
- package/types/x-modules/facets/components/filters/number-range-filter.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/filters/renderless-filter.vue.d.ts +5 -5
- package/types/x-modules/facets/components/filters/simple-filter.vue.d.ts +7 -5
- package/types/x-modules/facets/components/filters/simple-filter.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/lists/exclude-filters-with-no-results.vue.d.ts +4 -4
- package/types/x-modules/facets/components/lists/filters-list.vue.d.ts +5 -5
- package/types/x-modules/facets/components/lists/filters-search.vue.d.ts +6 -6
- package/types/x-modules/facets/components/lists/selected-filters-list.vue.d.ts +7 -5
- package/types/x-modules/facets/components/lists/selected-filters-list.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/lists/selected-filters.vue.d.ts +5 -5
- package/types/x-modules/facets/components/lists/sliced-filters.vue.d.ts +6 -6
- package/types/x-modules/facets/components/lists/sorted-filters.vue.d.ts +4 -4
- package/types/x-modules/facets/components/preselected-filters.vue.d.ts +5 -5
- package/types/x-modules/history-queries/components/clear-history-queries.vue.d.ts +3 -1
- package/types/x-modules/history-queries/components/clear-history-queries.vue.d.ts.map +1 -1
- package/types/x-modules/history-queries/components/history-queries-switch.vue.d.ts +3 -1
- package/types/x-modules/history-queries/components/history-queries-switch.vue.d.ts.map +1 -1
- package/types/x-modules/history-queries/components/history-queries.vue.d.ts +4 -1
- package/types/x-modules/history-queries/components/history-queries.vue.d.ts.map +1 -1
- package/types/x-modules/history-queries/components/history-query.vue.d.ts +8 -5
- package/types/x-modules/history-queries/components/history-query.vue.d.ts.map +1 -1
- package/types/x-modules/history-queries/components/my-history.vue.d.ts +8 -5
- package/types/x-modules/history-queries/components/my-history.vue.d.ts.map +1 -1
- package/types/x-modules/history-queries/components/remove-history-query.vue.d.ts +6 -4
- package/types/x-modules/history-queries/components/remove-history-query.vue.d.ts.map +1 -1
- package/types/x-modules/identifier-results/components/identifier-result.vue.d.ts +4 -4
- package/types/x-modules/identifier-results/components/identifier-results.vue.d.ts +5 -5
- package/types/x-modules/next-queries/components/next-queries-list.vue.d.ts +5 -5
- package/types/x-modules/next-queries/components/next-queries.vue.d.ts +8 -5
- package/types/x-modules/next-queries/components/next-queries.vue.d.ts.map +1 -1
- package/types/x-modules/next-queries/components/next-query-preview.vue.d.ts +4 -4
- package/types/x-modules/next-queries/components/next-query.vue.d.ts +7 -5
- package/types/x-modules/next-queries/components/next-query.vue.d.ts.map +1 -1
- package/types/x-modules/popular-searches/components/popular-search.vue.d.ts +6 -4
- package/types/x-modules/popular-searches/components/popular-search.vue.d.ts.map +1 -1
- package/types/x-modules/popular-searches/components/popular-searches.vue.d.ts +4 -1
- package/types/x-modules/popular-searches/components/popular-searches.vue.d.ts.map +1 -1
- package/types/x-modules/queries-preview/components/query-preview-button.vue.d.ts +6 -4
- package/types/x-modules/queries-preview/components/query-preview-button.vue.d.ts.map +1 -1
- package/types/x-modules/queries-preview/components/query-preview-list.vue.d.ts +8 -6
- package/types/x-modules/queries-preview/components/query-preview-list.vue.d.ts.map +1 -1
- package/types/x-modules/queries-preview/components/query-preview.vue.d.ts +6 -6
- package/types/x-modules/query-suggestions/components/query-suggestion.vue.d.ts +6 -4
- package/types/x-modules/query-suggestions/components/query-suggestion.vue.d.ts.map +1 -1
- package/types/x-modules/query-suggestions/components/query-suggestions.vue.d.ts +4 -1
- package/types/x-modules/query-suggestions/components/query-suggestions.vue.d.ts.map +1 -1
- package/types/x-modules/recommendations/components/recommendations.vue.d.ts +5 -5
- package/types/x-modules/related-prompts/components/related-prompt.vue.d.ts +9 -4
- package/types/x-modules/related-prompts/components/related-prompt.vue.d.ts.map +1 -1
- package/types/x-modules/related-prompts/components/related-prompts-list.vue.d.ts +5 -5
- package/types/x-modules/related-prompts/components/related-prompts-tag-list.vue.d.ts +11 -7
- package/types/x-modules/related-prompts/components/related-prompts-tag-list.vue.d.ts.map +1 -1
- package/types/x-modules/related-tags/components/related-tag.vue.d.ts +6 -6
- package/types/x-modules/related-tags/components/related-tags.vue.d.ts +7 -5
- package/types/x-modules/related-tags/components/related-tags.vue.d.ts.map +1 -1
- package/types/x-modules/scroll/components/main-scroll-item.vue.d.ts +6 -6
- package/types/x-modules/scroll/components/main-scroll.vue.d.ts +5 -5
- package/types/x-modules/scroll/components/scroll-to-top.vue.d.ts +7 -5
- package/types/x-modules/scroll/components/scroll-to-top.vue.d.ts.map +1 -1
- package/types/x-modules/scroll/components/scroll.vue.d.ts +8 -6
- package/types/x-modules/scroll/components/scroll.vue.d.ts.map +1 -1
- package/types/x-modules/search/components/banner.vue.d.ts +5 -5
- package/types/x-modules/search/components/banners-list.vue.d.ts +5 -5
- package/types/x-modules/search/components/fallback-disclaimer.vue.d.ts +1 -1
- package/types/x-modules/search/components/partial-query-button.vue.d.ts +5 -5
- package/types/x-modules/search/components/partial-results-list.vue.d.ts +5 -5
- package/types/x-modules/search/components/promoted.vue.d.ts +4 -4
- package/types/x-modules/search/components/promoteds-list.vue.d.ts +5 -5
- package/types/x-modules/search/components/redirection.vue.d.ts +6 -6
- package/types/x-modules/search/components/results-list.vue.d.ts +6 -6
- package/types/x-modules/search/components/sort-dropdown.vue.d.ts +8 -6
- package/types/x-modules/search/components/sort-dropdown.vue.d.ts.map +1 -1
- package/types/x-modules/search/components/sort-list.vue.d.ts +7 -5
- package/types/x-modules/search/components/sort-list.vue.d.ts.map +1 -1
- package/types/x-modules/search/components/sort-picker-list.vue.d.ts +7 -5
- package/types/x-modules/search/components/sort-picker-list.vue.d.ts.map +1 -1
- package/types/x-modules/search/components/spellcheck-button.vue.d.ts +2 -2
- package/types/x-modules/search/components/spellcheck.vue.d.ts +1 -1
- package/types/x-modules/search-box/components/clear-search-input.vue.d.ts +7 -1
- package/types/x-modules/search-box/components/clear-search-input.vue.d.ts.map +1 -1
- package/types/x-modules/search-box/components/search-button.vue.d.ts +2 -2
- package/types/x-modules/search-box/components/search-input-placeholder.vue.d.ts +6 -6
- package/types/x-modules/search-box/components/search-input.vue.d.ts +6 -6
- package/types/x-modules/semantic-queries/components/semantic-queries.vue.d.ts +4 -1
- package/types/x-modules/semantic-queries/components/semantic-queries.vue.d.ts.map +1 -1
- package/types/x-modules/semantic-queries/components/semantic-query.vue.d.ts +6 -4
- package/types/x-modules/semantic-queries/components/semantic-query.vue.d.ts.map +1 -1
- package/types/x-modules/tagging/components/tagging.vue.d.ts +4 -4
- package/types/x-modules/url/components/url-handler.vue.d.ts +5 -1
- package/types/x-modules/url/components/url-handler.vue.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staggered-fade-and-slide.vue.js","sources":["../../../../src/components/animations/staggered-fade-and-slide.vue"],"sourcesContent":["<template>\n <TransitionGroup\n :appear=\"appear\"\n :name=\"name\"\n :tag=\"tag\"\n @enter=\"onEnter\"\n @after-enter=\"onAfterEnter\"\n >\n <slot />\n </TransitionGroup>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onUpdated } from 'vue'\nimport { useDisableAnimation } from './use-disable-animation'\n\n/**\n * Renders a transition group wrapping the elements passed in the default slot and animating\n * them with a staggered fade and slide animation.\n *\n * @public\n */\nexport default defineComponent({\n name: 'StaggeredFadeAndSlide',\n props: {\n /** Indicates if the transition must be applied on the initial render of the node. */\n appear: {\n type: Boolean,\n default: true,\n },\n /** The tag of the node to render to the DOM. */\n tag: {\n type: String,\n default: 'div',\n },\n /** The time in ms to stagger each item. */\n stagger: {\n type: Number,\n default: 25,\n },\n },\n setup(props) {\n /** The duration of the transition in ms. */\n const transitionDuration = 250\n /** Indicates if there are new elements to animate. */\n let isNewSet = true\n /** The new elements to animate. */\n let elementsToAnimate: Element[] = []\n /** The name of the animation. */\n const { name } = useDisableAnimation('x-staggered-fade-and-slide')\n\n /**\n * When the component is updated, we are considering that\n * a new set of elements is being inserted, so we need\n * to refresh the elements to animate.\n */\n onUpdated(() => {\n isNewSet = true\n })\n\n /**\n * Listener called when one frame the element is inserted.\n * This calculates the stagger delay to be used as `transitionDelay` and finally resolve\n * the transition end after the CSS transition duration plus stagger delay.\n *\n * @param el - Element inserted.\n * @param done - Callback to indicate the transition end.\n */\n function onEnter(el: Element, done: () => void) {\n if (isNewSet) {\n refreshElementsToAnimate(el)\n }\n\n const elIndex = elementsToAnimate.indexOf(el)\n const staggerDelay = elIndex > 0 ? elIndex * props.stagger : 0\n\n ;(el as HTMLElement).style.transitionDelay = `${staggerDelay}ms`\n setTimeout(done, transitionDuration + staggerDelay)\n }\n\n /**\n * Finds he parent's children subset of new elements entering the DOM.\n * This is achieved by filtering out the elements that are already animated.\n * Those with 'transition-delay' equal to '0ms' are considered already animated.\n *\n * Also marks isNewSet as false as the elements are already updated.\n *\n * @param el - Current element.\n */\n function refreshElementsToAnimate(el: Element) {\n elementsToAnimate = [...el.parentElement!.children].filter(\n c => (c as HTMLElement).style.transitionDelay !== '0ms',\n )\n isNewSet = false\n }\n\n /**\n * Listener called when the enter transition has finished.\n * This resets the `transitionDelay`.\n *\n * @param el - Element inserted.\n */\n function onAfterEnter(el: Element) {\n ;(el as HTMLElement).style.transitionDelay = '0ms'\n }\n\n return {\n name,\n onEnter,\n onAfterEnter,\n transitionDurationInMs: `${transitionDuration}ms`,\n }\n },\n})\n</script>\n\n<style lang=\"css\">\n/* 1. Declare transitions */\n.x-staggered-fade-and-slide-enter-active,\n.x-staggered-fade-and-slide-leave-active {\n transition: v-bind(transitionDurationInMs) ease-out;\n transition-property: opacity, transform;\n}\n\n.x-staggered-fade-and-slide-move {\n transition: transform v-bind(transitionDurationInMs) ease-out;\n}\n\n/* 2. Declare enter, from and leave to state */\n.x-staggered-fade-and-slide-enter,\n.x-staggered-fade-and-slide-enter-from,\n.x-staggered-fade-and-slide-leave-to {\n opacity: 0;\n transform: translate3d(0, 50%, 0);\n}\n\n/* 3. Ensure leaving items are taken out of layout flow so that moving animations can be\n calculated correctly. */\n.x-staggered-fade-and-slide-leave-active {\n position: absolute;\n}\n</style>\n\n<docs lang=\"mdx\">\nThe Staggered fade and slide components works as the normal fade and slide components, but it also\nadds a configurable delay to each transition.\n\n## Example\n\n### Used with animatable components\n\n```vue\n<AnimatableComponent :animation=\"StaggeredFadeAndSlide\" />\n```\n\n### Used as a regular component:\n\nThis components exposes all the props and events of the Staggering transition group, like the `tag`\nor the `stagger` props:\n\n```vue\n<StaggeredFadeAndSlide tag=\"ul\" :stagger=\"50\">\n <li key=\"1\">Element to animate</li>\n <li key=\"2\">Element to animate</li>\n <li key=\"3\">Element to animate</li>\n</StaggeredFadeAndSlide>\n```\n</docs>\n"],"names":["_createBlock","_TransitionGroup","
|
|
1
|
+
{"version":3,"file":"staggered-fade-and-slide.vue.js","sources":["../../../../src/components/animations/staggered-fade-and-slide.vue"],"sourcesContent":["<template>\n <TransitionGroup\n :appear=\"appear\"\n :name=\"name\"\n :tag=\"tag\"\n @enter=\"onEnter\"\n @after-enter=\"onAfterEnter\"\n >\n <slot />\n </TransitionGroup>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onUpdated } from 'vue'\nimport { useDisableAnimation } from './use-disable-animation'\n\n/**\n * Renders a transition group wrapping the elements passed in the default slot and animating\n * them with a staggered fade and slide animation.\n *\n * @public\n */\nexport default defineComponent({\n name: 'StaggeredFadeAndSlide',\n props: {\n /** Indicates if the transition must be applied on the initial render of the node. */\n appear: {\n type: Boolean,\n default: true,\n },\n /** The tag of the node to render to the DOM. */\n tag: {\n type: String,\n default: 'div',\n },\n /** The time in ms to stagger each item. */\n stagger: {\n type: Number,\n default: 25,\n },\n },\n setup(props) {\n /** The duration of the transition in ms. */\n const transitionDuration = 250\n /** Indicates if there are new elements to animate. */\n let isNewSet = true\n /** The new elements to animate. */\n let elementsToAnimate: Element[] = []\n /** The name of the animation. */\n const { name } = useDisableAnimation('x-staggered-fade-and-slide')\n\n /**\n * When the component is updated, we are considering that\n * a new set of elements is being inserted, so we need\n * to refresh the elements to animate.\n */\n onUpdated(() => {\n isNewSet = true\n })\n\n /**\n * Listener called when one frame the element is inserted.\n * This calculates the stagger delay to be used as `transitionDelay` and finally resolve\n * the transition end after the CSS transition duration plus stagger delay.\n *\n * @param el - Element inserted.\n * @param done - Callback to indicate the transition end.\n */\n function onEnter(el: Element, done: () => void) {\n if (isNewSet) {\n refreshElementsToAnimate(el)\n }\n\n const elIndex = elementsToAnimate.indexOf(el)\n const staggerDelay = elIndex > 0 ? elIndex * props.stagger : 0\n\n ;(el as HTMLElement).style.transitionDelay = `${staggerDelay}ms`\n setTimeout(done, transitionDuration + staggerDelay)\n }\n\n /**\n * Finds he parent's children subset of new elements entering the DOM.\n * This is achieved by filtering out the elements that are already animated.\n * Those with 'transition-delay' equal to '0ms' are considered already animated.\n *\n * Also marks isNewSet as false as the elements are already updated.\n *\n * @param el - Current element.\n */\n function refreshElementsToAnimate(el: Element) {\n elementsToAnimate = [...el.parentElement!.children].filter(\n c => (c as HTMLElement).style.transitionDelay !== '0ms',\n )\n isNewSet = false\n }\n\n /**\n * Listener called when the enter transition has finished.\n * This resets the `transitionDelay`.\n *\n * @param el - Element inserted.\n */\n function onAfterEnter(el: Element) {\n ;(el as HTMLElement).style.transitionDelay = '0ms'\n }\n\n return {\n name,\n onEnter,\n onAfterEnter,\n transitionDurationInMs: `${transitionDuration}ms`,\n }\n },\n})\n</script>\n\n<style lang=\"css\">\n/* 1. Declare transitions */\n.x-staggered-fade-and-slide-enter-active,\n.x-staggered-fade-and-slide-leave-active {\n transition: v-bind(transitionDurationInMs) ease-out;\n transition-property: opacity, transform;\n}\n\n.x-staggered-fade-and-slide-move {\n transition: transform v-bind(transitionDurationInMs) ease-out;\n}\n\n/* 2. Declare enter, from and leave to state */\n.x-staggered-fade-and-slide-enter,\n.x-staggered-fade-and-slide-enter-from,\n.x-staggered-fade-and-slide-leave-to {\n opacity: 0;\n transform: translate3d(0, 50%, 0);\n}\n\n/* 3. Ensure leaving items are taken out of layout flow so that moving animations can be\n calculated correctly. */\n.x-staggered-fade-and-slide-leave-active {\n position: absolute;\n}\n</style>\n\n<docs lang=\"mdx\">\nThe Staggered fade and slide components works as the normal fade and slide components, but it also\nadds a configurable delay to each transition.\n\n## Example\n\n### Used with animatable components\n\n```vue\n<AnimatableComponent :animation=\"StaggeredFadeAndSlide\" />\n```\n\n### Used as a regular component:\n\nThis components exposes all the props and events of the Staggering transition group, like the `tag`\nor the `stagger` props:\n\n```vue\n<StaggeredFadeAndSlide tag=\"ul\" :stagger=\"50\">\n <li key=\"1\">Element to animate</li>\n <li key=\"2\">Element to animate</li>\n <li key=\"3\">Element to animate</li>\n</StaggeredFadeAndSlide>\n```\n</docs>\n"],"names":["_createBlock","_TransitionGroup","_renderSlot"],"mappings":";;;;;;sBACEA,WAQkB,CAAAC,eAAA,EAAA;AAAA,IAPf,MAAQ,EAAA,IAAA,CAAA,MAAA;AAAA,IACR,IAAM,EAAA,IAAA,CAAA,IAAA;AAAA,IACN,GAAK,EAAA,IAAA,CAAA,GAAA;AAAA,IACL,OAAO,EAAA,IAAA,CAAA,OAAA;AAAA,IACP,YAAa,EAAA,IAAA,CAAA,YAAA;AAAA,GAAA,EAAA;qBAEd,MAAQ;AAAA,MAARC,UAAQ,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;AAAA,KAAA,CAAA;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-progress-bar.vue.js","sources":["../../../src/components/auto-progress-bar.vue"],"sourcesContent":["<template>\n <div v-if=\"isLoading\" class=\"x-progress-bar\" data-test=\"progress-bar\" role=\"progressbar\">\n <div class=\"x-progress-bar-fill\" :style=\"cssStyles\" data-test=\"progress-bar-line\" />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport type { StyleValue } from 'vue'\nimport { computed, defineComponent } from 'vue'\n\n/**\n * The auto progress bar component is useful for displaying a visual indicator of numerical data\n * in a bar shape.\n *\n * @public\n */\nexport default defineComponent({\n name: 'AutoProgressBar',\n props: {\n /**\n * A boolean flag indicating if the bar is loading.\n *\n * @public\n */\n isLoading: {\n type: Boolean,\n default: true,\n },\n /**\n * The duration in seconds of the progress bar.\n *\n * @public\n */\n durationInSeconds: {\n type: Number,\n default: 5,\n },\n },\n setup(props) {\n /**\n * Computed property to calculate the animation's duration.\n *\n * @returns The CSS styles of the animation.\n *\n * @internal\n */\n const cssStyles = computed<StyleValue>(() => ({\n animationDuration: `${props.durationInSeconds}s`,\n }))\n\n return {\n cssStyles,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-progress-bar {\n display: inline-block;\n overflow: hidden;\n background-color: #dbe2e5;\n border-radius: 4px;\n}\n\n.x-progress-bar-fill {\n height: 4px;\n background-color: #283034;\n animation: slide linear;\n transform-origin: left;\n}\n\n@keyframes slide {\n 0% {\n transform: translateX(-100%);\n }\n 100% {\n transform: translateX(0);\n }\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`UserClickedARedirection`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n after the user clicks the redirection button.\n- [`UserClickedAbortARedirection`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n after the user clicks the abort redirection button.\n\n## See it in action\n\nHere you have a basic example of how the auto progress bar is rendered.\n\n```vue live\n<template>\n <AutoProgressBar :isLoading=\"isLoading\" :durationInSeconds=\"durationInSeconds\" />\n</template>\n\n<script>\nimport { AutoProgressBar } from '@empathyco/x-components'\nexport default {\n name: 'AutoProgressBarDemo',\n components: {\n AutoProgressBar,\n },\n data() {\n return {\n isLoading: true,\n durationInSeconds: 100,\n }\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the auto progress bar has been set to do an animation for 5 seconds. There is a way\nto cancel the animation by sending the isLoading prop to false.\n\n```vue live\n<template>\n <AutoProgressBar :durationInSeconds=\"5\" :isLoading=\"true\" />\n</template>\n\n<script>\nimport { AutoProgressBar } from '@empathyco/x-components'\nexport default {\n name: 'AutoProgressBarDemo',\n components: {\n AutoProgressBar,\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_normalizeStyle"
|
|
1
|
+
{"version":3,"file":"auto-progress-bar.vue.js","sources":["../../../src/components/auto-progress-bar.vue"],"sourcesContent":["<template>\n <div v-if=\"isLoading\" class=\"x-progress-bar\" data-test=\"progress-bar\" role=\"progressbar\">\n <div class=\"x-progress-bar-fill\" :style=\"cssStyles\" data-test=\"progress-bar-line\" />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport type { StyleValue } from 'vue'\nimport { computed, defineComponent } from 'vue'\n\n/**\n * The auto progress bar component is useful for displaying a visual indicator of numerical data\n * in a bar shape.\n *\n * @public\n */\nexport default defineComponent({\n name: 'AutoProgressBar',\n props: {\n /**\n * A boolean flag indicating if the bar is loading.\n *\n * @public\n */\n isLoading: {\n type: Boolean,\n default: true,\n },\n /**\n * The duration in seconds of the progress bar.\n *\n * @public\n */\n durationInSeconds: {\n type: Number,\n default: 5,\n },\n },\n setup(props) {\n /**\n * Computed property to calculate the animation's duration.\n *\n * @returns The CSS styles of the animation.\n *\n * @internal\n */\n const cssStyles = computed<StyleValue>(() => ({\n animationDuration: `${props.durationInSeconds}s`,\n }))\n\n return {\n cssStyles,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-progress-bar {\n display: inline-block;\n overflow: hidden;\n background-color: #dbe2e5;\n border-radius: 4px;\n}\n\n.x-progress-bar-fill {\n height: 4px;\n background-color: #283034;\n animation: slide linear;\n transform-origin: left;\n}\n\n@keyframes slide {\n 0% {\n transform: translateX(-100%);\n }\n 100% {\n transform: translateX(0);\n }\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`UserClickedARedirection`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n after the user clicks the redirection button.\n- [`UserClickedAbortARedirection`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n after the user clicks the abort redirection button.\n\n## See it in action\n\nHere you have a basic example of how the auto progress bar is rendered.\n\n```vue live\n<template>\n <AutoProgressBar :isLoading=\"isLoading\" :durationInSeconds=\"durationInSeconds\" />\n</template>\n\n<script>\nimport { AutoProgressBar } from '@empathyco/x-components'\nexport default {\n name: 'AutoProgressBarDemo',\n components: {\n AutoProgressBar,\n },\n data() {\n return {\n isLoading: true,\n durationInSeconds: 100,\n }\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the auto progress bar has been set to do an animation for 5 seconds. There is a way\nto cancel the animation by sending the isLoading prop to false.\n\n```vue live\n<template>\n <AutoProgressBar :durationInSeconds=\"5\" :isLoading=\"true\" />\n</template>\n\n<script>\nimport { AutoProgressBar } from '@empathyco/x-components'\nexport default {\n name: 'AutoProgressBarDemo',\n components: {\n AutoProgressBar,\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_normalizeStyle"],"mappings":";;;;;;;EACwB,KAAM,EAAA,gBAAA;AAAA,EAAiB,WAAU,EAAA,cAAA;AAAA,EAAe,IAAK,EAAA,aAAA;;;SAAhE,IAAX,CAAA,SAAA,IAAAA,SAAA,EAAA,EAAAC,kBAAA,CAEM,OAFN,UAEM,EAAA;AAAA,IADJC,kBAAA;AAAA,MAAoF,KAAA;AAAA,MAAA;AAAA,QAA/E,KAAM,EAAA,qBAAA;AAAA,QAAuB,KAAA,EAAKC,eAAE,IAAS,CAAA,SAAA,CAAA;AAAA,QAAE,WAAU,EAAA,mBAAA;AAAA,OAAA;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-dropdown.vue.js","sources":["../../../src/components/base-dropdown.vue"],"sourcesContent":["<template>\n <div\n ref=\"rootRef\"\n :class=\"dropdownCSSClasses\"\n class=\"x-dropdown\"\n @keydown=\"updateSearchBuffer\"\n @keydown.down.prevent=\"highlightNextItem\"\n @keydown.up.prevent=\"highlightPreviousItem\"\n >\n <button\n ref=\"toggleButtonRef\"\n class=\"x-dropdown__toggle\"\n data-test=\"dropdown-toggle\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n :aria-expanded=\"isOpen.toString()\"\n :aria-controls=\"listId\"\n :aria-label=\"ariaLabel\"\n aria-autocomplete=\"none\"\n @click=\"toggle\"\n @keydown.up.down.prevent.stop=\"open\"\n >\n <!--\n @slot Used to render the contents of the dropdown toggle button. If not provided, it uses\n the item slot as fallback.\n @binding {string|number|Identifiable} item - The item data to render.\n @binding {boolean} isOpen - True if the dropdown is opened, and false if it is closed.\n -->\n <slot v-if=\"hasToggleSlot\" :is-open=\"isOpen\" :item=\"modelValue\" name=\"toggle\">\n {{ modelValue }}\n </slot>\n <slot v-else :item=\"modelValue\" name=\"item\">{{ modelValue }}</slot>\n </button>\n\n <component :is=\"animation\">\n <ul\n v-show=\"isOpen\"\n :id=\"listId\"\n class=\"x-dropdown__items-list\"\n data-test=\"dropdown-list\"\n role=\"listbox\"\n tabindex=\"-1\"\n @keydown.end=\"highlightLastItem\"\n @keydown.esc=\"closeAndFocusToggleButton\"\n @keydown.home=\"highlightFirstItem\"\n >\n <li v-for=\"(item, index) in items\" :key=\"item.id || item\" class=\"x-dropdown__list-item\">\n <button\n :ref=\"el => (itemsButtonRefs[index] = el)\"\n :aria-selected=\"(item === modelValue).toString()\"\n :class=\"itemsCSSClasses[index]\"\n class=\"x-dropdown__item\"\n data-test=\"dropdown-item\"\n role=\"option\"\n @click=\"emitSelectedItemChanged(item)\"\n >\n <!--\n @slot (required) Used to render each one of the items content, and as fallback\n for the toggle button content slot if it is not provided.\n @binding {string|number|Identifiable} item - Item to render\n @binding {boolean} isHighlighted - True when the item has the focus.\n @binding {boolean} isSelected - True when the item is selected.\n -->\n <slot\n :is-highlighted=\"index === highlightedItemIndex\"\n :is-selected=\"item === modelValue\"\n :item=\"item\"\n name=\"item\"\n >\n {{ item }}\n </slot>\n </button>\n </li>\n </ul>\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport type { Identifiable } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport { computed, defineComponent, nextTick, onBeforeUnmount, ref, watch } from 'vue'\nimport { AnimationProp } from '../types'\nimport { debounceFunction, getTargetElement, normalizeString } from '../utils'\nimport { NoAnimation } from './animations'\n\ntype DropdownItem = string | number | Identifiable\nlet dropdownCount = 0\n\n/**\n * Dropdown component that mimics a Select element behavior, but with the option\n * to customize the toggle button and each item contents.\n */\nexport default defineComponent({\n name: 'BaseDropdown',\n props: {\n /** List of items to display.*/\n items: {\n type: Array as PropType<DropdownItem[]>,\n required: true,\n },\n /** The selected item. */\n modelValue: {\n type: null as unknown as PropType<DropdownItem | null>,\n validator: (v: any) =>\n typeof v === 'string' || typeof v === 'number' || typeof v === 'object' || v === null,\n required: true,\n },\n /** Description of what the dropdown is used for. */\n ariaLabel: String,\n /**\n * Animation component to use for expanding the dropdown. This is a single element animation,\n * so only `<transition>` components are allowed.\n */\n animation: {\n type: AnimationProp,\n default: () => NoAnimation,\n },\n /** Time to wait without receiving any keystroke before resetting the items search query. */\n searchTimeoutMs: {\n type: Number,\n default: 1000,\n },\n },\n emits: ['update:modelValue'],\n setup(props, { emit, slots }) {\n const rootRef = ref<HTMLElement>()\n /** The button that opens and closes the list of options. */\n const toggleButtonRef = ref<HTMLButtonElement>()\n /** Array containing the dropdown list buttons HTMLElements. */\n const itemsButtonRefs = ref<HTMLButtonElement[]>([])\n\n /** Property to check whether the dropdown is expanded or closed. */\n const isOpen = ref(false)\n /** Index of the element that has the focus in the list. -1 means no element has focus. */\n const highlightedItemIndex = ref(-1)\n /** String to search for the first element that starts with it. */\n const searchBuffer = ref('')\n\n /** Resets the search buffer after a certain time has passed. */\n let restartResetSearchTimeout: () => void\n /* Unique ID to identify the dropdown. */\n const listId = `x-dropdown-${dropdownCount++}`\n\n /**\n * Dynamic CSS classes to add to the dropdown root element.\n *\n * @returns An object containing the CSS classes to add to the dropdown root element.\n */\n const dropdownCSSClasses = computed(() => ({ 'x-dropdown--is-open': isOpen }))\n\n /**\n * Dynamic CSS classes to add to each one of the items.\n *\n * @returns An object containing the CSS classes to add to each item.\n */\n const itemsCSSClasses = computed(() =>\n props.items.map((item, index) => ({\n 'x-dropdown__item--is-selected': props.modelValue === item,\n 'x-dropdown__item--is-highlighted': highlightedItemIndex.value === index,\n })),\n )\n\n /* Opens the dropdown. */\n const open = () => (isOpen.value = true)\n /* Closes the dropdown. */\n const close = () => (isOpen.value = false)\n /* Toggles the dropdown. */\n const toggle = () => (isOpen.value = !isOpen.value)\n\n /**\n * Closes the modal and focuses the toggle button.\n */\n function closeAndFocusToggleButton() {\n close()\n toggleButtonRef.value?.focus()\n }\n\n /**\n * Emits the event that the selected item has changed.\n *\n * @param item - The new selected item.\n */\n function emitSelectedItemChanged(item: DropdownItem) {\n emit('update:modelValue', item)\n closeAndFocusToggleButton()\n }\n\n /**\n * Highlights the item after the one that is currently highlighted.\n */\n function highlightNextItem() {\n open()\n highlightedItemIndex.value = (highlightedItemIndex.value + 1) % props.items.length\n }\n\n /**\n * Highlights the item before the one that is currently highlighted.\n */\n function highlightPreviousItem() {\n const currentIndex = highlightedItemIndex.value\n open()\n highlightedItemIndex.value = currentIndex > 0 ? currentIndex - 1 : props.items.length - 1\n }\n\n /**\n * Highlights the first of the provided items.\n */\n function highlightFirstItem() {\n highlightedItemIndex.value = 0\n }\n\n /**\n * Highlights the last of the provided items.\n */\n function highlightLastItem() {\n highlightedItemIndex.value = props.items.length - 1\n }\n\n /**\n * Updates the variable that is used to search in the filters.\n *\n * @param event - The event coming from the user typing.\n */\n function updateSearchBuffer(event: KeyboardEvent) {\n if (/^\\w$/.test(event.key)) {\n const key = event.key\n searchBuffer.value += key\n restartResetSearchTimeout()\n }\n }\n\n /**\n * Resets the search buffer.\n */\n function resetSearchBuffer() {\n searchBuffer.value = ''\n }\n\n /**\n * Closes the dropdown if the passed event has happened on an element out of the dropdown.\n *\n * @param event - The event to check if it has happened out of the dropdown component.\n */\n function closeIfEventIsOutOfDropdown(event: MouseEvent | TouchEvent | FocusEvent) {\n if (!rootRef.value?.contains(getTargetElement(event))) {\n close()\n }\n }\n\n /**\n * Adds listeners to the document element to detect if the focus has moved out from the\n * dropdown.\n */\n function addDocumentCloseListeners() {\n document.addEventListener('mousedown', closeIfEventIsOutOfDropdown)\n document.addEventListener('touchstart', closeIfEventIsOutOfDropdown)\n document.addEventListener('focusin', closeIfEventIsOutOfDropdown)\n }\n\n /**\n * Removes the listeners of the document element to detect if the focus has moved out from the\n * dropdown.\n */\n function removeDocumentCloseListeners() {\n document.removeEventListener('mousedown', closeIfEventIsOutOfDropdown)\n document.removeEventListener('touchstart', closeIfEventIsOutOfDropdown)\n document.removeEventListener('focusin', closeIfEventIsOutOfDropdown)\n }\n\n /**\n * Highlights the item that matches the search buffer. To do so it checks the list buttons\n * text content. It highlights items following this priority:\n * - If an element is already highlighted, it starts searching from that element.\n * - If no element is found starting from the previously highlighted, it returns the first one.\n * - If no element is found matching the search query it highlights the first element.\n *\n * @param search - The search string to find in the HTML.\n */\n watch(searchBuffer, search => {\n if (search) {\n const normalizedSearch = normalizeString(search)\n const matchingIndices = itemsButtonRefs?.value?.reduce<number[]>(\n (matchingIndices, button, index) => {\n const safeButtonWordCharacters = button.textContent!.replace(/\\W/g, '')\n const normalizedButtonText = normalizeString(safeButtonWordCharacters)\n if (normalizedButtonText.startsWith(normalizedSearch)) {\n matchingIndices.push(index)\n }\n return matchingIndices\n },\n [],\n )\n highlightedItemIndex.value =\n // First matching item starting to search from the current highlighted element\n matchingIndices?.find(index => index >= highlightedItemIndex.value) ??\n // First matching item\n matchingIndices?.[0] ??\n // First item\n 0\n }\n })\n\n /**\n * Updates the debounced function to reset the search.\n *\n * @param searchTimeoutMs - The new milliseconds that have to pass without typing before\n * resetting the search.\n */\n watch(\n () => props.searchTimeoutMs,\n searchTimeoutMs => {\n restartResetSearchTimeout = debounceFunction(resetSearchBuffer, searchTimeoutMs)\n },\n { immediate: true },\n )\n\n /**\n * Focuses the DOM element which matches the `highlightedItemIndex`.\n *\n * @param highlightedItemIndex - The index of the HTML element to focus.\n */\n watch(\n highlightedItemIndex,\n highlightedItemIndex => {\n nextTick(() => itemsButtonRefs.value[highlightedItemIndex]?.focus())\n },\n { immediate: true },\n )\n\n /**\n * When the dropdown is open it sets the focused element to the one that is selected.\n *\n * @param isOpen - True if the dropdown is open, false otherwise.\n */\n watch(isOpen, isOpen => {\n highlightedItemIndex.value = isOpen\n ? props.modelValue === null\n ? 0\n : props.items.indexOf(props.modelValue)\n : -1\n })\n\n /**\n * Adds and removes listeners to close the dropdown when it loses the focus.\n *\n * @param isOpen - True if the dropdown is open, false otherwise.\n */\n watch(isOpen, isOpen => {\n /*\n * Because there is an issue with Firefox in macOS and Safari that doesn't focus the target\n * element of the `mousedown` events, the `focusout` event `relatedTarget` property can't be\n * used to detect whether the user has blurred the dropdown. The hack here is to use\n * document listeners that have the side effect of losing the focus.\n */\n if (isOpen) {\n addDocumentCloseListeners()\n } else {\n removeDocumentCloseListeners()\n }\n })\n\n /**\n * If the dropdown is destroyed before removing the document listeners, it ensures that they\n * are removed too.\n */\n onBeforeUnmount(() => {\n removeDocumentCloseListeners()\n })\n\n return {\n hasToggleSlot: !!slots.toggle,\n closeAndFocusToggleButton,\n dropdownCSSClasses,\n emitSelectedItemChanged,\n highlightFirstItem,\n highlightLastItem,\n highlightNextItem,\n highlightPreviousItem,\n highlightedItemIndex,\n isOpen,\n itemsButtonRefs,\n itemsCSSClasses,\n listId,\n open,\n rootRef,\n toggle,\n toggleButtonRef,\n updateSearchBuffer,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-dropdown {\n position: relative;\n}\n\n.x-dropdown__items-list {\n z-index: 1;\n list-style: none;\n position: absolute;\n padding: 0;\n margin: 0;\n top: calc(100% + var(--x-size-gap-dropdown-default, 0));\n}\n</style>\n\n<docs lang=\"mdx\">\n## Example\n\nThe `Dropdown` component is a simple yet customizable select component. The component needs to work\nthe list of items available to select, which are passed using the `items` prop, and the selected\nitem, which is passed in using the `value` prop.\n\nThe supported items must be an array that can contain unique strings, unique numbers, or objects\nwith a unique `id` property.\n\nThe content of each item can be customized using the `item` slot, which apart from the data of the\nitem, it also receives via prop if the element is selected or highlighted.\n\nThere `toggle` slot can be used to customize the button that opens the dropdown. If this is not\nprovided, the `item` slot will be used for that.\n\n```vue\n<template>\n <BaseDropdown v-model=\"value\" :items=\"items\">\n <template #toggle=\"{ item, isOpen }\">{{ item }} {{ isOpen ? '🔼' : '🔽' }}️</template>\n\n <template #item=\"{ item, isSelected, isHighlighted }\">\n <span v-if=\"isHighlighted\">🟢</span>\n <span v-if=\"isSelected\">✅</span>\n <span>{{ item }}</span>\n </template>\n </BaseDropdown>\n</template>\n\n<script>\nimport { BaseDropdown } from '@empathyco/x-components'\n\nexport default {\n name: 'DropdownTest',\n components: {\n BaseDropdown,\n },\n data() {\n return {\n items: ['a', 2, { id: '3' }],\n value: 'a',\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_normalizeClass","_withKeys","_createElementVNode","_withModifiers","_renderSlot","_createTextVNode","_toDisplayString","_createBlock","_resolveDynamicComponent","_withDirectives","_Fragment","_renderList","_vShow"],"mappings":";;;;;AAAA,MAAA,UAAA,GAAA,CAAA,eAAA,EAAA,eAAA,EAAA,YAAA,CAAA,CAAA;AAAA,MAAA,UAAA,GAAA,CAAA,IAAA,CAAA,CAAA;AAAA,MAAA,UAAA,GAAA,CAAA,eAAA,EAAA,SAAA,CAAA,CAAA;;AACE,EAAA,OAAAA,SAAA,EAAA,EAAAC,kBAAA;AAAA,IA0EM,KAAA;AAAA,IAAA;AAAA,MAzEJ,GAAI,EAAA,SAAA;AAAA,MACH,KAAA,EAHLC,cAGY,CAAA,CAAA,IAAA,CAAA,kBAAA,EACF,YAAY,CAAA,CAAA;AAAA,MACjB,SAAO,EAAA;AAAA,QAAE,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,QAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GALdC,oCAM2B,IAAiB,CAAA,iBAAA,IAAA,IAAA,CAAA,iBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AAAA,QAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAN5CA,oCAOyB,IAAqB,CAAA,qBAAA,IAAA,IAAA,CAAA,qBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,IAAA,CAAA,CAAA,CAAA;AAAA,OAAA;;;MAE1CC,kBAuBS,CAAA,QAAA,EAAA;AAAA,QAtBP,GAAI,EAAA,iBAAA;AAAA,QACJ,KAAM,EAAA,oBAAA;AAAA,QACN,WAAU,EAAA,iBAAA;AAAA,QACV,IAAK,EAAA,UAAA;AAAA,QACL,eAAc,EAAA,SAAA;AAAA,QACb,eAAA,EAAe,YAAO,QAAQ,EAAA;AAAA,QAC9B,eAAe,EAAA,IAAA,CAAA,MAAA;AAAA,QACf,YAAY,EAAA,IAAA,CAAA,SAAA;AAAA,QACb,mBAAkB,EAAA,MAAA;AAAA,QACjB,SAAK,MAAE,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,MAAA,IAAA,IAAA,CAAA,MAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,QACP,SAAA,EAAO,MApBd,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAD,QAAA,CAAAE,aAAA,CAAA,CAAA,GAAA,IAAA,KAoBqC,IAAI,CAAA,IAAA,IAAA,IAAA,CAAA,IAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,EAAA,MAAA,CAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,CAAA,CAAA,CAAA;AAAA,OAAA,EAAA;AAQvB,QAAA,IAAA,CAAA,aAAA,GAAZC,UAEO,CAAA,IAAA,CAAA,MAAA,EAAA,QAAA,EAAA;AAAA,UA9Bb,GAAA,EAAA,CAAA;AAAA,UA4BkC,MAAS,EAAA,IAAA,CAAA,MAAA;AAAA,UAAS,IAAM,EAAA,IAAA,CAAA,UAAA;AAAA,SAAA,EAApD,MAEO;AAAA,UA9BbC,eAAA;AAAA,YAAAC,eAAA,CA6BW,IAAU,CAAA,UAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,EAAA,IAAA,CAAA,GAEfF,UAAmE,CAAA,IAAA,CAAA,MAAA,EAAA,MAAA,EAAA;AAAA,UA/BzE,GAAA,EAAA,CAAA;AAAA,UA+BoB,IAAM,EAAA,IAAA,CAAA,UAAA;AAAA,SAAA,EAApB,MAAmE;AAAA,UA/BzEC,eAAA;AAAA,YAAAC,eAAA,CA+BqD,IAAU,CAAA,UAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,EAAA,IAAA,CAAA;AA/B/D,OAAA,EAAA,EAAA,EAAA,UAAA,CAAA;AAAA,OAkCIR,SAAA,EAAA,EAAAS,WAAA,CAwCYC,wBAxCI,IAAS,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA;AAAA,QAlC7B,iBAmCM,MAsCK;AAAA,UAAAC,cAAA,CAtCLP,kBAsCK,CAAA,IAAA,EAAA;AAAA,YApCF,EAAI,EAAA,IAAA,CAAA,MAAA;AAAA,YACL,KAAM,EAAA,wBAAA;AAAA,YACN,WAAU,EAAA,eAAA;AAAA,YACV,IAAK,EAAA,SAAA;AAAA,YACL,QAAS,EAAA,IAAA;AAAA,YACR,SAAO,EAAA;AAAA,cAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GA1ChBD,sBA0CsB,IAAiB,CAAA,iBAAA,IAAA,IAAA,CAAA,iBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,KAAA,CAAA,CAAA,CAAA;AAAA,cAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GA1CvCA,sBA2CsB,IAAyB,CAAA,yBAAA,IAAA,IAAA,CAAA,yBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,KAAA,CAAA,CAAA,CAAA;AAAA,cAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GA3C/CA,sBA4CuB,IAAkB,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AAAA,aAAA;;AAEjC,aAAAH,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA;AAAA,cA0BKW,QAAA;AAAA,cAAA,IAAA;AAAA,cAxEbC,UA8CoC,CAAA,IAAA,CAAA,KAAA,EA9CpC,CA8CoB,IAAA,EAAM,KAAK,KAAA;oCAAvBZ,kBA0BK,CAAA,IAAA,EAAA;AAAA,kBA1B+B,GAAA,EAAK,KAAK,EAAM,IAAA,IAAA;AAAA,kBAAM,KAAM,EAAA,uBAAA;AAAA,iBAAA,EAAA;kBAC9DG,kBAwBS,CAAA,QAAA,EAAA;AAAA,oBAvEnB,OAAA,EAAA,IAAA;AAAA,oBAgDa,GAAK,EAAA,CAAA,EAAA,KAAO,IAAgB,CAAA,eAAA,CAAA,KAAK,CAAI,GAAA,EAAA;AAAA,oBACrC,eAAA,EAAA,CAAgB,IAAS,KAAA,IAAA,CAAA,UAAA,EAAY,QAAQ,EAAA;AAAA,oBAC7C,KAlDb,EAAAF,cAAA,CAAA,CAkDoB,IAAgB,CAAA,eAAA,CAAA,KAAK,GACvB,kBAAkB,CAAA,CAAA;AAAA,oBACxB,WAAU,EAAA,eAAA;AAAA,oBACV,IAAK,EAAA,QAAA;AAAA,oBACJ,OAAA,EAAK,CAAE,MAAA,KAAA,IAAA,CAAA,uBAAA,CAAwB,IAAI,CAAA;AAAA,mBAAA,EAAA;oBASpCI,UAOO,CAAA,IAAA,CAAA,MAAA,EAAA,MAAA,EAAA;AAAA,sBANJ,eAAgB,KAAU,KAAA,IAAA,CAAA,oBAAA;AAAA,sBAC1B,YAAa,IAAS,KAAA,IAAA,CAAA,UAAA;AAAA,sBACtB,IAAA;AAAA,qBAAA,EAHH,MAOO;AAAA,sBAtEnBC,eAAA;AAAA,wBAAAC,eAAA,CAqEiB,IAAI,CAAA;AAAA,wBAAA,CAAA;AAAA;AAAA,uBAAA;AAAA,qBAAA,EAAA,IAAA,CAAA;AArErB,mBAAA,EAAA,EAAA,EAAA,UAAA,CAAA;AAAA,iBAAA,CAAA,CAAA;;;;;AAAA,WAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EAAA;AAAA,YAAA,CAAAM,KAAA,EAoCgB,IAAM,CAAA,MAAA,CAAA;AAAA,WAAA,CAAA;;AApCtB,QAAA,CAAA,EAAA,CAAA;AAAA;AAAA,OAAA,CAAA;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"base-dropdown.vue.js","sources":["../../../src/components/base-dropdown.vue"],"sourcesContent":["<template>\n <div\n ref=\"rootRef\"\n :class=\"dropdownCSSClasses\"\n class=\"x-dropdown\"\n @keydown=\"updateSearchBuffer\"\n @keydown.down.prevent=\"highlightNextItem\"\n @keydown.up.prevent=\"highlightPreviousItem\"\n >\n <button\n ref=\"toggleButtonRef\"\n class=\"x-dropdown__toggle\"\n data-test=\"dropdown-toggle\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n :aria-expanded=\"isOpen.toString()\"\n :aria-controls=\"listId\"\n :aria-label=\"ariaLabel\"\n aria-autocomplete=\"none\"\n @click=\"toggle\"\n @keydown.up.down.prevent.stop=\"open\"\n >\n <!--\n @slot Used to render the contents of the dropdown toggle button. If not provided, it uses\n the item slot as fallback.\n @binding {string|number|Identifiable} item - The item data to render.\n @binding {boolean} isOpen - True if the dropdown is opened, and false if it is closed.\n -->\n <slot v-if=\"hasToggleSlot\" :is-open=\"isOpen\" :item=\"modelValue\" name=\"toggle\">\n {{ modelValue }}\n </slot>\n <slot v-else :item=\"modelValue\" name=\"item\">{{ modelValue }}</slot>\n </button>\n\n <component :is=\"animation\">\n <ul\n v-show=\"isOpen\"\n :id=\"listId\"\n class=\"x-dropdown__items-list\"\n data-test=\"dropdown-list\"\n role=\"listbox\"\n tabindex=\"-1\"\n @keydown.end=\"highlightLastItem\"\n @keydown.esc=\"closeAndFocusToggleButton\"\n @keydown.home=\"highlightFirstItem\"\n >\n <li v-for=\"(item, index) in items\" :key=\"item.id || item\" class=\"x-dropdown__list-item\">\n <button\n :ref=\"el => (itemsButtonRefs[index] = el)\"\n :aria-selected=\"(item === modelValue).toString()\"\n :class=\"itemsCSSClasses[index]\"\n class=\"x-dropdown__item\"\n data-test=\"dropdown-item\"\n role=\"option\"\n @click=\"emitSelectedItemChanged(item)\"\n >\n <!--\n @slot (required) Used to render each one of the items content, and as fallback\n for the toggle button content slot if it is not provided.\n @binding {string|number|Identifiable} item - Item to render\n @binding {boolean} isHighlighted - True when the item has the focus.\n @binding {boolean} isSelected - True when the item is selected.\n -->\n <slot\n :is-highlighted=\"index === highlightedItemIndex\"\n :is-selected=\"item === modelValue\"\n :item=\"item\"\n name=\"item\"\n >\n {{ item }}\n </slot>\n </button>\n </li>\n </ul>\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport type { Identifiable } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport { computed, defineComponent, nextTick, onBeforeUnmount, ref, watch } from 'vue'\nimport { AnimationProp } from '../types'\nimport { debounceFunction, getTargetElement, normalizeString } from '../utils'\nimport { NoAnimation } from './animations'\n\ntype DropdownItem = string | number | Identifiable\nlet dropdownCount = 0\n\n/**\n * Dropdown component that mimics a Select element behavior, but with the option\n * to customize the toggle button and each item contents.\n */\nexport default defineComponent({\n name: 'BaseDropdown',\n props: {\n /** List of items to display.*/\n items: {\n type: Array as PropType<DropdownItem[]>,\n required: true,\n },\n /** The selected item. */\n modelValue: {\n type: null as unknown as PropType<DropdownItem | null>,\n validator: (v: any) =>\n typeof v === 'string' || typeof v === 'number' || typeof v === 'object' || v === null,\n required: true,\n },\n /** Description of what the dropdown is used for. */\n ariaLabel: String,\n /**\n * Animation component to use for expanding the dropdown. This is a single element animation,\n * so only `<transition>` components are allowed.\n */\n animation: {\n type: AnimationProp,\n default: () => NoAnimation,\n },\n /** Time to wait without receiving any keystroke before resetting the items search query. */\n searchTimeoutMs: {\n type: Number,\n default: 1000,\n },\n },\n emits: ['update:modelValue'],\n setup(props, { emit, slots }) {\n const rootRef = ref<HTMLElement>()\n /** The button that opens and closes the list of options. */\n const toggleButtonRef = ref<HTMLButtonElement>()\n /** Array containing the dropdown list buttons HTMLElements. */\n const itemsButtonRefs = ref<HTMLButtonElement[]>([])\n\n /** Property to check whether the dropdown is expanded or closed. */\n const isOpen = ref(false)\n /** Index of the element that has the focus in the list. -1 means no element has focus. */\n const highlightedItemIndex = ref(-1)\n /** String to search for the first element that starts with it. */\n const searchBuffer = ref('')\n\n /** Resets the search buffer after a certain time has passed. */\n let restartResetSearchTimeout: () => void\n /* Unique ID to identify the dropdown. */\n const listId = `x-dropdown-${dropdownCount++}`\n\n /**\n * Dynamic CSS classes to add to the dropdown root element.\n *\n * @returns An object containing the CSS classes to add to the dropdown root element.\n */\n const dropdownCSSClasses = computed(() => ({ 'x-dropdown--is-open': isOpen }))\n\n /**\n * Dynamic CSS classes to add to each one of the items.\n *\n * @returns An object containing the CSS classes to add to each item.\n */\n const itemsCSSClasses = computed(() =>\n props.items.map((item, index) => ({\n 'x-dropdown__item--is-selected': props.modelValue === item,\n 'x-dropdown__item--is-highlighted': highlightedItemIndex.value === index,\n })),\n )\n\n /* Opens the dropdown. */\n const open = () => (isOpen.value = true)\n /* Closes the dropdown. */\n const close = () => (isOpen.value = false)\n /* Toggles the dropdown. */\n const toggle = () => (isOpen.value = !isOpen.value)\n\n /**\n * Closes the modal and focuses the toggle button.\n */\n function closeAndFocusToggleButton() {\n close()\n toggleButtonRef.value?.focus()\n }\n\n /**\n * Emits the event that the selected item has changed.\n *\n * @param item - The new selected item.\n */\n function emitSelectedItemChanged(item: DropdownItem) {\n emit('update:modelValue', item)\n closeAndFocusToggleButton()\n }\n\n /**\n * Highlights the item after the one that is currently highlighted.\n */\n function highlightNextItem() {\n open()\n highlightedItemIndex.value = (highlightedItemIndex.value + 1) % props.items.length\n }\n\n /**\n * Highlights the item before the one that is currently highlighted.\n */\n function highlightPreviousItem() {\n const currentIndex = highlightedItemIndex.value\n open()\n highlightedItemIndex.value = currentIndex > 0 ? currentIndex - 1 : props.items.length - 1\n }\n\n /**\n * Highlights the first of the provided items.\n */\n function highlightFirstItem() {\n highlightedItemIndex.value = 0\n }\n\n /**\n * Highlights the last of the provided items.\n */\n function highlightLastItem() {\n highlightedItemIndex.value = props.items.length - 1\n }\n\n /**\n * Updates the variable that is used to search in the filters.\n *\n * @param event - The event coming from the user typing.\n */\n function updateSearchBuffer(event: KeyboardEvent) {\n if (/^\\w$/.test(event.key)) {\n const key = event.key\n searchBuffer.value += key\n restartResetSearchTimeout()\n }\n }\n\n /**\n * Resets the search buffer.\n */\n function resetSearchBuffer() {\n searchBuffer.value = ''\n }\n\n /**\n * Closes the dropdown if the passed event has happened on an element out of the dropdown.\n *\n * @param event - The event to check if it has happened out of the dropdown component.\n */\n function closeIfEventIsOutOfDropdown(event: MouseEvent | TouchEvent | FocusEvent) {\n if (!rootRef.value?.contains(getTargetElement(event))) {\n close()\n }\n }\n\n /**\n * Adds listeners to the document element to detect if the focus has moved out from the\n * dropdown.\n */\n function addDocumentCloseListeners() {\n document.addEventListener('mousedown', closeIfEventIsOutOfDropdown)\n document.addEventListener('touchstart', closeIfEventIsOutOfDropdown)\n document.addEventListener('focusin', closeIfEventIsOutOfDropdown)\n }\n\n /**\n * Removes the listeners of the document element to detect if the focus has moved out from the\n * dropdown.\n */\n function removeDocumentCloseListeners() {\n document.removeEventListener('mousedown', closeIfEventIsOutOfDropdown)\n document.removeEventListener('touchstart', closeIfEventIsOutOfDropdown)\n document.removeEventListener('focusin', closeIfEventIsOutOfDropdown)\n }\n\n /**\n * Highlights the item that matches the search buffer. To do so it checks the list buttons\n * text content. It highlights items following this priority:\n * - If an element is already highlighted, it starts searching from that element.\n * - If no element is found starting from the previously highlighted, it returns the first one.\n * - If no element is found matching the search query it highlights the first element.\n *\n * @param search - The search string to find in the HTML.\n */\n watch(searchBuffer, search => {\n if (search) {\n const normalizedSearch = normalizeString(search)\n const matchingIndices = itemsButtonRefs?.value?.reduce<number[]>(\n (matchingIndices, button, index) => {\n const safeButtonWordCharacters = button.textContent!.replace(/\\W/g, '')\n const normalizedButtonText = normalizeString(safeButtonWordCharacters)\n if (normalizedButtonText.startsWith(normalizedSearch)) {\n matchingIndices.push(index)\n }\n return matchingIndices\n },\n [],\n )\n highlightedItemIndex.value =\n // First matching item starting to search from the current highlighted element\n matchingIndices?.find(index => index >= highlightedItemIndex.value) ??\n // First matching item\n matchingIndices?.[0] ??\n // First item\n 0\n }\n })\n\n /**\n * Updates the debounced function to reset the search.\n *\n * @param searchTimeoutMs - The new milliseconds that have to pass without typing before\n * resetting the search.\n */\n watch(\n () => props.searchTimeoutMs,\n searchTimeoutMs => {\n restartResetSearchTimeout = debounceFunction(resetSearchBuffer, searchTimeoutMs)\n },\n { immediate: true },\n )\n\n /**\n * Focuses the DOM element which matches the `highlightedItemIndex`.\n *\n * @param highlightedItemIndex - The index of the HTML element to focus.\n */\n watch(\n highlightedItemIndex,\n highlightedItemIndex => {\n nextTick(() => itemsButtonRefs.value[highlightedItemIndex]?.focus())\n },\n { immediate: true },\n )\n\n /**\n * When the dropdown is open it sets the focused element to the one that is selected.\n *\n * @param isOpen - True if the dropdown is open, false otherwise.\n */\n watch(isOpen, isOpen => {\n highlightedItemIndex.value = isOpen\n ? props.modelValue === null\n ? 0\n : props.items.indexOf(props.modelValue)\n : -1\n })\n\n /**\n * Adds and removes listeners to close the dropdown when it loses the focus.\n *\n * @param isOpen - True if the dropdown is open, false otherwise.\n */\n watch(isOpen, isOpen => {\n /*\n * Because there is an issue with Firefox in macOS and Safari that doesn't focus the target\n * element of the `mousedown` events, the `focusout` event `relatedTarget` property can't be\n * used to detect whether the user has blurred the dropdown. The hack here is to use\n * document listeners that have the side effect of losing the focus.\n */\n if (isOpen) {\n addDocumentCloseListeners()\n } else {\n removeDocumentCloseListeners()\n }\n })\n\n /**\n * If the dropdown is destroyed before removing the document listeners, it ensures that they\n * are removed too.\n */\n onBeforeUnmount(() => {\n removeDocumentCloseListeners()\n })\n\n return {\n hasToggleSlot: !!slots.toggle,\n closeAndFocusToggleButton,\n dropdownCSSClasses,\n emitSelectedItemChanged,\n highlightFirstItem,\n highlightLastItem,\n highlightNextItem,\n highlightPreviousItem,\n highlightedItemIndex,\n isOpen,\n itemsButtonRefs,\n itemsCSSClasses,\n listId,\n open,\n rootRef,\n toggle,\n toggleButtonRef,\n updateSearchBuffer,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-dropdown {\n position: relative;\n}\n\n.x-dropdown__items-list {\n z-index: 1;\n list-style: none;\n position: absolute;\n padding: 0;\n margin: 0;\n top: calc(100% + var(--x-size-gap-dropdown-default, 0));\n}\n</style>\n\n<docs lang=\"mdx\">\n## Example\n\nThe `Dropdown` component is a simple yet customizable select component. The component needs to work\nthe list of items available to select, which are passed using the `items` prop, and the selected\nitem, which is passed in using the `value` prop.\n\nThe supported items must be an array that can contain unique strings, unique numbers, or objects\nwith a unique `id` property.\n\nThe content of each item can be customized using the `item` slot, which apart from the data of the\nitem, it also receives via prop if the element is selected or highlighted.\n\nThere `toggle` slot can be used to customize the button that opens the dropdown. If this is not\nprovided, the `item` slot will be used for that.\n\n```vue\n<template>\n <BaseDropdown v-model=\"value\" :items=\"items\">\n <template #toggle=\"{ item, isOpen }\">{{ item }} {{ isOpen ? '🔼' : '🔽' }}️</template>\n\n <template #item=\"{ item, isSelected, isHighlighted }\">\n <span v-if=\"isHighlighted\">🟢</span>\n <span v-if=\"isSelected\">✅</span>\n <span>{{ item }}</span>\n </template>\n </BaseDropdown>\n</template>\n\n<script>\nimport { BaseDropdown } from '@empathyco/x-components'\n\nexport default {\n name: 'DropdownTest',\n components: {\n BaseDropdown,\n },\n data() {\n return {\n items: ['a', 2, { id: '3' }],\n value: 'a',\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_normalizeClass","_withKeys","_withModifiers","_createElementVNode","_renderSlot","_createTextVNode","_createBlock","_resolveDynamicComponent","_withCtx","_withDirectives","_Fragment","_renderList"],"mappings":";;;;;;;;;AACE,EAAA,OAAAA,SAAA,EAAA,EAAAC,kBAAA;AAAA,IA0EM,KAAA;AAAA,IAAA;AAAA,MAzEJ,GAAI,EAAA,SAAA;AAAA,MACH,KAAA,EAAKC,cAAE,CAAA,CAAA,IAAA,CAAA,kBAAA,EACF,YAAY,CAAA,CAAA;AAAA,MACjB,SAAO,EAAA;AAAA,QAAE,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,QAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAC,QAAA,CAAAC,aAAA,CAAA,CAAA,GAAA,IAAA,KACa,IAAiB,CAAA,iBAAA,IAAA,IAAA,CAAA,iBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AAAA,QAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAD,QAAA,CAAAC,aAAA,CAAA,CAAA,GAAA,IAAA,KACnB,IAAqB,CAAA,qBAAA,IAAA,IAAA,CAAA,qBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,IAAA,CAAA,CAAA,CAAA;AAAA,OAAA;;;MAE1CC,kBAuBS,CAAA,QAAA,EAAA;AAAA,QAtBP,GAAI,EAAA,iBAAA;AAAA,QACJ,KAAM,EAAA,oBAAA;AAAA,QACN,WAAU,EAAA,iBAAA;AAAA,QACV,IAAK,EAAA,UAAA;AAAA,QACL,eAAc,EAAA,SAAA;AAAA,QACb,eAAA,EAAe,YAAO,QAAQ,EAAA;AAAA,QAC9B,eAAe,EAAA,IAAA,CAAA,MAAA;AAAA,QACf,YAAY,EAAA,IAAA,CAAA,SAAA;AAAA,QACb,mBAAkB,EAAA,MAAA;AAAA,QACjB,SAAK,MAAE,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,MAAA,IAAA,IAAA,CAAA,MAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,QACP,SAAA,EAAO,8DAAuB,IAAI,CAAA,IAAA,IAAA,IAAA,CAAA,IAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,EAAA,MAAA,CAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,CAAA,CAAA,CAAA;AAAA,OAAA,EAAA;AAQvB,QAAA,IAAA,CAAA,aAAA,GAAZC,UAEO,CAAA,IAAA,CAAA,MAAA,EAAA,QAAA,EAAA;AAAA,UAAA,GAAA,EAAA,CAAA;UAFqB,MAAS,EAAA,IAAA,CAAA,MAAA;AAAA,UAAS,IAAM,EAAA,IAAA,CAAA,UAAA;AAAA,SAAA,EAApD,MAEO;AAAA,UAAAC,eAAA;4BADF,IAAU,CAAA,UAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,EAAA,IAAA,CAAA,GAEfD,UAAmE,CAAA,IAAA,CAAA,MAAA,EAAA,MAAA,EAAA;AAAA,UAAA,GAAA,EAAA,CAAA;UAArD,IAAM,EAAA,IAAA,CAAA,UAAA;AAAA,SAAA,EAApB,MAAmE;AAAA,UAAAC,eAAA;4BAApB,IAAU,CAAA,UAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,EAAA,IAAA,CAAA;;AAG3D,OAAAP,SAAA,EAAA,EAAAQ,WAAA,CAwCYC,wBAxCI,IAAS,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA;AAAA,QAAA,OAAA,EAAAC,OAAA,CACvB,MAsCK;AAAA,UAAAC,cAAA,CAtCLN,kBAsCK,CAAA,IAAA,EAAA;AAAA,YApCF,EAAI,EAAA,IAAA,CAAA,MAAA;AAAA,YACL,KAAM,EAAA,wBAAA;AAAA,YACN,WAAU,EAAA,eAAA;AAAA,YACV,IAAK,EAAA,SAAA;AAAA,YACL,QAAS,EAAA,IAAA;AAAA,YACR,SAAO,EAAA;AAAA,cAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAF,QAAA,CAAA,CAAA,GAAA,IAAA,KAAM,IAAiB,CAAA,iBAAA,IAAA,IAAA,CAAA,iBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,KAAA,CAAA,CAAA,CAAA;AAAA,cAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAA,QAAA,CAAA,CAAA,GAAA,IAAA,KACjB,IAAyB,CAAA,yBAAA,IAAA,IAAA,CAAA,yBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,KAAA,CAAA,CAAA,CAAA;AAAA,cAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAA,QAAA,CAAA,CAAA,GAAA,IAAA,KACxB,IAAkB,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AAAA,aAAA;;AAEjC,aAAAH,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA;AAAA,cA0BKW,QAAA;AAAA,cAAA,IAAA;AAAA,cA1BuBC,UAAA,CAAA,IAAA,CAAA,KAAA,EAAK,CAArB,IAAA,EAAM,KAAK,KAAA;oCAAvBZ,kBA0BK,CAAA,IAAA,EAAA;AAAA,kBA1B+B,GAAA,EAAK,KAAK,EAAM,IAAA,IAAA;AAAA,kBAAM,KAAM,EAAA,uBAAA;AAAA,iBAAA,EAAA;kBAC9DI,kBAwBS,CAAA,QAAA,EAAA;AAAA,oBAAA,OAAA,EAAA,IAAA;oBAvBN,GAAK,EAAA,CAAA,EAAA,KAAO,IAAgB,CAAA,eAAA,CAAA,KAAK,CAAI,GAAA,EAAA;AAAA,oBACrC,eAAA,EAAA,CAAgB,IAAS,KAAA,IAAA,CAAA,UAAA,EAAY,QAAQ,EAAA;AAAA,oBAC7C,KAAK,EAAAH,cAAA,CAAA,CAAE,IAAgB,CAAA,eAAA,CAAA,KAAK,GACvB,kBAAkB,CAAA,CAAA;AAAA,oBACxB,WAAU,EAAA,eAAA;AAAA,oBACV,IAAK,EAAA,QAAA;AAAA,oBACJ,OAAA,EAAK,CAAE,MAAA,KAAA,IAAA,CAAA,uBAAA,CAAwB,IAAI,CAAA;AAAA,mBAAA,EAAA;oBASpCI,UAOO,CAAA,IAAA,CAAA,MAAA,EAAA,MAAA,EAAA;AAAA,sBANJ,eAAgB,KAAU,KAAA,IAAA,CAAA,oBAAA;AAAA,sBAC1B,YAAa,IAAS,KAAA,IAAA,CAAA,UAAA;AAAA,sBACtB,IAAA;AAAA,qBAAA,EAHH,MAOO;AAAA,sBAAAC,eAAA;wCADF,IAAI,CAAA;AAAA,wBAAA,CAAA;AAAA;AAAA,uBAAA;AAAA,qBAAA,EAAA,IAAA,CAAA;;;;;;;;oBAjCL,IAAM,CAAA,MAAA,CAAA;AAAA,WAAA,CAAA;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-grid.vue.js","sources":["../../../src/components/base-grid.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n ref=\"gridEl\"\n :style=\"style\"\n class=\"x-base-grid\"\n :class=\"cssClasses\"\n tag=\"ul\"\n data-test=\"grid\"\n >\n <li\n v-for=\"{ item, cssClass, slotName } in gridItems\"\n :key=\"item.id\"\n :class=\"cssClass\"\n class=\"x-base-grid__item\"\n >\n <!--\n @slot Customized item rendering. Specifying a slot with the item's modelName will result in\n the item using that slot composition to render.\n @binding {item} item - Item to render\n -->\n <slot v-if=\"slots[slotName]\" :name=\"slotName\" :item=\"item\" />\n <!--\n @slot (required) Default item rendering. This slot will be used by default for rendering\n the item without an specific slot implementation.\n @binding {item} item - Item to render\n -->\n <slot v-else :item=\"item\">{{ item.name || item.modelName || item.id || item }}</slot>\n </li>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { MaybeComputedElementRef, UseResizeObserverReturn } from '@vueuse/core'\nimport type { PropType, Ref } from 'vue'\nimport type { ListItem, VueCSSClasses } from '../utils/types'\nimport { useResizeObserver } from '@vueuse/core'\nimport { computed, defineComponent, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport { toKebabCase } from '../utils/string'\nimport { LIST_ITEMS_KEY } from './decorators/injection.consts'\n\n/**\n * The type returned by the gridItems function. Basically it's a list of items with its CSS\n * classes and a slotName.\n */\ninterface GridItem {\n slotName: string\n item: ListItem\n cssClass: VueCSSClasses\n}\n\n/**\n * Grid component that is able to render different items based on their modelName value. In order\n * to achieve this, it exposes a scopedSlot for each different modelName. In case the items used\n * do not have modelName property, the default slot is used instead. It has a required property:\n * the `items` to render; and an optional one: the number `columns` the grid is divided in. If the\n * number of columns is not specified, the grid automatically fills the rows with as many columns\n * as it can fit.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseGrid',\n props: {\n /** Animation component that will be used to animate the base grid. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * Number of columns the grid is divided into. By default, its value is 0, setting the grid\n * columns mode to auto-fill.\n */\n columns: {\n type: Number,\n default: 0,\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an ID property.\n */\n items: {\n type: Array as PropType<ListItem[]>,\n },\n },\n setup(props, { slots }) {\n // eslint-disable-next-line ts/consistent-type-definitions\n type ElementRef = {\n $el: HTMLElement\n }\n\n const xBus = useXBus()\n\n /** It injects {@link ListItem} provided by an ancestor. */\n const injectedListItems = inject<Ref<ListItem[]>>(LIST_ITEMS_KEY as string)\n const gridEl = ref<ElementRef | HTMLElement>()\n const renderedColumnsNumber = ref(0)\n\n /**\n * Emits the {@link XEventsTypes.RenderedColumnsNumberChanged}\n * event whenever the number of columns rendered inside the grid changes.\n */\n watch(\n renderedColumnsNumber,\n () => xBus.emit('RenderedColumnsNumberChanged', renderedColumnsNumber.value),\n { immediate: false },\n )\n\n /**\n * It returns the items passed as props or the injected ones.\n *\n * @returns List of grid items.\n */\n const computedItems = computed<ListItem[] | void>(() => {\n return (\n props.items ??\n injectedListItems?.value ??\n console.warn('It is necessary to pass a prop or inject the list of filters')\n )\n })\n\n /**\n * CSS class based on the column property value so items inside the grid can fill different\n * amount of columns or rows based on how many columns the grid is divided into.\n *\n * @returns CSS class with the column property value.\n */\n const cssClasses = computed(() => `x-base-grid--cols-${props.columns || 'auto'}`)\n\n /**\n * CSSStyleDeclaration object specifying the number of columns the grid is divided into based on\n * the column property value.\n *\n * @returns A CSSStyleDeclaration to use as the style attribute.\n */\n const style = computed<Partial<CSSStyleDeclaration>>(() => ({\n gridTemplateColumns: props.columns\n ? `repeat(${props.columns}, minmax(0, 1fr))`\n : 'repeat(auto-fill, minmax(var(--x-size-min-width-grid-item, 150px), 1fr))',\n }))\n\n /**\n * Maps the item to an object containing: the `item`, its `CSS class` and its slot name.\n *\n * @returns An array of objects containing the item and its CSS class.\n */\n const gridItems = computed<GridItem[]>(() =>\n (computedItems.value as ListItem[]).map(item => {\n const slotName = toKebabCase(item.modelName)\n return {\n slotName,\n item,\n cssClass: `x-base-grid__${slotName}`,\n }\n }),\n )\n\n /**\n * Checks if a given value is an `ElementRef` object.\n *\n * @param value - The value to check.\n * @returns `true` if the value is an `ElementRef` object, `false` otherwise.\n */\n const isElementRef = (value: any): value is ElementRef => {\n return value && value.$el instanceof HTMLElement\n }\n\n /** Updates the number of columns rendered inside the grid. */\n function updateRenderedColumnsNumber() {\n const { gridTemplateColumns } = getComputedStyle(\n isElementRef(gridEl.value) ? gridEl.value.$el : (gridEl.value as Element),\n )\n renderedColumnsNumber.value = gridTemplateColumns.split(' ').length\n }\n\n /** Initialises the rendered columns number and sets a ResizeObserver to keep it updated. */\n let resizeObserver: UseResizeObserverReturn\n onMounted(() => {\n resizeObserver = useResizeObserver(\n gridEl as MaybeComputedElementRef,\n updateRenderedColumnsNumber,\n )\n })\n onBeforeUnmount(() => resizeObserver?.stop())\n\n return {\n gridItems,\n cssClasses,\n style,\n gridEl,\n slots,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-base-grid {\n display: grid;\n grid-auto-flow: dense;\n list-style: none;\n align-items: stretch;\n}\n\n.x-base-grid__banner,\n.x-base-grid__next-queries-group,\n.x-base-grid__related-prompts-group {\n grid-column-start: 1;\n grid-column-end: -1;\n}\n\n.x-base-grid__related-prompts-group.x-staggered-fade-and-slide-leave-active,\n.x-base-grid__related-prompts-group.x-staggered-fade-and-slide-enter-active {\n transition: none;\n position: relative;\n}\n\n.x-base-grid__item {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-grid__item > * {\n flex-grow: 1;\n}\n\n.x-base-grid--cols-auto .x-base-grid__item {\n min-width: var(--x-size-min-width-grid-item);\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a list of elements in different slots depending on their modelName. In order\nto achieve this, it exposes a scopedSlot for each different modelName. In case the items used do not\nhave modelName property, the default slot is used instead. It has a required property, the `items`\nto render, and an optional one, the number of `columns` the grid is divided in. If the number of\ncolumns is not specified, the grid automatically fills the rows with as many columns as it can fit.\n\n### Basic example\n\nIt renders a list of items using the default slot:\n\n```vue\n<template>\n <BaseGrid :items=\"items\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Configuring the number of columns\n\nIt renders a grid with 12 columns instead of 6, which is the default value:\n\n```vue\n<template>\n <BaseGrid :items=\"items\" :columns=\"12\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Rendering usage\n\nConfiguring the number of columns.\n\nIt renders a list of items using the different scopedSlots created by the item's modelName. For\nexample, if you want to use this component as the search grid, you pass the search results (results,\nbanners, promoted, next queries...etc) as items. Each of these results have a different modelName\nand are rendered in different slots.\n\n```vue\n<template>\n <BaseGrid :animation=\"animation\" :items=\"items\">\n <template #banner=\"{ item }\">\n <span class=\"banner\">\n {{ `${item.title} banner` }}\n </span>\n </template>\n <template #next-queries=\"{ item }\">\n <span>\n {{ `${item.totalResults} next queries` }}\n </span>\n </template>\n <template #promoted=\"{ item }\">\n <span class=\"promoted\">\n {{ `${item.title} promoted` }}\n </span>\n </template>\n <template #result=\"{ item }\">\n <BaseResultLink :result=\"item\">\n {{ item.name }}\n </BaseResultLink>\n </template>\n </BaseGrid>\n</template>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseGrid :items=\"items\" style=\"--x-size-min-width-grid-item: 150px\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n</docs>\n"],"names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeStyle","_normalizeClass","_withCtx","_createElementBlock","_Fragment","_renderList","_renderSlot","_createTextVNode","_toDisplayString"],"mappings":";;;;;;AACE,EAAA,OAAAA,SAAA,EAAA,EAAAC,WAAA,CA4BYC,wBA3BL,IAAS,CAAA,SAAA,CAAA,EAAA;AAAA,IACd,GAAI,EAAA,QAAA;AAAA,IACH,KAAA,EAJLC,eAIY,IAAK,CAAA,KAAA,CAAA;AAAA,IACb,KAAA,EALJC,cAKU,CAAA,CAAA,aAAA,EACE,IAAU,CAAA,UAAA,CAAA,CAAA;AAAA,IAClB,GAAI,EAAA,IAAA;AAAA,IACJ,WAAU,EAAA,MAAA;AAAA,GAAA,EAAA;AARd,IAAA,OAAA,EAAAC,OAAA,CAWM,MAAiD;AAAA,OADnDL,SAAA,CAAA,IAAA,CAAA,EAAAM,kBAAA;AAAA,QAkBKC,QAAA;AAAA,QAAA,IAAA;AAAA,QA5BTC,UAW6C,CAAA,IAAA,CAAA,SAAA,EAX7C,CAWe,EAAA,IAAA,EAAM,UAAU,QAAQ,EAAA,KAAA;AADnC,UAAA,OAAAR,SAAA,EAAA,EAAAM,kBAAA;AAAA,YAkBK,IAAA;AAAA,YAAA;AAAA,cAhBF,KAAK,IAAK,CAAA,EAAA;AAAA,cACV,KAAA,EAbPF,cAac,CAAA,CAAA,QAAA,EACF,mBAAmB,CAAA,CAAA;AAAA,aAAA;;AAOb,cAAA,IAAA,CAAA,KAAA,CAAM,QAAQ,CAAA,GAA1BK,UAA6D,CAAA,IAAA,CAAA,MAAA,EAAzB,QAAQ,EAAA;AAAA,gBArBlD,GAAA,EAAA,CAAA;AAAA,gBAqBqD,IAAA;AAAA,eAAA,EAAA,KAAA,CAAA,EAAA,IAAA,CAAA,GAM/CA,UAAqF,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA;AAAA,gBA3B3F,GAAA,EAAA,CAAA;AAAA,gBA2BoB,IAAA;AAAA,eAAA,EAAd,MAAqF;AAAA,gBA3B3FC,eAAA;AAAA,kBAAAC,eAAA,CA2BmC,KAAK,IAAQ,IAAA,IAAA,CAAK,SAAa,IAAA,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,kBAAA,CAAA;AAAA;AAAA,iBAAA;AAAA,eAAA,EAAA,IAAA,CAAA;;;;;;;;;;AA3BjF,IAAA,CAAA,EAAA,CAAA;AAAA;AAAA,GAAA,EAAA,CAAA,EAAA,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA,CAAA;;;;;;"}
|
|
1
|
+
{"version":3,"file":"base-grid.vue.js","sources":["../../../src/components/base-grid.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n ref=\"gridEl\"\n :style=\"style\"\n class=\"x-base-grid\"\n :class=\"cssClasses\"\n tag=\"ul\"\n data-test=\"grid\"\n >\n <li\n v-for=\"{ item, cssClass, slotName } in gridItems\"\n :key=\"item.id\"\n :class=\"cssClass\"\n class=\"x-base-grid__item\"\n >\n <!--\n @slot Customized item rendering. Specifying a slot with the item's modelName will result in\n the item using that slot composition to render.\n @binding {item} item - Item to render\n -->\n <slot v-if=\"slots[slotName]\" :name=\"slotName\" :item=\"item\" />\n <!--\n @slot (required) Default item rendering. This slot will be used by default for rendering\n the item without an specific slot implementation.\n @binding {item} item - Item to render\n -->\n <slot v-else :item=\"item\">{{ item.name || item.modelName || item.id || item }}</slot>\n </li>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { MaybeComputedElementRef, UseResizeObserverReturn } from '@vueuse/core'\nimport type { PropType, Ref } from 'vue'\nimport type { ListItem, VueCSSClasses } from '../utils/types'\nimport { useResizeObserver } from '@vueuse/core'\nimport { computed, defineComponent, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport { toKebabCase } from '../utils/string'\nimport { LIST_ITEMS_KEY } from './decorators/injection.consts'\n\n/**\n * The type returned by the gridItems function. Basically it's a list of items with its CSS\n * classes and a slotName.\n */\ninterface GridItem {\n slotName: string\n item: ListItem\n cssClass: VueCSSClasses\n}\n\n/**\n * Grid component that is able to render different items based on their modelName value. In order\n * to achieve this, it exposes a scopedSlot for each different modelName. In case the items used\n * do not have modelName property, the default slot is used instead. It has a required property:\n * the `items` to render; and an optional one: the number `columns` the grid is divided in. If the\n * number of columns is not specified, the grid automatically fills the rows with as many columns\n * as it can fit.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseGrid',\n props: {\n /** Animation component that will be used to animate the base grid. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * Number of columns the grid is divided into. By default, its value is 0, setting the grid\n * columns mode to auto-fill.\n */\n columns: {\n type: Number,\n default: 0,\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an ID property.\n */\n items: {\n type: Array as PropType<ListItem[]>,\n },\n },\n setup(props, { slots }) {\n // eslint-disable-next-line ts/consistent-type-definitions\n type ElementRef = {\n $el: HTMLElement\n }\n\n const xBus = useXBus()\n\n /** It injects {@link ListItem} provided by an ancestor. */\n const injectedListItems = inject<Ref<ListItem[]>>(LIST_ITEMS_KEY as string)\n const gridEl = ref<ElementRef | HTMLElement>()\n const renderedColumnsNumber = ref(0)\n\n /**\n * Emits the {@link XEventsTypes.RenderedColumnsNumberChanged}\n * event whenever the number of columns rendered inside the grid changes.\n */\n watch(\n renderedColumnsNumber,\n () => xBus.emit('RenderedColumnsNumberChanged', renderedColumnsNumber.value),\n { immediate: false },\n )\n\n /**\n * It returns the items passed as props or the injected ones.\n *\n * @returns List of grid items.\n */\n const computedItems = computed<ListItem[] | void>(() => {\n return (\n props.items ??\n injectedListItems?.value ??\n console.warn('It is necessary to pass a prop or inject the list of filters')\n )\n })\n\n /**\n * CSS class based on the column property value so items inside the grid can fill different\n * amount of columns or rows based on how many columns the grid is divided into.\n *\n * @returns CSS class with the column property value.\n */\n const cssClasses = computed(() => `x-base-grid--cols-${props.columns || 'auto'}`)\n\n /**\n * CSSStyleDeclaration object specifying the number of columns the grid is divided into based on\n * the column property value.\n *\n * @returns A CSSStyleDeclaration to use as the style attribute.\n */\n const style = computed<Partial<CSSStyleDeclaration>>(() => ({\n gridTemplateColumns: props.columns\n ? `repeat(${props.columns}, minmax(0, 1fr))`\n : 'repeat(auto-fill, minmax(var(--x-size-min-width-grid-item, 150px), 1fr))',\n }))\n\n /**\n * Maps the item to an object containing: the `item`, its `CSS class` and its slot name.\n *\n * @returns An array of objects containing the item and its CSS class.\n */\n const gridItems = computed<GridItem[]>(() =>\n (computedItems.value as ListItem[]).map(item => {\n const slotName = toKebabCase(item.modelName)\n return {\n slotName,\n item,\n cssClass: `x-base-grid__${slotName}`,\n }\n }),\n )\n\n /**\n * Checks if a given value is an `ElementRef` object.\n *\n * @param value - The value to check.\n * @returns `true` if the value is an `ElementRef` object, `false` otherwise.\n */\n const isElementRef = (value: any): value is ElementRef => {\n return value && value.$el instanceof HTMLElement\n }\n\n /** Updates the number of columns rendered inside the grid. */\n function updateRenderedColumnsNumber() {\n const { gridTemplateColumns } = getComputedStyle(\n isElementRef(gridEl.value) ? gridEl.value.$el : (gridEl.value as Element),\n )\n renderedColumnsNumber.value = gridTemplateColumns.split(' ').length\n }\n\n /** Initialises the rendered columns number and sets a ResizeObserver to keep it updated. */\n let resizeObserver: UseResizeObserverReturn\n onMounted(() => {\n resizeObserver = useResizeObserver(\n gridEl as MaybeComputedElementRef,\n updateRenderedColumnsNumber,\n )\n })\n onBeforeUnmount(() => resizeObserver?.stop())\n\n return {\n gridItems,\n cssClasses,\n style,\n gridEl,\n slots,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-base-grid {\n display: grid;\n grid-auto-flow: dense;\n list-style: none;\n align-items: stretch;\n}\n\n.x-base-grid__banner,\n.x-base-grid__next-queries-group,\n.x-base-grid__related-prompts-group {\n grid-column-start: 1;\n grid-column-end: -1;\n}\n\n.x-base-grid__related-prompts-group.x-staggered-fade-and-slide-leave-active,\n.x-base-grid__related-prompts-group.x-staggered-fade-and-slide-enter-active {\n transition: none;\n position: relative;\n}\n\n.x-base-grid__item {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-grid__item > * {\n flex-grow: 1;\n}\n\n.x-base-grid--cols-auto .x-base-grid__item {\n min-width: var(--x-size-min-width-grid-item);\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a list of elements in different slots depending on their modelName. In order\nto achieve this, it exposes a scopedSlot for each different modelName. In case the items used do not\nhave modelName property, the default slot is used instead. It has a required property, the `items`\nto render, and an optional one, the number of `columns` the grid is divided in. If the number of\ncolumns is not specified, the grid automatically fills the rows with as many columns as it can fit.\n\n### Basic example\n\nIt renders a list of items using the default slot:\n\n```vue\n<template>\n <BaseGrid :items=\"items\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Configuring the number of columns\n\nIt renders a grid with 12 columns instead of 6, which is the default value:\n\n```vue\n<template>\n <BaseGrid :items=\"items\" :columns=\"12\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Rendering usage\n\nConfiguring the number of columns.\n\nIt renders a list of items using the different scopedSlots created by the item's modelName. For\nexample, if you want to use this component as the search grid, you pass the search results (results,\nbanners, promoted, next queries...etc) as items. Each of these results have a different modelName\nand are rendered in different slots.\n\n```vue\n<template>\n <BaseGrid :animation=\"animation\" :items=\"items\">\n <template #banner=\"{ item }\">\n <span class=\"banner\">\n {{ `${item.title} banner` }}\n </span>\n </template>\n <template #next-queries=\"{ item }\">\n <span>\n {{ `${item.totalResults} next queries` }}\n </span>\n </template>\n <template #promoted=\"{ item }\">\n <span class=\"promoted\">\n {{ `${item.title} promoted` }}\n </span>\n </template>\n <template #result=\"{ item }\">\n <BaseResultLink :result=\"item\">\n {{ item.name }}\n </BaseResultLink>\n </template>\n </BaseGrid>\n</template>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseGrid :items=\"items\" style=\"--x-size-min-width-grid-item: 150px\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n</docs>\n"],"names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeStyle","_normalizeClass","_createElementBlock","_Fragment","_renderList","_renderSlot","_createTextVNode","_toDisplayString"],"mappings":";;;;;;AACE,EAAA,OAAAA,SAAA,EAAA,EAAAC,WAAA,CA4BYC,wBA3BL,IAAS,CAAA,SAAA,CAAA,EAAA;AAAA,IACd,GAAI,EAAA,QAAA;AAAA,IACH,KAAA,EAAKC,eAAE,IAAK,CAAA,KAAA,CAAA;AAAA,IACb,KAAA,EAAKC,cAAC,CAAA,CAAA,aAAA,EACE,IAAU,CAAA,UAAA,CAAA,CAAA;AAAA,IAClB,GAAI,EAAA,IAAA;AAAA,IACJ,WAAU,EAAA,MAAA;AAAA,GAAA,EAAA;qBAGR,MAAiD;AAAA,OADnDJ,SAAA,CAAA,IAAA,CAAA,EAAAK,kBAAA;AAAA,QAkBKC,QAAA;AAAA,QAAA,IAAA;AAAA,QAAAC,UAAA,CAjBoC,IAAS,CAAA,SAAA,EAAA,CAAA,EAAvC,IAAM,EAAA,QAAA,EAAU,QAAQ,EAAA,KAAA;AADnC,UAAA,OAAAP,SAAA,EAAA,EAAAK,kBAAA;AAAA,YAkBK,IAAA;AAAA,YAAA;AAAA,cAhBF,KAAK,IAAK,CAAA,EAAA;AAAA,cACV,KAAA,EAAKD,cAAE,CAAA,CAAA,QAAA,EACF,mBAAmB,CAAA,CAAA;AAAA,aAAA;;AAOb,cAAA,IAAA,CAAA,KAAA,CAAM,QAAQ,CAAA,GAA1BI,UAA6D,CAAA,IAAA,CAAA,MAAA,EAAzB,QAAQ,EAAA;AAAA,gBAAA,GAAA,EAAA,CAAA;AAAG,gBAAA,IAAA;AAAA,eAAA,EAAA,KAAA,CAAA,EAAA,IAAA,CAAA,GAM/CA,UAAqF,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA;AAAA,gBAAA,GAAA,EAAA,CAAA;AAAvE,gBAAA,IAAA;AAAA,eAAA,EAAd,MAAqF;AAAA,gBAAAC,eAAA;AAAxD,kBAAAC,eAAA,CAAA,IAAA,CAAK,IAAQ,IAAA,IAAA,CAAK,SAAa,IAAA,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,kBAAA,CAAA;AAAA;AAAA,iBAAA;AAAA,eAAA,EAAA,IAAA,CAAA;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-keyboard-navigation.vue.js","sources":["../../../src/components/base-keyboard-navigation.vue"],"sourcesContent":["<template>\n <div\n ref=\"el\"\n class=\"x-keyboard-navigation\"\n data-test=\"keyboard-navigation\"\n @keydown.up.down.right.left.prevent=\"focusNextNavigableElement\"\n >\n <!-- @slot (Required) Container content -->\n <slot />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport type { SpatialNavigation } from '../services/services.types'\n\nimport type { ArrowKey, EventsForDirectionLimit, TakeNavigationControl } from '../utils/types'\nimport type { XEventsOf } from '../wiring/events.types'\nimport type { WireMetadata } from '../wiring/wiring.types'\nimport { computed, defineComponent, onMounted, ref } from 'vue'\nimport { useXBus } from '../composables'\nimport { DirectionalFocusNavigationService } from '../services/directional-focus-navigation.service'\n\n/**\n * Base component to handle keyboard navigation for elements inside it. It has a required slot to\n * include the navigable elements.\n *\n * @remarks\n * The component can be customized through props: an array of navigationHijacker objects, which\n * contains: the xEvent to listen to, the moduleName in charge of emitting the event and to which\n * direction it should react to; to take control of the navigation and eventsForDirectionLimit, to\n * emit an xEvent when reaching the navigation limit in any direction.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseKeyboardNavigation',\n props: {\n /**\n * An array of {@link TakeNavigationControl} objects defining when to\n * take control of the keyboard navigation.\n */\n navigationHijacker: {\n type: Array as PropType<TakeNavigationControl[]>,\n default: () => [\n { xEvent: 'UserPressedArrowKey', moduleName: 'searchBox', direction: 'ArrowDown' },\n ],\n },\n /**\n * An {@link EventsForDirectionLimit} to emit when the user is already at the furthest element\n * in a direction and tries to keep going on the same direction.\n */\n eventsForDirectionLimit: {\n type: Object as PropType<Partial<EventsForDirectionLimit>>,\n default: () => ({ ArrowUp: 'UserReachedEmpathizeTop' }),\n },\n },\n setup(props) {\n const el = ref<HTMLElement>()\n const xBus = useXBus()\n\n /**\n * The {@link SpatialNavigation} service to use.\n */\n let navigationService!: SpatialNavigation\n\n /**\n * The element to focus.\n */\n let elementToFocus: HTMLElement | undefined\n\n /**\n * Get the navigation hijacker events.\n *\n * @remarks\n * If the same {@link XEvent} is defined multiple times it is only inserted once.\n *\n * @returns The events to hijack the navigation.\n */\n const navigationHijackerEvents = computed((): XEventsOf<ArrowKey>[] => {\n const eventsSet = props.navigationHijacker.map(({ xEvent }) => xEvent)\n return Array.from(new Set(eventsSet))\n })\n\n onMounted(() => {\n // TODO Replace this with injection\n navigationService = new DirectionalFocusNavigationService(el.value!)\n })\n\n /**\n * Checks if the component has to take control of the keyboard navigation.\n *\n * @param eventPayload - The {@link ArrowKey}.\n * @param metadata - The {@link WireMetadata}.\n *\n * @returns Whether the component needs to take control of the keyboard navigation or not.\n * @internal\n */\n function hasToTakeNavigationControl(eventPayload: ArrowKey, metadata: WireMetadata): boolean {\n return props.navigationHijacker.some(\n ({ moduleName, direction }) =>\n moduleName === metadata.moduleName && direction === eventPayload,\n )\n }\n\n /**\n * Focus the next navigable element returned by the navigation service.\n *\n * @param direction - The navigation direction.\n * @internal\n */\n function focusNextNavigableElement(direction: ArrowKey | KeyboardEvent): void {\n const dir = typeof direction === 'object' ? (direction.key as ArrowKey) : direction\n const nextElementToFocus = navigationService?.navigateTo(dir)\n\n if (elementToFocus !== nextElementToFocus) {\n elementToFocus = nextElementToFocus\n elementToFocus.focus()\n } else {\n emitDirectionalLimitReached(dir)\n elementToFocus = undefined\n }\n }\n\n /**\n * Emit the {@link XEvent} associated to the navigation's direction when reaching its limit.\n *\n * @param direction - The navigation direction.\n * @internal\n */\n function emitDirectionalLimitReached(direction: ArrowKey): void {\n const xEvent = props.eventsForDirectionLimit?.[direction]\n if (xEvent) {\n xBus.emit(xEvent, undefined, { target: elementToFocus })\n }\n }\n\n /**\n * Trigger navigation if this component is in control of it.\n *\n * @param eventPayload - The {@link @empathyco/x-bus#SubjectPayload.eventPayload}.\n * @param metadata - The {@link @empathyco/x-bus#SubjectPayload.metadata}.\n * @public\n */\n navigationHijackerEvents.value.forEach(event => {\n xBus.on(event, true).subscribe(({ eventPayload, metadata }) => {\n if (hasToTakeNavigationControl(eventPayload, metadata)) {\n focusNextNavigableElement(eventPayload)\n }\n })\n })\n\n return { el, focusNextNavigableElement }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nAn event that the component will emit:\n\n- [`UserReachedEmpathizeTop`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts):\n the event emitted by default when the container reaches its top navigation, but more events can be\n emitted for each direction using the `eventsForDirectionLimit` prop.\n\n## Examples\n\nThis component has a slot to inject other components inside it. The component expects a required\nprop, navigationHijacker, which is an array of objects containing: the xEvent to listen to, the\nmoduleName in charge of emitting the event and to which direction it should react to; to take\ncontrol of the navigation. It has another prop, optional in this case, to emit an xEvent when\nreaching the navigation limit in any direction.\n\n### Basic Usage\n\n```vue\n<KeyboardNavigation>\n <QuerySuggestions/>\n</KeyboardNavigation>\n```\n\n### Defining multiple conditions to take navigation's control\n\n```vue\n<KeyboardNavigation\n :navigationHijacker=\"[\n {\n xEvent: 'UserPressedArrowKey',\n moduleName: 'searchBox',\n direction: 'ArrowDown',\n },\n {\n xEvent: 'UserPressedArrowKey',\n moduleName: 'facets',\n direction: 'ArrowRight',\n },\n ]\"\n>\n <QuerySuggestions/>\n</KeyboardNavigation>\n```\n\n### Defining events to emit when reaching a navigation limit\n\n```vue\n<KeyboardNavigation\n :navigationHijacker=\"[\n {\n xEvent: 'UserPressedArrowKey',\n moduleName: 'searchBox',\n direction: 'ArrowDown',\n },\n ]\"\n :eventsForDirectionLimit=\"{\n ArrowUp: 'UserReachedEmpathizeTop',\n }\"\n>\n <QuerySuggestions/>\n</KeyboardNavigation>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","
|
|
1
|
+
{"version":3,"file":"base-keyboard-navigation.vue.js","sources":["../../../src/components/base-keyboard-navigation.vue"],"sourcesContent":["<template>\n <div\n ref=\"el\"\n class=\"x-keyboard-navigation\"\n data-test=\"keyboard-navigation\"\n @keydown.up.down.right.left.prevent=\"focusNextNavigableElement\"\n >\n <!-- @slot (Required) Container content -->\n <slot />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport type { SpatialNavigation } from '../services/services.types'\n\nimport type { ArrowKey, EventsForDirectionLimit, TakeNavigationControl } from '../utils/types'\nimport type { XEventsOf } from '../wiring/events.types'\nimport type { WireMetadata } from '../wiring/wiring.types'\nimport { computed, defineComponent, onMounted, ref } from 'vue'\nimport { useXBus } from '../composables'\nimport { DirectionalFocusNavigationService } from '../services/directional-focus-navigation.service'\n\n/**\n * Base component to handle keyboard navigation for elements inside it. It has a required slot to\n * include the navigable elements.\n *\n * @remarks\n * The component can be customized through props: an array of navigationHijacker objects, which\n * contains: the xEvent to listen to, the moduleName in charge of emitting the event and to which\n * direction it should react to; to take control of the navigation and eventsForDirectionLimit, to\n * emit an xEvent when reaching the navigation limit in any direction.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseKeyboardNavigation',\n props: {\n /**\n * An array of {@link TakeNavigationControl} objects defining when to\n * take control of the keyboard navigation.\n */\n navigationHijacker: {\n type: Array as PropType<TakeNavigationControl[]>,\n default: () => [\n { xEvent: 'UserPressedArrowKey', moduleName: 'searchBox', direction: 'ArrowDown' },\n ],\n },\n /**\n * An {@link EventsForDirectionLimit} to emit when the user is already at the furthest element\n * in a direction and tries to keep going on the same direction.\n */\n eventsForDirectionLimit: {\n type: Object as PropType<Partial<EventsForDirectionLimit>>,\n default: () => ({ ArrowUp: 'UserReachedEmpathizeTop' }),\n },\n },\n setup(props) {\n const el = ref<HTMLElement>()\n const xBus = useXBus()\n\n /**\n * The {@link SpatialNavigation} service to use.\n */\n let navigationService!: SpatialNavigation\n\n /**\n * The element to focus.\n */\n let elementToFocus: HTMLElement | undefined\n\n /**\n * Get the navigation hijacker events.\n *\n * @remarks\n * If the same {@link XEvent} is defined multiple times it is only inserted once.\n *\n * @returns The events to hijack the navigation.\n */\n const navigationHijackerEvents = computed((): XEventsOf<ArrowKey>[] => {\n const eventsSet = props.navigationHijacker.map(({ xEvent }) => xEvent)\n return Array.from(new Set(eventsSet))\n })\n\n onMounted(() => {\n // TODO Replace this with injection\n navigationService = new DirectionalFocusNavigationService(el.value!)\n })\n\n /**\n * Checks if the component has to take control of the keyboard navigation.\n *\n * @param eventPayload - The {@link ArrowKey}.\n * @param metadata - The {@link WireMetadata}.\n *\n * @returns Whether the component needs to take control of the keyboard navigation or not.\n * @internal\n */\n function hasToTakeNavigationControl(eventPayload: ArrowKey, metadata: WireMetadata): boolean {\n return props.navigationHijacker.some(\n ({ moduleName, direction }) =>\n moduleName === metadata.moduleName && direction === eventPayload,\n )\n }\n\n /**\n * Focus the next navigable element returned by the navigation service.\n *\n * @param direction - The navigation direction.\n * @internal\n */\n function focusNextNavigableElement(direction: ArrowKey | KeyboardEvent): void {\n const dir = typeof direction === 'object' ? (direction.key as ArrowKey) : direction\n const nextElementToFocus = navigationService?.navigateTo(dir)\n\n if (elementToFocus !== nextElementToFocus) {\n elementToFocus = nextElementToFocus\n elementToFocus.focus()\n } else {\n emitDirectionalLimitReached(dir)\n elementToFocus = undefined\n }\n }\n\n /**\n * Emit the {@link XEvent} associated to the navigation's direction when reaching its limit.\n *\n * @param direction - The navigation direction.\n * @internal\n */\n function emitDirectionalLimitReached(direction: ArrowKey): void {\n const xEvent = props.eventsForDirectionLimit?.[direction]\n if (xEvent) {\n xBus.emit(xEvent, undefined, { target: elementToFocus })\n }\n }\n\n /**\n * Trigger navigation if this component is in control of it.\n *\n * @param eventPayload - The {@link @empathyco/x-bus#SubjectPayload.eventPayload}.\n * @param metadata - The {@link @empathyco/x-bus#SubjectPayload.metadata}.\n * @public\n */\n navigationHijackerEvents.value.forEach(event => {\n xBus.on(event, true).subscribe(({ eventPayload, metadata }) => {\n if (hasToTakeNavigationControl(eventPayload, metadata)) {\n focusNextNavigableElement(eventPayload)\n }\n })\n })\n\n return { el, focusNextNavigableElement }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nAn event that the component will emit:\n\n- [`UserReachedEmpathizeTop`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts):\n the event emitted by default when the container reaches its top navigation, but more events can be\n emitted for each direction using the `eventsForDirectionLimit` prop.\n\n## Examples\n\nThis component has a slot to inject other components inside it. The component expects a required\nprop, navigationHijacker, which is an array of objects containing: the xEvent to listen to, the\nmoduleName in charge of emitting the event and to which direction it should react to; to take\ncontrol of the navigation. It has another prop, optional in this case, to emit an xEvent when\nreaching the navigation limit in any direction.\n\n### Basic Usage\n\n```vue\n<KeyboardNavigation>\n <QuerySuggestions/>\n</KeyboardNavigation>\n```\n\n### Defining multiple conditions to take navigation's control\n\n```vue\n<KeyboardNavigation\n :navigationHijacker=\"[\n {\n xEvent: 'UserPressedArrowKey',\n moduleName: 'searchBox',\n direction: 'ArrowDown',\n },\n {\n xEvent: 'UserPressedArrowKey',\n moduleName: 'facets',\n direction: 'ArrowRight',\n },\n ]\"\n>\n <QuerySuggestions/>\n</KeyboardNavigation>\n```\n\n### Defining events to emit when reaching a navigation limit\n\n```vue\n<KeyboardNavigation\n :navigationHijacker=\"[\n {\n xEvent: 'UserPressedArrowKey',\n moduleName: 'searchBox',\n direction: 'ArrowDown',\n },\n ]\"\n :eventsForDirectionLimit=\"{\n ArrowUp: 'UserReachedEmpathizeTop',\n }\"\n>\n <QuerySuggestions/>\n</KeyboardNavigation>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_renderSlot"],"mappings":";;;;;AACE,EAAA,OAAAA,SAAA,EAAA,EAAAC,kBAAA;AAAA,IAQM,KAAA;AAAA,IAAA;AAAA,MAPJ,GAAI,EAAA,IAAA;AAAA,MACJ,KAAM,EAAA,uBAAA;AAAA,MACN,WAAU,EAAA,qBAAA;AAAA,MACT,SAAA,EAAO,8DAA6B,IAAyB,CAAA,yBAAA,IAAA,IAAA,CAAA,yBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,CAAA,CAAA,CAAA;AAAA,KAAA;;MAG9DC,UAAQ,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;AAAA,KAAA;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-rating.vue.js","sources":["../../../src/components/base-rating.vue"],"sourcesContent":["<template>\n <span class=\"x-rating\" role=\"img\" :aria-label=\"ariaLabel\" data-test=\"rating\">\n <div class=\"x-rating--empty\" data-test=\"rating-empty\">\n <!--\n @slot The content to render as empty icon\n -->\n <slot v-for=\"i in max\" name=\"empty-icon\">\n <DefaultIcon :key=\"i\" class=\"x-rating__default-icon x-rating__default-icon--empty\" />\n </slot>\n </div>\n <div\n class=\"x-rating--filled\"\n :style=\"{ width: calculateFilledWrapperWidth }\"\n data-test=\"rating-filled\"\n >\n <!--\n @slot The content to render as filled icon\n -->\n <slot v-for=\"i in max\" name=\"filled-icon\">\n <DefaultIcon :key=\"i\" class=\"x-rating__default-icon x-rating__default-icon--filled\" />\n </slot>\n </div>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent } from 'vue'\nimport StarIcon from './icons/star.vue'\n\n/**\n * Rating component. This component renders a set of elements filled based on the value passed as\n * prop.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseRating',\n components: {\n DefaultIcon: StarIcon,\n },\n props: {\n /**\n * Numeric value used to calculates the width of the filled elements.\n *\n * @public\n */\n value: {\n type: Number,\n required: true,\n },\n /**\n * Maximum number of elements to paint.\n *\n * @public\n */\n max: {\n type: Number,\n default: 5,\n },\n },\n setup(props) {\n /**\n * Calculates the width of the filled elements wrapper.\n *\n * @returns The % of the wrapper width.\n *\n * @internal\n */\n const calculateFilledWrapperWidth = computed(() => {\n return props.value < 0 ? '0%' : `${(props.value * 100) / props.max}%`\n })\n\n /**\n * Creates the aria label for accessibility purpose.\n *\n * @returns The aria label.\n *\n * @internal\n */\n const ariaLabel = computed(() => {\n return `${props.value}/${props.max}`\n })\n\n return {\n calculateFilledWrapperWidth,\n ariaLabel,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-rating {\n position: relative;\n display: inline-block;\n max-width: fit-content;\n}\n\n.x-rating--empty {\n overflow: hidden;\n display: flex;\n flex-flow: row nowrap;\n white-space: nowrap;\n}\n\n.x-rating--filled {\n display: flex;\n flex-flow: row nowrap;\n white-space: nowrap;\n position: absolute;\n overflow: hidden;\n top: 0;\n left: 0;\n height: 100%;\n}\n\n.x-rating__default-icon {\n fill: currentColor;\n stroke: currentColor;\n}\n\n.x-rating__default-icon--empty {\n fill: none;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component receives a `value` as prop and renders a set of elements, which will be filled based\non this value.\n\n### Basic usage\n\n```vue\n<BaseRating :value=\"5.23\" />\n```\n\n### Customizing its contents\n\n```vue\n<BaseRating :value=\"7.15\" :max=\"10\">\n <template #filled-icon>\n <TestIcon/>\n </template>\n <template #empty-icon>\n <TestIcon/>\n </template>\n</BaseRating>\n```\n</docs>\n"],"names":["_createElementBlock","_createElementVNode","_openBlock","_Fragment","_renderList","_renderSlot","_createBlock","_normalizeStyle"],"mappings":"
|
|
1
|
+
{"version":3,"file":"base-rating.vue.js","sources":["../../../src/components/base-rating.vue"],"sourcesContent":["<template>\n <span class=\"x-rating\" role=\"img\" :aria-label=\"ariaLabel\" data-test=\"rating\">\n <div class=\"x-rating--empty\" data-test=\"rating-empty\">\n <!--\n @slot The content to render as empty icon\n -->\n <slot v-for=\"i in max\" name=\"empty-icon\">\n <DefaultIcon :key=\"i\" class=\"x-rating__default-icon x-rating__default-icon--empty\" />\n </slot>\n </div>\n <div\n class=\"x-rating--filled\"\n :style=\"{ width: calculateFilledWrapperWidth }\"\n data-test=\"rating-filled\"\n >\n <!--\n @slot The content to render as filled icon\n -->\n <slot v-for=\"i in max\" name=\"filled-icon\">\n <DefaultIcon :key=\"i\" class=\"x-rating__default-icon x-rating__default-icon--filled\" />\n </slot>\n </div>\n </span>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent } from 'vue'\nimport StarIcon from './icons/star.vue'\n\n/**\n * Rating component. This component renders a set of elements filled based on the value passed as\n * prop.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseRating',\n components: {\n DefaultIcon: StarIcon,\n },\n props: {\n /**\n * Numeric value used to calculates the width of the filled elements.\n *\n * @public\n */\n value: {\n type: Number,\n required: true,\n },\n /**\n * Maximum number of elements to paint.\n *\n * @public\n */\n max: {\n type: Number,\n default: 5,\n },\n },\n setup(props) {\n /**\n * Calculates the width of the filled elements wrapper.\n *\n * @returns The % of the wrapper width.\n *\n * @internal\n */\n const calculateFilledWrapperWidth = computed(() => {\n return props.value < 0 ? '0%' : `${(props.value * 100) / props.max}%`\n })\n\n /**\n * Creates the aria label for accessibility purpose.\n *\n * @returns The aria label.\n *\n * @internal\n */\n const ariaLabel = computed(() => {\n return `${props.value}/${props.max}`\n })\n\n return {\n calculateFilledWrapperWidth,\n ariaLabel,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-rating {\n position: relative;\n display: inline-block;\n max-width: fit-content;\n}\n\n.x-rating--empty {\n overflow: hidden;\n display: flex;\n flex-flow: row nowrap;\n white-space: nowrap;\n}\n\n.x-rating--filled {\n display: flex;\n flex-flow: row nowrap;\n white-space: nowrap;\n position: absolute;\n overflow: hidden;\n top: 0;\n left: 0;\n height: 100%;\n}\n\n.x-rating__default-icon {\n fill: currentColor;\n stroke: currentColor;\n}\n\n.x-rating__default-icon--empty {\n fill: none;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component receives a `value` as prop and renders a set of elements, which will be filled based\non this value.\n\n### Basic usage\n\n```vue\n<BaseRating :value=\"5.23\" />\n```\n\n### Customizing its contents\n\n```vue\n<BaseRating :value=\"7.15\" :max=\"10\">\n <template #filled-icon>\n <TestIcon/>\n </template>\n <template #empty-icon>\n <TestIcon/>\n </template>\n</BaseRating>\n```\n</docs>\n"],"names":["_createElementBlock","_createElementVNode","_openBlock","_Fragment","_renderList","_renderSlot","_createBlock","_normalizeStyle"],"mappings":";;;;;;;EAES,KAAM,EAAA,iBAAA;AAAA,EAAkB,WAAU,EAAA,cAAA;;;;sBADzCA,kBAqBO,CAAA,MAAA,EAAA;AAAA,IArBD,KAAM,EAAA,UAAA;AAAA,IAAW,IAAK,EAAA,KAAA;AAAA,IAAO,YAAY,EAAA,IAAA,CAAA,SAAA;AAAA,IAAW,WAAU,EAAA,QAAA;AAAA,GAAA,EAAA;AAClE,IAAAC,kBAAA,CAOM,OAPN,UAOM,EAAA;AAAA,OAHJC,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA;AAAA,QAEOG,QAAA;AAAA,QAAA,IAAA;AAAA,QAFWC,UAAA,CAAA,IAAA,CAAA,GAAA,EAAG,CAAR,CAAC,KAAA;AAAd,UAAA,OAAAC,UAAA,CAEO,+BAFP,MAEO;AAAA,aAAAH,SAAA,EAAA,EADLI,WAAqF,CAAA,sBAAA,EAAA;AAAA,cAAvE,GAAK,EAAA,CAAA;AAAA,cAAG,KAAM,EAAA,sDAAA;AAAA,aAAA,CAAA;;;;;;;AAGhC,IAAAL,kBAAA;AAAA,MAWM,KAAA;AAAA,MAAA;AAAA,QAVJ,KAAM,EAAA,kBAAA;AAAA,QACL,KAAA,EAAKM,wBAAW,IAA2B,CAAA,2BAAA,EAAA,CAAA;AAAA,QAC5C,WAAU,EAAA,eAAA;AAAA,OAAA;;AAKV,SAAAL,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA;AAAA,UAEOG,QAAA;AAAA,UAAA,IAAA;AAAA,UAFWC,UAAA,CAAA,IAAA,CAAA,GAAA,EAAG,CAAR,CAAC,KAAA;AAAd,YAAA,OAAAC,UAAA,CAEO,gCAFP,MAEO;AAAA,eAAAH,SAAA,EAAA,EADLI,WAAsF,CAAA,sBAAA,EAAA;AAAA,gBAAxE,GAAK,EAAA,CAAA;AAAA,gBAAG,KAAM,EAAA,uDAAA;AAAA,eAAA,CAAA;;;;;;;;;;;;;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import injectCss from '../../tools/inject-css.js';
|
|
2
2
|
|
|
3
|
-
var css = ".x-rating[data-v-f3b7cb68]{display:inline-block;max-width:fit-content;position:relative}.x-rating--empty[data-v-f3b7cb68]
|
|
3
|
+
var css = ".x-rating[data-v-f3b7cb68]{display:inline-block;max-width:fit-content;position:relative}.x-rating--empty[data-v-f3b7cb68]{display:flex;flex-flow:row nowrap;overflow:hidden;white-space:nowrap}.x-rating--filled[data-v-f3b7cb68]{display:flex;flex-flow:row nowrap;height:100%;left:0;overflow:hidden;position:absolute;top:0;white-space:nowrap}.x-rating__default-icon[data-v-f3b7cb68]{fill:currentColor;stroke:currentColor}.x-rating__default-icon--empty[data-v-f3b7cb68]{fill:none}";
|
|
4
4
|
injectCss(css);
|
|
5
5
|
|
|
6
6
|
export { css, css as default };
|
|
@@ -6,21 +6,7 @@ import _export_sfc from '../_virtual/_plugin-vue_export-helper.js';
|
|
|
6
6
|
const _hoisted_1 = { class: "x-base-slider" };
|
|
7
7
|
const _hoisted_2 = { class: "x-base-slider__selected" };
|
|
8
8
|
const _hoisted_3 = { class: "x-base-slider__selected-min" };
|
|
9
|
-
const _hoisted_4 =
|
|
10
|
-
"span",
|
|
11
|
-
null,
|
|
12
|
-
"min value",
|
|
13
|
-
-1
|
|
14
|
-
/* HOISTED */
|
|
15
|
-
);
|
|
16
|
-
const _hoisted_5 = { class: "x-base-slider__selected-max" };
|
|
17
|
-
const _hoisted_6 = /* @__PURE__ */ createElementVNode(
|
|
18
|
-
"span",
|
|
19
|
-
null,
|
|
20
|
-
"max value",
|
|
21
|
-
-1
|
|
22
|
-
/* HOISTED */
|
|
23
|
-
);
|
|
9
|
+
const _hoisted_4 = { class: "x-base-slider__selected-max" };
|
|
24
10
|
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
25
11
|
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
26
12
|
createElementVNode(
|
|
@@ -36,7 +22,13 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
36
22
|
createElementVNode("div", _hoisted_2, [
|
|
37
23
|
renderSlot(_ctx.$slots, "default", { rangeSelected: _ctx.rangeSelected }, () => [
|
|
38
24
|
createElementVNode("p", _hoisted_3, [
|
|
39
|
-
|
|
25
|
+
_cache[0] || (_cache[0] = createElementVNode(
|
|
26
|
+
"span",
|
|
27
|
+
null,
|
|
28
|
+
"min value",
|
|
29
|
+
-1
|
|
30
|
+
/* CACHED */
|
|
31
|
+
)),
|
|
40
32
|
createElementVNode(
|
|
41
33
|
"span",
|
|
42
34
|
null,
|
|
@@ -45,8 +37,14 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
45
37
|
/* TEXT */
|
|
46
38
|
)
|
|
47
39
|
]),
|
|
48
|
-
createElementVNode("p",
|
|
49
|
-
|
|
40
|
+
createElementVNode("p", _hoisted_4, [
|
|
41
|
+
_cache[1] || (_cache[1] = createElementVNode(
|
|
42
|
+
"span",
|
|
43
|
+
null,
|
|
44
|
+
"max value",
|
|
45
|
+
-1
|
|
46
|
+
/* CACHED */
|
|
47
|
+
)),
|
|
50
48
|
createElementVNode(
|
|
51
49
|
"span",
|
|
52
50
|
null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-slider.vue.js","sources":["../../../src/components/base-slider.vue"],"sourcesContent":["<template>\n <div class=\"x-base-slider\">\n <div ref=\"slider\" :class=\"['x-base-slider__nouislider'].concat(`${contentClass}`)\" />\n <div class=\"x-base-slider__selected\">\n <!--\n @slot Default selected range rendering. This slot will be used by default for rendering\n the selected range without an specific slot implementation.\n @binding {number[]} rangeSelected - The selected range values. Min position 0, Max position 1.\n -->\n <slot :range-selected=\"rangeSelected\">\n <p class=\"x-base-slider__selected-min\">\n <span>min value</span>\n <span>\n {{ rangeSelected[0] }}\n </span>\n </p>\n <p class=\"x-base-slider__selected-max\">\n <span>max value</span>\n <span>\n {{ rangeSelected[1] }}\n </span>\n </p>\n </slot>\n </div>\n </div>\n</template>\n<script lang=\"ts\">\nimport type { API } from 'nouislider'\nimport type { PropType } from 'vue'\nimport { create } from 'nouislider'\nimport { computed, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'\n\n/**\n * This component implements a range slider and prints the selected values.\n * It receives a threshold prop to set the limits and uses v-model to get and set\n * the selected values.\n *\n * It makes use of the nouslider library @see https://refreshless.com/nouislider/\n * for the slider implementation.\n *\n */\nexport default defineComponent({\n name: 'BaseSlider',\n props: {\n /** The threshold prop sets the limits for the slider. */\n threshold: {\n type: Object as PropType<{ min: number; max: number }>,\n default: () => ({ min: 0, max: Number.MAX_SAFE_INTEGER }),\n },\n /** The modelValue prop sets the initial values for the slider. */\n modelValue: {\n type: Object as PropType<{ min: number; max: number }>,\n required: true,\n },\n /** Class to be able to customize slider styles. */\n contentClass: {\n type: String,\n default: '',\n },\n },\n /**\n * The component emits an event with the selected values whenever\n * the user changes the slider.\n */\n emits: ['update:modelValue'],\n setup(props, { emit }) {\n /** The nouislider instance. */\n let sliderInstance: API\n /** The nouislider element reference. */\n const slider = ref<HTMLElement>()\n\n /** The selected min value. */\n const minSelected = ref(props.modelValue?.min ?? props.threshold.min)\n /** The selected max value. */\n const maxSelected = ref(props.modelValue?.max ?? props.threshold.max)\n\n /** The selected range as an array. */\n const rangeSelected = computed(() => [minSelected.value, maxSelected.value])\n /** The range for the nouislider. */\n const slideRange = computed(() => ({ min: props.threshold.min, max: props.threshold.max }))\n\n onMounted(() => {\n // Create the slider instance\n sliderInstance = create(slider.value!, {\n start: rangeSelected.value,\n range: slideRange.value,\n step: 1,\n connect: true,\n margin: 1,\n })\n\n // Update the selected values when the slider update its values\n sliderInstance.on('update', ([min, max]) => {\n minSelected.value = Number(min)\n maxSelected.value = Number(max)\n })\n\n // Emits the selected values when the slider values change\n sliderInstance.on('change', () =>\n emit('update:modelValue', { min: minSelected.value, max: maxSelected.value }),\n )\n })\n\n onUnmounted(() => {\n // Waiting to finish the collapse animation before destroying it\n setTimeout(sliderInstance.destroy.bind(sliderInstance), 600)\n })\n\n /**\n * Watch the threshold prop to update the slider state and emit the selected values.\n */\n watch(\n () => props.threshold,\n ({ min, max }) => {\n sliderInstance.updateOptions({ range: slideRange.value, start: [min, max] }, false)\n emit('update:modelValue', { min, max })\n },\n )\n\n /**\n * Watch the modelValue prop to update the slider state.\n *\n * @remarks It only update the values if the values are corrects. It means,\n * values within the threshold limits and not equal to the current values.\n *\n * @returns Undefined.\n */\n watch([() => props.modelValue.min, () => props.modelValue.max], ([min, max]) => {\n // Check if the values are the same\n if (min === minSelected.value && max === maxSelected.value) {\n return\n }\n\n // Validate the values\n const minValidated = min < props.threshold.min ? props.threshold.min : min\n const maxValidated = max > props.threshold.max ? props.threshold.max : max\n\n // Update the nouislider values\n sliderInstance.set([minValidated, maxValidated])\n\n // Emit the selected values\n if (minValidated !== min || maxValidated !== max) {\n emit('update:modelValue', { min: minValidated, max: maxValidated })\n }\n })\n\n return {\n slider,\n rangeSelected,\n }\n },\n})\n</script>\n<style lang=\"css\">\n@import 'nouislider/dist/nouislider.css';\n/** Customize nouislider styles: https://refreshless.com/nouislider/examples/#section-styling */\n\n.x-base-slider {\n gap: 16px;\n}\n\n.x-base-slider,\n.x-base-slider__selected-min,\n.x-base-slider__selected-max {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-slider__selected {\n display: inline-flex;\n}\n\n.x-base-slider__selected-min,\n.x-base-slider__selected-max {\n flex: 50%;\n}\n\n.x-base-slider__nouislider {\n margin: 16px 0;\n padding: 0 16px;\n}\n\n.x-base-slider__nouislider .noUi-handle {\n box-shadow: none;\n}\n\n.x-base-slider__nouislider .noUi-handle:before,\n.x-base-slider__nouislider .noUi-handle:after {\n content: none;\n}\n</style>\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a slider and the selected values. The component needs the threshold for the\nslider, although is not required (If not passed, fallback is min: 0, max: Number.MAX_SAFE_INTEGER ),\nwhich are passed using the `threshold` prop and the selected range, which is passed in using the\nv-model.\n\n### Default usage\n\nIt is required to send the value prop which holds the selected values.\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" />\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSlider,\n },\n setup() {\n const selectedRange = ref({ min: 0, max: 1000 })\n\n return {\n selectedRange,\n }\n },\n}\n</script>\n```\n\n#### With threshold\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" :threshold=\"threshold\" />\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSliderDemo,\n },\n setup() {\n const threshold = ref({ min: 0, max: 1000 })\n const selectedRange = ref(threshold.value)\n\n return {\n selectedRange,\n threshold,\n }\n },\n}\n</script>\n```\n\n### Customized usage\n\n#### Overriding the slots\n\nIt is possible to override the default slot to customize the layout for the selected values.\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" :threshold=\"threshold\" v-slot=\"{ rangeSelected }\">\n <p class=\"x-base-slider__selected-min\">\n <span>min value</span>\n <span>\n {{ rangeSelected[0] }}\n </span>\n </p>\n <p class=\"x-base-slider__selected-max\">\n <span>max value</span>\n <span>\n {{ rangeSelected[1] }}\n </span>\n </p>\n </BaseSlider>\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSliderDemo,\n },\n setup() {\n const threshold = ref({ min: 0, max: 1000 })\n const selectedRange = ref(threshold.value)\n\n return {\n selectedRange,\n threshold,\n }\n },\n}\n</script>\n```\n\nIt is also possible to add inputs to complement the slider and allow to change the selected values\nmanually.\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" :threshold=\"threshold\">\n <input\n @change=\"selectedRange.min = $event.target?.valueAsNumber || 0\"\n class=\"x-input\"\n name=\"min\"\n type=\"number\"\n :value=\"selectedRange.min\"\n :aria-label=\"'min'\"\n />\n\n <input\n @change=\"selectedRange.max = $event.target?.valueAsNumber || 1000000\"\n style=\"display: block\"\n class=\"x-input\"\n name=\"max\"\n type=\"number\"\n :value=\"selectedRange.max\"\n :aria-label=\"'max'\"\n />\n </BaseSlider>\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSliderDemo,\n },\n setup() {\n const threshold = ref({ min: 0, max: 1000 })\n const selectedRange = ref(threshold.value)\n\n return {\n selectedRange,\n threshold,\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_createElementVNode","_openBlock","_createElementBlock","_normalizeClass","_renderSlot","_toDisplayString"],"mappings":";;;;;AACO,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,eAAe,EAAA,CAAA;AAEnB,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,yBAAyB,EAAA,CAAA;AAO7B,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,6BAA6B,EAAA,CAAA;AACpC,MAAA,UAAA,mBAAAA,kBAAA;AAAA,EAAsB,MAAA;AAAA,EAAA,IAAA;AAAA,EAAhB,WAAA;AAAA,EAAS,CAAA,CAAA;AAAA;AAAA,CAAA,CAAA;AAKd,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,6BAA6B,EAAA,CAAA;AACpC,MAAA,UAAA,mBAAAA,kBAAA;AAAA,EAAsB,MAAA;AAAA,EAAA,IAAA;AAAA,EAAhB,WAAA;AAAA,EAAS,CAAA,CAAA;AAAA;AAAA,CAAA,CAAA;;AAhBvB,EAAA,OAAAC,SAAA,EAAA,EAAAC,kBAAA,CAuBM,OAvBN,UAuBM,EAAA;AAAA,IAtBJF,kBAAA;AAAA,MAAqF,KAAA;AAAA,MAAA;AAAA,QAAhF,GAAI,EAAA,QAAA;AAAA,QAAU,KAFvB,EAAAG,cAAA,CAAA,CAAA,2BAAA,CAAA,CAE4D,MAAM,CAAA,CAAA,EAAI,IAAY,CAAA,YAAA,CAAA,CAAA,CAAA,CAAA;AAAA,OAAA;;;;;AAC9E,IAAAH,kBAAA,CAoBM,OApBN,UAoBM,EAAA;AAAA,MAdJI,UAaO,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA,EAbA,aAAgB,EAAA,IAAA,CAAA,aAAA,IAAvB,MAaO;AAAA,QAZLJ,kBAAA,CAKI,KALJ,UAKI,EAAA;AAAA,UAJF,UAAA;AAAA,UACAA,kBAAA;AAAA,YAEO,MAAA;AAAA,YAAA,IAAA;AAAA,YAAAK,eAAA,CADF,IAAa,CAAA,aAAA,CAAA,CAAA,CAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,CAAA;AAGpB,QAAAL,kBAAA,CAKI,KALJ,UAKI,EAAA;AAAA,UAJF,UAAA;AAAA,UACAA,kBAAA;AAAA,YAEO,MAAA;AAAA,YAAA,IAAA;AAAA,YAAAK,eAAA,CADF,IAAa,CAAA,aAAA,CAAA,CAAA,CAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,CAAA;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"base-slider.vue.js","sources":["../../../src/components/base-slider.vue"],"sourcesContent":["<template>\n <div class=\"x-base-slider\">\n <div ref=\"slider\" :class=\"['x-base-slider__nouislider'].concat(`${contentClass}`)\" />\n <div class=\"x-base-slider__selected\">\n <!--\n @slot Default selected range rendering. This slot will be used by default for rendering\n the selected range without an specific slot implementation.\n @binding {number[]} rangeSelected - The selected range values. Min position 0, Max position 1.\n -->\n <slot :range-selected=\"rangeSelected\">\n <p class=\"x-base-slider__selected-min\">\n <span>min value</span>\n <span>\n {{ rangeSelected[0] }}\n </span>\n </p>\n <p class=\"x-base-slider__selected-max\">\n <span>max value</span>\n <span>\n {{ rangeSelected[1] }}\n </span>\n </p>\n </slot>\n </div>\n </div>\n</template>\n<script lang=\"ts\">\nimport type { API } from 'nouislider'\nimport type { PropType } from 'vue'\nimport { create } from 'nouislider'\nimport { computed, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'\n\n/**\n * This component implements a range slider and prints the selected values.\n * It receives a threshold prop to set the limits and uses v-model to get and set\n * the selected values.\n *\n * It makes use of the nouslider library @see https://refreshless.com/nouislider/\n * for the slider implementation.\n *\n */\nexport default defineComponent({\n name: 'BaseSlider',\n props: {\n /** The threshold prop sets the limits for the slider. */\n threshold: {\n type: Object as PropType<{ min: number; max: number }>,\n default: () => ({ min: 0, max: Number.MAX_SAFE_INTEGER }),\n },\n /** The modelValue prop sets the initial values for the slider. */\n modelValue: {\n type: Object as PropType<{ min: number; max: number }>,\n required: true,\n },\n /** Class to be able to customize slider styles. */\n contentClass: {\n type: String,\n default: '',\n },\n },\n /**\n * The component emits an event with the selected values whenever\n * the user changes the slider.\n */\n emits: ['update:modelValue'],\n setup(props, { emit }) {\n /** The nouislider instance. */\n let sliderInstance: API\n /** The nouislider element reference. */\n const slider = ref<HTMLElement>()\n\n /** The selected min value. */\n const minSelected = ref(props.modelValue?.min ?? props.threshold.min)\n /** The selected max value. */\n const maxSelected = ref(props.modelValue?.max ?? props.threshold.max)\n\n /** The selected range as an array. */\n const rangeSelected = computed(() => [minSelected.value, maxSelected.value])\n /** The range for the nouislider. */\n const slideRange = computed(() => ({ min: props.threshold.min, max: props.threshold.max }))\n\n onMounted(() => {\n // Create the slider instance\n sliderInstance = create(slider.value!, {\n start: rangeSelected.value,\n range: slideRange.value,\n step: 1,\n connect: true,\n margin: 1,\n })\n\n // Update the selected values when the slider update its values\n sliderInstance.on('update', ([min, max]) => {\n minSelected.value = Number(min)\n maxSelected.value = Number(max)\n })\n\n // Emits the selected values when the slider values change\n sliderInstance.on('change', () =>\n emit('update:modelValue', { min: minSelected.value, max: maxSelected.value }),\n )\n })\n\n onUnmounted(() => {\n // Waiting to finish the collapse animation before destroying it\n setTimeout(sliderInstance.destroy.bind(sliderInstance), 600)\n })\n\n /**\n * Watch the threshold prop to update the slider state and emit the selected values.\n */\n watch(\n () => props.threshold,\n ({ min, max }) => {\n sliderInstance.updateOptions({ range: slideRange.value, start: [min, max] }, false)\n emit('update:modelValue', { min, max })\n },\n )\n\n /**\n * Watch the modelValue prop to update the slider state.\n *\n * @remarks It only update the values if the values are corrects. It means,\n * values within the threshold limits and not equal to the current values.\n *\n * @returns Undefined.\n */\n watch([() => props.modelValue.min, () => props.modelValue.max], ([min, max]) => {\n // Check if the values are the same\n if (min === minSelected.value && max === maxSelected.value) {\n return\n }\n\n // Validate the values\n const minValidated = min < props.threshold.min ? props.threshold.min : min\n const maxValidated = max > props.threshold.max ? props.threshold.max : max\n\n // Update the nouislider values\n sliderInstance.set([minValidated, maxValidated])\n\n // Emit the selected values\n if (minValidated !== min || maxValidated !== max) {\n emit('update:modelValue', { min: minValidated, max: maxValidated })\n }\n })\n\n return {\n slider,\n rangeSelected,\n }\n },\n})\n</script>\n<style lang=\"css\">\n@import 'nouislider/dist/nouislider.css';\n/** Customize nouislider styles: https://refreshless.com/nouislider/examples/#section-styling */\n\n.x-base-slider {\n gap: 16px;\n}\n\n.x-base-slider,\n.x-base-slider__selected-min,\n.x-base-slider__selected-max {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-slider__selected {\n display: inline-flex;\n}\n\n.x-base-slider__selected-min,\n.x-base-slider__selected-max {\n flex: 50%;\n}\n\n.x-base-slider__nouislider {\n margin: 16px 0;\n padding: 0 16px;\n}\n\n.x-base-slider__nouislider .noUi-handle {\n box-shadow: none;\n}\n\n.x-base-slider__nouislider .noUi-handle:before,\n.x-base-slider__nouislider .noUi-handle:after {\n content: none;\n}\n</style>\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a slider and the selected values. The component needs the threshold for the\nslider, although is not required (If not passed, fallback is min: 0, max: Number.MAX_SAFE_INTEGER ),\nwhich are passed using the `threshold` prop and the selected range, which is passed in using the\nv-model.\n\n### Default usage\n\nIt is required to send the value prop which holds the selected values.\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" />\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSlider,\n },\n setup() {\n const selectedRange = ref({ min: 0, max: 1000 })\n\n return {\n selectedRange,\n }\n },\n}\n</script>\n```\n\n#### With threshold\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" :threshold=\"threshold\" />\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSliderDemo,\n },\n setup() {\n const threshold = ref({ min: 0, max: 1000 })\n const selectedRange = ref(threshold.value)\n\n return {\n selectedRange,\n threshold,\n }\n },\n}\n</script>\n```\n\n### Customized usage\n\n#### Overriding the slots\n\nIt is possible to override the default slot to customize the layout for the selected values.\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" :threshold=\"threshold\" v-slot=\"{ rangeSelected }\">\n <p class=\"x-base-slider__selected-min\">\n <span>min value</span>\n <span>\n {{ rangeSelected[0] }}\n </span>\n </p>\n <p class=\"x-base-slider__selected-max\">\n <span>max value</span>\n <span>\n {{ rangeSelected[1] }}\n </span>\n </p>\n </BaseSlider>\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSliderDemo,\n },\n setup() {\n const threshold = ref({ min: 0, max: 1000 })\n const selectedRange = ref(threshold.value)\n\n return {\n selectedRange,\n threshold,\n }\n },\n}\n</script>\n```\n\nIt is also possible to add inputs to complement the slider and allow to change the selected values\nmanually.\n\n```vue live\n<template>\n <BaseSlider v-model=\"selectedRange\" :threshold=\"threshold\">\n <input\n @change=\"selectedRange.min = $event.target?.valueAsNumber || 0\"\n class=\"x-input\"\n name=\"min\"\n type=\"number\"\n :value=\"selectedRange.min\"\n :aria-label=\"'min'\"\n />\n\n <input\n @change=\"selectedRange.max = $event.target?.valueAsNumber || 1000000\"\n style=\"display: block\"\n class=\"x-input\"\n name=\"max\"\n type=\"number\"\n :value=\"selectedRange.max\"\n :aria-label=\"'max'\"\n />\n </BaseSlider>\n</template>\n\n<script>\nimport { BaseSlider } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSliderDemo',\n components: {\n BaseSliderDemo,\n },\n setup() {\n const threshold = ref({ min: 0, max: 1000 })\n const selectedRange = ref(threshold.value)\n\n return {\n selectedRange,\n threshold,\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_normalizeClass","_renderSlot","_toDisplayString"],"mappings":";;;;;AACO,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,eAAe,EAAA,CAAA;AAEnB,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,yBAAyB,EAAA,CAAA;AAO7B,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,6BAA6B,EAAA,CAAA;AAMnC,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,6BAA6B,EAAA,CAAA;;AAf5C,EAAA,OAAAA,SAAA,EAAA,EAAAC,kBAAA,CAuBM,OAvBN,UAuBM,EAAA;AAAA,IAtBJC,kBAAA;AAAA,MAAqF,KAAA;AAAA,MAAA;AAAA,QAAhF,GAAI,EAAA,QAAA;AAAA,QAAU,KAAK,EAAAC,cAAA,CAAA,CAAA,2BAAA,CAAA,CAAgC,MAAM,CAAA,CAAA,EAAI,IAAY,CAAA,YAAA,CAAA,CAAA,CAAA,CAAA;AAAA,OAAA;;;;;AAC9E,IAAAD,kBAAA,CAoBM,OApBN,UAoBM,EAAA;AAAA,MAdJE,UAaO,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA,EAbA,aAAgB,EAAA,IAAA,CAAA,aAAA,IAAvB,MAaO;AAAA,QAZLF,kBAAA,CAKI,KALJ,UAKI,EAAA;AAAA,UAJF,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAA,kBAAA;AAAA,YAAsB,MAAA;AAAA,YAAA,IAAA;AAAA,YAAhB,WAAA;AAAA,YAAS,CAAA,CAAA;AAAA;AAAA,WAAA,CAAA;AAAA,UACfA,kBAAA;AAAA,YAEO,MAAA;AAAA,YAAA,IAAA;AAAA,YAAAG,eAAA,CADF,IAAa,CAAA,aAAA,CAAA,CAAA,CAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,CAAA;AAGpB,QAAAH,kBAAA,CAKI,KALJ,UAKI,EAAA;AAAA,UAJF,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAA,kBAAA;AAAA,YAAsB,MAAA;AAAA,YAAA,IAAA;AAAA,YAAhB,WAAA;AAAA,YAAS,CAAA,CAAA;AAAA;AAAA,WAAA,CAAA;AAAA,UACfA,kBAAA;AAAA,YAEO,MAAA;AAAA,YAAA,IAAA;AAAA,YAAAG,eAAA,CADF,IAAa,CAAA,aAAA,CAAA,CAAA,CAAA,CAAA;AAAA,YAAA,CAAA;AAAA;AAAA,WAAA;AAAA,SAAA,CAAA;;;;;;;;;"}
|
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
import _sfc_main from './base-switch.vue2.js';
|
|
2
|
-
import { openBlock, createElementBlock, normalizeClass,
|
|
2
|
+
import { openBlock, createElementBlock, normalizeClass, createElementVNode } from 'vue';
|
|
3
3
|
import './base-switch.vue3.js';
|
|
4
4
|
import _export_sfc from '../_virtual/_plugin-vue_export-helper.js';
|
|
5
5
|
|
|
6
|
-
const _withScopeId = (n) => (pushScopeId("data-v-3ae6056b"), n = n(), popScopeId(), n);
|
|
7
6
|
const _hoisted_1 = ["aria-checked"];
|
|
8
|
-
const _hoisted_2 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElementVNode(
|
|
9
|
-
"div",
|
|
10
|
-
{ class: "x-switch__handle" },
|
|
11
|
-
null,
|
|
12
|
-
-1
|
|
13
|
-
/* HOISTED */
|
|
14
|
-
));
|
|
15
|
-
const _hoisted_3 = [
|
|
16
|
-
_hoisted_2
|
|
17
|
-
];
|
|
18
7
|
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
19
8
|
return openBlock(), createElementBlock("button", {
|
|
20
9
|
"aria-checked": _ctx.modelValue || void 0,
|
|
21
10
|
class: normalizeClass([_ctx.cssClasses, "x-switch"]),
|
|
22
11
|
role: "switch",
|
|
23
12
|
onClick: _cache[0] || (_cache[0] = (...args) => _ctx.toggle && _ctx.toggle(...args))
|
|
24
|
-
}, [...
|
|
13
|
+
}, [..._cache[1] || (_cache[1] = [
|
|
14
|
+
createElementVNode(
|
|
15
|
+
"div",
|
|
16
|
+
{ class: "x-switch__handle" },
|
|
17
|
+
null,
|
|
18
|
+
-1
|
|
19
|
+
/* CACHED */
|
|
20
|
+
)
|
|
21
|
+
])], 10, _hoisted_1);
|
|
25
22
|
}
|
|
26
23
|
var BaseSwitch = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-3ae6056b"]]);
|
|
27
24
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-switch.vue.js","sources":["../../../src/components/base-switch.vue"],"sourcesContent":["<template>\n <button\n :aria-checked=\"modelValue || undefined\"\n :class=\"cssClasses\"\n class=\"x-switch\"\n role=\"switch\"\n @click=\"toggle\"\n >\n <div class=\"x-switch__handle\" />\n </button>\n</template>\n\n<script lang=\"ts\">\nimport type { VueCSSClasses } from '../utils/types'\nimport { computed, defineComponent } from 'vue'\n\n/**\n * Basic switch component to handle boolean values. This component receives\n * its selected state using a prop, and emits a Vue event whenever the user\n * clicks it.\n *\n * @public\n */\n\nexport default defineComponent({\n name: 'BaseSwitch',\n /**\n * The selected value of the switch.\n *\n * @public\n */\n props: {\n modelValue: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:modelValue'],\n setup(props, { emit }) {\n /**\n * Dynamic CSS classes to add to the switch component\n * depending on its internal state.\n *\n * @returns A boolean dictionary with dynamic CSS classes.\n * @internal\n */\n const cssClasses = computed<VueCSSClasses>(() => ({\n 'x-switch--is-selected x-selected': props.modelValue,\n }))\n\n /**\n * Emits an event with the new value of the switch.\n *\n * @internal\n */\n const toggle = (): void => {\n const newValue = !props.modelValue\n emit('update:modelValue', newValue)\n }\n\n return {\n cssClasses,\n toggle,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-switch {\n --x-switch-height: 16px;\n --x-switch-width: calc(2 * (var(--x-switch-height)) + 2 * var(--x-switch-padding));\n --x-switch-background: #b3b3b3;\n --x-switch-padding: 2px;\n --x-switch-handle-size: var(--x-switch-height);\n box-sizing: content-box;\n height: var(--x-switch-height);\n padding: var(--x-switch-padding);\n border-radius: 99999px;\n background: var(--x-switch-background);\n width: var(--x-switch-width);\n border: none;\n transition: 0.25s ease-out background-color;\n cursor: pointer;\n}\n\n.x-switch__handle {\n background: #ffffff;\n border-radius: 50%;\n height: var(--x-switch-handle-size);\n width: var(--x-switch-handle-size);\n transition: 0.25s ease-out transform;\n transform: translateX(var(--x-switch-translate-x, 0%));\n}\n\n.x-switch--is-selected {\n --x-switch-translate-x: calc(var(--x-switch-padding) + var(--x-switch-width) / 2);\n --x-switch-background: #1a1a1a;\n}\n\n.x-switch--sm {\n --x-switch-height: 12px;\n}\n\n.x-switch--lg {\n --x-switch-height: 24px;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits no events.\n\n## See it in action\n\nHere you have a basic example of how the switch is rendered.\n\n_Try clicking it to see how it changes its state_\n\n```vue live\n<template>\n <BaseSwitch @update:modelValue=\"value = !value\" :modelValue=\"value\" />\n</template>\n\n<script>\nimport { BaseSwitch } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSwitchDemo',\n components: {\n BaseSwitch,\n },\n data() {\n return {\n value: false,\n }\n },\n}\n</script>\n```\n\nThe switch component also supports using the `v-model` directive, to automatically handle its state\nchange:\n\n```vue live\n<template>\n <BaseSwitch v-model=\"value\" />\n</template>\n\n<script>\nimport { BaseSwitch } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSwitchDemo',\n components: {\n BaseSwitch,\n },\n data() {\n return {\n value: false,\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["
|
|
1
|
+
{"version":3,"file":"base-switch.vue.js","sources":["../../../src/components/base-switch.vue"],"sourcesContent":["<template>\n <button\n :aria-checked=\"modelValue || undefined\"\n :class=\"cssClasses\"\n class=\"x-switch\"\n role=\"switch\"\n @click=\"toggle\"\n >\n <div class=\"x-switch__handle\" />\n </button>\n</template>\n\n<script lang=\"ts\">\nimport type { VueCSSClasses } from '../utils/types'\nimport { computed, defineComponent } from 'vue'\n\n/**\n * Basic switch component to handle boolean values. This component receives\n * its selected state using a prop, and emits a Vue event whenever the user\n * clicks it.\n *\n * @public\n */\n\nexport default defineComponent({\n name: 'BaseSwitch',\n /**\n * The selected value of the switch.\n *\n * @public\n */\n props: {\n modelValue: {\n type: Boolean,\n default: false,\n },\n },\n emits: ['update:modelValue'],\n setup(props, { emit }) {\n /**\n * Dynamic CSS classes to add to the switch component\n * depending on its internal state.\n *\n * @returns A boolean dictionary with dynamic CSS classes.\n * @internal\n */\n const cssClasses = computed<VueCSSClasses>(() => ({\n 'x-switch--is-selected x-selected': props.modelValue,\n }))\n\n /**\n * Emits an event with the new value of the switch.\n *\n * @internal\n */\n const toggle = (): void => {\n const newValue = !props.modelValue\n emit('update:modelValue', newValue)\n }\n\n return {\n cssClasses,\n toggle,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-switch {\n --x-switch-height: 16px;\n --x-switch-width: calc(2 * (var(--x-switch-height)) + 2 * var(--x-switch-padding));\n --x-switch-background: #b3b3b3;\n --x-switch-padding: 2px;\n --x-switch-handle-size: var(--x-switch-height);\n box-sizing: content-box;\n height: var(--x-switch-height);\n padding: var(--x-switch-padding);\n border-radius: 99999px;\n background: var(--x-switch-background);\n width: var(--x-switch-width);\n border: none;\n transition: 0.25s ease-out background-color;\n cursor: pointer;\n}\n\n.x-switch__handle {\n background: #ffffff;\n border-radius: 50%;\n height: var(--x-switch-handle-size);\n width: var(--x-switch-handle-size);\n transition: 0.25s ease-out transform;\n transform: translateX(var(--x-switch-translate-x, 0%));\n}\n\n.x-switch--is-selected {\n --x-switch-translate-x: calc(var(--x-switch-padding) + var(--x-switch-width) / 2);\n --x-switch-background: #1a1a1a;\n}\n\n.x-switch--sm {\n --x-switch-height: 12px;\n}\n\n.x-switch--lg {\n --x-switch-height: 24px;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits no events.\n\n## See it in action\n\nHere you have a basic example of how the switch is rendered.\n\n_Try clicking it to see how it changes its state_\n\n```vue live\n<template>\n <BaseSwitch @update:modelValue=\"value = !value\" :modelValue=\"value\" />\n</template>\n\n<script>\nimport { BaseSwitch } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSwitchDemo',\n components: {\n BaseSwitch,\n },\n data() {\n return {\n value: false,\n }\n },\n}\n</script>\n```\n\nThe switch component also supports using the `v-model` directive, to automatically handle its state\nchange:\n\n```vue live\n<template>\n <BaseSwitch v-model=\"value\" />\n</template>\n\n<script>\nimport { BaseSwitch } from '@empathyco/x-components'\n\nexport default {\n name: 'BaseSwitchDemo',\n components: {\n BaseSwitch,\n },\n data() {\n return {\n value: false,\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode"],"mappings":";;;;;;;sBACEA,kBAQS,CAAA,QAAA,EAAA;AAAA,IAPN,gBAAc,IAAc,CAAA,UAAA,IAAA,KAAA,CAAA;AAAA,IAC5B,KAAA,EAAKC,cAAE,CAAA,CAAA,IAAA,CAAA,UAAA,EACF,UAAU,CAAA,CAAA;AAAA,IAChB,IAAK,EAAA,QAAA;AAAA,IACJ,SAAK,MAAE,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,MAAA,IAAA,IAAA,CAAA,MAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,GAAA,EAAA,CAAA,GAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA;AAER,IAAAC,kBAAA;AAAA,MAAgC,KAAA;AAAA,MAAA,EAA3B,OAAM,kBAAkB,EAAA;AAAA,MAAA,IAAA;AAAA,MAAA,CAAA,CAAA;AAAA;AAAA,KAAA;AAAA,GAAA,CAAA,CAAA,EAAA,EAAA,EAAA,UAAA,CAAA,CAAA;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-teleport.vue.js","sources":["../../../src/components/base-teleport.vue"],"sourcesContent":["<template>\n <Teleport v-if=\"teleportHost\" :to=\"teleportHost.shadowRoot ?? teleportHost\" :disabled>\n <slot></slot>\n </Teleport>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport {\n defineComponent,\n getCurrentInstance,\n onBeforeUnmount,\n onMounted,\n onUnmounted,\n ref,\n watch,\n watchEffect,\n} from 'vue'\n\nexport default defineComponent({\n name: 'BaseTeleport',\n props: {\n /** The element or css selector to which the component will be teleported. */\n target: {\n type: [String, Object] as PropType<string | Element>,\n required: true,\n },\n /**\n * The position relative to the target\n * - `beforebegin`: Before the target element.\n * - `afterbegin`: Inside the target element, before its first child.\n * - `beforeend`: Inside the target element, after its last child.\n * - `afterend`: After the target element.\n * - `onlychild`: Adds it as child and hides all other children of the target element.\n */\n position: {\n type: String as PropType<\n 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'onlychild'\n >,\n default: 'onlychild',\n },\n /** If disabled, the slot content will not be teleported */\n disabled: {\n type: Boolean,\n default: false,\n },\n /** Styles for the teleport (content container) */\n hostStyle: Object as PropType<string | CSSStyleDeclaration>,\n },\n setup(props) {\n if (typeof document === 'undefined') {\n return { teleportHost: ref<HTMLElement>() }\n }\n\n const instance = getCurrentInstance()\n /** Hook where the slot content will be teleported to. */\n const teleportHost = ref<HTMLElement>()\n /** The page element where the teleport host will be inserted. */\n const targetElement = ref<HTMLElement>()\n let isIsolated = false\n\n // Before doing app.mount it is unknown if it will be mounted in a shadow so we need to wait.\n if (instance?.appContext.app._container) {\n createHost()\n } else {\n afterAppMount(createHost)\n }\n\n const targetAddedObserver = new MutationObserver(targetAdded)\n const targetRemovedObserver = new MutationObserver(targetRemoved)\n\n onUnmounted(() => {\n if (isIsolated && teleportHost.value) {\n ;(window as any).xCSSInjector.removeHost(teleportHost.value.shadowRoot)\n }\n })\n\n onBeforeUnmount(() => {\n targetAddedObserver.disconnect()\n targetRemovedObserver.disconnect()\n teleportHost.value?.remove()\n })\n\n // Handles target prop changes and init the observers accordingly.\n watch(\n () => props.target,\n newTarget => {\n targetAddedObserver.disconnect()\n targetRemovedObserver.disconnect()\n const target = typeof newTarget === 'string' ? document.querySelector(newTarget) : newTarget\n if (target?.isConnected) {\n targetAdded()\n } else {\n targetRemoved()\n }\n },\n { immediate: true },\n )\n\n // Updates the teleport host when props change.\n watchEffect(() => {\n if (!teleportHost.value) {\n return\n }\n if (props.disabled) {\n teleportHost.value.remove()\n return\n }\n teleportHost.value.className = `x-base-teleport x-base-teleport--${props.position}`\n\n if (!targetElement.value) {\n console.warn(`BaseTeleport: Target element \"${props.target}\" not found.`)\n return\n }\n const position = props.position === 'onlychild' ? 'beforeend' : props.position\n targetElement.value.insertAdjacentElement(position, teleportHost.value)\n })\n\n /* Update the host inline styles when it changes */\n watchEffect(() => {\n if (teleportHost.value && props.hostStyle) {\n if (typeof props.hostStyle === 'string') {\n teleportHost.value.style.cssText = props.hostStyle\n } else {\n Object.assign(teleportHost.value.style, props.hostStyle)\n }\n }\n })\n\n /** Checks if the target element exists in the DOM and updates the observers */\n function targetAdded() {\n let element: string | Element | null = props.target\n if (typeof element === 'string') {\n element = document.querySelector(element)\n }\n if (element instanceof HTMLElement && element.isConnected) {\n targetAddedObserver.disconnect()\n targetElement.value = element\n while (element.parentElement) {\n element = element.parentElement\n targetRemovedObserver.observe(element, { childList: true })\n }\n }\n }\n\n /** Checks if the target was disconnected from the DOM and updates the observers */\n function targetRemoved() {\n if (targetElement.value && !targetElement.value.isConnected) {\n targetRemovedObserver.disconnect()\n targetAddedObserver.observe(document.body, { childList: true, subtree: true })\n targetElement.value = undefined\n }\n }\n\n /** Creates and sets the teleport host element */\n function createHost() {\n teleportHost.value = document.createElement('div')\n isIsolated = instance?.appContext.app._container instanceof ShadowRoot\n if (isIsolated) {\n teleportHost.value.attachShadow({ mode: 'open' })\n ;(window as any).xCSSInjector.addHost(teleportHost.value.shadowRoot)\n }\n }\n\n function afterAppMount(fn: () => void) {\n onMounted(() => setTimeout(fn, 0))\n }\n\n return { teleportHost }\n },\n})\n\n/** Teleport host styles should be injected outside our shadowRoots */\nif (typeof document !== 'undefined') {\n const css = document.createElement('style')\n css.textContent =\n ':has(> .x-base-teleport--onlychild) > *:not(.x-base-teleport) { display: none; }'\n document.head?.appendChild(css) ||\n document.addEventListener('DOMContentLoaded', () => document.head.appendChild(css))\n}\n</script>\n\n<docs lang=\"mdx\">\n## Example\n\nThe BaseTeleport component allows you to teleport its slot content to a specified target element in\nthe DOM. It provides flexibility in positioning the content relative to the target element and\nsupports shadow DOM integration.\n\n### Basic example\n\nTeleport content to a specific element in the DOM:\n\n```vue\n<template>\n <BaseTeleport target=\"#my-target\">\n <div>This content will be teleported.</div>\n </BaseTeleport>\n</template>\n```\n\n### Positioning options\n\nTeleport content inside the target element, before its first child:\n\n```vue\n<template>\n <BaseTeleport target=\"#my-target\" position=\"afterbegin\">\n <div>Teleported content at the beginning.</div>\n </BaseTeleport>\n</template>\n```\n\n### Disabled Teleport\n\nPrevent teleporting the content:\n\n```vue\n<template>\n <BaseTeleport target=\"#my-target\" :disabled=\"true\">\n <div>This content will not be teleported.</div>\n </BaseTeleport>\n</template>\n```\n\n### Notes\n\n- When using the `onlychild` position, all other children of the target element will be hidden.\n- The component supports shadow DOM integration, automatically handling style injection. Anyway, Empathy's custom CSS\n injector is required. Teleport depends on it to add the styles.\n</docs>\n"],"names":["_openBlock","_createBlock","_Teleport","_renderSlot","_createCommentVNode"],"mappings":";;;;;AACkB,EAAA,OAAA,IAAA,CAAA,YAAA,IAAAA,SAAA,EAAA,EAAhBC,WAEW,CAAAC,QAAA,EAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"base-teleport.vue.js","sources":["../../../src/components/base-teleport.vue"],"sourcesContent":["<template>\n <Teleport v-if=\"teleportHost\" :to=\"teleportHost.shadowRoot ?? teleportHost\" :disabled>\n <slot></slot>\n </Teleport>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport {\n defineComponent,\n getCurrentInstance,\n onBeforeUnmount,\n onMounted,\n onUnmounted,\n ref,\n watch,\n watchEffect,\n} from 'vue'\n\nexport default defineComponent({\n name: 'BaseTeleport',\n props: {\n /** The element or css selector to which the component will be teleported. */\n target: {\n type: [String, Object] as PropType<string | Element>,\n required: true,\n },\n /**\n * The position relative to the target\n * - `beforebegin`: Before the target element.\n * - `afterbegin`: Inside the target element, before its first child.\n * - `beforeend`: Inside the target element, after its last child.\n * - `afterend`: After the target element.\n * - `onlychild`: Adds it as child and hides all other children of the target element.\n */\n position: {\n type: String as PropType<\n 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'onlychild'\n >,\n default: 'onlychild',\n },\n /** If disabled, the slot content will not be teleported */\n disabled: {\n type: Boolean,\n default: false,\n },\n /** Styles for the teleport (content container) */\n hostStyle: Object as PropType<string | CSSStyleDeclaration>,\n },\n setup(props) {\n if (typeof document === 'undefined') {\n return { teleportHost: ref<HTMLElement>() }\n }\n\n const instance = getCurrentInstance()\n /** Hook where the slot content will be teleported to. */\n const teleportHost = ref<HTMLElement>()\n /** The page element where the teleport host will be inserted. */\n const targetElement = ref<HTMLElement>()\n let isIsolated = false\n\n // Before doing app.mount it is unknown if it will be mounted in a shadow so we need to wait.\n if (instance?.appContext.app._container) {\n createHost()\n } else {\n afterAppMount(createHost)\n }\n\n const targetAddedObserver = new MutationObserver(targetAdded)\n const targetRemovedObserver = new MutationObserver(targetRemoved)\n\n onUnmounted(() => {\n if (isIsolated && teleportHost.value) {\n ;(window as any).xCSSInjector.removeHost(teleportHost.value.shadowRoot)\n }\n })\n\n onBeforeUnmount(() => {\n targetAddedObserver.disconnect()\n targetRemovedObserver.disconnect()\n teleportHost.value?.remove()\n })\n\n // Handles target prop changes and init the observers accordingly.\n watch(\n () => props.target,\n newTarget => {\n targetAddedObserver.disconnect()\n targetRemovedObserver.disconnect()\n const target = typeof newTarget === 'string' ? document.querySelector(newTarget) : newTarget\n if (target?.isConnected) {\n targetAdded()\n } else {\n targetRemoved()\n }\n },\n { immediate: true },\n )\n\n // Updates the teleport host when props change.\n watchEffect(() => {\n if (!teleportHost.value) {\n return\n }\n if (props.disabled) {\n teleportHost.value.remove()\n return\n }\n teleportHost.value.className = `x-base-teleport x-base-teleport--${props.position}`\n\n if (!targetElement.value) {\n console.warn(`BaseTeleport: Target element \"${props.target}\" not found.`)\n return\n }\n const position = props.position === 'onlychild' ? 'beforeend' : props.position\n targetElement.value.insertAdjacentElement(position, teleportHost.value)\n })\n\n /* Update the host inline styles when it changes */\n watchEffect(() => {\n if (teleportHost.value && props.hostStyle) {\n if (typeof props.hostStyle === 'string') {\n teleportHost.value.style.cssText = props.hostStyle\n } else {\n Object.assign(teleportHost.value.style, props.hostStyle)\n }\n }\n })\n\n /** Checks if the target element exists in the DOM and updates the observers */\n function targetAdded() {\n let element: string | Element | null = props.target\n if (typeof element === 'string') {\n element = document.querySelector(element)\n }\n if (element instanceof HTMLElement && element.isConnected) {\n targetAddedObserver.disconnect()\n targetElement.value = element\n while (element.parentElement) {\n element = element.parentElement\n targetRemovedObserver.observe(element, { childList: true })\n }\n }\n }\n\n /** Checks if the target was disconnected from the DOM and updates the observers */\n function targetRemoved() {\n if (targetElement.value && !targetElement.value.isConnected) {\n targetRemovedObserver.disconnect()\n targetAddedObserver.observe(document.body, { childList: true, subtree: true })\n targetElement.value = undefined\n }\n }\n\n /** Creates and sets the teleport host element */\n function createHost() {\n teleportHost.value = document.createElement('div')\n isIsolated = instance?.appContext.app._container instanceof ShadowRoot\n if (isIsolated) {\n teleportHost.value.attachShadow({ mode: 'open' })\n ;(window as any).xCSSInjector.addHost(teleportHost.value.shadowRoot)\n }\n }\n\n function afterAppMount(fn: () => void) {\n onMounted(() => setTimeout(fn, 0))\n }\n\n return { teleportHost }\n },\n})\n\n/** Teleport host styles should be injected outside our shadowRoots */\nif (typeof document !== 'undefined') {\n const css = document.createElement('style')\n css.textContent =\n ':has(> .x-base-teleport--onlychild) > *:not(.x-base-teleport) { display: none; }'\n document.head?.appendChild(css) ||\n document.addEventListener('DOMContentLoaded', () => document.head.appendChild(css))\n}\n</script>\n\n<docs lang=\"mdx\">\n## Example\n\nThe BaseTeleport component allows you to teleport its slot content to a specified target element in\nthe DOM. It provides flexibility in positioning the content relative to the target element and\nsupports shadow DOM integration.\n\n### Basic example\n\nTeleport content to a specific element in the DOM:\n\n```vue\n<template>\n <BaseTeleport target=\"#my-target\">\n <div>This content will be teleported.</div>\n </BaseTeleport>\n</template>\n```\n\n### Positioning options\n\nTeleport content inside the target element, before its first child:\n\n```vue\n<template>\n <BaseTeleport target=\"#my-target\" position=\"afterbegin\">\n <div>Teleported content at the beginning.</div>\n </BaseTeleport>\n</template>\n```\n\n### Disabled Teleport\n\nPrevent teleporting the content:\n\n```vue\n<template>\n <BaseTeleport target=\"#my-target\" :disabled=\"true\">\n <div>This content will not be teleported.</div>\n </BaseTeleport>\n</template>\n```\n\n### Notes\n\n- When using the `onlychild` position, all other children of the target element will be hidden.\n- The component supports shadow DOM integration, automatically handling style injection. Anyway, Empathy's custom CSS\n injector is required. Teleport depends on it to add the styles.\n</docs>\n"],"names":["_openBlock","_createBlock","_Teleport","_renderSlot","_createCommentVNode"],"mappings":";;;;;AACkB,EAAA,OAAA,IAAA,CAAA,YAAA,IAAAA,SAAA,EAAA,EAAhBC,WAEW,CAAAC,QAAA,EAAA;AAAA,IAAA,GAAA,EAAA,CAAA;AAFoB,IAAA,EAAA,EAAI,kBAAa,UAAc,IAAA,IAAA,CAAA,YAAA;AAAA,IAAe,QAAA,EAAA,IAAA,CAAA,QAAA;AAAA,GAAA,EAAA;IAC3EC,UAAa,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;AAAA,GAAA,EAAA,CAAA,EAAA,CAAA,IAAA,EAAA,UAAA,CAAA,CAAA,IAAAC,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA,CAAA;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-variable-column-grid.vue.js","sources":["../../../src/components/base-variable-column-grid.vue"],"sourcesContent":["<template>\n <BaseGrid :animation=\"animation\" :columns=\"columnsToRender\" :items=\"items\">\n <template v-for=\"(_, name) in slots\" #[name]=\"{ item }\">\n <!--\n @slot Customized item rendering. The slot name can either be default or the item's model\n name.\n @binding {GridItem} item - Item to render.\n -->\n <slot :name=\"name\" v-bind=\"{ item }\" />\n </template>\n </BaseGrid>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport type { ListItem } from '../utils/types'\nimport { computed, defineComponent, ref } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport BaseGrid from './base-grid.vue'\n\n/**\n * The `BaseVariableColumnGrid` component is a wrapper of the `BaseGrid` component that listens to\n * the `UserClickedColumnPicker` and the `ColumnsNumberProvided` events and passes the\n * selected number of columns to the grid. It also allows to customize the grid items using the\n * available `scopedSlots`.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseVariableColumnGrid',\n components: {\n BaseGrid,\n },\n props: {\n /**\n * Animation component that will be used to animate the grid.\n *\n * @public\n */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an id property.\n *\n * @public\n */\n items: Array as PropType<ListItem[]>,\n /**\n * The columns to render by default in the grid. This property is used when the user has not\n * selected any value in the column picker.\n *\n * @internal\n */\n columns: {\n type: Number,\n default: 0,\n },\n },\n setup(props, { slots }) {\n const bus = useXBus()\n /**\n * The number of columns provided by a user interaction.\n *\n * @internal\n */\n const providedColumns = ref<number | null>(null)\n\n /**\n * The number of columns to render in the grid.\n *\n * @returns The number of columns.\n *\n * @internal\n */\n const columnsToRender = computed(() =>\n providedColumns.value === null ? props.columns : providedColumns.value,\n )\n\n /**\n * Handler to update the number of columns when the user selects a new value.\n *\n * @param newColumns - The new columns value.\n *\n * @internal\n */\n bus\n .on('ColumnsNumberProvided', false)\n .subscribe(newColumns => (providedColumns.value = newColumns))\n\n return {\n columnsToRender,\n slots,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Example\n\nThe `BaseVariableColumnGrid` component is a wrapper of the `BaseGrid` component that listens to the\n`ColumnsNumberProvided` events and passes the selected amount of columns to the grid. It also allows\nyou to customize the grid items using the available `scopedSlots`.\n\n```vue\n<template>\n <section class=\"results\">\n <button @click=\"setColumns(4)\" class=\"column-picker-selector\">\n <span class=\"column-picker-selector__text\">4 columns</span>\n </button>\n <BaseVariableColumnGrid :animation=\"animation\" :items=\"items\">\n <template #default=\"{ item }\">\n <span data-test=\"default-slot\">{{ item.id }}</span>\n </template>\n <template #result=\"{ item }\">\n <span data-test=\"result-slot\">{{ 'Result ' + item.id }}</span>\n </template>\n </BaseVariableColumnGrid>\n </section>\n</template>\n\n<script>\nimport { BaseVariableColumnGrid, StaggeredFadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultsSection',\n components: {\n BaseVariableColumnGrid,\n },\n data() {\n return {\n animation: StaggeredFadeAndSlide,\n items: [\n {\n id: 'res-1',\n modelName: 'Result',\n name: 'Product 1',\n },\n {\n id: 'res-2',\n modelName: 'Result',\n name: 'Product 2',\n },\n ],\n }\n },\n methods: {\n setColumns(columns) {\n this.$x.emit('UserClickedColumnPicker', columns)\n },\n },\n}\n</script>\n```\n\n### Playing with props\n\nConfiguring the default columns to be rendered. These columns will be the default value until the\n`ColumnsNumberProvided` is emitted and changes the value.\n\n```vue\n<template>\n <section class=\"results\">\n <button @click=\"setColumns(5)\" class=\"column-picker-selector\">\n <span class=\"column-picker-selector__text\">5 columns</span>\n </button>\n <BaseVariableColumnGrid :animation=\"animation\" :items=\"items\" :columns=\"3\">\n <template #default=\"{ item }\">\n <span data-test=\"default-slot\">{{ item.id }}</span>\n </template>\n <template #result=\"{ item }\">\n <span data-test=\"result-slot\">{{ 'Result ' + item.id }}</span>\n </template>\n </BaseVariableColumnGrid>\n </section>\n</template>\n\n<script>\nimport { BaseVariableColumnGrid, StaggeredFadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultsSection',\n components: {\n BaseVariableColumnGrid,\n },\n data() {\n return {\n animation: StaggeredFadeAndSlide,\n items: [\n {\n id: 'res-1',\n modelName: 'Result',\n name: 'Product 1',\n },\n {\n id: 'res-2',\n modelName: 'Result',\n name: 'Product 2',\n },\n ],\n }\n },\n methods: {\n setColumns(columns) {\n this.$x.emit('UserClickedColumnPicker', columns)\n },\n },\n}\n</script>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseVariableColumnGrid\n :animation=\"animation\"\n :items=\"items\"\n style=\"--x-size-min-width-grid-item: 150px\"\n >\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseVariableColumnGrid>\n</template>\n\n<script>\nimport { BaseVariableColumnGrid, StaggeredFadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultsSection',\n components: {\n BaseVariableColumnGrid,\n },\n data() {\n return {\n animation: StaggeredFadeAndSlide,\n items: [\n {\n id: 'res-1',\n modelName: 'Result',\n name: 'Product 1',\n },\n {\n id: 'res-2',\n modelName: 'Result',\n name: 'Product 2',\n },\n ],\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_createBlock","_createSlots","
|
|
1
|
+
{"version":3,"file":"base-variable-column-grid.vue.js","sources":["../../../src/components/base-variable-column-grid.vue"],"sourcesContent":["<template>\n <BaseGrid :animation=\"animation\" :columns=\"columnsToRender\" :items=\"items\">\n <template v-for=\"(_, name) in slots\" #[name]=\"{ item }\">\n <!--\n @slot Customized item rendering. The slot name can either be default or the item's model\n name.\n @binding {GridItem} item - Item to render.\n -->\n <slot :name=\"name\" v-bind=\"{ item }\" />\n </template>\n </BaseGrid>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport type { ListItem } from '../utils/types'\nimport { computed, defineComponent, ref } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport BaseGrid from './base-grid.vue'\n\n/**\n * The `BaseVariableColumnGrid` component is a wrapper of the `BaseGrid` component that listens to\n * the `UserClickedColumnPicker` and the `ColumnsNumberProvided` events and passes the\n * selected number of columns to the grid. It also allows to customize the grid items using the\n * available `scopedSlots`.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseVariableColumnGrid',\n components: {\n BaseGrid,\n },\n props: {\n /**\n * Animation component that will be used to animate the grid.\n *\n * @public\n */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an id property.\n *\n * @public\n */\n items: Array as PropType<ListItem[]>,\n /**\n * The columns to render by default in the grid. This property is used when the user has not\n * selected any value in the column picker.\n *\n * @internal\n */\n columns: {\n type: Number,\n default: 0,\n },\n },\n setup(props, { slots }) {\n const bus = useXBus()\n /**\n * The number of columns provided by a user interaction.\n *\n * @internal\n */\n const providedColumns = ref<number | null>(null)\n\n /**\n * The number of columns to render in the grid.\n *\n * @returns The number of columns.\n *\n * @internal\n */\n const columnsToRender = computed(() =>\n providedColumns.value === null ? props.columns : providedColumns.value,\n )\n\n /**\n * Handler to update the number of columns when the user selects a new value.\n *\n * @param newColumns - The new columns value.\n *\n * @internal\n */\n bus\n .on('ColumnsNumberProvided', false)\n .subscribe(newColumns => (providedColumns.value = newColumns))\n\n return {\n columnsToRender,\n slots,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Example\n\nThe `BaseVariableColumnGrid` component is a wrapper of the `BaseGrid` component that listens to the\n`ColumnsNumberProvided` events and passes the selected amount of columns to the grid. It also allows\nyou to customize the grid items using the available `scopedSlots`.\n\n```vue\n<template>\n <section class=\"results\">\n <button @click=\"setColumns(4)\" class=\"column-picker-selector\">\n <span class=\"column-picker-selector__text\">4 columns</span>\n </button>\n <BaseVariableColumnGrid :animation=\"animation\" :items=\"items\">\n <template #default=\"{ item }\">\n <span data-test=\"default-slot\">{{ item.id }}</span>\n </template>\n <template #result=\"{ item }\">\n <span data-test=\"result-slot\">{{ 'Result ' + item.id }}</span>\n </template>\n </BaseVariableColumnGrid>\n </section>\n</template>\n\n<script>\nimport { BaseVariableColumnGrid, StaggeredFadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultsSection',\n components: {\n BaseVariableColumnGrid,\n },\n data() {\n return {\n animation: StaggeredFadeAndSlide,\n items: [\n {\n id: 'res-1',\n modelName: 'Result',\n name: 'Product 1',\n },\n {\n id: 'res-2',\n modelName: 'Result',\n name: 'Product 2',\n },\n ],\n }\n },\n methods: {\n setColumns(columns) {\n this.$x.emit('UserClickedColumnPicker', columns)\n },\n },\n}\n</script>\n```\n\n### Playing with props\n\nConfiguring the default columns to be rendered. These columns will be the default value until the\n`ColumnsNumberProvided` is emitted and changes the value.\n\n```vue\n<template>\n <section class=\"results\">\n <button @click=\"setColumns(5)\" class=\"column-picker-selector\">\n <span class=\"column-picker-selector__text\">5 columns</span>\n </button>\n <BaseVariableColumnGrid :animation=\"animation\" :items=\"items\" :columns=\"3\">\n <template #default=\"{ item }\">\n <span data-test=\"default-slot\">{{ item.id }}</span>\n </template>\n <template #result=\"{ item }\">\n <span data-test=\"result-slot\">{{ 'Result ' + item.id }}</span>\n </template>\n </BaseVariableColumnGrid>\n </section>\n</template>\n\n<script>\nimport { BaseVariableColumnGrid, StaggeredFadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultsSection',\n components: {\n BaseVariableColumnGrid,\n },\n data() {\n return {\n animation: StaggeredFadeAndSlide,\n items: [\n {\n id: 'res-1',\n modelName: 'Result',\n name: 'Product 1',\n },\n {\n id: 'res-2',\n modelName: 'Result',\n name: 'Product 2',\n },\n ],\n }\n },\n methods: {\n setColumns(columns) {\n this.$x.emit('UserClickedColumnPicker', columns)\n },\n },\n}\n</script>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseVariableColumnGrid\n :animation=\"animation\"\n :items=\"items\"\n style=\"--x-size-min-width-grid-item: 150px\"\n >\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseVariableColumnGrid>\n</template>\n\n<script>\nimport { BaseVariableColumnGrid, StaggeredFadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultsSection',\n components: {\n BaseVariableColumnGrid,\n },\n data() {\n return {\n animation: StaggeredFadeAndSlide,\n items: [\n {\n id: 'res-1',\n modelName: 'Result',\n name: 'Product 1',\n },\n {\n id: 'res-2',\n modelName: 'Result',\n name: 'Product 2',\n },\n ],\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_createBlock","_createSlots","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps"],"mappings":";;;;;;sBACEA,WASW,CAAA,mBAAA,EAAA;AAAA,IATA,SAAW,EAAA,IAAA,CAAA,SAAA;AAAA,IAAY,OAAS,EAAA,IAAA,CAAA,eAAA;AAAA,IAAkB,KAAO,EAAA,IAAA,CAAA,KAAA;AAAA,GAAA,EAAAC,WAAA,CAAA;;;;eACpC,IAAK,CAAA,KAAA,EAAA,CAAjB,GAAG,IAAI,KAAA;;;AAMvB,QAAA,EAAA,EAAAC,OAAA,CAAA,CAAuC,EANO,IAAI,EAAA,KAAA;AAAA,UAMlDC,UAAuC,CAAA,IAAA,CAAA,MAAA,EAA1B,IAAI,EAAAC,cAAA,CAAAC,kBAAA,CAAA,EAAY,IAAI,EAAA,CAAA,CAAA,CAAA;AAAA,SAAA,CAAA;;;;;;;;;"}
|