@milaboratories/uikit 2.15.37 → 2.15.38
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/.turbo/turbo-build.log +173 -173
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +2 -2
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +6 -0
- package/dist/__tests__/default-testid.test.d.ts +2 -0
- package/dist/__tests__/default-testid.test.d.ts.map +1 -0
- package/dist/base/BtnBase.js.map +1 -1
- package/dist/base/BtnBase.vue.d.ts.map +1 -1
- package/dist/base/BtnBase.vue2.js +6 -1
- package/dist/base/BtnBase.vue2.js.map +1 -1
- package/dist/components/DropdownListItem.js.map +1 -1
- package/dist/components/DropdownListItem.vue.d.ts.map +1 -1
- package/dist/components/DropdownListItem.vue2.js +13 -4
- package/dist/components/DropdownListItem.vue2.js.map +1 -1
- package/dist/components/InputRange.js.map +1 -1
- package/dist/components/InputRange.vue.d.ts.map +1 -1
- package/dist/components/InputRange.vue2.js +10 -2
- package/dist/components/InputRange.vue2.js.map +1 -1
- package/dist/components/PlAccordion/PlAccordionSection.js.map +1 -1
- package/dist/components/PlAccordion/PlAccordionSection.style.js.map +1 -1
- package/dist/components/PlAccordion/PlAccordionSection.vue.d.ts.map +1 -1
- package/dist/components/PlAccordion/PlAccordionSection.vue2.js +7 -1
- package/dist/components/PlAccordion/PlAccordionSection.vue2.js.map +1 -1
- package/dist/components/PlAlert/PlAlert.js.map +1 -1
- package/dist/components/PlAlert/PlAlert.vue.d.ts.map +1 -1
- package/dist/components/PlAlert/PlAlert.vue2.js +10 -1
- package/dist/components/PlAlert/PlAlert.vue2.js.map +1 -1
- package/dist/components/PlAutocomplete/PlAutocomplete.js.map +1 -1
- package/dist/components/PlAutocomplete/PlAutocomplete.vue.d.ts.map +1 -1
- package/dist/components/PlAutocomplete/PlAutocomplete.vue2.js +29 -11
- package/dist/components/PlAutocomplete/PlAutocomplete.vue2.js.map +1 -1
- package/dist/components/PlAutocompleteMulti/PlAutocompleteMulti.js.map +1 -1
- package/dist/components/PlAutocompleteMulti/PlAutocompleteMulti.vue.d.ts.map +1 -1
- package/dist/components/PlAutocompleteMulti/PlAutocompleteMulti.vue2.js +30 -9
- package/dist/components/PlAutocompleteMulti/PlAutocompleteMulti.vue2.js.map +1 -1
- package/dist/components/PlBtnAccent/PlBtnAccent.js.map +1 -1
- package/dist/components/PlBtnAccent/PlBtnAccent.vue.d.ts.map +1 -1
- package/dist/components/PlBtnAccent/PlBtnAccent.vue2.js +4 -1
- package/dist/components/PlBtnAccent/PlBtnAccent.vue2.js.map +1 -1
- package/dist/components/PlBtnDanger/PlBtnDanger.js.map +1 -1
- package/dist/components/PlBtnDanger/PlBtnDanger.vue.d.ts.map +1 -1
- package/dist/components/PlBtnDanger/PlBtnDanger.vue2.js +4 -1
- package/dist/components/PlBtnDanger/PlBtnDanger.vue2.js.map +1 -1
- package/dist/components/PlBtnGhost/PlBtnGhost.js.map +1 -1
- package/dist/components/PlBtnGhost/PlBtnGhost.vue.d.ts.map +1 -1
- package/dist/components/PlBtnGhost/PlBtnGhost.vue2.js +7 -1
- package/dist/components/PlBtnGhost/PlBtnGhost.vue2.js.map +1 -1
- package/dist/components/PlBtnGroup/PlBtnGroup.js.map +1 -1
- package/dist/components/PlBtnGroup/PlBtnGroup.vue.d.ts.map +1 -1
- package/dist/components/PlBtnGroup/PlBtnGroup.vue2.js +19 -6
- package/dist/components/PlBtnGroup/PlBtnGroup.vue2.js.map +1 -1
- package/dist/components/PlBtnLink/PlBtnLink.js.map +1 -1
- package/dist/components/PlBtnLink/PlBtnLink.vue.d.ts.map +1 -1
- package/dist/components/PlBtnLink/PlBtnLink.vue2.js +2 -0
- package/dist/components/PlBtnLink/PlBtnLink.vue2.js.map +1 -1
- package/dist/components/PlBtnPrimary/PlBtnPrimary.js.map +1 -1
- package/dist/components/PlBtnPrimary/PlBtnPrimary.vue.d.ts.map +1 -1
- package/dist/components/PlBtnPrimary/PlBtnPrimary.vue2.js +4 -1
- package/dist/components/PlBtnPrimary/PlBtnPrimary.vue2.js.map +1 -1
- package/dist/components/PlBtnSecondary/PlBtnSecondary.js.map +1 -1
- package/dist/components/PlBtnSecondary/PlBtnSecondary.vue.d.ts.map +1 -1
- package/dist/components/PlBtnSecondary/PlBtnSecondary.vue2.js +1 -1
- package/dist/components/PlBtnSecondary/PlBtnSecondary.vue2.js.map +1 -1
- package/dist/components/PlBtnSplit/PlBtnSplit.js.map +1 -1
- package/dist/components/PlBtnSplit/PlBtnSplit.vue.d.ts.map +1 -1
- package/dist/components/PlBtnSplit/PlBtnSplit.vue2.js +6 -0
- package/dist/components/PlBtnSplit/PlBtnSplit.vue2.js.map +1 -1
- package/dist/components/PlChartHistogram/PlChartHistogram.js.map +1 -1
- package/dist/components/PlChartHistogram/PlChartHistogram.style.js.map +1 -1
- package/dist/components/PlChartHistogram/PlChartHistogram.vue.d.ts.map +1 -1
- package/dist/components/PlChartHistogram/PlChartHistogram.vue2.js +7 -2
- package/dist/components/PlChartHistogram/PlChartHistogram.vue2.js.map +1 -1
- package/dist/components/PlChartHistogram/createGridlines.d.ts.map +1 -1
- package/dist/components/PlChartHistogram/createGridlines.js +1 -1
- package/dist/components/PlChartHistogram/createGridlines.js.map +1 -1
- package/dist/components/PlChartHistogram/createLabels.d.ts.map +1 -1
- package/dist/components/PlChartHistogram/createLabels.js +1 -1
- package/dist/components/PlChartHistogram/createLabels.js.map +1 -1
- package/dist/components/PlChartHistogram/createSvgContainer.d.ts.map +1 -1
- package/dist/components/PlChartHistogram/createSvgContainer.js +1 -1
- package/dist/components/PlChartHistogram/createSvgContainer.js.map +1 -1
- package/dist/components/PlChartHistogram/drawBins.d.ts.map +1 -1
- package/dist/components/PlChartHistogram/drawBins.js +2 -2
- package/dist/components/PlChartHistogram/drawBins.js.map +1 -1
- package/dist/components/PlChartHistogram/drawThreshold.d.ts.map +1 -1
- package/dist/components/PlChartHistogram/drawThreshold.js +1 -1
- package/dist/components/PlChartHistogram/drawThreshold.js.map +1 -1
- package/dist/components/PlChartHistogram/histogram.d.ts.map +1 -1
- package/dist/components/PlChartHistogram/histogram.js +1 -1
- package/dist/components/PlChartHistogram/histogram.js.map +1 -1
- package/dist/components/PlChartStackedBar/Legends.js.map +1 -1
- package/dist/components/PlChartStackedBar/Legends.style.js.map +1 -1
- package/dist/components/PlChartStackedBar/Legends.vue.d.ts.map +1 -1
- package/dist/components/PlChartStackedBar/Legends.vue2.js +7 -1
- package/dist/components/PlChartStackedBar/Legends.vue2.js.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBar.js.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBar.style.js.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBar.vue.d.ts.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBar.vue2.js +5 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBar.vue2.js.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBarCompact.js.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBarCompact.style.js.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBarCompact.vue.d.ts.map +1 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBarCompact.vue2.js +4 -1
- package/dist/components/PlChartStackedBar/PlChartStackedBarCompact.vue2.js.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRow.js.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRow.style.js.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRow.vue.d.ts.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRow.vue2.js +13 -3
- package/dist/components/PlChartStackedBar/StackedRow.vue2.js.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRowCompact.js.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRowCompact.style.js.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRowCompact.vue.d.ts.map +1 -1
- package/dist/components/PlChartStackedBar/StackedRowCompact.vue2.js +8 -2
- package/dist/components/PlChartStackedBar/StackedRowCompact.vue2.js.map +1 -1
- package/dist/components/PlCheckbox/PlCheckbox.js.map +1 -1
- package/dist/components/PlCheckbox/PlCheckbox.vue.d.ts.map +1 -1
- package/dist/components/PlCheckbox/PlCheckbox.vue2.js +9 -2
- package/dist/components/PlCheckbox/PlCheckbox.vue2.js.map +1 -1
- package/dist/components/PlCheckbox/PlCheckboxBase.js.map +1 -1
- package/dist/components/PlCheckbox/PlCheckboxBase.vue.d.ts.map +1 -1
- package/dist/components/PlCheckbox/PlCheckboxBase.vue2.js +1 -0
- package/dist/components/PlCheckbox/PlCheckboxBase.vue2.js.map +1 -1
- package/dist/components/PlCheckboxGroup/PlCheckboxGroup.js.map +1 -1
- package/dist/components/PlCheckboxGroup/PlCheckboxGroup.vue.d.ts.map +1 -1
- package/dist/components/PlCheckboxGroup/PlCheckboxGroup.vue2.js +19 -5
- package/dist/components/PlCheckboxGroup/PlCheckboxGroup.vue2.js.map +1 -1
- package/dist/components/PlChip/PlChip.js.map +1 -1
- package/dist/components/PlChip/PlChip.vue.d.ts.map +1 -1
- package/dist/components/PlChip/PlChip.vue2.js +7 -1
- package/dist/components/PlChip/PlChip.vue2.js.map +1 -1
- package/dist/components/PlClipboard/PlClipboard.js.map +1 -1
- package/dist/components/PlClipboard/PlClipboard.style.js.map +1 -1
- package/dist/components/PlClipboard/PlClipboard.vue.d.ts.map +1 -1
- package/dist/components/PlClipboard/PlClipboard.vue2.js +1 -0
- package/dist/components/PlClipboard/PlClipboard.vue2.js.map +1 -1
- package/dist/components/PlConfirmDialog.js.map +1 -1
- package/dist/components/PlConfirmDialog.vue.d.ts.map +1 -1
- package/dist/components/PlConfirmDialog.vue2.js +9 -2
- package/dist/components/PlConfirmDialog.vue2.js.map +1 -1
- package/dist/components/PlDialogModal/PlDialogModal.js.map +1 -1
- package/dist/components/PlDialogModal/PlDialogModal.vue.d.ts.map +1 -1
- package/dist/components/PlDialogModal/PlDialogModal.vue2.js +12 -5
- package/dist/components/PlDialogModal/PlDialogModal.vue2.js.map +1 -1
- package/dist/components/PlDropdown/OptionList.js.map +1 -1
- package/dist/components/PlDropdown/OptionList.vue.d.ts.map +1 -1
- package/dist/components/PlDropdown/OptionList.vue2.js +11 -5
- package/dist/components/PlDropdown/OptionList.vue2.js.map +1 -1
- package/dist/components/PlDropdown/PlDropdown.js.map +1 -1
- package/dist/components/PlDropdown/PlDropdown.vue.d.ts.map +1 -1
- package/dist/components/PlDropdown/PlDropdown.vue2.js +26 -10
- package/dist/components/PlDropdown/PlDropdown.vue2.js.map +1 -1
- package/dist/components/PlDropdownLegacy/PlDropdownLegacy.js.map +1 -1
- package/dist/components/PlDropdownLegacy/PlDropdownLegacy.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownLegacy/PlDropdownLegacy.vue2.js +32 -10
- package/dist/components/PlDropdownLegacy/PlDropdownLegacy.vue2.js.map +1 -1
- package/dist/components/PlDropdownLine/PlDropdownLine.js.map +1 -1
- package/dist/components/PlDropdownLine/PlDropdownLine.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownLine/PlDropdownLine.vue2.js +17 -3
- package/dist/components/PlDropdownLine/PlDropdownLine.vue2.js.map +1 -1
- package/dist/components/PlDropdownLine/ResizableInput.js.map +1 -1
- package/dist/components/PlDropdownLine/ResizableInput.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownLine/ResizableInput.vue2.js +5 -2
- package/dist/components/PlDropdownLine/ResizableInput.vue2.js.map +1 -1
- package/dist/components/PlDropdownMulti/PlDropdownMulti.js.map +1 -1
- package/dist/components/PlDropdownMulti/PlDropdownMulti.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownMulti/PlDropdownMulti.vue2.js +31 -10
- package/dist/components/PlDropdownMulti/PlDropdownMulti.vue2.js.map +1 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.js.map +1 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.vue2.js +1 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.vue2.js.map +1 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.js.map +1 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.vue2.js +1 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.vue2.js.map +1 -1
- package/dist/components/PlEditableTitle/PlEditableTitle.js.map +1 -1
- package/dist/components/PlEditableTitle/PlEditableTitle.vue.d.ts.map +1 -1
- package/dist/components/PlEditableTitle/PlEditableTitle.vue2.js +9 -3
- package/dist/components/PlEditableTitle/PlEditableTitle.vue2.js.map +1 -1
- package/dist/components/PlElementList/PlElementList.js.map +1 -1
- package/dist/components/PlElementList/PlElementList.style.js.map +1 -1
- package/dist/components/PlElementList/PlElementList.vue.d.ts.map +1 -1
- package/dist/components/PlElementList/PlElementList.vue2.js +6 -1
- package/dist/components/PlElementList/PlElementList.vue2.js.map +1 -1
- package/dist/components/PlElementList/PlElementListItem.js.map +1 -1
- package/dist/components/PlElementList/PlElementListItem.style.js.map +1 -1
- package/dist/components/PlElementList/PlElementListItem.vue.d.ts.map +1 -1
- package/dist/components/PlElementList/PlElementListItem.vue2.js +34 -13
- package/dist/components/PlElementList/PlElementListItem.vue2.js.map +1 -1
- package/dist/components/PlErrorAlert/PlErrorAlert.js.map +1 -1
- package/dist/components/PlErrorAlert/PlErrorAlert.style.js.map +1 -1
- package/dist/components/PlErrorAlert/PlErrorAlert.vue.d.ts.map +1 -1
- package/dist/components/PlErrorAlert/PlErrorAlert.vue2.js +15 -3
- package/dist/components/PlErrorAlert/PlErrorAlert.vue2.js.map +1 -1
- package/dist/components/PlErrorBoundary/PlErrorBoundary.js.map +1 -1
- package/dist/components/PlErrorBoundary/PlErrorBoundary.vue.d.ts.map +1 -1
- package/dist/components/PlErrorBoundary/PlErrorBoundary.vue2.js +1 -0
- package/dist/components/PlErrorBoundary/PlErrorBoundary.vue2.js.map +1 -1
- package/dist/components/PlFileDialog/Local.js.map +1 -1
- package/dist/components/PlFileDialog/Local.vue.d.ts.map +1 -1
- package/dist/components/PlFileDialog/Local.vue2.js +23 -20
- package/dist/components/PlFileDialog/Local.vue2.js.map +1 -1
- package/dist/components/PlFileDialog/PlFileDialog.js.map +1 -1
- package/dist/components/PlFileDialog/PlFileDialog.vue.d.ts.map +1 -1
- package/dist/components/PlFileDialog/PlFileDialog.vue2.js +5 -1
- package/dist/components/PlFileDialog/PlFileDialog.vue2.js.map +1 -1
- package/dist/components/PlFileDialog/Remote.js.map +1 -1
- package/dist/components/PlFileDialog/Remote.vue.d.ts.map +1 -1
- package/dist/components/PlFileDialog/Remote.vue2.js +108 -94
- package/dist/components/PlFileDialog/Remote.vue2.js.map +1 -1
- package/dist/components/PlFileDialog/Shortcuts.js.map +1 -1
- package/dist/components/PlFileDialog/Shortcuts.style.js.map +1 -1
- package/dist/components/PlFileDialog/Shortcuts.vue.d.ts.map +1 -1
- package/dist/components/PlFileDialog/Shortcuts.vue2.js +2 -1
- package/dist/components/PlFileDialog/Shortcuts.vue2.js.map +1 -1
- package/dist/components/PlFileInput/PlFileInput.js.map +1 -1
- package/dist/components/PlFileInput/PlFileInput.vue.d.ts.map +1 -1
- package/dist/components/PlFileInput/PlFileInput.vue2.js +92 -71
- package/dist/components/PlFileInput/PlFileInput.vue2.js.map +1 -1
- package/dist/components/PlLoaderCircular/PlLoaderCircular.js.map +1 -1
- package/dist/components/PlLoaderCircular/PlLoaderCircular.vue.d.ts.map +1 -1
- package/dist/components/PlLoaderCircular/PlLoaderCircular.vue2.js +4 -1
- package/dist/components/PlLoaderCircular/PlLoaderCircular.vue2.js.map +1 -1
- package/dist/components/PlLoaderLogo.js.map +1 -1
- package/dist/components/PlLoaderLogo.style.js.map +1 -1
- package/dist/components/PlLoaderLogo.vue.css +1 -1
- package/dist/components/PlLoaderLogo.vue.d.ts.map +1 -1
- package/dist/components/PlLoaderLogo.vue2.js +4 -3
- package/dist/components/PlLoaderLogo.vue2.js.map +1 -1
- package/dist/components/PlLogView/PlLogView.js.map +1 -1
- package/dist/components/PlLogView/PlLogView.vue.d.ts.map +1 -1
- package/dist/components/PlLogView/PlLogView.vue2.js +13 -1
- package/dist/components/PlLogView/PlLogView.vue2.js.map +1 -1
- package/dist/components/PlNotificationAlert/PlNotificationAlert.js.map +1 -1
- package/dist/components/PlNotificationAlert/PlNotificationAlert.vue.d.ts.map +1 -1
- package/dist/components/PlNotificationAlert/PlNotificationAlert.vue2.js +8 -2
- package/dist/components/PlNotificationAlert/PlNotificationAlert.vue2.js.map +1 -1
- package/dist/components/PlNumberField/PlNumberField.js.map +1 -1
- package/dist/components/PlNumberField/PlNumberField.vue.d.ts.map +1 -1
- package/dist/components/PlNumberField/PlNumberField.vue2.js +12 -3
- package/dist/components/PlNumberField/PlNumberField.vue2.js.map +1 -1
- package/dist/components/PlProgressBar/PlProgressBar.js.map +1 -1
- package/dist/components/PlProgressBar/PlProgressBar.vue.d.ts.map +1 -1
- package/dist/components/PlProgressBar/PlProgressBar.vue2.js +9 -1
- package/dist/components/PlProgressBar/PlProgressBar.vue2.js.map +1 -1
- package/dist/components/PlProgressCell/PlProgressCell.js.map +1 -1
- package/dist/components/PlProgressCell/PlProgressCell.vue.d.ts.map +1 -1
- package/dist/components/PlProgressCell/PlProgressCell.vue2.js +19 -7
- package/dist/components/PlProgressCell/PlProgressCell.vue2.js.map +1 -1
- package/dist/components/PlRadio/PlRadio.js.map +1 -1
- package/dist/components/PlRadio/PlRadio.style.js.map +1 -1
- package/dist/components/PlRadio/PlRadio.vue.d.ts.map +1 -1
- package/dist/components/PlRadio/PlRadio.vue2.js +10 -3
- package/dist/components/PlRadio/PlRadio.vue2.js.map +1 -1
- package/dist/components/PlRadio/PlRadioGroup.js.map +1 -1
- package/dist/components/PlRadio/PlRadioGroup.style.js.map +1 -1
- package/dist/components/PlRadio/PlRadioGroup.vue.d.ts.map +1 -1
- package/dist/components/PlRadio/PlRadioGroup.vue2.js +10 -3
- package/dist/components/PlRadio/PlRadioGroup.vue2.js.map +1 -1
- package/dist/components/PlSearchField/PlSearchField.js.map +1 -1
- package/dist/components/PlSearchField/PlSearchField.style.js.map +1 -1
- package/dist/components/PlSearchField/PlSearchField.vue.d.ts.map +1 -1
- package/dist/components/PlSearchField/PlSearchField.vue2.js +11 -4
- package/dist/components/PlSearchField/PlSearchField.vue2.js.map +1 -1
- package/dist/components/PlSectionSeparator/PlSectionSeparator.js.map +1 -1
- package/dist/components/PlSectionSeparator/PlSectionSeparator.style.js.map +1 -1
- package/dist/components/PlSectionSeparator/PlSectionSeparator.vue.d.ts.map +1 -1
- package/dist/components/PlSectionSeparator/PlSectionSeparator.vue2.js +7 -1
- package/dist/components/PlSectionSeparator/PlSectionSeparator.vue2.js.map +1 -1
- package/dist/components/PlSidebar/PlSidebarGroup.js.map +1 -1
- package/dist/components/PlSidebar/PlSidebarGroup.style.js.map +1 -1
- package/dist/components/PlSidebar/PlSidebarGroup.vue.d.ts.map +1 -1
- package/dist/components/PlSidebar/PlSidebarGroup.vue2.js +5 -1
- package/dist/components/PlSidebar/PlSidebarGroup.vue2.js.map +1 -1
- package/dist/components/PlSidebar/PlSidebarItem.js.map +1 -1
- package/dist/components/PlSidebar/PlSidebarItem.style.js.map +1 -1
- package/dist/components/PlSidebar/PlSidebarItem.vue.d.ts.map +1 -1
- package/dist/components/PlSidebar/PlSidebarItem.vue2.js +7 -1
- package/dist/components/PlSidebar/PlSidebarItem.vue2.js.map +1 -1
- package/dist/components/PlSlideModal/PlPureSlideModal.js.map +1 -1
- package/dist/components/PlSlideModal/PlPureSlideModal.vue.d.ts.map +1 -1
- package/dist/components/PlSlideModal/PlPureSlideModal.vue2.js +4 -1
- package/dist/components/PlSlideModal/PlPureSlideModal.vue2.js.map +1 -1
- package/dist/components/PlSlideModal/PlSlideModal.js.map +1 -1
- package/dist/components/PlSlideModal/PlSlideModal.style.js.map +1 -1
- package/dist/components/PlSlideModal/PlSlideModal.vue.d.ts.map +1 -1
- package/dist/components/PlSlideModal/PlSlideModal.vue2.js +7 -2
- package/dist/components/PlSlideModal/PlSlideModal.vue2.js.map +1 -1
- package/dist/components/PlSpacer/PlSpacer.vue.d.ts.map +1 -1
- package/dist/components/PlSplash/PlSplash.js.map +1 -1
- package/dist/components/PlSplash/PlSplash.vue.d.ts.map +1 -1
- package/dist/components/PlSplash/PlSplash.vue2.js +13 -5
- package/dist/components/PlSplash/PlSplash.vue2.js.map +1 -1
- package/dist/components/PlStatusTag/PlStatusTag.js.map +1 -1
- package/dist/components/PlStatusTag/PlStatusTag.vue.d.ts.map +1 -1
- package/dist/components/PlStatusTag/PlStatusTag.vue2.js +4 -1
- package/dist/components/PlStatusTag/PlStatusTag.vue2.js.map +1 -1
- package/dist/components/PlTabs/PlTabs.js.map +1 -1
- package/dist/components/PlTabs/PlTabs.vue.d.ts.map +1 -1
- package/dist/components/PlTabs/PlTabs.vue2.js +16 -11
- package/dist/components/PlTabs/PlTabs.vue2.js.map +1 -1
- package/dist/components/PlTextArea/PlTextArea.js.map +1 -1
- package/dist/components/PlTextArea/PlTextArea.vue.d.ts.map +1 -1
- package/dist/components/PlTextArea/PlTextArea.vue2.js +21 -8
- package/dist/components/PlTextArea/PlTextArea.vue2.js.map +1 -1
- package/dist/components/PlTextField/PlTextField.js.map +1 -1
- package/dist/components/PlTextField/PlTextField.vue.d.ts.map +1 -1
- package/dist/components/PlTextField/PlTextField.vue2.js +23 -9
- package/dist/components/PlTextField/PlTextField.vue2.js.map +1 -1
- package/dist/components/PlToggleSwitch/PlToggleSwitch.js.map +1 -1
- package/dist/components/PlToggleSwitch/PlToggleSwitch.vue.d.ts.map +1 -1
- package/dist/components/PlToggleSwitch/PlToggleSwitch.vue2.js +10 -2
- package/dist/components/PlToggleSwitch/PlToggleSwitch.vue2.js.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.js.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.style.js.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.vue.css +1 -1
- package/dist/components/PlTooltip/PlTooltip.vue.d.ts.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.vue2.js +7 -2
- package/dist/components/PlTooltip/PlTooltip.vue2.js.map +1 -1
- package/dist/components/Slider.js.map +1 -1
- package/dist/components/Slider.vue.d.ts.map +1 -1
- package/dist/components/Slider.vue2.js +13 -1
- package/dist/components/Slider.vue2.js.map +1 -1
- package/dist/components/SliderRange.js.map +1 -1
- package/dist/components/SliderRange.vue.d.ts.map +1 -1
- package/dist/components/SliderRange.vue2.js +14 -1
- package/dist/components/SliderRange.vue2.js.map +1 -1
- package/dist/components/SliderRangeTriple.js.map +1 -1
- package/dist/components/SliderRangeTriple.vue.d.ts.map +1 -1
- package/dist/components/SliderRangeTriple.vue2.js +13 -1
- package/dist/components/SliderRangeTriple.vue2.js.map +1 -1
- package/dist/components/TabItem.js.map +1 -1
- package/dist/components/TabItem.vue.d.ts.map +1 -1
- package/dist/components/TabItem.vue2.js +8 -2
- package/dist/components/TabItem.vue2.js.map +1 -1
- package/dist/components/contextMenu/Menu.js +1 -1
- package/dist/components/contextMenu/Menu.js.map +1 -1
- package/dist/components/contextMenu/Menu.style.css +1 -1
- package/dist/components/contextMenu/Menu.vue.d.ts.map +1 -1
- package/dist/components/contextMenu/Menu.vue2.js +12 -8
- package/dist/components/contextMenu/Menu.vue2.js.map +1 -1
- package/dist/layout/PlBlockPage/PlBlockPage.js.map +1 -1
- package/dist/layout/PlBlockPage/PlBlockPage.style.js.map +1 -1
- package/dist/layout/PlBlockPage/PlBlockPage.vue.d.ts.map +1 -1
- package/dist/layout/PlBlockPage/PlBlockPage.vue2.js +45 -25
- package/dist/layout/PlBlockPage/PlBlockPage.vue2.js.map +1 -1
- package/dist/layout/PlContainer/PlContainer.js.map +1 -1
- package/dist/layout/PlContainer/PlContainer.vue.d.ts.map +1 -1
- package/dist/layout/PlContainer/PlContainer.vue2.js +1 -0
- package/dist/layout/PlContainer/PlContainer.vue2.js.map +1 -1
- package/dist/layout/PlGrid/PlGrid.js.map +1 -1
- package/dist/layout/PlGrid/PlGrid.vue.d.ts.map +1 -1
- package/dist/layout/PlGrid/PlGrid.vue2.js +1 -0
- package/dist/layout/PlGrid/PlGrid.vue2.js.map +1 -1
- package/dist/layout/PlPlaceholder/PlPlaceholder.js.map +1 -1
- package/dist/layout/PlPlaceholder/PlPlaceholder.style.js.map +1 -1
- package/dist/layout/PlPlaceholder/PlPlaceholder.vue.d.ts.map +1 -1
- package/dist/layout/PlPlaceholder/PlPlaceholder.vue2.js +25 -6
- package/dist/layout/PlPlaceholder/PlPlaceholder.vue2.js.map +1 -1
- package/dist/layout/PlRow/PlRow.js.map +1 -1
- package/dist/layout/PlRow/PlRow.vue.d.ts.map +1 -1
- package/dist/layout/PlRow/PlRow.vue2.js +7 -4
- package/dist/layout/PlRow/PlRow.vue2.js.map +1 -1
- package/dist/layout/PlSpacer/PlSpacer.js.map +1 -1
- package/dist/layout/PlSpacer/PlSpacer.vue.d.ts.map +1 -1
- package/dist/layout/PlSpacer/PlSpacer.vue2.js +1 -0
- package/dist/layout/PlSpacer/PlSpacer.vue2.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/default-testid.test.ts +95 -0
- package/src/base/BtnBase.vue +3 -3
- package/src/components/DropdownListItem.vue +14 -4
- package/src/components/InputRange.vue +6 -2
- package/src/components/PlAccordion/PlAccordionSection.vue +13 -4
- package/src/components/PlAlert/PlAlert.vue +5 -3
- package/src/components/PlAutocomplete/PlAutocomplete.vue +47 -11
- package/src/components/PlAutocompleteMulti/PlAutocompleteMulti.vue +53 -11
- package/src/components/PlBtnAccent/PlBtnAccent.vue +1 -1
- package/src/components/PlBtnDanger/PlBtnDanger.vue +1 -1
- package/src/components/PlBtnGhost/PlBtnGhost.vue +4 -3
- package/src/components/PlBtnGroup/PlBtnGroup.vue +16 -6
- package/src/components/PlBtnLink/PlBtnLink.vue +2 -1
- package/src/components/PlBtnPrimary/PlBtnPrimary.vue +1 -1
- package/src/components/PlBtnSecondary/PlBtnSecondary.vue +1 -1
- package/src/components/PlBtnSplit/PlBtnSplit.vue +12 -2
- package/src/components/PlChartHistogram/PlChartHistogram.vue +9 -3
- package/src/components/PlChartHistogram/createGridlines.ts +2 -0
- package/src/components/PlChartHistogram/createLabels.ts +2 -0
- package/src/components/PlChartHistogram/createSvgContainer.ts +2 -0
- package/src/components/PlChartHistogram/drawBins.ts +2 -0
- package/src/components/PlChartHistogram/drawThreshold.ts +1 -0
- package/src/components/PlChartHistogram/histogram.ts +6 -1
- package/src/components/PlChartStackedBar/Legends.vue +18 -4
- package/src/components/PlChartStackedBar/PlChartStackedBar.vue +4 -2
- package/src/components/PlChartStackedBar/PlChartStackedBarCompact.vue +1 -1
- package/src/components/PlChartStackedBar/StackedRow.vue +12 -4
- package/src/components/PlChartStackedBar/StackedRowCompact.vue +10 -3
- package/src/components/PlCheckbox/PlCheckbox.vue +15 -4
- package/src/components/PlCheckbox/PlCheckboxBase.vue +1 -0
- package/src/components/PlCheckboxGroup/PlCheckboxGroup.vue +15 -4
- package/src/components/PlChip/PlChip.vue +4 -3
- package/src/components/PlClipboard/PlClipboard.vue +7 -1
- package/src/components/PlConfirmDialog.vue +8 -3
- package/src/components/PlDialogModal/PlDialogModal.vue +15 -2
- package/src/components/PlDropdown/OptionList.vue +13 -3
- package/src/components/PlDropdown/PlDropdown.vue +35 -11
- package/src/components/PlDropdownLegacy/PlDropdownLegacy.vue +51 -12
- package/src/components/PlDropdownLine/PlDropdownLine.vue +29 -5
- package/src/components/PlDropdownLine/ResizableInput.vue +2 -1
- package/src/components/PlDropdownMulti/PlDropdownMulti.vue +47 -11
- package/src/components/PlDropdownMultiRef/PlDropdownMultiRef.vue +1 -0
- package/src/components/PlDropdownRef/PlDropdownRef.vue +1 -0
- package/src/components/PlEditableTitle/PlEditableTitle.vue +11 -3
- package/src/components/PlElementList/PlElementList.vue +8 -3
- package/src/components/PlElementList/PlElementListItem.vue +16 -5
- package/src/components/PlErrorAlert/PlErrorAlert.vue +8 -6
- package/src/components/PlErrorBoundary/PlErrorBoundary.vue +7 -1
- package/src/components/PlFileDialog/Local.vue +12 -4
- package/src/components/PlFileDialog/PlFileDialog.vue +13 -3
- package/src/components/PlFileDialog/Remote.vue +39 -11
- package/src/components/PlFileDialog/Shortcuts.vue +7 -1
- package/src/components/PlFileInput/PlFileInput.vue +44 -19
- package/src/components/PlLoaderCircular/PlLoaderCircular.vue +1 -1
- package/src/components/PlLoaderLogo.vue +6 -1
- package/src/components/PlLogView/PlLogView.vue +30 -8
- package/src/components/PlNotificationAlert/PlNotificationAlert.vue +15 -3
- package/src/components/PlNumberField/PlNumberField.vue +14 -3
- package/src/components/PlProgressBar/PlProgressBar.vue +12 -4
- package/src/components/PlProgressCell/PlProgressCell.vue +13 -4
- package/src/components/PlRadio/PlRadio.vue +10 -3
- package/src/components/PlRadio/PlRadioGroup.vue +3 -2
- package/src/components/PlSearchField/PlSearchField.vue +5 -3
- package/src/components/PlSectionSeparator/PlSectionSeparator.vue +6 -2
- package/src/components/PlSidebar/PlSidebarGroup.vue +2 -2
- package/src/components/PlSidebar/PlSidebarItem.vue +12 -4
- package/src/components/PlSlideModal/PlPureSlideModal.vue +7 -1
- package/src/components/PlSlideModal/PlSlideModal.vue +4 -3
- package/src/components/PlSpacer/PlSpacer.vue +1 -1
- package/src/components/PlSplash/PlSplash.vue +6 -3
- package/src/components/PlStatusTag/PlStatusTag.vue +1 -0
- package/src/components/PlTabs/PlTabs.vue +6 -2
- package/src/components/PlTextArea/PlTextArea.vue +21 -8
- package/src/components/PlTextField/PlTextField.vue +23 -8
- package/src/components/PlToggleSwitch/PlToggleSwitch.vue +4 -3
- package/src/components/PlTooltip/PlTooltip.vue +3 -0
- package/src/components/Slider.vue +27 -7
- package/src/components/SliderRange.vue +28 -7
- package/src/components/SliderRangeTriple.vue +19 -5
- package/src/components/TabItem.vue +2 -2
- package/src/components/contextMenu/Menu.vue +8 -3
- package/src/layout/PlBlockPage/PlBlockPage.vue +40 -11
- package/src/layout/PlContainer/PlContainer.vue +1 -0
- package/src/layout/PlGrid/PlGrid.vue +1 -1
- package/src/layout/PlPlaceholder/PlPlaceholder.vue +20 -8
- package/src/layout/PlRow/PlRow.vue +5 -1
- package/src/layout/PlSpacer/PlSpacer.vue +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OptionList.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlDropdown/OptionList.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport { DropdownOverlay } from \"../../utils/DropdownOverlay\";\nimport TextLabel from \"../../utils/TextLabel.vue\";\nimport { computed, useTemplateRef } from \"vue\";\nimport type { LOption } from \"./types\";\n\nconst props = defineProps<{\n rootRef: HTMLElement;\n groups: Map<string, LOption[]>;\n rest: LOption[];\n optionSize: \"small\" | \"medium\";\n selectOption: (v: unknown) => void;\n}>();\n\nconst overlay = useTemplateRef(\"overlay\");\n\nconst listRef = computed(() => overlay.value?.listRef);\n\nconst hasGroups = computed(() => props.groups.size > 0);\n\nconst optionsLength = computed(() => {\n let totalGroupItems = 0;\n for (const items of props.groups.values()) {\n totalGroupItems += items.length;\n }\n return totalGroupItems + props.rest.length;\n});\n\nconst scrollIntoActive = () => {\n overlay.value?.scrollIntoActive();\n};\n\ndefineExpose({\n scrollIntoActive,\n listRef,\n});\n</script>\n\n<template>\n <DropdownOverlay\n ref=\"overlay\"\n :root=\"rootRef\"\n class=\"pl-dropdown__options\"\n tabindex=\"-1\"\n :gap=\"3\"\n >\n <div\n v-for=\"[group, items] in groups.entries()\"\n :key=\"group\"\n :class=\"{ 'group-container': hasGroups }\"\n >\n <TextLabel>{{ group }}</TextLabel>\n <div>\n <DropdownListItem\n v-for=\"(item, index) in items\"\n :key=\"index\"\n :option=\"item\"\n :is-selected=\"item.isSelected\"\n :is-hovered=\"item.isActive\"\n :size=\"optionSize\"\n @click.stop=\"selectOption(item.value)\"\n />\n </div>\n </div>\n <div
|
|
1
|
+
{"version":3,"file":"OptionList.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlDropdown/OptionList.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport { DropdownOverlay } from \"../../utils/DropdownOverlay\";\nimport TextLabel from \"../../utils/TextLabel.vue\";\nimport { computed, useTemplateRef } from \"vue\";\nimport type { LOption } from \"./types\";\n\nconst props = defineProps<{\n rootRef: HTMLElement;\n groups: Map<string, LOption[]>;\n rest: LOption[];\n optionSize: \"small\" | \"medium\";\n selectOption: (v: unknown) => void;\n}>();\n\nconst overlay = useTemplateRef(\"overlay\");\n\nconst listRef = computed(() => overlay.value?.listRef);\n\nconst hasGroups = computed(() => props.groups.size > 0);\n\nconst optionsLength = computed(() => {\n let totalGroupItems = 0;\n for (const items of props.groups.values()) {\n totalGroupItems += items.length;\n }\n return totalGroupItems + props.rest.length;\n});\n\nconst scrollIntoActive = () => {\n overlay.value?.scrollIntoActive();\n};\n\ndefineExpose({\n scrollIntoActive,\n listRef,\n});\n</script>\n\n<template>\n <DropdownOverlay\n ref=\"overlay\"\n :root=\"rootRef\"\n class=\"pl-dropdown__options\"\n data-testid=\"pl-dropdown-options\"\n tabindex=\"-1\"\n :gap=\"3\"\n >\n <div\n v-for=\"[group, items] in groups.entries()\"\n :key=\"group\"\n :class=\"{ 'group-container': hasGroups }\"\n data-testid=\"pl-dropdown-option-group\"\n >\n <TextLabel data-testid=\"pl-dropdown-option-group-label\">{{ group }}</TextLabel>\n <div>\n <DropdownListItem\n v-for=\"(item, index) in items\"\n :key=\"index\"\n :option=\"item\"\n :is-selected=\"item.isSelected\"\n :is-hovered=\"item.isActive\"\n :size=\"optionSize\"\n data-testid=\"pl-dropdown-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n </div>\n </div>\n <div\n v-if=\"rest.length\"\n :class=\"{ 'group-container': hasGroups }\"\n data-testid=\"pl-dropdown-option-group\"\n >\n <TextLabel />\n <div>\n <DropdownListItem\n v-for=\"(item, index) in rest\"\n :key=\"index\"\n :option=\"item\"\n :is-selected=\"item.isSelected\"\n :is-hovered=\"item.isActive\"\n :size=\"optionSize\"\n data-testid=\"pl-dropdown-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n </div>\n </div>\n <div v-if=\"!optionsLength\" class=\"nothing-found\" data-testid=\"pl-dropdown-options-empty\">\n Nothing found\n </div>\n </DropdownOverlay>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAOA,IAAM,IAAQ,GAQR,IAAU,EAAe,UAAU,EAEnC,IAAU,QAAe,EAAQ,OAAO,QAAQ,EAEhD,IAAY,QAAe,EAAM,OAAO,OAAO,EAAE,EAEjD,IAAgB,QAAe;GACnC,IAAI,IAAkB;AACtB,QAAK,IAAM,KAAS,EAAM,OAAO,QAAQ,CACvC,MAAmB,EAAM;AAE3B,UAAO,IAAkB,EAAM,KAAK;IACpC;SAMF,EAAa;GACX,wBAL6B;AAC7B,MAAQ,OAAO,kBAAkB;;GAKjC;GACD,CAAC,kBAIA,EAkDkB,EAAA,EAAA,EAAA;YAjDZ;GAAJ,KAAI;GACH,MAAM,EAAA;GACP,OAAM;GACN,eAAY;GACZ,UAAS;GACR,KAAK;;oBAGsC;YAD5C,EAmBM,GAAA,MAAA,EAlBqB,EAAA,OAAO,SAAO,GAAA,CAA/B,GAAO,aADjB,EAmBM,OAAA;KAjBH,KAAK;KACL,OAAK,EAAA,EAAA,mBAAuB,EAAA,OAAS,CAAA;KACtC,eAAY;QAEZ,EAA+E,GAAA,EAApE,eAAY,kCAAgC,EAAA;sBAAY,CAAA,EAAA,EAAR,EAAK,EAAA,EAAA,CAAA,CAAA;;cAChE,EAWM,OAAA,MAAA,EAAA,EAAA,GAAA,EAVJ,EASE,GAAA,MAAA,EARwB,IAAhB,GAAM,YADhB,EASE,GAAA;KAPC,KAAK;KACL,QAAQ;KACR,eAAa,EAAK;KAClB,cAAY,EAAK;KACjB,MAAM,EAAA;KACP,eAAY;KACX,SAAK,GAAA,MAAO,EAAA,aAAa,EAAK,MAAK,EAAA,CAAA,OAAA,CAAA;;;;;;;;IAKlC,EAAA,KAAK,UAAA,GAAA,EADb,EAkBM,OAAA;;KAhBH,OAAK,EAAA,EAAA,mBAAuB,EAAA,OAAS,CAAA;KACtC,eAAY;QAEZ,EAAa,EAAA,EACb,EAWM,OAAA,MAAA,EAAA,EAAA,GAAA,EAVJ,EASE,GAAA,MAAA,EARwB,EAAA,OAAhB,GAAM,YADhB,EASE,GAAA;KAPC,KAAK;KACL,QAAQ;KACR,eAAa,EAAK;KAClB,cAAY,EAAK;KACjB,MAAM,EAAA;KACP,eAAY;KACX,SAAK,GAAA,MAAO,EAAA,aAAa,EAAK,MAAK,EAAA,CAAA,OAAA,CAAA;;;;;;;;IAI9B,EAAA,QAEZ,EAAA,IAAA,GAAA,IAFY,GAAA,EAAZ,EAEM,OAFN,GAAyF,kBAEzF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdown.js","names":[],"sources":["../../../src/components/PlDropdown/PlDropdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport { computed, reactive, ref, unref, useTemplateRef, watch, watchPostEffect } from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { tap } from \"../../helpers/functions\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption, ListOptionNormalized, MaskIconName16, MaskIconName24 } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport OptionList from \"./OptionList.vue\";\nimport \"./pl-dropdown.scss\";\nimport type { LOption } from \"./types\";\nimport { useGroupBy } from \"./useGroupBy\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Shows red border even without an error message\n */\n errorStatus?: boolean;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in the field when `modelValue` has no matching option — e.g. its\n * upstream block was deleted. Rendered italic in error color.\n */\n missingValueLabel?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: MaskIconName16;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: MaskIconName24;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n showErrorMessage: true,\n placeholder: \"...\",\n missingValueLabel: \"Value not available\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst optionListRef = useTemplateRef<InstanceType<typeof OptionList>>(\"optionListRef\");\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst findActiveIndex = () =>\n tap(\n orderedRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\n/**\n * Loading spinner should not be shown when the dropdown is explicitly disabled,\n * even if options are undefined. The disabled state takes precedence.\n */\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst isMissing = computed(() => {\n return hasValue.value && selectedIndex.value === -1 && !isLoadingOptions.value;\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n // The field renders the missing state via `missingValueLabel`; no need to\n // duplicate it as a helper error.\n return undefined;\n});\n\nconst optionsRef = computed<LOption<M>[]>(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n return item?.label;\n});\n\n// Native tooltip with the full selected value. The `.input-value` layer has\n// `pointer-events: none`, so the title must sit on the field wrapper, which is\n// what actually receives the hover.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n if (isMissing.value) return props.missingValueLabel;\n return textValue.value !== undefined ? String(textValue.value) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && hasValue.value) {\n return \"\";\n }\n\n return textValue.value ? String(textValue.value) : props.placeholder;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst { orderedRef, groupsRef, restRef } = useGroupBy(filteredRef, \"group\");\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n rootRef?.value?.focus();\n};\n\nconst selectOptionWrapper = (v: unknown) => {\n selectOption(v as M | undefined);\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (\n !rootRef.value?.contains(relatedTarget) &&\n !optionListRef.value?.listRef?.contains(relatedTarget)\n ) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const ordered = orderedRef.value;\n\n const { length } = ordered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(ordered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = ordered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = ordered[newIndex].index ?? -1;\n};\n\nuseLabelNotch(rootRef);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n optionListRef.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown__envelope\" @click=\"setFocusOnInput\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown\"\n :class=\"{ open: data.open, error: error || errorStatus, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown__container\">\n <div class=\"pl-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" class=\"input-value\">\n <LongText v-if=\"isMissing\" class=\"input-value--missing\">\n {{ missingValueLabel }}\n </LongText>\n <LongText v-else-if=\"textValue !== undefined\">\n {{ textValue }}\n </LongText>\n </div>\n\n <div class=\"pl-dropdown__controls\">\n <PlIcon24 v-if=\"showLoadingSpinner\" name=\"loading\" />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div class=\"pl-dropdown__arrow-wrapper\" @click.stop=\"toggleOpen\">\n <PlIcon24 v-if=\"arrowIconLarge\" :name=\"arrowIconLarge\" class=\"arrow-icon\" />\n <PlIcon16 v-else-if=\"arrowIcon\" :name=\"arrowIcon\" class=\"arrow-icon\" />\n <PlIcon16 v-else name=\"chevron-down\" class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" />\n <span>{{ label }}</span>\n <PlTooltip v-if=\"$slots.tooltip\" class=\"info\" position=\"top\">\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <OptionList\n v-if=\"data.open\"\n ref=\"optionListRef\"\n :root-ref=\"rootRef!\"\n :groups=\"groupsRef\"\n :rest=\"restRef\"\n :option-size=\"optionSize\"\n :select-option=\"selectOptionWrapper\"\n />\n <DoubleContour class=\"pl-dropdown__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"pl-dropdown__error\">{{ computedError }}</div>\n <div v-else-if=\"showLoadingSpinner && loadingOptionsHelper\" class=\"pl-dropdown__helper\">\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"pl-dropdown__helper\">{{ helper }}</div>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"PlDropdown.js","names":[],"sources":["../../../src/components/PlDropdown/PlDropdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport { computed, reactive, ref, unref, useTemplateRef, watch, watchPostEffect } from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { tap } from \"../../helpers/functions\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption, ListOptionNormalized, MaskIconName16, MaskIconName24 } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport OptionList from \"./OptionList.vue\";\nimport \"./pl-dropdown.scss\";\nimport type { LOption } from \"./types\";\nimport { useGroupBy } from \"./useGroupBy\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Shows red border even without an error message\n */\n errorStatus?: boolean;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in the field when `modelValue` has no matching option — e.g. its\n * upstream block was deleted. Rendered italic in error color.\n */\n missingValueLabel?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: MaskIconName16;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: MaskIconName24;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n showErrorMessage: true,\n placeholder: \"...\",\n missingValueLabel: \"Value not available\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst optionListRef = useTemplateRef<InstanceType<typeof OptionList>>(\"optionListRef\");\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst findActiveIndex = () =>\n tap(\n orderedRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\n/**\n * Loading spinner should not be shown when the dropdown is explicitly disabled,\n * even if options are undefined. The disabled state takes precedence.\n */\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst isMissing = computed(() => {\n return hasValue.value && selectedIndex.value === -1 && !isLoadingOptions.value;\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n // The field renders the missing state via `missingValueLabel`; no need to\n // duplicate it as a helper error.\n return undefined;\n});\n\nconst optionsRef = computed<LOption<M>[]>(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n return item?.label;\n});\n\n// Native tooltip with the full selected value. The `.input-value` layer has\n// `pointer-events: none`, so the title must sit on the field wrapper, which is\n// what actually receives the hover.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n if (isMissing.value) return props.missingValueLabel;\n return textValue.value !== undefined ? String(textValue.value) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && hasValue.value) {\n return \"\";\n }\n\n return textValue.value ? String(textValue.value) : props.placeholder;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst { orderedRef, groupsRef, restRef } = useGroupBy(filteredRef, \"group\");\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n rootRef?.value?.focus();\n};\n\nconst selectOptionWrapper = (v: unknown) => {\n selectOption(v as M | undefined);\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (\n !rootRef.value?.contains(relatedTarget) &&\n !optionListRef.value?.listRef?.contains(relatedTarget)\n ) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const ordered = orderedRef.value;\n\n const { length } = ordered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(ordered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = ordered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = ordered[newIndex].index ?? -1;\n};\n\nuseLabelNotch(rootRef);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n optionListRef.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown__envelope\" @click=\"setFocusOnInput\" data-testid=\"pl-dropdown\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown\"\n data-testid=\"pl-dropdown-control\"\n :class=\"{ open: data.open, error: error || errorStatus, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown__container\">\n <div class=\"pl-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-input\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" class=\"input-value\" data-testid=\"pl-dropdown-value\">\n <LongText\n v-if=\"isMissing\"\n class=\"input-value--missing\"\n data-testid=\"pl-dropdown-value-missing\"\n >\n {{ missingValueLabel }}\n </LongText>\n <LongText v-else-if=\"textValue !== undefined\">\n {{ textValue }}\n </LongText>\n </div>\n\n <div class=\"pl-dropdown__controls\">\n <PlIcon24 v-if=\"showLoadingSpinner\" name=\"loading\" data-testid=\"pl-dropdown-loading\" />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n data-testid=\"pl-dropdown-clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div\n class=\"pl-dropdown__arrow-wrapper\"\n data-testid=\"pl-dropdown-arrow\"\n @click.stop=\"toggleOpen\"\n >\n <PlIcon24 v-if=\"arrowIconLarge\" :name=\"arrowIconLarge\" class=\"arrow-icon\" />\n <PlIcon16 v-else-if=\"arrowIcon\" :name=\"arrowIcon\" class=\"arrow-icon\" />\n <PlIcon16 v-else name=\"chevron-down\" class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"$slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <OptionList\n v-if=\"data.open\"\n ref=\"optionListRef\"\n :root-ref=\"rootRef!\"\n :groups=\"groupsRef\"\n :rest=\"restRef\"\n :option-size=\"optionSize\"\n :select-option=\"selectOptionWrapper\"\n />\n <DoubleContour class=\"pl-dropdown__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"pl-dropdown__error\" data-testid=\"pl-dropdown-error\">\n {{ computedError }}\n </div>\n <div\n v-else-if=\"showLoadingSpinner && loadingOptionsHelper\"\n class=\"pl-dropdown__helper\"\n data-testid=\"pl-dropdown-helper\"\n >\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"pl-dropdown__helper\" data-testid=\"pl-dropdown-helper\">\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdown.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDropdown/PlDropdown.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlDropdown.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDropdown/PlDropdown.vue"],"names":[],"mappings":"AAmdA,OAAO,KAAK,EAAE,UAAU,EAAwB,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AASpG,OAAO,oBAAoB,CAAC;AAK5B;;GAEG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY,GAAK,CAAC,GAAG,OAAO,EACjC,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WA+qBO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB,CAAC;QArqBpD;;WAEG;oBACS,CAAC;QACb;;WAEG;gBACK,MAAM;QACd;;WAEG;kBACO,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC;;WAEG;iBACM,MAAM;QACf;;WAEG;+BACoB,MAAM;QAC7B;;WAEG;gBACK,OAAO;QACf;;WAEG;sBACW,OAAO;QACrB;;WAEG;sBACW,MAAM;QACpB;;;WAGG;4BACiB,MAAM;QAC1B;;WAEG;oBACS,OAAO;QACnB;;WAEG;mBACQ,OAAO;QAClB;;WAEG;mBACQ,OAAO;QAClB;;WAEG;oBACS,cAAc;QAC1B;;WAEG;yBACc,cAAc;QAC/B;;WAEG;qBACU,OAAO,GAAG,QAAQ;QAC/B;;aAEK;wBAED,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,GACd,QAAQ;;;KA4lB2E,CAAC,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC5J,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;iBAbE,CAAC,KAAK,IAAiB,KAAK,GAAG;;kBAC9B,CAAC,KAAK,IAAiB,KAAK,GAAG;;cAhqBvC,mBAAmB,SAAS,CAAC,GAAG,SAAS,KAAG,IAAI;EAgrBlD,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CAAI,CAAC;AACzF,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
|
|
@@ -21,16 +21,23 @@ import { computed as p, createBlock as m, createCommentVNode as h, createElement
|
|
|
21
21
|
//#region src/components/PlDropdown/PlDropdown.vue?vue&type=script&setup=true&lang.ts
|
|
22
22
|
var ie = ["tabindex"], ae = { class: "pl-dropdown__container" }, oe = ["title"], se = ["disabled", "placeholder"], ce = {
|
|
23
23
|
key: 0,
|
|
24
|
-
class: "input-value"
|
|
25
|
-
|
|
24
|
+
class: "input-value",
|
|
25
|
+
"data-testid": "pl-dropdown-value"
|
|
26
|
+
}, le = { class: "pl-dropdown__controls" }, ue = {
|
|
26
27
|
key: 0,
|
|
27
|
-
|
|
28
|
+
"data-testid": "pl-dropdown-label"
|
|
29
|
+
}, de = {
|
|
30
|
+
key: 0,
|
|
31
|
+
class: "pl-dropdown__error",
|
|
32
|
+
"data-testid": "pl-dropdown-error"
|
|
28
33
|
}, M = {
|
|
29
34
|
key: 1,
|
|
30
|
-
class: "pl-dropdown__helper"
|
|
35
|
+
class: "pl-dropdown__helper",
|
|
36
|
+
"data-testid": "pl-dropdown-helper"
|
|
31
37
|
}, N = {
|
|
32
38
|
key: 2,
|
|
33
|
-
class: "pl-dropdown__helper"
|
|
39
|
+
class: "pl-dropdown__helper",
|
|
40
|
+
"data-testid": "pl-dropdown-helper"
|
|
34
41
|
}, P = /* @__PURE__ */ b({
|
|
35
42
|
name: "PlDropdown",
|
|
36
43
|
props: {
|
|
@@ -115,7 +122,8 @@ var ie = ["tabindex"], ae = { class: "pl-dropdown__container" }, oe = ["title"],
|
|
|
115
122
|
B.search, B.activeIndex >= 0 && B.open && z.value?.scrollIntoActive();
|
|
116
123
|
}), (e, t) => (S(), g("div", {
|
|
117
124
|
class: "pl-dropdown__envelope",
|
|
118
|
-
onClick: ye
|
|
125
|
+
onClick: ye,
|
|
126
|
+
"data-testid": "pl-dropdown"
|
|
119
127
|
}, [_("div", {
|
|
120
128
|
ref_key: "rootRef",
|
|
121
129
|
ref: L,
|
|
@@ -125,6 +133,7 @@ var ie = ["tabindex"], ae = { class: "pl-dropdown__container" }, oe = ["title"],
|
|
|
125
133
|
error: b.error || b.errorStatus,
|
|
126
134
|
disabled: G.value
|
|
127
135
|
}]),
|
|
136
|
+
"data-testid": "pl-dropdown-control",
|
|
128
137
|
onKeydown: Ce,
|
|
129
138
|
onFocusout: Se
|
|
130
139
|
}, [_("div", ae, [
|
|
@@ -142,11 +151,13 @@ var ie = ["tabindex"], ae = { class: "pl-dropdown__container" }, oe = ["title"],
|
|
|
142
151
|
placeholder: pe.value,
|
|
143
152
|
spellcheck: "false",
|
|
144
153
|
autocomplete: "chrome-off",
|
|
154
|
+
"data-testid": "pl-dropdown-input",
|
|
145
155
|
onFocus: xe
|
|
146
156
|
}, null, 40, se), [[re, B.search]]),
|
|
147
157
|
B.open ? h("", !0) : (S(), g("div", ce, [J.value ? (S(), m(i, {
|
|
148
158
|
key: 0,
|
|
149
|
-
class: "input-value--missing"
|
|
159
|
+
class: "input-value--missing",
|
|
160
|
+
"data-testid": "pl-dropdown-value-missing"
|
|
150
161
|
}, {
|
|
151
162
|
default: k(() => [v(T(b.missingValueLabel), 1)]),
|
|
152
163
|
_: 1
|
|
@@ -157,17 +168,20 @@ var ie = ["tabindex"], ae = { class: "pl-dropdown__container" }, oe = ["title"],
|
|
|
157
168
|
_("div", le, [
|
|
158
169
|
W.value ? (S(), m(E(o), {
|
|
159
170
|
key: 0,
|
|
160
|
-
name: "loading"
|
|
171
|
+
name: "loading",
|
|
172
|
+
"data-testid": "pl-dropdown-loading"
|
|
161
173
|
})) : h("", !0),
|
|
162
174
|
b.clearable && q.value ? (S(), m(E(s), {
|
|
163
175
|
key: 1,
|
|
164
176
|
class: "clear",
|
|
177
|
+
"data-testid": "pl-dropdown-clear",
|
|
165
178
|
name: "delete-clear",
|
|
166
179
|
onClick: j(ve, ["stop"])
|
|
167
180
|
})) : h("", !0),
|
|
168
181
|
w(e.$slots, "append"),
|
|
169
182
|
_("div", {
|
|
170
183
|
class: "pl-dropdown__arrow-wrapper",
|
|
184
|
+
"data-testid": "pl-dropdown-arrow",
|
|
171
185
|
onClick: j(be, ["stop"])
|
|
172
186
|
}, [b.arrowIconLarge ? (S(), m(E(o), {
|
|
173
187
|
key: 0,
|
|
@@ -187,13 +201,15 @@ var ie = ["tabindex"], ae = { class: "pl-dropdown__container" }, oe = ["title"],
|
|
|
187
201
|
b.label ? (S(), g("label", ue, [
|
|
188
202
|
b.required ? (S(), m(E(a), {
|
|
189
203
|
key: 0,
|
|
190
|
-
uri: E(u)
|
|
204
|
+
uri: E(u),
|
|
205
|
+
"data-testid": "pl-dropdown-required"
|
|
191
206
|
}, null, 8, ["uri"])) : h("", !0),
|
|
192
207
|
_("span", null, T(b.label), 1),
|
|
193
208
|
e.$slots.tooltip ? (S(), m(E(n), {
|
|
194
209
|
key: 1,
|
|
195
210
|
class: "info",
|
|
196
|
-
position: "top"
|
|
211
|
+
position: "top",
|
|
212
|
+
"data-testid": "pl-dropdown-tooltip"
|
|
197
213
|
}, {
|
|
198
214
|
tooltip: k(() => [w(e.$slots, "tooltip")]),
|
|
199
215
|
_: 3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdown.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/PlDropdown/PlDropdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport { computed, reactive, ref, unref, useTemplateRef, watch, watchPostEffect } from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { tap } from \"../../helpers/functions\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption, ListOptionNormalized, MaskIconName16, MaskIconName24 } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport OptionList from \"./OptionList.vue\";\nimport \"./pl-dropdown.scss\";\nimport type { LOption } from \"./types\";\nimport { useGroupBy } from \"./useGroupBy\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Shows red border even without an error message\n */\n errorStatus?: boolean;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in the field when `modelValue` has no matching option — e.g. its\n * upstream block was deleted. Rendered italic in error color.\n */\n missingValueLabel?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: MaskIconName16;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: MaskIconName24;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n showErrorMessage: true,\n placeholder: \"...\",\n missingValueLabel: \"Value not available\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst optionListRef = useTemplateRef<InstanceType<typeof OptionList>>(\"optionListRef\");\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst findActiveIndex = () =>\n tap(\n orderedRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\n/**\n * Loading spinner should not be shown when the dropdown is explicitly disabled,\n * even if options are undefined. The disabled state takes precedence.\n */\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst isMissing = computed(() => {\n return hasValue.value && selectedIndex.value === -1 && !isLoadingOptions.value;\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n // The field renders the missing state via `missingValueLabel`; no need to\n // duplicate it as a helper error.\n return undefined;\n});\n\nconst optionsRef = computed<LOption<M>[]>(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n return item?.label;\n});\n\n// Native tooltip with the full selected value. The `.input-value` layer has\n// `pointer-events: none`, so the title must sit on the field wrapper, which is\n// what actually receives the hover.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n if (isMissing.value) return props.missingValueLabel;\n return textValue.value !== undefined ? String(textValue.value) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && hasValue.value) {\n return \"\";\n }\n\n return textValue.value ? String(textValue.value) : props.placeholder;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst { orderedRef, groupsRef, restRef } = useGroupBy(filteredRef, \"group\");\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n rootRef?.value?.focus();\n};\n\nconst selectOptionWrapper = (v: unknown) => {\n selectOption(v as M | undefined);\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (\n !rootRef.value?.contains(relatedTarget) &&\n !optionListRef.value?.listRef?.contains(relatedTarget)\n ) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const ordered = orderedRef.value;\n\n const { length } = ordered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(ordered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = ordered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = ordered[newIndex].index ?? -1;\n};\n\nuseLabelNotch(rootRef);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n optionListRef.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown__envelope\" @click=\"setFocusOnInput\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown\"\n :class=\"{ open: data.open, error: error || errorStatus, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown__container\">\n <div class=\"pl-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" class=\"input-value\">\n <LongText v-if=\"isMissing\" class=\"input-value--missing\">\n {{ missingValueLabel }}\n </LongText>\n <LongText v-else-if=\"textValue !== undefined\">\n {{ textValue }}\n </LongText>\n </div>\n\n <div class=\"pl-dropdown__controls\">\n <PlIcon24 v-if=\"showLoadingSpinner\" name=\"loading\" />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div class=\"pl-dropdown__arrow-wrapper\" @click.stop=\"toggleOpen\">\n <PlIcon24 v-if=\"arrowIconLarge\" :name=\"arrowIconLarge\" class=\"arrow-icon\" />\n <PlIcon16 v-else-if=\"arrowIcon\" :name=\"arrowIcon\" class=\"arrow-icon\" />\n <PlIcon16 v-else name=\"chevron-down\" class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" />\n <span>{{ label }}</span>\n <PlTooltip v-if=\"$slots.tooltip\" class=\"info\" position=\"top\">\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <OptionList\n v-if=\"data.open\"\n ref=\"optionListRef\"\n :root-ref=\"rootRef!\"\n :groups=\"groupsRef\"\n :rest=\"restRef\"\n :option-size=\"optionSize\"\n :select-option=\"selectOptionWrapper\"\n />\n <DoubleContour class=\"pl-dropdown__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"pl-dropdown__error\">{{ computedError }}</div>\n <div v-else-if=\"showLoadingSpinner && loadingOptionsHelper\" class=\"pl-dropdown__helper\">\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"pl-dropdown__helper\">{{ helper }}</div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBR,IAAM,IAAO,GAOP,IAAQ,GAgGR,IAAU,GAA8B,EACxC,IAAQ,GAAmC,EAE3C,IAAgB,GAAgD,gBAAgB,EAEhF,IAAO,GAAS;GACpB,QAAQ;GACR,aAAa;GACb,MAAM;GACN,eAAe;GAChB,CAAC,EAEI,UACJ,EACE,EAAW,MAAM,WAAW,MAAM,EAAU,EAAE,OAAO,EAAM,WAAW,CAAC,GACtE,MAAO,IAAI,IAAI,IAAI,EACrB,EAEG,UAAsB,EAAK,cAAc,GAAiB,EAE1D,IAAmB,QAChB,EAAM,YAAY,KAAA,EACzB,EAMI,IAAqB,QAClB,CAAC,EAAM,YAAY,EAAiB,MAC3C,EAEI,IAAa,QACb,EAAiB,QACZ,KAGF,EAAM,SACb,EAEI,IAAgB,SACZ,EAAM,WAAW,EAAE,EAAE,WAAW,MAAM,EAAU,EAAE,OAAO,EAAM,WAAW,CAAC,CACnF,EAEI,IAAW,QACR,EAAM,eAAe,KAAA,KAAa,EAAM,eAAe,KAC9D,EAEI,IAAY,QACT,EAAS,SAAS,EAAc,UAAU,MAAM,CAAC,EAAiB,MACzE,EAEI,IAAgB,QAAe;AAC/B,UAAiB,SAIjB,EAAM,MACR,QAAO,EAAgB,EAAM,MAAM;IAMrC,EAEI,IAAa,QACjB,EAAqB,EAAM,WAAW,EAAE,CAAC,CAAC,KAAK,GAAK,OAAW;GAC7D,GAAG;GACH;GACA,YAAY,MAAU,EAAc;GACpC,UAAU,MAAU,EAAK;GAC1B,EAAE,CACJ,EAEK,IAAY,QACA,EAAM,EAAW,CACY,MAAM,MAAM,EAAU,EAAE,OAAO,EAAM,WAAW,CAAC,EACjF,MACb,EAKI,KAAa,QAAe;AAC5B,UAAK,KAET,QADI,EAAU,QAAc,EAAM,oBAC3B,EAAU,UAAU,KAAA,IAAsC,KAAA,IAA1B,OAAO,EAAU,MAAM;IAC9D,EAEI,KAAsB,QACtB,CAAC,EAAK,QAAQ,EAAS,QAClB,KAGF,EAAU,QAAQ,OAAO,EAAU,MAAM,GAAG,EAAM,YACzD,EA4BI,EAAE,eAAY,eAAW,gBAAY,EA1BvB,QAAe;GACjC,IAAM,IAAU,EAAW;AAsB3B,UApBI,EAAK,SACA,EAAQ,QAAQ,MAA4B;IACjD,IAAM,IAAS,EAAK,OAAO,aAAa;AAcxC,WAZI,EAAE,MAAM,aAAa,CAAC,SAAS,EAAO,IAItC,EAAE,eAAe,EAAE,YAAY,aAAa,CAAC,SAAS,EAAO,GACxD,KAGL,OAAO,EAAE,SAAU,WACd,EAAE,MAAM,aAAa,CAAC,SAAS,EAAO,GAGxC,EAAE,UAAU,EAAK;KACxB,GAGG;IACP,EAEiE,QAAQ,EAErE,KAAW,QAAgB,EAAW,QAAQ,KAAA,IAAY,IAAK,EAE/D,KAAgB,MAAqB;AAIzC,GAHA,EAAK,qBAAqB,EAAE,EAC5B,EAAK,SAAS,IACd,EAAK,OAAO,IACZ,GAAS,OAAO,OAAO;KAGnB,MAAuB,MAAe;AAC1C,KAAa,EAAmB;KAG5B,WAAc,EAAK,qBAAqB,KAAA,EAAU,EAElD,WAAwB,EAAM,OAAO,OAAO,EAE5C,WAAmB;AAEvB,GADA,EAAK,OAAO,CAAC,EAAK,MACb,EAAK,SACR,EAAK,SAAS;KAIZ,WAAsB,EAAK,OAAO,IAElC,MAAc,MAAsB;GACxC,IAAM,IAAgB,EAAM;AAE5B,GACE,CAAC,EAAQ,OAAO,SAAS,EAAc,IACvC,CAAC,EAAc,OAAO,SAAS,SAAS,EAAa,KAErD,EAAK,SAAS,IACd,EAAK,OAAO;KAIV,MAAiB,MAAgD;AACrE,OAAK;IAAC;IAAa;IAAW;IAAS;IAAS,CAAC,SAAS,EAAE,KAAK,CAG/D,GAAE,gBAAgB;OAFlB;GAKF,IAAM,EAAE,SAAM,mBAAgB;AAE9B,OAAI,CAAC,GAAM;AACT,IAAI,EAAE,SAAS,YACb,EAAK,OAAO;AAEd;;AAGF,GAAI,EAAE,SAAS,aACb,EAAK,OAAO,IACZ,EAAQ,OAAO,OAAO;GAGxB,IAAM,IAAU,EAAW,OAErB,EAAE,cAAW;AAEnB,OAAI,CAAC,EACH;AAGF,GAAI,EAAE,SAAS,WACb,EAAa,EAAQ,MAAM,MAAO,EAAG,UAAU,EAAY,EAAE,MAAM;GAGrE,IAAM,IAAa,EAAQ,WAAW,MAAO,EAAG,UAAU,EAAY,IAAI,IAEpE,IAAQ,EAAE,SAAS,cAAc,IAAI,EAAE,SAAS,YAAY,KAAK;AAIvE,KAAK,cAAc,EAFF,KAAK,IAAI,IAAa,IAAQ,EAAO,GAAG,GAEpB,SAAS;;SAGhD,EAAc,EAAQ,EAEtB,QAAY,EAAM,YAAY,GAAc,EAAE,WAAW,IAAM,CAAC,EAEhE,QACQ,EAAK,OACV,MAAU,IAAO,EAAM,OAAO,OAAO,GAAG,GAC1C,EAED,QAAsB;AAIpB,GAFA,EAAK,QAED,EAAK,eAAe,KAAK,EAAK,QAChC,EAAc,OAAO,kBAAkB;IAEzC,kBAIA,EA0EM,OAAA;GA1ED,OAAM;GAAyB,SAAO;MACzC,EAmEM,OAAA;YAlEA;GAAJ,KAAI;GACH,UAAU,GAAA;GACX,OAAK,EAAA,CAAC,eAAa;IAAA,MACH,EAAK;IAAI,OAAS,EAAA,SAAS,EAAA;IAAW,UAAY,EAAA;IAAU,CAAA,CAAA;GAC3E,WAAS;GACT,YAAU;MAEX,EA0DM,OA1DN,IA0DM;GAzDJ,EAqCM,OAAA;IArCD,OAAM;IAAsB,OAAO,GAAA;;MACtC,EAUE,SAAA;cATI;KAAJ,KAAI;8CACU,SAAM;KACpB,MAAK;KACL,UAAS;KACR,UAAU,EAAA;KACV,aAAa,GAAA;KACd,YAAW;KACX,cAAa;KACZ,SAAO;4BAPC,EAAK,OAAM,CAAA,CAAA;IAUV,EAAK,oBAAA,GAAA,EAAjB,EAOM,OAPN,IAOM,CANY,EAAA,SAAA,GAAA,EAAhB,EAEW,GAAA;;KAFgB,OAAM;;sBACR,CAAA,EAAA,EAApB,EAAA,kBAAiB,EAAA,EAAA,CAAA,CAAA;;UAED,EAAA,UAAc,KAAA,iBAAA,GAAA,EAAnC,EAEW,GAAA,EAAA,KAAA,GAAA,EAAA;sBADM,CAAA,EAAA,EAAZ,EAAA,MAAS,EAAA,EAAA,CAAA,CAAA;;;IAIhB,EAcM,OAdN,IAcM;KAbY,EAAA,SAAA,GAAA,EAAhB,EAAqD,EAAA,EAAA,EAAA;;MAAjB,MAAK;;KAEjC,EAAA,aAAa,EAAA,SAAA,GAAA,EADrB,EAKE,EAAA,EAAA,EAAA;;MAHA,OAAM;MACN,MAAK;MACJ,SAAK,EAAO,IAAK,CAAA,OAAA,CAAA;;KAEpB,EAAsB,EAAA,QAAA,SAAA;KACtB,EAIM,OAAA;MAJD,OAAM;MAA8B,SAAK,EAAO,IAAU,CAAA,OAAA,CAAA;SAC7C,EAAA,kBAAA,GAAA,EAAhB,EAA4E,EAAA,EAAA,EAAA;;MAA3C,MAAM,EAAA;MAAgB,OAAM;8BACxC,EAAA,aAAA,GAAA,EAArB,EAAuE,EAAA,EAAA,EAAA;;MAAtC,MAAM,EAAA;MAAW,OAAM;oCACxD,EAA6E,EAAA,EAAA,EAAA;;MAA5D,MAAK;MAAe,OAAM;;;;GAIpC,EAAA,SAAA,GAAA,EAAb,EAQQ,SAAA,IAAA;IAPO,EAAA,YAAA,GAAA,EAAb,EAA4C,EAAA,EAAA,EAAA;;KAApB,KAAK,EAAA,EAAW;;IACxC,EAAwB,QAAA,MAAA,EAAf,EAAA,MAAK,EAAA,EAAA;IACGA,EAAAA,OAAO,WAAA,GAAA,EAAxB,EAIY,EAAA,EAAA,EAAA;;KAJqB,OAAM;KAAO,UAAS;;KAC1C,SAAO,QACO,CAAvB,EAAuB,EAAA,QAAA,UAAA,CAAA,CAAA;;;;GAKrB,EAAK,QAAA,GAAA,EADb,EAQE,GAAA;;aANI;IAAJ,KAAI;IACH,YAAU,EAAA;IACV,QAAQ,EAAA,GAAS;IACjB,MAAM,EAAA,GAAO;IACb,eAAa,EAAA;IACb,iBAAe;;;;;;;GAElB,EAA8E,IAAA;IAA/D,OAAM;IAAwB,kBAAgB,EAAA;;gBAGtD,EAAA,SAAA,GAAA,EAAX,EAA8E,OAA9E,IAA8E,EAAtB,EAAA,MAAa,EAAA,EAAA,IACrD,EAAA,SAAsB,EAAA,wBAAA,GAAA,EAAtC,EAEM,OAFN,GAEM,EADD,EAAA,qBAAoB,EAAA,EAAA,IAET,EAAA,UAAA,GAAA,EAAhB,EAAsE,OAAtE,GAAsE,EAAf,EAAA,OAAM,EAAA,EAAA,IAAA,EAAA,IAAA,GAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"PlDropdown.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/PlDropdown/PlDropdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport { computed, reactive, ref, unref, useTemplateRef, watch, watchPostEffect } from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { tap } from \"../../helpers/functions\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption, ListOptionNormalized, MaskIconName16, MaskIconName24 } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport OptionList from \"./OptionList.vue\";\nimport \"./pl-dropdown.scss\";\nimport type { LOption } from \"./types\";\nimport { useGroupBy } from \"./useGroupBy\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Shows red border even without an error message\n */\n errorStatus?: boolean;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in the field when `modelValue` has no matching option — e.g. its\n * upstream block was deleted. Rendered italic in error color.\n */\n missingValueLabel?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: MaskIconName16;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: MaskIconName24;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n showErrorMessage: true,\n placeholder: \"...\",\n missingValueLabel: \"Value not available\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst optionListRef = useTemplateRef<InstanceType<typeof OptionList>>(\"optionListRef\");\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst findActiveIndex = () =>\n tap(\n orderedRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\n/**\n * Loading spinner should not be shown when the dropdown is explicitly disabled,\n * even if options are undefined. The disabled state takes precedence.\n */\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst isMissing = computed(() => {\n return hasValue.value && selectedIndex.value === -1 && !isLoadingOptions.value;\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n // The field renders the missing state via `missingValueLabel`; no need to\n // duplicate it as a helper error.\n return undefined;\n});\n\nconst optionsRef = computed<LOption<M>[]>(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n return item?.label;\n});\n\n// Native tooltip with the full selected value. The `.input-value` layer has\n// `pointer-events: none`, so the title must sit on the field wrapper, which is\n// what actually receives the hover.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n if (isMissing.value) return props.missingValueLabel;\n return textValue.value !== undefined ? String(textValue.value) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && hasValue.value) {\n return \"\";\n }\n\n return textValue.value ? String(textValue.value) : props.placeholder;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst { orderedRef, groupsRef, restRef } = useGroupBy(filteredRef, \"group\");\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n rootRef?.value?.focus();\n};\n\nconst selectOptionWrapper = (v: unknown) => {\n selectOption(v as M | undefined);\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (\n !rootRef.value?.contains(relatedTarget) &&\n !optionListRef.value?.listRef?.contains(relatedTarget)\n ) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const ordered = orderedRef.value;\n\n const { length } = ordered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(ordered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = ordered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = ordered[newIndex].index ?? -1;\n};\n\nuseLabelNotch(rootRef);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n optionListRef.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown__envelope\" @click=\"setFocusOnInput\" data-testid=\"pl-dropdown\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown\"\n data-testid=\"pl-dropdown-control\"\n :class=\"{ open: data.open, error: error || errorStatus, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown__container\">\n <div class=\"pl-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-input\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" class=\"input-value\" data-testid=\"pl-dropdown-value\">\n <LongText\n v-if=\"isMissing\"\n class=\"input-value--missing\"\n data-testid=\"pl-dropdown-value-missing\"\n >\n {{ missingValueLabel }}\n </LongText>\n <LongText v-else-if=\"textValue !== undefined\">\n {{ textValue }}\n </LongText>\n </div>\n\n <div class=\"pl-dropdown__controls\">\n <PlIcon24 v-if=\"showLoadingSpinner\" name=\"loading\" data-testid=\"pl-dropdown-loading\" />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n data-testid=\"pl-dropdown-clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div\n class=\"pl-dropdown__arrow-wrapper\"\n data-testid=\"pl-dropdown-arrow\"\n @click.stop=\"toggleOpen\"\n >\n <PlIcon24 v-if=\"arrowIconLarge\" :name=\"arrowIconLarge\" class=\"arrow-icon\" />\n <PlIcon16 v-else-if=\"arrowIcon\" :name=\"arrowIcon\" class=\"arrow-icon\" />\n <PlIcon16 v-else name=\"chevron-down\" class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"$slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <OptionList\n v-if=\"data.open\"\n ref=\"optionListRef\"\n :root-ref=\"rootRef!\"\n :groups=\"groupsRef\"\n :rest=\"restRef\"\n :option-size=\"optionSize\"\n :select-option=\"selectOptionWrapper\"\n />\n <DoubleContour class=\"pl-dropdown__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"pl-dropdown__error\" data-testid=\"pl-dropdown-error\">\n {{ computedError }}\n </div>\n <div\n v-else-if=\"showLoadingSpinner && loadingOptionsHelper\"\n class=\"pl-dropdown__helper\"\n data-testid=\"pl-dropdown-helper\"\n >\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"pl-dropdown__helper\" data-testid=\"pl-dropdown-helper\">\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdownLegacy.js","names":[],"sources":["../../../src/components/PlDropdownLegacy/PlDropdownLegacy.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport \"./pl-dropdown-legacy.scss\";\nimport { computed, reactive, ref, unref, useSlots, watch, watchPostEffect } from \"vue\";\nimport { tap, tapIf } from \"../../helpers/functions\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport type { ListOption, ListOptionNormalized } from \"../../types\";\nimport { scrollIntoView } from \"../../helpers/dom\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlMaskIcon24 } from \"../PlMaskIcon24\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { PlSvg } from \"../PlSvg\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: string;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: string;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n },\n);\n\nconst slots = useSlots();\n\nconst root = ref<HTMLElement | undefined>();\nconst list = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n});\n\nconst findActiveIndex = () =>\n tap(\n filteredRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n if (props.modelValue !== undefined && selectedIndex.value === -1) {\n return \"The selected value is not one of the options\";\n }\n\n return undefined;\n});\n\nconst optionsRef = computed(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n\n return item?.label || props.modelValue; // @todo show inner value?\n});\n\n// Native tooltip with the full selected value; the value layer itself has\n// `pointer-events: none`, so the title goes on the field wrapper.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n const v = textValue.value;\n return v !== undefined && v !== null && v !== \"\" ? String(v) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && props.modelValue) {\n return \"\";\n }\n\n return props.modelValue ? String(textValue.value) : props.placeholder;\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n root?.value?.focus();\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => (data.open = !data.open);\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n if (!root?.value?.contains(event.relatedTarget as Node | null)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst scrollIntoActive = () => {\n const $list = list.value;\n\n if (!$list) {\n return;\n }\n\n tapIf($list.querySelector(\".hovered-item\") as HTMLElement, (opt) => {\n scrollIntoView($list, opt);\n });\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n root.value?.focus();\n }\n\n const filtered = unref(filteredRef);\n\n const { length } = filtered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(filtered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = filtered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = filteredRef.value[newIndex].index ?? -1;\n};\n\nuseLabelNotch(root);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"ui-dropdown__envelope\">\n <div\n ref=\"root\"\n :tabindex=\"tabindex\"\n class=\"ui-dropdown\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"ui-dropdown__container\">\n <div class=\"ui-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" @click=\"setFocusOnInput\">\n <LongText class=\"input-value\"> {{ textValue }} </LongText>\n </div>\n\n <div class=\"ui-dropdown__controls\">\n <PlMaskIcon24 v-if=\"isLoadingOptions\" name=\"loading\" />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div\n v-if=\"arrowIconLarge\"\n class=\"arrow-icon\"\n :class=\"[`icon-24 ${arrowIconLarge}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div\n v-else-if=\"arrowIcon\"\n class=\"arrow-icon\"\n :class=\"[`icon-16 ${arrowIcon}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div v-else class=\"arrow-icon arrow-icon-default\" @click.stop=\"toggleOpen\" />\n </div>\n </div>\n <label v-if=\"label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" />\n <span>{{ label }}</span>\n <PlTooltip v-if=\"slots.tooltip\" class=\"info\" position=\"top\">\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <div v-if=\"data.open\" ref=\"list\" class=\"ui-dropdown__options\">\n <DropdownListItem\n v-for=\"(item, index) in filteredRef\"\n :key=\"index\"\n :option=\"item\"\n :is-selected=\"item.isSelected\"\n :is-hovered=\"item.isActive\"\n :size=\"optionSize\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div v-if=\"!filteredRef.length\" class=\"nothing-found\">Nothing found</div>\n </div>\n <DoubleContour class=\"ui-dropdown__contour\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"ui-dropdown__error\">{{ computedError }}</div>\n <div v-else-if=\"isLoadingOptions && loadingOptionsHelper\" class=\"ui-dropdown__helper\">\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"ui-dropdown__helper\">{{ helper }}</div>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"PlDropdownLegacy.js","names":[],"sources":["../../../src/components/PlDropdownLegacy/PlDropdownLegacy.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport \"./pl-dropdown-legacy.scss\";\nimport { computed, reactive, ref, unref, useSlots, watch, watchPostEffect } from \"vue\";\nimport { tap, tapIf } from \"../../helpers/functions\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport type { ListOption, ListOptionNormalized } from \"../../types\";\nimport { scrollIntoView } from \"../../helpers/dom\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlMaskIcon24 } from \"../PlMaskIcon24\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { PlSvg } from \"../PlSvg\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: string;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: string;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n },\n);\n\nconst slots = useSlots();\n\nconst root = ref<HTMLElement | undefined>();\nconst list = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n});\n\nconst findActiveIndex = () =>\n tap(\n filteredRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n if (props.modelValue !== undefined && selectedIndex.value === -1) {\n return \"The selected value is not one of the options\";\n }\n\n return undefined;\n});\n\nconst optionsRef = computed(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n\n return item?.label || props.modelValue; // @todo show inner value?\n});\n\n// Native tooltip with the full selected value; the value layer itself has\n// `pointer-events: none`, so the title goes on the field wrapper.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n const v = textValue.value;\n return v !== undefined && v !== null && v !== \"\" ? String(v) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && props.modelValue) {\n return \"\";\n }\n\n return props.modelValue ? String(textValue.value) : props.placeholder;\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n root?.value?.focus();\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => (data.open = !data.open);\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n if (!root?.value?.contains(event.relatedTarget as Node | null)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst scrollIntoActive = () => {\n const $list = list.value;\n\n if (!$list) {\n return;\n }\n\n tapIf($list.querySelector(\".hovered-item\") as HTMLElement, (opt) => {\n scrollIntoView($list, opt);\n });\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n root.value?.focus();\n }\n\n const filtered = unref(filteredRef);\n\n const { length } = filtered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(filtered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = filtered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = filteredRef.value[newIndex].index ?? -1;\n};\n\nuseLabelNotch(root);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"ui-dropdown__envelope\" data-testid=\"pl-dropdown-legacy\">\n <div\n ref=\"root\"\n :tabindex=\"tabindex\"\n class=\"ui-dropdown\"\n data-testid=\"pl-dropdown-legacy-control\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"ui-dropdown__container\">\n <div class=\"ui-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-legacy-input\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" data-testid=\"pl-dropdown-legacy-value\" @click=\"setFocusOnInput\">\n <LongText class=\"input-value\"> {{ textValue }} </LongText>\n </div>\n\n <div class=\"ui-dropdown__controls\">\n <PlMaskIcon24\n v-if=\"isLoadingOptions\"\n name=\"loading\"\n data-testid=\"pl-dropdown-legacy-loading\"\n />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n data-testid=\"pl-dropdown-legacy-clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div\n v-if=\"arrowIconLarge\"\n class=\"arrow-icon\"\n data-testid=\"pl-dropdown-legacy-arrow\"\n :class=\"[`icon-24 ${arrowIconLarge}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div\n v-else-if=\"arrowIcon\"\n class=\"arrow-icon\"\n data-testid=\"pl-dropdown-legacy-arrow\"\n :class=\"[`icon-16 ${arrowIcon}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div\n v-else\n class=\"arrow-icon arrow-icon-default\"\n data-testid=\"pl-dropdown-legacy-arrow\"\n @click.stop=\"toggleOpen\"\n />\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-legacy-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-legacy-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-legacy-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <div\n v-if=\"data.open\"\n ref=\"list\"\n class=\"ui-dropdown__options\"\n data-testid=\"pl-dropdown-legacy-options\"\n >\n <DropdownListItem\n v-for=\"(item, index) in filteredRef\"\n :key=\"index\"\n :option=\"item\"\n :is-selected=\"item.isSelected\"\n :is-hovered=\"item.isActive\"\n :size=\"optionSize\"\n data-testid=\"pl-dropdown-legacy-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div\n v-if=\"!filteredRef.length\"\n class=\"nothing-found\"\n data-testid=\"pl-dropdown-legacy-options-empty\"\n >\n Nothing found\n </div>\n </div>\n <DoubleContour class=\"ui-dropdown__contour\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"ui-dropdown__error\" data-testid=\"pl-dropdown-legacy-error\">\n {{ computedError }}\n </div>\n <div\n v-else-if=\"isLoadingOptions && loadingOptionsHelper\"\n class=\"ui-dropdown__helper\"\n data-testid=\"pl-dropdown-legacy-helper\"\n >\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"ui-dropdown__helper\" data-testid=\"pl-dropdown-legacy-helper\">\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdownLegacy.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDropdownLegacy/PlDropdownLegacy.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlDropdownLegacy.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDropdownLegacy/PlDropdownLegacy.vue"],"names":[],"mappings":"AA2bA,OAAO,2BAA2B,CAAC;AAMnC,OAAO,KAAK,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAapE;;GAEG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY,GAAK,CAAC,GAAG,OAAO,EACjC,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WAmnBO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB,CAAC;QAzmBpD;;WAEG;oBACS,CAAC;QACb;;WAEG;gBACK,MAAM;QACd;;WAEG;kBACO,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC;;WAEG;iBACM,MAAM;QACf;;WAEG;+BACoB,MAAM;QAC7B;;WAEG;gBACK,OAAO;QACf;;WAEG;sBACW,MAAM;QACpB;;WAEG;oBACS,OAAO;QACnB;;WAEG;mBACQ,OAAO;QAClB;;WAEG;mBACQ,OAAO;QAClB;;WAEG;oBACS,MAAM;QAClB;;WAEG;yBACc,MAAM;QACvB;;WAEG;qBACU,OAAO,GAAG,QAAQ;;;KAsjBwD,CAAC,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC5J,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;iBAbE,CAAC,KAAK,IAAiB,KAAK,GAAG;;kBAC9B,CAAC,KAAK,IAAiB,KAAK,GAAG;;cApmBvC,mBAAmB,SAAS,CAAC,GAAG,SAAS,KAAG,IAAI;EAonBlD,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CAAI,CAAC;AACzF,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
|
|
@@ -19,18 +19,28 @@ import re from "../../assets/images/required.js";
|
|
|
19
19
|
/* empty css */
|
|
20
20
|
import { Fragment as ie, computed as d, createBlock as f, createCommentVNode as p, createElementBlock as m, createElementVNode as h, createTextVNode as ae, createVNode as g, defineComponent as _, normalizeClass as v, openBlock as y, reactive as b, ref as x, renderList as S, renderSlot as C, toDisplayString as w, unref as T, useSlots as oe, vModelText as se, watch as E, watchPostEffect as ce, withCtx as D, withDirectives as le, withModifiers as O } from "vue";
|
|
21
21
|
//#region src/components/PlDropdownLegacy/PlDropdownLegacy.vue?vue&type=script&setup=true&lang.ts
|
|
22
|
-
var ue = {
|
|
22
|
+
var ue = {
|
|
23
|
+
class: "ui-dropdown__envelope",
|
|
24
|
+
"data-testid": "pl-dropdown-legacy"
|
|
25
|
+
}, de = ["tabindex"], fe = { class: "ui-dropdown__container" }, pe = ["title"], k = ["disabled", "placeholder"], A = { class: "ui-dropdown__controls" }, j = {
|
|
23
26
|
key: 0,
|
|
24
|
-
|
|
27
|
+
"data-testid": "pl-dropdown-legacy-label"
|
|
28
|
+
}, M = {
|
|
29
|
+
key: 0,
|
|
30
|
+
class: "nothing-found",
|
|
31
|
+
"data-testid": "pl-dropdown-legacy-options-empty"
|
|
25
32
|
}, N = {
|
|
26
33
|
key: 0,
|
|
27
|
-
class: "ui-dropdown__error"
|
|
34
|
+
class: "ui-dropdown__error",
|
|
35
|
+
"data-testid": "pl-dropdown-legacy-error"
|
|
28
36
|
}, P = {
|
|
29
37
|
key: 1,
|
|
30
|
-
class: "ui-dropdown__helper"
|
|
38
|
+
class: "ui-dropdown__helper",
|
|
39
|
+
"data-testid": "pl-dropdown-legacy-helper"
|
|
31
40
|
}, F = {
|
|
32
41
|
key: 2,
|
|
33
|
-
class: "ui-dropdown__helper"
|
|
42
|
+
class: "ui-dropdown__helper",
|
|
43
|
+
"data-testid": "pl-dropdown-legacy-helper"
|
|
34
44
|
}, I = /* @__PURE__ */ _({
|
|
35
45
|
name: "PlDropdown",
|
|
36
46
|
props: {
|
|
@@ -123,6 +133,7 @@ var ue = { class: "ui-dropdown__envelope" }, de = ["tabindex"], fe = { class: "u
|
|
|
123
133
|
error: _.error,
|
|
124
134
|
disabled: G.value
|
|
125
135
|
}]),
|
|
136
|
+
"data-testid": "pl-dropdown-legacy-control",
|
|
126
137
|
onKeydown: we,
|
|
127
138
|
onFocusout: Se
|
|
128
139
|
}, [h("div", fe, [
|
|
@@ -140,10 +151,12 @@ var ue = { class: "ui-dropdown__envelope" }, de = ["tabindex"], fe = { class: "u
|
|
|
140
151
|
placeholder: _e.value,
|
|
141
152
|
spellcheck: "false",
|
|
142
153
|
autocomplete: "chrome-off",
|
|
154
|
+
"data-testid": "pl-dropdown-legacy-input",
|
|
143
155
|
onFocus: xe
|
|
144
156
|
}, null, 40, k), [[se, U.search]]),
|
|
145
157
|
U.open ? p("", !0) : (y(), m("div", {
|
|
146
158
|
key: 0,
|
|
159
|
+
"data-testid": "pl-dropdown-legacy-value",
|
|
147
160
|
onClick: be
|
|
148
161
|
}, [g(o, { class: "input-value" }, {
|
|
149
162
|
default: D(() => [ae(w(Y.value), 1)]),
|
|
@@ -152,11 +165,13 @@ var ue = { class: "ui-dropdown__envelope" }, de = ["tabindex"], fe = { class: "u
|
|
|
152
165
|
h("div", A, [
|
|
153
166
|
W.value ? (y(), f(T(te), {
|
|
154
167
|
key: 0,
|
|
155
|
-
name: "loading"
|
|
168
|
+
name: "loading",
|
|
169
|
+
"data-testid": "pl-dropdown-legacy-loading"
|
|
156
170
|
})) : p("", !0),
|
|
157
171
|
_.clearable && ve.value ? (y(), f(T(c), {
|
|
158
172
|
key: 1,
|
|
159
173
|
class: "clear",
|
|
174
|
+
"data-testid": "pl-dropdown-legacy-clear",
|
|
160
175
|
name: "delete-clear",
|
|
161
176
|
onClick: O(ye, ["stop"])
|
|
162
177
|
})) : p("", !0),
|
|
@@ -164,14 +179,17 @@ var ue = { class: "ui-dropdown__envelope" }, de = ["tabindex"], fe = { class: "u
|
|
|
164
179
|
_.arrowIconLarge ? (y(), m("div", {
|
|
165
180
|
key: 2,
|
|
166
181
|
class: v(["arrow-icon", [`icon-24 ${_.arrowIconLarge}`]]),
|
|
182
|
+
"data-testid": "pl-dropdown-legacy-arrow",
|
|
167
183
|
onClick: O($, ["stop"])
|
|
168
184
|
}, null, 2)) : _.arrowIcon ? (y(), m("div", {
|
|
169
185
|
key: 3,
|
|
170
186
|
class: v(["arrow-icon", [`icon-16 ${_.arrowIcon}`]]),
|
|
187
|
+
"data-testid": "pl-dropdown-legacy-arrow",
|
|
171
188
|
onClick: O($, ["stop"])
|
|
172
189
|
}, null, 2)) : (y(), m("div", {
|
|
173
190
|
key: 4,
|
|
174
191
|
class: "arrow-icon arrow-icon-default",
|
|
192
|
+
"data-testid": "pl-dropdown-legacy-arrow",
|
|
175
193
|
onClick: O($, ["stop"])
|
|
176
194
|
}))
|
|
177
195
|
])
|
|
@@ -179,13 +197,15 @@ var ue = { class: "ui-dropdown__envelope" }, de = ["tabindex"], fe = { class: "u
|
|
|
179
197
|
_.label ? (y(), m("label", j, [
|
|
180
198
|
_.required ? (y(), f(T(ee), {
|
|
181
199
|
key: 0,
|
|
182
|
-
uri: T(re)
|
|
200
|
+
uri: T(re),
|
|
201
|
+
"data-testid": "pl-dropdown-legacy-required"
|
|
183
202
|
}, null, 8, ["uri"])) : p("", !0),
|
|
184
203
|
h("span", null, w(_.label), 1),
|
|
185
204
|
T(z).tooltip ? (y(), f(T(i), {
|
|
186
205
|
key: 1,
|
|
187
206
|
class: "info",
|
|
188
|
-
position: "top"
|
|
207
|
+
position: "top",
|
|
208
|
+
"data-testid": "pl-dropdown-legacy-tooltip"
|
|
189
209
|
}, {
|
|
190
210
|
tooltip: D(() => [C(t.$slots, "tooltip")]),
|
|
191
211
|
_: 3
|
|
@@ -195,13 +215,15 @@ var ue = { class: "ui-dropdown__envelope" }, de = ["tabindex"], fe = { class: "u
|
|
|
195
215
|
key: 1,
|
|
196
216
|
ref_key: "list",
|
|
197
217
|
ref: V,
|
|
198
|
-
class: "ui-dropdown__options"
|
|
218
|
+
class: "ui-dropdown__options",
|
|
219
|
+
"data-testid": "pl-dropdown-legacy-options"
|
|
199
220
|
}, [(y(!0), m(ie, null, S(X.value, (t, n) => (y(), f(e, {
|
|
200
221
|
key: n,
|
|
201
222
|
option: t,
|
|
202
223
|
"is-selected": t.isSelected,
|
|
203
224
|
"is-hovered": t.isActive,
|
|
204
225
|
size: _.optionSize,
|
|
226
|
+
"data-testid": "pl-dropdown-legacy-option",
|
|
205
227
|
onClick: O((e) => Q(t.value), ["stop"])
|
|
206
228
|
}, null, 8, [
|
|
207
229
|
"option",
|
|
@@ -209,7 +231,7 @@ var ue = { class: "ui-dropdown__envelope" }, de = ["tabindex"], fe = { class: "u
|
|
|
209
231
|
"is-hovered",
|
|
210
232
|
"size",
|
|
211
233
|
"onClick"
|
|
212
|
-
]))), 128)), X.value.length ? p("", !0) : (y(), m("div", M, "Nothing found"))], 512)) : p("", !0),
|
|
234
|
+
]))), 128)), X.value.length ? p("", !0) : (y(), m("div", M, " Nothing found "))], 512)) : p("", !0),
|
|
213
235
|
g(l, { class: "ui-dropdown__contour" })
|
|
214
236
|
])], 42, de), q.value ? (y(), m("div", N, w(q.value), 1)) : W.value && _.loadingOptionsHelper ? (y(), m("div", P, w(_.loadingOptionsHelper), 1)) : _.helper ? (y(), m("div", F, w(_.helper), 1)) : p("", !0)]));
|
|
215
237
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdownLegacy.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlDropdownLegacy/PlDropdownLegacy.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport \"./pl-dropdown-legacy.scss\";\nimport { computed, reactive, ref, unref, useSlots, watch, watchPostEffect } from \"vue\";\nimport { tap, tapIf } from \"../../helpers/functions\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport type { ListOption, ListOptionNormalized } from \"../../types\";\nimport { scrollIntoView } from \"../../helpers/dom\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlMaskIcon24 } from \"../PlMaskIcon24\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { PlSvg } from \"../PlSvg\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: string;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: string;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n },\n);\n\nconst slots = useSlots();\n\nconst root = ref<HTMLElement | undefined>();\nconst list = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n});\n\nconst findActiveIndex = () =>\n tap(\n filteredRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n if (props.modelValue !== undefined && selectedIndex.value === -1) {\n return \"The selected value is not one of the options\";\n }\n\n return undefined;\n});\n\nconst optionsRef = computed(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n\n return item?.label || props.modelValue; // @todo show inner value?\n});\n\n// Native tooltip with the full selected value; the value layer itself has\n// `pointer-events: none`, so the title goes on the field wrapper.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n const v = textValue.value;\n return v !== undefined && v !== null && v !== \"\" ? String(v) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && props.modelValue) {\n return \"\";\n }\n\n return props.modelValue ? String(textValue.value) : props.placeholder;\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n root?.value?.focus();\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => (data.open = !data.open);\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n if (!root?.value?.contains(event.relatedTarget as Node | null)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst scrollIntoActive = () => {\n const $list = list.value;\n\n if (!$list) {\n return;\n }\n\n tapIf($list.querySelector(\".hovered-item\") as HTMLElement, (opt) => {\n scrollIntoView($list, opt);\n });\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n root.value?.focus();\n }\n\n const filtered = unref(filteredRef);\n\n const { length } = filtered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(filtered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = filtered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = filteredRef.value[newIndex].index ?? -1;\n};\n\nuseLabelNotch(root);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"ui-dropdown__envelope\">\n <div\n ref=\"root\"\n :tabindex=\"tabindex\"\n class=\"ui-dropdown\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"ui-dropdown__container\">\n <div class=\"ui-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" @click=\"setFocusOnInput\">\n <LongText class=\"input-value\"> {{ textValue }} </LongText>\n </div>\n\n <div class=\"ui-dropdown__controls\">\n <PlMaskIcon24 v-if=\"isLoadingOptions\" name=\"loading\" />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div\n v-if=\"arrowIconLarge\"\n class=\"arrow-icon\"\n :class=\"[`icon-24 ${arrowIconLarge}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div\n v-else-if=\"arrowIcon\"\n class=\"arrow-icon\"\n :class=\"[`icon-16 ${arrowIcon}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div v-else class=\"arrow-icon arrow-icon-default\" @click.stop=\"toggleOpen\" />\n </div>\n </div>\n <label v-if=\"label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" />\n <span>{{ label }}</span>\n <PlTooltip v-if=\"slots.tooltip\" class=\"info\" position=\"top\">\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <div v-if=\"data.open\" ref=\"list\" class=\"ui-dropdown__options\">\n <DropdownListItem\n v-for=\"(item, index) in filteredRef\"\n :key=\"index\"\n :option=\"item\"\n :is-selected=\"item.isSelected\"\n :is-hovered=\"item.isActive\"\n :size=\"optionSize\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div v-if=\"!filteredRef.length\" class=\"nothing-found\">Nothing found</div>\n </div>\n <DoubleContour class=\"ui-dropdown__contour\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"ui-dropdown__error\">{{ computedError }}</div>\n <div v-else-if=\"isLoadingOptions && loadingOptionsHelper\" class=\"ui-dropdown__helper\">\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"ui-dropdown__helper\">{{ helper }}</div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PlDropdownLegacy.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlDropdownLegacy/PlDropdownLegacy.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting one value from a list of options\n */\nexport default {\n name: \"PlDropdown\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport \"./pl-dropdown-legacy.scss\";\nimport { computed, reactive, ref, unref, useSlots, watch, watchPostEffect } from \"vue\";\nimport { tap, tapIf } from \"../../helpers/functions\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport type { ListOption, ListOptionNormalized } from \"../../types\";\nimport { scrollIntoView } from \"../../helpers/dom\";\nimport { deepEqual } from \"../../helpers/objects\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport LongText from \"../LongText.vue\";\nimport { PlIcon16 } from \"../PlIcon16\";\nimport { PlMaskIcon24 } from \"../PlMaskIcon24\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { PlSvg } from \"../PlSvg\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\n\nconst emit = defineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: M | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected value of the dropdown.\n */\n modelValue: M;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * A helper text displayed below the dropdown when there are no options yet or options is undefined (optional).\n */\n loadingOptionsHelper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Enables a button to clear the selected value (default: false)\n */\n clearable?: boolean;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Custom icon (16px) class for the dropdown arrow (optional)\n */\n arrowIcon?: string;\n /**\n * Custom icon (24px) class for the dropdown arrow (optional)\n */\n arrowIconLarge?: string;\n /**\n * Option list item size\n */\n optionSize?: \"small\" | \"medium\";\n }>(),\n {\n label: \"\",\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n arrowIcon: undefined,\n arrowIconLarge: undefined,\n optionSize: \"small\",\n options: undefined,\n },\n);\n\nconst slots = useSlots();\n\nconst root = ref<HTMLElement | undefined>();\nconst list = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst data = reactive({\n search: \"\",\n activeIndex: -1,\n open: false,\n});\n\nconst findActiveIndex = () =>\n tap(\n filteredRef.value.findIndex((o) => deepEqual(o.value, props.modelValue)),\n (v) => (v < 0 ? 0 : v),\n );\n\nconst updateActive = () => (data.activeIndex = findActiveIndex());\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst selectedIndex = computed(() => {\n return (props.options ?? []).findIndex((o) => deepEqual(o.value, props.modelValue));\n});\n\nconst computedError = computed(() => {\n if (isLoadingOptions.value) {\n return undefined;\n }\n\n if (props.error) {\n return getErrorMessage(props.error);\n }\n\n if (props.modelValue !== undefined && selectedIndex.value === -1) {\n return \"The selected value is not one of the options\";\n }\n\n return undefined;\n});\n\nconst optionsRef = computed(() =>\n normalizeListOptions(props.options ?? []).map((opt, index) => ({\n ...opt,\n index,\n isSelected: index === selectedIndex.value,\n isActive: index === data.activeIndex,\n })),\n);\n\nconst textValue = computed(() => {\n const options = unref(optionsRef);\n\n const item: ListOption | undefined = options.find((o) => deepEqual(o.value, props.modelValue));\n\n return item?.label || props.modelValue; // @todo show inner value?\n});\n\n// Native tooltip with the full selected value; the value layer itself has\n// `pointer-events: none`, so the title goes on the field wrapper.\nconst fieldTitle = computed(() => {\n if (data.open) return undefined;\n const v = textValue.value;\n return v !== undefined && v !== null && v !== \"\" ? String(v) : undefined;\n});\n\nconst computedPlaceholder = computed(() => {\n if (!data.open && props.modelValue) {\n return \"\";\n }\n\n return props.modelValue ? String(textValue.value) : props.placeholder;\n});\n\nconst hasValue = computed(() => {\n return props.modelValue !== undefined && props.modelValue !== null;\n});\n\nconst filteredRef = computed(() => {\n const options = optionsRef.value;\n\n if (data.search) {\n return options.filter((o: ListOptionNormalized) => {\n const search = data.search.toLowerCase();\n\n if (o.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (o.description && o.description.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof o.value === \"string\") {\n return o.value.toLowerCase().includes(search);\n }\n\n return o.value === data.search;\n });\n }\n\n return options;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst selectOption = (v: M | undefined) => {\n emit(\"update:modelValue\", v);\n data.search = \"\";\n data.open = false;\n root?.value?.focus();\n};\n\nconst clear = () => emit(\"update:modelValue\", undefined);\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleOpen = () => (data.open = !data.open);\n\nconst onInputFocus = () => (data.open = true);\n\nconst onFocusOut = (event: FocusEvent) => {\n if (!root?.value?.contains(event.relatedTarget as Node | null)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst scrollIntoActive = () => {\n const $list = list.value;\n\n if (!$list) {\n return;\n }\n\n tapIf($list.querySelector(\".hovered-item\") as HTMLElement, (opt) => {\n scrollIntoView($list, opt);\n });\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n if (![\"ArrowDown\", \"ArrowUp\", \"Enter\", \"Escape\"].includes(e.code)) {\n return;\n } else {\n e.preventDefault();\n }\n\n const { open, activeIndex } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n root.value?.focus();\n }\n\n const filtered = unref(filteredRef);\n\n const { length } = filtered;\n\n if (!length) {\n return;\n }\n\n if (e.code === \"Enter\") {\n selectOption(filtered.find((it) => it.index === activeIndex)?.value);\n }\n\n const localIndex = filtered.findIndex((it) => it.index === activeIndex) ?? -1;\n\n const delta = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n const newIndex = Math.abs(localIndex + delta + length) % length;\n\n data.activeIndex = filteredRef.value[newIndex].index ?? -1;\n};\n\nuseLabelNotch(root);\n\nwatch(() => props.modelValue, updateActive, { immediate: true });\n\nwatch(\n () => data.open,\n (open) => (open ? input.value?.focus() : \"\"),\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search; // to watch\n\n if (data.activeIndex >= 0 && data.open) {\n scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"ui-dropdown__envelope\" data-testid=\"pl-dropdown-legacy\">\n <div\n ref=\"root\"\n :tabindex=\"tabindex\"\n class=\"ui-dropdown\"\n data-testid=\"pl-dropdown-legacy-control\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"ui-dropdown__container\">\n <div class=\"ui-dropdown__field\" :title=\"fieldTitle\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"computedPlaceholder\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-legacy-input\"\n @focus=\"onInputFocus\"\n />\n\n <div v-if=\"!data.open\" data-testid=\"pl-dropdown-legacy-value\" @click=\"setFocusOnInput\">\n <LongText class=\"input-value\"> {{ textValue }} </LongText>\n </div>\n\n <div class=\"ui-dropdown__controls\">\n <PlMaskIcon24\n v-if=\"isLoadingOptions\"\n name=\"loading\"\n data-testid=\"pl-dropdown-legacy-loading\"\n />\n <PlIcon16\n v-if=\"clearable && hasValue\"\n class=\"clear\"\n data-testid=\"pl-dropdown-legacy-clear\"\n name=\"delete-clear\"\n @click.stop=\"clear\"\n />\n <slot name=\"append\" />\n <div\n v-if=\"arrowIconLarge\"\n class=\"arrow-icon\"\n data-testid=\"pl-dropdown-legacy-arrow\"\n :class=\"[`icon-24 ${arrowIconLarge}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div\n v-else-if=\"arrowIcon\"\n class=\"arrow-icon\"\n data-testid=\"pl-dropdown-legacy-arrow\"\n :class=\"[`icon-16 ${arrowIcon}`]\"\n @click.stop=\"toggleOpen\"\n />\n <div\n v-else\n class=\"arrow-icon arrow-icon-default\"\n data-testid=\"pl-dropdown-legacy-arrow\"\n @click.stop=\"toggleOpen\"\n />\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-legacy-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-legacy-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-legacy-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <div\n v-if=\"data.open\"\n ref=\"list\"\n class=\"ui-dropdown__options\"\n data-testid=\"pl-dropdown-legacy-options\"\n >\n <DropdownListItem\n v-for=\"(item, index) in filteredRef\"\n :key=\"index\"\n :option=\"item\"\n :is-selected=\"item.isSelected\"\n :is-hovered=\"item.isActive\"\n :size=\"optionSize\"\n data-testid=\"pl-dropdown-legacy-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div\n v-if=\"!filteredRef.length\"\n class=\"nothing-found\"\n data-testid=\"pl-dropdown-legacy-options-empty\"\n >\n Nothing found\n </div>\n </div>\n <DoubleContour class=\"ui-dropdown__contour\" />\n </div>\n </div>\n <div v-if=\"computedError\" class=\"ui-dropdown__error\" data-testid=\"pl-dropdown-legacy-error\">\n {{ computedError }}\n </div>\n <div\n v-else-if=\"isLoadingOptions && loadingOptionsHelper\"\n class=\"ui-dropdown__helper\"\n data-testid=\"pl-dropdown-legacy-helper\"\n >\n {{ loadingOptionsHelper }}\n </div>\n <div v-else-if=\"helper\" class=\"ui-dropdown__helper\" data-testid=\"pl-dropdown-legacy-helper\">\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|