@rotki/ui-library 2.23.5 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/accordions/accordions/RuiAccordions.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/avatars/RuiAvatar.vue.d.ts +1 -1
- package/dist/components/avatars/RuiAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/avatars/RuiAvatarGroup.js.map +1 -1
- package/dist/components/avatars/RuiAvatarGroup.vue.d.ts +1 -1
- package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/avatars/use-avatar-group.d.ts +1 -1
- package/dist/components/buttons/button/RuiButton.vue.d.ts +1 -1
- package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/buttons/button/button-styles.d.ts +40 -2
- package/dist/components/buttons/button/button-styles.js +38 -0
- package/dist/components/buttons/button/button-styles.js.map +1 -1
- package/dist/components/buttons/button-group/RuiButtonGroup.js.map +1 -1
- package/dist/components/buttons/button-group/RuiButtonGroup.vue.d.ts +1 -1
- package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js +26 -14
- package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/calendar/RuiCalendar.js.map +1 -1
- package/dist/components/calendar/RuiCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/calendar/RuiCalendarGrid.js.map +1 -1
- package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js +7 -0
- package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/calendar/RuiCalendarHeader.vue.d.ts +1 -1
- package/dist/components/calendar/RuiCalendarHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/calendar/RuiCalendarMenu.js.map +1 -1
- package/dist/components/calendar/RuiCalendarMenu.vue.d.ts +1 -1
- package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cards/RuiCardHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/chips/RuiChip.vue.d.ts +1 -1
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorDisplay.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePicker.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePicker.vue.d.ts +18 -2
- package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +73 -28
- package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePickerMenu.vue.d.ts +2 -2
- package/dist/components/date-time-picker/RuiDateTimePickerMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/RuiTimezoneSelect.vue.d.ts +3 -3
- package/dist/components/date-time-picker/RuiTimezoneSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/date-time-picker-styles.d.ts +48 -3
- package/dist/components/date-time-picker/partial-time.d.ts +35 -0
- package/dist/components/date-time-picker/partial-time.js +82 -0
- package/dist/components/date-time-picker/partial-time.js.map +1 -0
- package/dist/components/date-time-picker/segment-config.d.ts +1 -1
- package/dist/components/date-time-picker/segment-utils.d.ts +2 -2
- package/dist/components/date-time-picker/segment-utils.js +17 -5
- package/dist/components/date-time-picker/segment-utils.js.map +1 -1
- package/dist/components/date-time-picker/timezones.js.map +1 -1
- package/dist/components/date-time-picker/use-date-bounds.d.ts +28 -0
- package/dist/components/date-time-picker/use-date-bounds.js +60 -0
- package/dist/components/date-time-picker/use-date-bounds.js.map +1 -0
- package/dist/components/date-time-picker/use-date-time-selection.d.ts +16 -12
- package/dist/components/date-time-picker/use-date-time-selection.js +126 -115
- package/dist/components/date-time-picker/use-date-time-selection.js.map +1 -1
- package/dist/components/date-time-picker/use-input-handler.d.ts +1 -1
- package/dist/components/date-time-picker/use-keyboard-handler.d.ts +2 -2
- package/dist/components/date-time-picker/use-keyboard-handler.js +52 -13
- package/dist/components/date-time-picker/use-keyboard-handler.js.map +1 -1
- package/dist/components/date-time-picker/utils.d.ts +1 -1
- package/dist/components/date-time-picker/utils.js.map +1 -1
- package/dist/components/divider/RuiDivider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoComplete.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue.d.ts +2 -2
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +136 -158
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoCompleteOption.js +7 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOption.js.map +1 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue.d.ts +45 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue_vue_type_script_setup_true_lang.js +58 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.js +7 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.js.map +1 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue.d.ts +70 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue_vue_type_script_setup_true_lang.js +140 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.js +7 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.js.map +1 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue.d.ts +39 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js +56 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/forms/auto-complete/auto-complete-styles.d.ts +48 -3
- package/dist/components/forms/category-picker/RuiCategoryPicker.js.map +1 -1
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue.d.ts +2 -2
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js +49 -5
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/category-picker/category-picker-styles.d.ts +69 -5
- package/dist/components/forms/category-picker/category-picker-styles.js +19 -0
- package/dist/components/forms/category-picker/category-picker-styles.js.map +1 -1
- package/dist/components/forms/check-control-styles.d.ts +2 -2
- package/dist/components/forms/checkbox/RuiCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/file-upload/RuiFileUpload.js.map +1 -1
- package/dist/components/forms/file-upload/RuiFileUpload.vue.d.ts +1 -1
- package/dist/components/forms/file-upload/RuiFileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/radio-button/radio/RuiRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.js.map +1 -1
- package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue.d.ts +1 -1
- package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/select/RuiMenuSelect.js.map +1 -1
- package/dist/components/forms/select/RuiMenuSelect.vue.d.ts +2 -2
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +10 -8
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/select/RuiSimpleSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/select/menu-select-styles.d.ts +48 -3
- package/dist/components/forms/slider/RuiSlider.js.map +1 -1
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js +22 -12
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/slider/RuiSliderTicks.js +7 -0
- package/dist/components/forms/slider/RuiSliderTicks.js.map +1 -0
- package/dist/components/forms/slider/RuiSliderTicks.vue.d.ts +15 -0
- package/dist/components/forms/slider/RuiSliderTicks.vue_vue_type_script_setup_true_lang.js +59 -0
- package/dist/components/forms/slider/RuiSliderTicks.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/forms/slider/slider-styles.d.ts +2 -2
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-area/RuiTextArea.vue.d.ts +1 -1
- package/dist/components/forms/text-area/RuiTextArea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-area/text-area-styles.d.ts +3 -3
- package/dist/components/forms/text-area/text-area-styles.js.map +1 -1
- package/dist/components/forms/text-field/RuiTextField.vue.d.ts +3 -3
- package/dist/components/forms/text-field/RuiTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-field/text-field-styles.d.ts +37 -4
- package/dist/components/forms/text-field/text-field-styles.js +34 -1
- package/dist/components/forms/text-field/text-field-styles.js.map +1 -1
- package/dist/components/forms/text-input-styles.d.ts +20 -5
- package/dist/components/forms/text-input-styles.js +16 -1
- package/dist/components/forms/text-input-styles.js.map +1 -1
- package/dist/components/helpers/RuiFormTextDetail.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/icons/RuiIcon.js.map +1 -1
- package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js +26 -0
- package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/index.d.ts +57 -53
- package/dist/components/index.js +5 -1
- package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/loaders/RuiSkeletonLoader.vue.d.ts +2 -2
- package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/logos/RuiLogo.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/logos/use-logo-sources.d.ts +1 -1
- package/dist/components/logos/use-logo-sources.js +6 -1
- package/dist/components/logos/use-logo-sources.js.map +1 -1
- package/dist/components/overlays/badge/RuiBadge.vue.d.ts +1 -1
- package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/bottom-sheet/RuiBottomSheet.js.map +1 -1
- package/dist/components/overlays/bottom-sheet/RuiBottomSheet.vue.d.ts +1 -0
- package/dist/components/overlays/bottom-sheet/RuiBottomSheet.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/dialog/RuiDialog.js.map +1 -1
- package/dist/components/overlays/dialog/RuiDialog.vue.d.ts +2 -0
- package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js +15 -1
- package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/menu/RuiMenu.js.map +1 -1
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +20 -0
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.js.map +1 -1
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/tooltip/tooltip-styles.d.ts +2 -2
- package/dist/components/progress/RuiProgress.js.map +1 -1
- package/dist/components/progress/RuiProgress.vue.d.ts +3 -3
- package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/RuiFooterStepper.vue.d.ts +1 -1
- package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/RuiStepper.js.map +1 -1
- package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js +8 -0
- package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/RuiStepperCustomIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/RuiStepperIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiDataTable.js.map +1 -1
- package/dist/components/tables/RuiDataTable.vue.d.ts +5 -6
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +42 -22
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiExpandButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTable.js +7 -0
- package/dist/components/tables/RuiTable.js.map +1 -0
- package/dist/components/tables/RuiTable.vue.d.ts +40 -0
- package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js +95 -0
- package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/tables/RuiTableEmptyState.js.map +1 -1
- package/dist/components/tables/RuiTableEmptyState.vue.d.ts +5 -0
- package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js +25 -10
- package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableErrorState.js +7 -0
- package/dist/components/tables/RuiTableErrorState.js.map +1 -0
- package/dist/components/tables/RuiTableErrorState.vue.d.ts +28 -0
- package/dist/components/tables/RuiTableErrorState.vue_vue_type_script_setup_true_lang.js +44 -0
- package/dist/components/tables/RuiTableErrorState.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/tables/RuiTableHead.js.map +1 -1
- package/dist/components/tables/RuiTableHead.vue.d.ts +5 -9
- package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableLoadingState.js +7 -0
- package/dist/components/tables/RuiTableLoadingState.js.map +1 -0
- package/dist/components/tables/RuiTableLoadingState.vue.d.ts +13 -0
- package/dist/components/tables/RuiTableLoadingState.vue_vue_type_script_setup_true_lang.js +40 -0
- package/dist/components/tables/RuiTableLoadingState.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/tables/RuiTablePagination.vue.d.ts +1 -1
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableBody.vue.d.ts +1 -1
- package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableCell.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableCell.vue.d.ts +1 -1
- package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js +6 -0
- package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableEmptyRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableExpandedRow.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js +6 -0
- package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableGroupRow.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js +5 -0
- package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableLoadingRow.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableLoadingRow.vue_vue_type_script_setup_true_lang.js +2 -6
- package/dist/components/tables/data-table/RuiDataTableLoadingRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableMobileSort.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableMobileSort.vue.d.ts +2 -2
- package/dist/components/tables/data-table/RuiDataTableMobileSort.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/components/tables/data-table/RuiDataTableMobileSort.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.vue.d.ts +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js +25 -0
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/context.d.ts +2 -3
- package/dist/components/tables/data-table/context.js.map +1 -1
- package/dist/components/tables/data-table-styles.d.ts +2 -5
- package/dist/components/tables/data-table-styles.js +1 -2
- package/dist/components/tables/data-table-styles.js.map +1 -1
- package/dist/components/tabs/tab/RuiTab.js.map +1 -1
- package/dist/components/tabs/tab/RuiTab.vue.d.ts +1 -1
- package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tab-item/RuiTabItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tab-items/RuiTabItems.js.map +1 -1
- package/dist/components/tabs/tab-items/RuiTabItems.vue.d.ts +9 -0
- package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js +16 -0
- package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tabs/RuiTabs.js.map +1 -1
- package/dist/components/tabs/tabs/RuiTabs.vue.d.ts +6 -1
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js +12 -0
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tabs/use-tab-routing.d.ts +1 -1
- package/dist/components/time-picker/RuiTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/time-picker/time-picker-styles.d.ts +2 -2
- package/dist/composables/colors/index.d.ts +3 -3
- package/dist/composables/dropdown-menu.d.ts +2 -2
- package/dist/composables/dropdown-menu.js +26 -23
- package/dist/composables/dropdown-menu.js.map +1 -1
- package/dist/composables/floating.d.ts +7 -8
- package/dist/composables/floating.js +19 -14
- package/dist/composables/floating.js.map +1 -1
- package/dist/composables/forms/auto-complete/focus.js +5 -0
- package/dist/composables/forms/auto-complete/focus.js.map +1 -1
- package/dist/composables/forms/auto-complete/keyboard-navigation.js +12 -5
- package/dist/composables/forms/auto-complete/keyboard-navigation.js.map +1 -1
- package/dist/composables/forms/auto-complete/search.d.ts +1 -1
- package/dist/composables/forms/auto-complete/search.js +5 -0
- package/dist/composables/forms/auto-complete/search.js.map +1 -1
- package/dist/composables/forms/auto-complete/value.js.map +1 -1
- package/dist/composables/forms/category-picker/use-category-picker.d.ts +1 -1
- package/dist/composables/forms/category-picker/use-category-picker.js +1 -0
- package/dist/composables/forms/category-picker/use-category-picker.js.map +1 -1
- package/dist/composables/forms/use-prepend-append-width.d.ts +18 -3
- package/dist/composables/forms/use-prepend-append-width.js +18 -3
- package/dist/composables/forms/use-prepend-append-width.js.map +1 -1
- package/dist/composables/index.d.ts +4 -3
- package/dist/composables/index.js +2 -1
- package/dist/composables/overlay-stack.d.ts +52 -0
- package/dist/composables/overlay-stack.js +93 -0
- package/dist/composables/overlay-stack.js.map +1 -0
- package/dist/composables/sticky-header.js.map +1 -1
- package/dist/composables/tables/data-table/expansion.js +7 -0
- package/dist/composables/tables/data-table/expansion.js.map +1 -1
- package/dist/composables/tables/data-table/grouping.d.ts +1 -1
- package/dist/composables/tables/data-table/pagination.d.ts +2 -2
- package/dist/composables/tables/data-table/selection.d.ts +1 -1
- package/dist/composables/tables/data-table/selection.js +37 -34
- package/dist/composables/tables/data-table/selection.js.map +1 -1
- package/dist/composables/theme.d.ts +4 -2
- package/dist/composables/theme.js +18 -24
- package/dist/composables/theme.js.map +1 -1
- package/dist/i18n/keys.d.ts +1 -1
- package/dist/i18n/keys.js +1 -1
- package/dist/i18n/keys.js.map +1 -1
- package/dist/icons/icons_1.d.ts +8 -8
- package/dist/icons/icons_1.js +246 -223
- package/dist/icons/icons_1.js.map +1 -1
- package/dist/icons/icons_2.d.ts +26 -26
- package/dist/icons/icons_2.js +320 -400
- package/dist/icons/icons_2.js.map +1 -1
- package/dist/icons/icons_3.d.ts +46 -46
- package/dist/icons/icons_3.js +661 -706
- package/dist/icons/icons_3.js.map +1 -1
- package/dist/icons/icons_4.d.ts +63 -63
- package/dist/icons/icons_4.js +4347 -4480
- package/dist/icons/icons_4.js.map +1 -1
- package/dist/icons/icons_5.d.ts +60 -1
- package/dist/icons/icons_5.js +774 -31
- package/dist/icons/icons_5.js.map +1 -1
- package/dist/icons/index.d.ts +1 -1
- package/dist/icons/index.js +84 -25
- package/dist/icons/index.js.map +1 -1
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/dist/style.css +83 -10
- package/dist/theme/index.js +1 -0
- package/dist/theme/index.js.map +1 -1
- package/dist/types/theme.d.ts +1 -1
- package/dist/utils/assert.js +2 -2
- package/dist/utils/assert.js.map +1 -1
- package/dist/utils/blockie.d.ts +4 -0
- package/dist/utils/blockie.js +8 -0
- package/dist/utils/blockie.js.map +1 -1
- package/dist/utils/helpers.d.ts +24 -18
- package/dist/utils/helpers.js +28 -21
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/is-equal.d.ts +9 -0
- package/dist/utils/is-equal.js +22 -15
- package/dist/utils/is-equal.js.map +1 -1
- package/dist/utils/tv.d.ts +6 -2
- package/dist/utils/tv.js +30 -14
- package/dist/utils/tv.js.map +1 -1
- package/dist/vite-plugin/client.d.ts +1 -1
- package/dist/vite-plugin/index.js +29 -21
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/scanner.d.ts +5 -2
- package/dist/vite-plugin/scanner.js +5 -2
- package/dist/vite-plugin/scanner.js.map +1 -1
- package/dist/vite-plugin/types.d.ts +4 -8
- package/dist/web-types.json +872 -50
- package/package.json +32 -33
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floating.js","names":[],"sources":["../../src/composables/floating.ts"],"sourcesContent":["import {\n arrow,\n autoUpdate,\n computePosition,\n type ComputePositionReturn,\n flip,\n type VirtualElement as FloatingVirtualElement,\n type Middleware,\n offset,\n shift,\n size,\n} from '@floating-ui/dom';\nimport { type MaybeElement, unrefElement } from '@vueuse/core';\nimport { type MaybeRefOrGetter, onMounted, type Ref, ref, watchEffect } from 'vue';\nimport { useTimeoutManager } from './timeout-manager';\n\ntype VirtualElement = FloatingVirtualElement;\n\nexport const Placement = {\n bottom: 'bottom',\n bottomEnd: 'bottom-end',\n bottomStart: 'bottom-start',\n left: 'left',\n leftEnd: 'left-end',\n leftStart: 'left-start',\n right: 'right',\n rightEnd: 'right-end',\n rightStart: 'right-start',\n top: 'top',\n topEnd: 'top-end',\n topStart: 'top-start',\n} as const;\n\nexport type Placement = (typeof Placement)[keyof typeof Placement];\n\nexport const Strategy = {\n absolute: 'absolute',\n fixed: 'fixed',\n} as const;\n\nexport type Strategy = (typeof Strategy)[keyof typeof Strategy];\n\nexport interface FloatingOptions {\n /** Preferred placement relative to the reference element. @default Placement.bottom */\n placement?: Placement;\n /** CSS positioning strategy. @default Strategy.absolute */\n strategy?: Strategy;\n /** Main-axis and/or cross-axis offset from the reference element. @default 2 */\n offset?: number | { mainAxis?: number; crossAxis?: number };\n /** Whether to flip to the opposite side when overflowing. @default true */\n flip?: boolean;\n /** Padding from viewport edges for shift middleware. @default 8 */\n shiftPadding?: number;\n /** Whether to auto-update position on scroll/resize. @default true */\n autoUpdate?: boolean | { scroll?: boolean; resize?: boolean };\n /**\n * Cap the floating element to the space available toward the viewport edge so\n * it never overflows the window. Exposes the measured space as the\n * `--rui-floating-max-height` custom property on the floating element; the\n * content is responsible for consuming it by capping its own max-height to\n * that variable and scrolling internally.\n * @default false\n */\n size?: boolean;\n}\n\n/** Custom property carrying the space-aware max height set by the size middleware. */\nexport const FLOATING_MAX_HEIGHT_VAR = '--rui-floating-max-height';\n\nexport const DEFAULT_FLOATING_OPTIONS: Required<FloatingOptions> = {\n autoUpdate: true,\n flip: true,\n offset: 2,\n placement: Placement.bottom,\n shiftPadding: 8,\n size: false,\n strategy: Strategy.absolute,\n};\n\nexport interface UseFloatingReturn {\n currentPlacement: Readonly<Ref<Placement>>;\n leavePending: Ref<boolean>;\n onClose: (immediate?: boolean) => void;\n onLeaveComplete: () => void;\n onLeavePending: () => void;\n onOpen: (immediate?: boolean) => void;\n open: Ref<boolean>;\n popover: Ref<MaybeElement>;\n reference: Ref<HTMLElement | undefined>;\n updatePosition: () => Promise<void>;\n visible: Ref<boolean>;\n}\n\n/**\n * Cap the floating element to the space available toward the viewport edge and\n * expose it as {@link FLOATING_MAX_HEIGHT_VAR}. The content decides how to use\n * it (cap its own height and scroll internally); writing a custom property\n * instead of a hard max-height keeps this non-invasive for elements that opt in\n * but size themselves differently.\n */\nfunction buildSizeMiddleware(padding: number): Middleware {\n return size({\n padding,\n apply({ availableHeight, elements }) {\n elements.floating.style.setProperty(FLOATING_MAX_HEIGHT_VAR, `${Math.max(0, Math.floor(availableHeight))}px`);\n },\n });\n}\n\nfunction buildMiddleware(opts: FloatingOptions, arrowEl: HTMLElement | null): Middleware[] {\n const mw: Middleware[] = [];\n\n const off = opts.offset ?? DEFAULT_FLOATING_OPTIONS.offset;\n if (typeof off === 'number') {\n mw.push(offset(off));\n }\n else {\n const defaultOffset = typeof DEFAULT_FLOATING_OPTIONS.offset === 'number' ? DEFAULT_FLOATING_OPTIONS.offset : 0;\n mw.push(offset({ mainAxis: off.mainAxis ?? defaultOffset, crossAxis: off.crossAxis ?? 0 }));\n }\n\n if (opts.flip !== false)\n mw.push(flip());\n\n mw.push(shift({ padding: opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding }));\n\n if (arrowEl)\n mw.push(arrow({ element: arrowEl, padding: 4 }));\n\n if (opts.size === true)\n mw.push(buildSizeMiddleware(opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding));\n\n return mw;\n}\n\nfunction applyArrowStyles(arrowEl: HTMLElement | null, result: ComputePositionReturn): void {\n const arrowData = result.middlewareData.arrow;\n if (!arrowEl || !arrowData)\n return;\n\n Object.assign(arrowEl.style, {\n left: arrowData.x != null ? `${arrowData.x}px` : '',\n top: arrowData.y != null ? `${arrowData.y}px` : '',\n });\n}\n\nexport function useFloating(\n options: MaybeRefOrGetter<FloatingOptions>,\n disabled: MaybeRefOrGetter<boolean> = false,\n openDelay: MaybeRefOrGetter<number> = 0,\n closeDelay: MaybeRefOrGetter<number> = 0,\n virtualReference?: MaybeRefOrGetter<Element | VirtualElement | undefined>,\n): UseFloatingReturn {\n const reference = ref<HTMLElement>();\n const popover = ref<MaybeElement>();\n const open = shallowRef<boolean>(false);\n const visible = shallowRef<boolean>(false);\n const leavePending = shallowRef<boolean>(false);\n const currentPlacement = shallowRef<Placement>(toValue(options).placement ?? DEFAULT_FLOATING_OPTIONS.placement);\n\n let cleanupAutoUpdate: (() => void) | null = null;\n\n const openTimeoutManager = useTimeoutManager();\n const closeTimeoutManager = useTimeoutManager();\n\n function onLeaveComplete(): void {\n set(visible, false);\n }\n\n function onOpen(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n closeTimeoutManager.clear();\n\n set(leavePending, false);\n if (!openTimeoutManager.isActive()) {\n set(visible, true);\n\n openTimeoutManager.create(\n () => {\n set(open, true);\n },\n immediate ? 0 : toValue(openDelay),\n );\n }\n }\n\n function onClose(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n openTimeoutManager.clear();\n\n if (!closeTimeoutManager.isActive()) {\n closeTimeoutManager.create(\n () => {\n if (!get(open))\n onLeaveComplete();\n\n set(open, false);\n },\n immediate ? 0 : toValue(closeDelay),\n );\n }\n }\n\n function onLeavePending(): void {\n set(leavePending, true);\n }\n\n function getValidElements(): { popoverEl: HTMLElement; referenceEl: Element | VirtualElement } | null {\n if (!get(popover) || (!get(reference) && !toValue(virtualReference)))\n return null;\n\n const popoverEl = unrefElement(popover);\n const referenceEl = toValue(virtualReference) || unrefElement(reference);\n\n if (!(popoverEl instanceof HTMLElement) || !referenceEl)\n return null;\n\n return { popoverEl, referenceEl };\n }\n\n async function updatePosition(): Promise<void> {\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const arrowEl = popoverEl.querySelector<HTMLElement>('[data-id=\"arrow\"]');\n const strategy = opts.strategy ?? DEFAULT_FLOATING_OPTIONS.strategy;\n\n const result = await computePosition(referenceEl, popoverEl, {\n middleware: buildMiddleware(opts, arrowEl),\n placement: opts.placement ?? DEFAULT_FLOATING_OPTIONS.placement,\n strategy,\n });\n\n Object.assign(popoverEl.style, {\n left: `${result.x}px`,\n position: strategy,\n top: `${result.y}px`,\n });\n\n set(currentPlacement, result.placement);\n applyArrowStyles(arrowEl, result);\n }\n\n function startAutoUpdate(): void {\n stopAutoUpdate();\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const autoUpdateOpt = opts.autoUpdate ?? DEFAULT_FLOATING_OPTIONS.autoUpdate;\n\n if (autoUpdateOpt === false)\n return;\n\n const autoUpdateOptions = typeof autoUpdateOpt === 'object'\n ? {\n ancestorResize: autoUpdateOpt.resize ?? true,\n ancestorScroll: autoUpdateOpt.scroll ?? true,\n elementResize: true,\n }\n : undefined;\n\n cleanupAutoUpdate = autoUpdate(\n referenceEl,\n popoverEl,\n () => { updatePosition().catch(() => {}); },\n autoUpdateOptions,\n );\n }\n\n function stopAutoUpdate(): void {\n cleanupAutoUpdate?.();\n cleanupAutoUpdate = null;\n }\n\n onMounted(() => {\n watchEffect((onCleanup) => {\n startAutoUpdate();\n onCleanup(stopAutoUpdate);\n });\n });\n\n return {\n currentPlacement: readonly(currentPlacement),\n leavePending, // eslint-disable-line @rotki/composable-return-readonly -- written by consumer transition hooks\n onClose,\n onLeaveComplete,\n onLeavePending,\n onOpen,\n open, // eslint-disable-line @rotki/composable-return-readonly -- v-model bound by consumers\n popover, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n reference, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n updatePosition,\n visible, // eslint-disable-line @rotki/composable-return-readonly -- used as v-if condition by consumers\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"floating.js","names":[],"sources":["../../src/composables/floating.ts"],"sourcesContent":["import {\n arrow,\n autoUpdate,\n computePosition,\n type ComputePositionReturn,\n flip,\n type VirtualElement as FloatingVirtualElement,\n type Middleware,\n offset,\n shift,\n size,\n} from '@floating-ui/dom';\nimport { type MaybeElement, unrefElement } from '@vueuse/core';\nimport { type MaybeRefOrGetter, onMounted, type Ref, ref, watchEffect } from 'vue';\nimport { useTimeoutManager } from './timeout-manager';\n\ntype VirtualElement = FloatingVirtualElement;\n\nexport const Placement = {\n bottom: 'bottom',\n bottomEnd: 'bottom-end',\n bottomStart: 'bottom-start',\n left: 'left',\n leftEnd: 'left-end',\n leftStart: 'left-start',\n right: 'right',\n rightEnd: 'right-end',\n rightStart: 'right-start',\n top: 'top',\n topEnd: 'top-end',\n topStart: 'top-start',\n} as const;\n\nexport type Placement = (typeof Placement)[keyof typeof Placement];\n\nexport const Strategy = {\n absolute: 'absolute',\n fixed: 'fixed',\n} as const;\n\nexport type Strategy = (typeof Strategy)[keyof typeof Strategy];\n\nexport interface FloatingOptions {\n /** Preferred placement relative to the reference element; defaults to `Placement.bottom`. */\n placement?: Placement;\n /** CSS positioning strategy; defaults to `Strategy.absolute`. */\n strategy?: Strategy;\n /** Main-axis and/or cross-axis offset from the reference element; defaults to 2. */\n offset?: number | { mainAxis?: number; crossAxis?: number };\n /** Whether to flip to the opposite side when overflowing; defaults to true. */\n flip?: boolean;\n /** Padding from viewport edges for shift middleware; defaults to 8. */\n shiftPadding?: number;\n /** Whether to auto-update position on scroll/resize; defaults to true. */\n autoUpdate?: boolean | { scroll?: boolean; resize?: boolean };\n /**\n * Cap the floating element to the space available toward the viewport edge so\n * it never overflows the window. Exposes the measured space as the\n * `--rui-floating-max-height` custom property on the floating element; the\n * content is responsible for consuming it by capping its own max-height to\n * that variable and scrolling internally. Defaults to false.\n */\n size?: boolean;\n}\n\n/** Custom property carrying the space-aware max height set by the size middleware. */\nexport const FLOATING_MAX_HEIGHT_VAR = '--rui-floating-max-height';\n\nexport const DEFAULT_FLOATING_OPTIONS: Required<FloatingOptions> = {\n autoUpdate: true,\n flip: true,\n offset: 2,\n placement: Placement.bottom,\n shiftPadding: 8,\n size: false,\n strategy: Strategy.absolute,\n};\n\nexport interface UseFloatingReturn {\n currentPlacement: Readonly<Ref<Placement>>;\n leavePending: Ref<boolean>;\n onClose: (immediate?: boolean) => void;\n onLeaveComplete: () => void;\n onLeavePending: () => void;\n onOpen: (immediate?: boolean) => void;\n open: Ref<boolean>;\n popover: Ref<MaybeElement>;\n reference: Ref<HTMLElement | undefined>;\n updatePosition: () => Promise<void>;\n visible: Ref<boolean>;\n}\n\n/**\n * Cap the floating element to the space available toward the viewport edge and\n * expose it as {@link FLOATING_MAX_HEIGHT_VAR}. The content decides how to use\n * it (cap its own height and scroll internally); writing a custom property\n * instead of a hard max-height keeps this non-invasive for elements that opt in\n * but size themselves differently.\n */\nfunction buildSizeMiddleware(padding: number): Middleware {\n return size({\n padding,\n apply({ availableHeight, elements }) {\n elements.floating.style.setProperty(FLOATING_MAX_HEIGHT_VAR, `${Math.max(0, Math.floor(availableHeight))}px`);\n },\n });\n}\n\n/**\n * The offset middleware, from either the shorthand distance or the per-axis\n * form, falling back to the default distance on the main axis.\n */\nfunction buildOffsetMiddleware(opts: FloatingOptions): Middleware {\n const off = opts.offset ?? DEFAULT_FLOATING_OPTIONS.offset;\n\n if (typeof off === 'number')\n return offset(off);\n\n const defaultOffset = typeof DEFAULT_FLOATING_OPTIONS.offset === 'number' ? DEFAULT_FLOATING_OPTIONS.offset : 0;\n return offset({ mainAxis: off.mainAxis ?? defaultOffset, crossAxis: off.crossAxis ?? 0 });\n}\n\nfunction buildMiddleware(opts: FloatingOptions, arrowEl: HTMLElement | null): Middleware[] {\n const mw: Middleware[] = [buildOffsetMiddleware(opts)];\n\n if (opts.flip !== false)\n mw.push(flip());\n\n mw.push(shift({ padding: opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding }));\n\n if (arrowEl)\n mw.push(arrow({ element: arrowEl, padding: 4 }));\n\n if (opts.size === true)\n mw.push(buildSizeMiddleware(opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding));\n\n return mw;\n}\n\nfunction applyArrowStyles(arrowEl: HTMLElement | null, result: ComputePositionReturn): void {\n const arrowData = result.middlewareData.arrow;\n if (!arrowEl || !arrowData)\n return;\n\n Object.assign(arrowEl.style, {\n left: arrowData.x != null ? `${arrowData.x}px` : '',\n top: arrowData.y != null ? `${arrowData.y}px` : '',\n });\n}\n\nexport function useFloating(\n options: MaybeRefOrGetter<FloatingOptions>,\n disabled: MaybeRefOrGetter<boolean> = false,\n openDelay: MaybeRefOrGetter<number> = 0,\n closeDelay: MaybeRefOrGetter<number> = 0,\n virtualReference?: MaybeRefOrGetter<Element | VirtualElement | undefined>,\n): UseFloatingReturn {\n const reference = ref<HTMLElement>();\n const popover = ref<MaybeElement>();\n const open = shallowRef<boolean>(false);\n const visible = shallowRef<boolean>(false);\n const leavePending = shallowRef<boolean>(false);\n const currentPlacement = shallowRef<Placement>(toValue(options).placement ?? DEFAULT_FLOATING_OPTIONS.placement);\n\n let cleanupAutoUpdate: (() => void) | null = null;\n\n const openTimeoutManager = useTimeoutManager();\n const closeTimeoutManager = useTimeoutManager();\n\n function onLeaveComplete(): void {\n set(visible, false);\n }\n\n function onOpen(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n closeTimeoutManager.clear();\n\n set(leavePending, false);\n if (!openTimeoutManager.isActive()) {\n set(visible, true);\n\n openTimeoutManager.create(\n () => {\n set(open, true);\n },\n immediate ? 0 : toValue(openDelay),\n );\n }\n }\n\n function onClose(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n openTimeoutManager.clear();\n\n if (!closeTimeoutManager.isActive()) {\n closeTimeoutManager.create(\n () => {\n if (!get(open))\n onLeaveComplete();\n\n set(open, false);\n },\n immediate ? 0 : toValue(closeDelay),\n );\n }\n }\n\n function onLeavePending(): void {\n set(leavePending, true);\n }\n\n function getValidElements(): { popoverEl: HTMLElement; referenceEl: Element | VirtualElement } | null {\n if (!get(popover) || (!get(reference) && !toValue(virtualReference)))\n return null;\n\n const popoverEl = unrefElement(popover);\n const referenceEl = toValue(virtualReference) || unrefElement(reference);\n\n if (!(popoverEl instanceof HTMLElement) || !referenceEl)\n return null;\n\n return { popoverEl, referenceEl };\n }\n\n async function updatePosition(): Promise<void> {\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const arrowEl = popoverEl.querySelector<HTMLElement>('[data-id=\"arrow\"]');\n const strategy = opts.strategy ?? DEFAULT_FLOATING_OPTIONS.strategy;\n\n const result = await computePosition(referenceEl, popoverEl, {\n middleware: buildMiddleware(opts, arrowEl),\n placement: opts.placement ?? DEFAULT_FLOATING_OPTIONS.placement,\n strategy,\n });\n\n Object.assign(popoverEl.style, {\n left: `${result.x}px`,\n position: strategy,\n top: `${result.y}px`,\n });\n\n set(currentPlacement, result.placement);\n applyArrowStyles(arrowEl, result);\n }\n\n function startAutoUpdate(): void {\n stopAutoUpdate();\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const autoUpdateOpt = opts.autoUpdate ?? DEFAULT_FLOATING_OPTIONS.autoUpdate;\n\n if (autoUpdateOpt === false)\n return;\n\n const autoUpdateOptions = typeof autoUpdateOpt === 'object'\n ? {\n ancestorResize: autoUpdateOpt.resize ?? true,\n ancestorScroll: autoUpdateOpt.scroll ?? true,\n elementResize: true,\n }\n : undefined;\n\n cleanupAutoUpdate = autoUpdate(\n referenceEl,\n popoverEl,\n () => { updatePosition().catch(() => {}); },\n autoUpdateOptions,\n );\n }\n\n function stopAutoUpdate(): void {\n cleanupAutoUpdate?.();\n cleanupAutoUpdate = null;\n }\n\n onMounted(() => {\n watchEffect((onCleanup) => {\n startAutoUpdate();\n onCleanup(stopAutoUpdate);\n });\n });\n\n return {\n currentPlacement: readonly(currentPlacement),\n leavePending, // eslint-disable-line @rotki/composable-return-readonly -- written by consumer transition hooks\n onClose,\n onLeaveComplete,\n onLeavePending,\n onOpen,\n open, // eslint-disable-line @rotki/composable-return-readonly -- v-model bound by consumers\n popover, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n reference, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n updatePosition,\n visible, // eslint-disable-line @rotki/composable-return-readonly -- used as v-if condition by consumers\n };\n}\n"],"mappings":"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"}
|
|
@@ -28,6 +28,11 @@ function useAutoCompleteFocus(options, deps) {
|
|
|
28
28
|
if (toValue(options.shouldApplyValueAsSearch)) get$1(deps.textInput)?.select();
|
|
29
29
|
if (!get$1(deps.isOpen)) set$1(deps.justOpened, true);
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* The search text as it stood when focus was lost, kept for the custom-value
|
|
33
|
+
* blur flow: it is captured before the debounced handler runs, because the
|
|
34
|
+
* watchers in value.ts clear the search when the menu closes.
|
|
35
|
+
*/
|
|
31
36
|
let pendingCustomSearch = "";
|
|
32
37
|
watch(anyFocused, (focused) => {
|
|
33
38
|
if (!focused && toValue(options.customValue)) pendingCustomSearch = get$1(deps.internalSearch);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focus.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/focus.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\n\nexport interface UseAutoCompleteFocusOptions {\n /** Whether custom (free-text) values are allowed. */\n customValue: MaybeRefOrGetter<boolean>;\n /** Whether to apply the current value as the search text when focused. */\n shouldApplyValueAsSearch: MaybeRefOrGetter<boolean>;\n /** Whether the autocomplete is disabled. */\n disabled: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteFocusDeps {\n activatorFocused: Ref<boolean>;\n activatorFocusedWithin: Ref<boolean>;\n focusedValueIndex: Ref<number>;\n internalSearch: Ref<string>;\n isOpen: Ref<boolean>;\n justOpened: Ref<boolean>;\n menuWrapperFocusedWithin: Ref<boolean>;\n searchInputFocused: Ref<boolean>;\n textInput: Ref<HTMLInputElement | undefined> | TemplateRef<HTMLInputElement>;\n setSearchAsValue: () => void;\n updateInternalSearch: (value?: string) => void;\n}\n\nexport interface UseAutoCompleteFocusReturn {\n anyFocused: ComputedRef<boolean>;\n inputClass: ComputedRef<string>;\n onActivatorFocused: () => Promise<void>;\n onInputFocused: () => void;\n setInputFocus: () => Promise<void>;\n}\n\nexport function useAutoCompleteFocus(\n options: UseAutoCompleteFocusOptions,\n deps: UseAutoCompleteFocusDeps,\n): UseAutoCompleteFocusReturn {\n const anyFocused = computed<boolean>(\n () => get(deps.activatorFocusedWithin) || get(deps.menuWrapperFocusedWithin),\n );\n\n const inputClass = computed<string>(() => {\n const isFocused = get(anyFocused);\n const isDisabled = toValue(options.disabled);\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n const hasSearch = get(deps.internalSearch);\n\n if ((!isFocused || isDisabled) && !shouldApply)\n return 'w-0 h-0';\n if (hasSearch)\n return 'flex-1 min-w-[4rem]';\n return 'flex-1 min-w-0';\n });\n\n async function setInputFocus(): Promise<void> {\n await nextTick(() => {\n set(deps.searchInputFocused, true);\n });\n }\n\n async function onActivatorFocused(): Promise<void> {\n await nextTick(() => {\n if (!get(deps.activatorFocused)) {\n set(deps.searchInputFocused, true);\n }\n });\n }\n\n function onInputFocused(): void {\n set(deps.focusedValueIndex, -1);\n\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n if (shouldApply) {\n const textInput = get(deps.textInput);\n textInput?.select();\n }\n\n if (!get(deps.isOpen)) {\n set(deps.justOpened, true);\n }\n }\n\n
|
|
1
|
+
{"version":3,"file":"focus.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/focus.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\n\nexport interface UseAutoCompleteFocusOptions {\n /** Whether custom (free-text) values are allowed. */\n customValue: MaybeRefOrGetter<boolean>;\n /** Whether to apply the current value as the search text when focused. */\n shouldApplyValueAsSearch: MaybeRefOrGetter<boolean>;\n /** Whether the autocomplete is disabled. */\n disabled: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteFocusDeps {\n activatorFocused: Ref<boolean>;\n activatorFocusedWithin: Ref<boolean>;\n focusedValueIndex: Ref<number>;\n internalSearch: Ref<string>;\n isOpen: Ref<boolean>;\n justOpened: Ref<boolean>;\n menuWrapperFocusedWithin: Ref<boolean>;\n searchInputFocused: Ref<boolean>;\n textInput: Ref<HTMLInputElement | undefined> | TemplateRef<HTMLInputElement>;\n setSearchAsValue: () => void;\n updateInternalSearch: (value?: string) => void;\n}\n\nexport interface UseAutoCompleteFocusReturn {\n anyFocused: ComputedRef<boolean>;\n inputClass: ComputedRef<string>;\n onActivatorFocused: () => Promise<void>;\n onInputFocused: () => void;\n setInputFocus: () => Promise<void>;\n}\n\nexport function useAutoCompleteFocus(\n options: UseAutoCompleteFocusOptions,\n deps: UseAutoCompleteFocusDeps,\n): UseAutoCompleteFocusReturn {\n const anyFocused = computed<boolean>(\n () => get(deps.activatorFocusedWithin) || get(deps.menuWrapperFocusedWithin),\n );\n\n const inputClass = computed<string>(() => {\n const isFocused = get(anyFocused);\n const isDisabled = toValue(options.disabled);\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n const hasSearch = get(deps.internalSearch);\n\n if ((!isFocused || isDisabled) && !shouldApply)\n return 'w-0 h-0';\n if (hasSearch)\n return 'flex-1 min-w-[4rem]';\n return 'flex-1 min-w-0';\n });\n\n async function setInputFocus(): Promise<void> {\n await nextTick(() => {\n set(deps.searchInputFocused, true);\n });\n }\n\n async function onActivatorFocused(): Promise<void> {\n await nextTick(() => {\n if (!get(deps.activatorFocused)) {\n set(deps.searchInputFocused, true);\n }\n });\n }\n\n function onInputFocused(): void {\n set(deps.focusedValueIndex, -1);\n\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n if (shouldApply) {\n const textInput = get(deps.textInput);\n textInput?.select();\n }\n\n if (!get(deps.isOpen)) {\n set(deps.justOpened, true);\n }\n }\n\n /**\n * The search text as it stood when focus was lost, kept for the custom-value\n * blur flow: it is captured before the debounced handler runs, because the\n * watchers in value.ts clear the search when the menu closes.\n */\n let pendingCustomSearch = '';\n\n watch(anyFocused, (focused) => {\n if (!focused && toValue(options.customValue)) {\n pendingCustomSearch = get(deps.internalSearch);\n }\n });\n\n // Debounced, so the menu does not close for a moment while focus moves between its own elements\n watchDebounced(\n anyFocused,\n (focused) => {\n if (!focused) {\n set(deps.isOpen, false);\n\n const customValue = toValue(options.customValue);\n const searchToUse = pendingCustomSearch;\n pendingCustomSearch = '';\n\n if (customValue && searchToUse) {\n deps.updateInternalSearch(searchToUse);\n deps.setSearchAsValue();\n }\n\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n if (!shouldApply) {\n deps.updateInternalSearch();\n }\n }\n },\n {\n debounce: 100,\n maxWait: 200,\n },\n );\n\n return {\n anyFocused,\n inputClass,\n onActivatorFocused,\n onInputFocused,\n setInputFocus,\n };\n}\n"],"mappings":";;;;AAiCA,SAAgB,qBACd,SACA,MAC4B;CAC5B,MAAM,aAAa,eACX,MAAI,KAAK,sBAAsB,KAAK,MAAI,KAAK,wBAAwB,CAC7E;CAEA,MAAM,aAAa,eAAuB;EACxC,MAAM,YAAY,MAAI,UAAU;EAChC,MAAM,aAAa,QAAQ,QAAQ,QAAQ;EAC3C,MAAM,cAAc,QAAQ,QAAQ,wBAAwB;EAC5D,MAAM,YAAY,MAAI,KAAK,cAAc;EAEzC,KAAK,CAAC,aAAa,eAAe,CAAC,aACjC,OAAO;EACT,IAAI,WACF,OAAO;EACT,OAAO;CACT,CAAC;CAED,eAAe,gBAA+B;EAC5C,MAAM,eAAe;GACnB,MAAI,KAAK,oBAAoB,IAAI;EACnC,CAAC;CACH;CAEA,eAAe,qBAAoC;EACjD,MAAM,eAAe;GACnB,IAAI,CAAC,MAAI,KAAK,gBAAgB,GAC5B,MAAI,KAAK,oBAAoB,IAAI;EAErC,CAAC;CACH;CAEA,SAAS,iBAAuB;EAC9B,MAAI,KAAK,mBAAmB,EAAE;EAG9B,IADoB,QAAQ,QAAQ,wBAChC,GAEF,MADsB,KAAK,SAC3B,CAAA,EAAW,OAAO;EAGpB,IAAI,CAAC,MAAI,KAAK,MAAM,GAClB,MAAI,KAAK,YAAY,IAAI;CAE7B;;;;;;CAOA,IAAI,sBAAsB;CAE1B,MAAM,aAAa,YAAY;EAC7B,IAAI,CAAC,WAAW,QAAQ,QAAQ,WAAW,GACzC,sBAAsB,MAAI,KAAK,cAAc;CAEjD,CAAC;CAGD,eACE,aACC,YAAY;EACX,IAAI,CAAC,SAAS;GACZ,MAAI,KAAK,QAAQ,KAAK;GAEtB,MAAM,cAAc,QAAQ,QAAQ,WAAW;GAC/C,MAAM,cAAc;GACpB,sBAAsB;GAEtB,IAAI,eAAe,aAAa;IAC9B,KAAK,qBAAqB,WAAW;IACrC,KAAK,iBAAiB;GACxB;GAGA,IAAI,CADgB,QAAQ,QAAQ,wBAC/B,GACH,KAAK,qBAAqB;EAE9B;CACF,GACA;EACE,UAAU;EACV,SAAS;CACX,CACF;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF"}
|
|
@@ -56,6 +56,10 @@ function useAutoCompleteKeyboardNavigation(options, deps) {
|
|
|
56
56
|
applyCustomValue(event, toValue(options.multiple));
|
|
57
57
|
return true;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Enter with the menu open, which takes the option the user navigated to
|
|
61
|
+
* before anything the component highlighted on its own.
|
|
62
|
+
*/
|
|
59
63
|
function handleOpenMenuEnter(event) {
|
|
60
64
|
if (get(deps.userNavigated) && tryApplyHighlight(event)) return true;
|
|
61
65
|
if (tryApplyCustom(event, false)) return true;
|
|
@@ -89,12 +93,15 @@ function useAutoCompleteKeyboardNavigation(options, deps) {
|
|
|
89
93
|
const value = get(deps.value);
|
|
90
94
|
const total = value.length;
|
|
91
95
|
const multiple = toValue(options.multiple);
|
|
92
|
-
if (!internalSearch && total > 0)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
if (!internalSearch && total > 0) {
|
|
97
|
+
if (multiple) {
|
|
98
|
+
if (toValue(options.chips)) set(focusedValueIndex, total - 1);
|
|
99
|
+
else {
|
|
100
|
+
const lastItem = value[total - 1];
|
|
101
|
+
if (lastItem !== void 0) deps.removeValue(lastItem);
|
|
102
|
+
}
|
|
103
|
+
} else deps.clear();
|
|
96
104
|
}
|
|
97
|
-
else deps.clear();
|
|
98
105
|
}
|
|
99
106
|
watch(deps.value, () => {
|
|
100
107
|
setValueFocus(-1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard-navigation.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/keyboard-navigation.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\nimport { get, set } from '@vueuse/shared';\n\nexport interface UseAutoCompleteKeyboardNavigationOptions {\n /** Whether multiple items can be selected. */\n multiple: MaybeRefOrGetter<boolean>;\n /** Whether custom (free-text) values are allowed. */\n customValue: MaybeRefOrGetter<boolean>;\n /** Whether selected values are displayed as chips. */\n chips: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteKeyboardNavigationDeps<TItem> {\n internalSearch: Ref<string>;\n value: Ref<TItem[]>;\n filteredOptions: Ref<TItem[]>;\n isOpen: Ref<boolean>;\n highlightedIndex: Ref<number>;\n userNavigated: Ref<boolean>;\n searchInputFocused: Ref<boolean>;\n applyHighlighted: () => void;\n clear: () => void;\n removeValue: (item: TItem) => void;\n setSearchAsValue: () => void;\n getText: (item: TItem) => string | undefined;\n activator: Ref<HTMLElement | undefined> | TemplateRef<HTMLElement>;\n}\n\nexport interface UseAutoCompleteKeyboardNavigationReturn {\n focusedValueIndex: Ref<number>;\n moveSelectedValueHighlight: (event: KeyboardEvent, next: boolean) => void;\n onEnter: (event: KeyboardEvent) => void;\n onTab: (event: KeyboardEvent) => void;\n onInputDeletePressed: () => void;\n setValueFocus: (index: number) => void;\n}\n\nexport function useAutoCompleteKeyboardNavigation<TItem>(\n options: UseAutoCompleteKeyboardNavigationOptions,\n deps: UseAutoCompleteKeyboardNavigationDeps<TItem>,\n): UseAutoCompleteKeyboardNavigationReturn {\n const focusedValueIndex = ref<number>(-1);\n\n function setValueFocus(index: number): void {\n set(focusedValueIndex, index);\n }\n\n function moveSelectedValueHighlight(event: KeyboardEvent, next: boolean): void {\n const multiple = toValue(options.multiple);\n const internalSearchValue = get(deps.internalSearch);\n\n if (!multiple || internalSearchValue.length > 0)\n return;\n\n event.preventDefault();\n const total = get(deps.value).length;\n\n let current = get(focusedValueIndex);\n\n if (current === -1) {\n set(focusedValueIndex, next ? 0 : total - 1);\n return;\n }\n\n const move = next ? 1 : -1;\n current += move;\n\n if (current < 0 || current >= total) {\n set(focusedValueIndex, -1);\n set(deps.searchInputFocused, true);\n }\n else {\n set(focusedValueIndex, current);\n }\n }\n\n function highlightedMatchesSearch(filteredOptions: TItem[], highlightedIndex: number, search: string): boolean {\n if (highlightedIndex < 0 || highlightedIndex >= filteredOptions.length)\n return false;\n\n const option = filteredOptions[highlightedIndex];\n if (typeof option === 'string')\n return option === search;\n\n if (option && typeof option === 'object')\n return (deps.getText(option) ?? '') === search;\n\n return false;\n }\n\n function applyCustomValue(event: KeyboardEvent, multiple: boolean): void {\n deps.setSearchAsValue();\n if (!multiple)\n set(deps.isOpen, false);\n event.preventDefault();\n }\n\n function submitClosestForm(): void {\n const activator = get(deps.activator);\n const form = activator?.closest('form');\n form?.dispatchEvent(new Event('submit'));\n }\n\n function tryApplyHighlight(event: KeyboardEvent): boolean {\n const filteredOptions = get(deps.filteredOptions);\n const highlightedIndex = get(deps.highlightedIndex);\n if (highlightedIndex <= -1 || filteredOptions.length === 0)\n return false;\n\n deps.applyHighlighted();\n event.preventDefault();\n return true;\n }\n\n function tryApplyCustom(event: KeyboardEvent, requireEmptyOptions: boolean): boolean {\n const customValue = toValue(options.customValue);\n const internalSearch = get(deps.internalSearch);\n if (!customValue || !internalSearch)\n return false;\n\n const filteredOptions = get(deps.filteredOptions);\n if (requireEmptyOptions) {\n if (filteredOptions.length > 0)\n return false;\n }\n else {\n const highlightedIndex = get(deps.highlightedIndex);\n if (highlightedMatchesSearch(filteredOptions, highlightedIndex, internalSearch))\n return false;\n }\n\n applyCustomValue(event, toValue(options.multiple));\n return true;\n }\n\n function handleOpenMenuEnter(event: KeyboardEvent): boolean {\n // Prefer the user's explicit navigation.\n if (get(deps.userNavigated) && tryApplyHighlight(event))\n return true;\n\n // Fall back to a typed custom value when it differs from the highlight.\n if (tryApplyCustom(event, false))\n return true;\n\n // Use the (auto-)highlighted option if there is one.\n if (tryApplyHighlight(event))\n return true;\n\n // No options matched but custom values are allowed — accept the typed text.\n return tryApplyCustom(event, true);\n }\n\n function onEnter(event: KeyboardEvent): void {\n if (get(deps.isOpen)) {\n if (handleOpenMenuEnter(event))\n return;\n\n // Menu is open but no actionable selection (e.g. typed text with no\n // matches and customValue=false, or no highlighted option). Swallow\n // Enter so it does not bubble up and submit a surrounding form.\n event.preventDefault();\n return;\n }\n\n // Nothing selected, menu closed: open menu\n if (get(deps.value).length === 0) {\n set(deps.isOpen, true);\n return event.preventDefault();\n }\n\n // Menu closed with a value selected: let Enter submit the parent form.\n submitClosestForm();\n }\n\n function onTab(event: KeyboardEvent): void {\n const isOpen = get(deps.isOpen);\n const filteredOptions = get(deps.filteredOptions);\n const highlightedIndex = get(deps.highlightedIndex);\n const multiple = toValue(options.multiple);\n\n if (isOpen && filteredOptions.length > 0 && highlightedIndex > -1 && !multiple) {\n deps.applyHighlighted();\n event.preventDefault();\n }\n }\n\n function onInputDeletePressed(): void {\n const internalSearch = get(deps.internalSearch);\n const value = get(deps.value);\n const total = value.length;\n const multiple = toValue(options.multiple);\n\n if (!internalSearch && total > 0) {\n if (multiple) {\n if (toValue(options.chips)) {\n set(focusedValueIndex, total - 1);\n }\n else {\n const lastItem = value[total - 1];\n if (lastItem !== undefined)\n deps.removeValue(lastItem);\n }\n }\n else {\n deps.clear();\n }\n }\n }\n\n // Watch value changes to reset focused index\n watch(deps.value, () => {\n setValueFocus(-1);\n });\n\n // Watch focused value index to handle chip focus\n watch(focusedValueIndex, async (index) => {\n const multiple = toValue(options.multiple);\n if (index === -1 || !multiple)\n return;\n\n await nextTick(() => {\n const activator = get(deps.activator);\n const element = activator?.querySelector<HTMLElement>(`[data-index=\"${index}\"]`);\n element?.focus();\n });\n });\n\n return {\n // eslint-disable-next-line @rotki/composable-return-readonly -- written by focus.ts onInputFocused\n focusedValueIndex,\n moveSelectedValueHighlight,\n onEnter,\n onInputDeletePressed,\n onTab,\n setValueFocus,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"keyboard-navigation.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/keyboard-navigation.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\nimport { get, set } from '@vueuse/shared';\n\nexport interface UseAutoCompleteKeyboardNavigationOptions {\n /** Whether multiple items can be selected. */\n multiple: MaybeRefOrGetter<boolean>;\n /** Whether custom (free-text) values are allowed. */\n customValue: MaybeRefOrGetter<boolean>;\n /** Whether selected values are displayed as chips. */\n chips: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteKeyboardNavigationDeps<TItem> {\n internalSearch: Ref<string>;\n value: Ref<TItem[]>;\n filteredOptions: Ref<TItem[]>;\n isOpen: Ref<boolean>;\n highlightedIndex: Ref<number>;\n userNavigated: Ref<boolean>;\n searchInputFocused: Ref<boolean>;\n applyHighlighted: () => void;\n clear: () => void;\n removeValue: (item: TItem) => void;\n setSearchAsValue: () => void;\n getText: (item: TItem) => string | undefined;\n activator: Ref<HTMLElement | undefined> | TemplateRef<HTMLElement>;\n}\n\nexport interface UseAutoCompleteKeyboardNavigationReturn {\n focusedValueIndex: Ref<number>;\n moveSelectedValueHighlight: (event: KeyboardEvent, next: boolean) => void;\n onEnter: (event: KeyboardEvent) => void;\n onTab: (event: KeyboardEvent) => void;\n onInputDeletePressed: () => void;\n setValueFocus: (index: number) => void;\n}\n\nexport function useAutoCompleteKeyboardNavigation<TItem>(\n options: UseAutoCompleteKeyboardNavigationOptions,\n deps: UseAutoCompleteKeyboardNavigationDeps<TItem>,\n): UseAutoCompleteKeyboardNavigationReturn {\n const focusedValueIndex = ref<number>(-1);\n\n function setValueFocus(index: number): void {\n set(focusedValueIndex, index);\n }\n\n function moveSelectedValueHighlight(event: KeyboardEvent, next: boolean): void {\n const multiple = toValue(options.multiple);\n const internalSearchValue = get(deps.internalSearch);\n\n if (!multiple || internalSearchValue.length > 0)\n return;\n\n event.preventDefault();\n const total = get(deps.value).length;\n\n let current = get(focusedValueIndex);\n\n if (current === -1) {\n set(focusedValueIndex, next ? 0 : total - 1);\n return;\n }\n\n const move = next ? 1 : -1;\n current += move;\n\n if (current < 0 || current >= total) {\n set(focusedValueIndex, -1);\n set(deps.searchInputFocused, true);\n }\n else {\n set(focusedValueIndex, current);\n }\n }\n\n function highlightedMatchesSearch(filteredOptions: TItem[], highlightedIndex: number, search: string): boolean {\n if (highlightedIndex < 0 || highlightedIndex >= filteredOptions.length)\n return false;\n\n const option = filteredOptions[highlightedIndex];\n if (typeof option === 'string')\n return option === search;\n\n if (option && typeof option === 'object')\n return (deps.getText(option) ?? '') === search;\n\n return false;\n }\n\n function applyCustomValue(event: KeyboardEvent, multiple: boolean): void {\n deps.setSearchAsValue();\n if (!multiple)\n set(deps.isOpen, false);\n event.preventDefault();\n }\n\n function submitClosestForm(): void {\n const activator = get(deps.activator);\n const form = activator?.closest('form');\n form?.dispatchEvent(new Event('submit'));\n }\n\n function tryApplyHighlight(event: KeyboardEvent): boolean {\n const filteredOptions = get(deps.filteredOptions);\n const highlightedIndex = get(deps.highlightedIndex);\n if (highlightedIndex <= -1 || filteredOptions.length === 0)\n return false;\n\n deps.applyHighlighted();\n event.preventDefault();\n return true;\n }\n\n function tryApplyCustom(event: KeyboardEvent, requireEmptyOptions: boolean): boolean {\n const customValue = toValue(options.customValue);\n const internalSearch = get(deps.internalSearch);\n if (!customValue || !internalSearch)\n return false;\n\n const filteredOptions = get(deps.filteredOptions);\n if (requireEmptyOptions) {\n if (filteredOptions.length > 0)\n return false;\n }\n else {\n const highlightedIndex = get(deps.highlightedIndex);\n if (highlightedMatchesSearch(filteredOptions, highlightedIndex, internalSearch))\n return false;\n }\n\n applyCustomValue(event, toValue(options.multiple));\n return true;\n }\n\n /**\n * Enter with the menu open, which takes the option the user navigated to\n * before anything the component highlighted on its own.\n */\n function handleOpenMenuEnter(event: KeyboardEvent): boolean {\n if (get(deps.userNavigated) && tryApplyHighlight(event))\n return true;\n\n // Fall back to a typed custom value when it differs from the highlight.\n if (tryApplyCustom(event, false))\n return true;\n\n // Use the (auto-)highlighted option if there is one.\n if (tryApplyHighlight(event))\n return true;\n\n // No options matched but custom values are allowed — accept the typed text.\n return tryApplyCustom(event, true);\n }\n\n function onEnter(event: KeyboardEvent): void {\n if (get(deps.isOpen)) {\n if (handleOpenMenuEnter(event))\n return;\n\n // Open with nothing to act on, so Enter is swallowed rather than submitting a surrounding form\n event.preventDefault();\n return;\n }\n\n // Nothing selected, menu closed: open menu\n if (get(deps.value).length === 0) {\n set(deps.isOpen, true);\n return event.preventDefault();\n }\n\n // Menu closed with a value selected: let Enter submit the parent form.\n submitClosestForm();\n }\n\n function onTab(event: KeyboardEvent): void {\n const isOpen = get(deps.isOpen);\n const filteredOptions = get(deps.filteredOptions);\n const highlightedIndex = get(deps.highlightedIndex);\n const multiple = toValue(options.multiple);\n\n if (isOpen && filteredOptions.length > 0 && highlightedIndex > -1 && !multiple) {\n deps.applyHighlighted();\n event.preventDefault();\n }\n }\n\n function onInputDeletePressed(): void {\n const internalSearch = get(deps.internalSearch);\n const value = get(deps.value);\n const total = value.length;\n const multiple = toValue(options.multiple);\n\n if (!internalSearch && total > 0) {\n if (multiple) {\n if (toValue(options.chips)) {\n set(focusedValueIndex, total - 1);\n }\n else {\n const lastItem = value[total - 1];\n if (lastItem !== undefined)\n deps.removeValue(lastItem);\n }\n }\n else {\n deps.clear();\n }\n }\n }\n\n // Watch value changes to reset focused index\n watch(deps.value, () => {\n setValueFocus(-1);\n });\n\n // Watch focused value index to handle chip focus\n watch(focusedValueIndex, async (index) => {\n const multiple = toValue(options.multiple);\n if (index === -1 || !multiple)\n return;\n\n await nextTick(() => {\n const activator = get(deps.activator);\n const element = activator?.querySelector<HTMLElement>(`[data-index=\"${index}\"]`);\n element?.focus();\n });\n });\n\n return {\n // eslint-disable-next-line @rotki/composable-return-readonly -- written by focus.ts onInputFocused\n focusedValueIndex,\n moveSelectedValueHighlight,\n onEnter,\n onInputDeletePressed,\n onTab,\n setValueFocus,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MaybeRefOrGetter, Ref } from 'vue';
|
|
2
|
-
import type { GroupBy } from '
|
|
2
|
+
import type { GroupBy } from '../../dropdown-menu.js';
|
|
3
3
|
export interface UseAutoCompleteSearchOptions<TItem> {
|
|
4
4
|
/** The property used as the unique identifier for each item. */
|
|
5
5
|
keyAttr?: MaybeRefOrGetter<keyof TItem | undefined>;
|
|
@@ -20,6 +20,11 @@ function useAutoCompleteSearch(options, searchModel, opts) {
|
|
|
20
20
|
tokenCache.set(text, token);
|
|
21
21
|
return token;
|
|
22
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* The group label an item sits under. Mirrors `getGroupKey` in
|
|
25
|
+
* dropdown-menu.ts, so the filter matches the labels the rendered group
|
|
26
|
+
* headers show.
|
|
27
|
+
*/
|
|
23
28
|
const resolveGroup = (item, groupBy) => {
|
|
24
29
|
if (!groupBy) return void 0;
|
|
25
30
|
if (typeof groupBy === "function") return groupBy(item);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/search.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport type { GroupBy } from '@/composables/dropdown-menu';\nimport { get, set } from '@vueuse/shared';\nimport { getTextToken } from '@/utils/helpers';\n\nexport interface UseAutoCompleteSearchOptions<TItem> {\n /** The property used as the unique identifier for each item. */\n keyAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** The property used to display text for each item. */\n textAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** Whether to disable client-side filtering of options. */\n noFilter?: MaybeRefOrGetter<boolean>;\n /** Custom filter function to match items against the search query. */\n filter?: MaybeRefOrGetter<((item: TItem, queryText: string, group?: string) => boolean) | undefined>;\n /** Whether custom (free-text) values are allowed. */\n customValue?: MaybeRefOrGetter<boolean>;\n /** Whether to hide the custom value option from the dropdown. */\n hideCustomValue?: MaybeRefOrGetter<boolean>;\n /** Whether to return the full item object instead of just the key. */\n returnObject?: MaybeRefOrGetter<boolean>;\n /** How items are grouped, used to resolve group labels for filtering. */\n groupBy?: MaybeRefOrGetter<GroupBy<TItem> | undefined>;\n /** When true and `groupBy` is set, the default filter also matches the resolved group label. */\n searchIncludesGroupLabel?: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteSearchReturn<TItem> {\n internalSearch: Readonly<Ref<string>>;\n debouncedInternalSearch: Readonly<Ref<string>>;\n filteredOptions: Readonly<Ref<TItem[]>>;\n justOpened: Ref<boolean>;\n updateInternalSearch: (value?: string) => void;\n textValueToProperValue: (val: any, returnObject?: boolean) => TItem;\n}\n\nexport function useAutoCompleteSearch<TItem>(\n options: MaybeRefOrGetter<TItem[]>,\n searchModel: Ref<string>,\n opts: UseAutoCompleteSearchOptions<TItem>,\n): UseAutoCompleteSearchReturn<TItem> {\n const internalSearch = shallowRef<string>('');\n const debouncedInternalSearch = refDebounced(internalSearch, 50);\n const justOpened = shallowRef<boolean>(false);\n\n //
|
|
1
|
+
{"version":3,"file":"search.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/search.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport type { GroupBy } from '@/composables/dropdown-menu';\nimport { get, set } from '@vueuse/shared';\nimport { getTextToken } from '@/utils/helpers';\n\nexport interface UseAutoCompleteSearchOptions<TItem> {\n /** The property used as the unique identifier for each item. */\n keyAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** The property used to display text for each item. */\n textAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** Whether to disable client-side filtering of options. */\n noFilter?: MaybeRefOrGetter<boolean>;\n /** Custom filter function to match items against the search query. */\n filter?: MaybeRefOrGetter<((item: TItem, queryText: string, group?: string) => boolean) | undefined>;\n /** Whether custom (free-text) values are allowed. */\n customValue?: MaybeRefOrGetter<boolean>;\n /** Whether to hide the custom value option from the dropdown. */\n hideCustomValue?: MaybeRefOrGetter<boolean>;\n /** Whether to return the full item object instead of just the key. */\n returnObject?: MaybeRefOrGetter<boolean>;\n /** How items are grouped, used to resolve group labels for filtering. */\n groupBy?: MaybeRefOrGetter<GroupBy<TItem> | undefined>;\n /** When true and `groupBy` is set, the default filter also matches the resolved group label. */\n searchIncludesGroupLabel?: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteSearchReturn<TItem> {\n internalSearch: Readonly<Ref<string>>;\n debouncedInternalSearch: Readonly<Ref<string>>;\n filteredOptions: Readonly<Ref<TItem[]>>;\n justOpened: Ref<boolean>;\n updateInternalSearch: (value?: string) => void;\n textValueToProperValue: (val: any, returnObject?: boolean) => TItem;\n}\n\nexport function useAutoCompleteSearch<TItem>(\n options: MaybeRefOrGetter<TItem[]>,\n searchModel: Ref<string>,\n opts: UseAutoCompleteSearchOptions<TItem>,\n): UseAutoCompleteSearchReturn<TItem> {\n const internalSearch = shallowRef<string>('');\n const debouncedInternalSearch = refDebounced(internalSearch, 50);\n const justOpened = shallowRef<boolean>(false);\n\n // Map iteration order is insertion order, so deleting the first key evicts the oldest token\n const MAX_CACHE_SIZE = 100;\n const tokenCache = new Map<string, string>();\n const getCachedTextToken = (text: string): string => {\n const cached = tokenCache.get(text);\n if (cached !== undefined)\n return cached;\n\n if (tokenCache.size >= MAX_CACHE_SIZE) {\n const oldest = tokenCache.keys().next().value;\n if (oldest !== undefined)\n tokenCache.delete(oldest);\n }\n\n const token = getTextToken(text);\n tokenCache.set(text, token);\n return token;\n };\n\n /**\n * The group label an item sits under. Mirrors `getGroupKey` in\n * dropdown-menu.ts, so the filter matches the labels the rendered group\n * headers show.\n */\n const resolveGroup = (item: TItem, groupBy: GroupBy<TItem> | undefined): string | undefined => {\n if (!groupBy)\n return undefined;\n\n if (typeof groupBy === 'function')\n return groupBy(item);\n\n return String((item as any)?.[groupBy] ?? '');\n };\n\n const filteredOptions = computed<TItem[]>(() => {\n const search = get(debouncedInternalSearch);\n const optionsValue = toValue(options);\n\n const noFilter = toValue(opts.noFilter);\n if (noFilter || !search || get(justOpened))\n return optionsValue;\n\n const keyAttr = toValue(opts.keyAttr);\n const textAttr = toValue(opts.textAttr);\n const filter = toValue(opts.filter);\n const groupBy = toValue(opts.groupBy);\n const searchIncludesGroupLabel = toValue(opts.searchIncludesGroupLabel);\n\n // Cache the search token once\n const searchToken = getCachedTextToken(search);\n\n const filtered = filter\n ? optionsValue.filter(item => filter(item, search, resolveGroup(item, groupBy)))\n : optionsValue.filter((item) => {\n if (!item)\n return false;\n\n const keywords: string[] = [getCachedTextToken(keyAttr ? String((item as any)[keyAttr]) : item.toString())];\n\n if (textAttr && typeof item === 'object')\n keywords.push(getCachedTextToken(String((item as any)[textAttr])));\n\n // Matching the group label too surfaces every item under a \"Trade\" section for \"trade\"\n if (searchIncludesGroupLabel && groupBy) {\n const group = resolveGroup(item, groupBy);\n if (group)\n keywords.push(getCachedTextToken(group));\n }\n\n return keywords.some(keyword => keyword.includes(searchToken));\n });\n\n const customValue = toValue(opts.customValue);\n const hideCustomValue = toValue(opts.hideCustomValue);\n if (!customValue || hideCustomValue || !search) {\n return filtered;\n }\n\n // Use a more efficient check for custom value inclusion\n const isCustomValueIncluded = filtered.some((item) => {\n if (!item) {\n return false;\n }\n\n const val = textAttr ? (item as any)[textAttr] : item.toString();\n return val === search;\n });\n\n if (isCustomValueIncluded) {\n return filtered;\n }\n\n return [textValueToProperValue(search, {\n keyAttr,\n returnObject: toValue(opts.returnObject),\n textAttr,\n }), ...filtered];\n });\n\n function textValueToProperValue(val: any, options: { keyAttr?: keyof TItem; textAttr?: keyof TItem; returnObject?: boolean }): TItem {\n const { keyAttr, returnObject, textAttr } = options;\n if (!keyAttr || returnObject)\n return val;\n\n return {\n [keyAttr]: val,\n ...(\n textAttr\n ? { [textAttr]: val }\n : {}\n ),\n } as TItem;\n }\n\n function updateInternalSearch(value: string = ''): void {\n set(searchModel, value);\n set(internalSearch, value);\n }\n\n watch(searchModel, (search) => {\n set(internalSearch, search);\n }, { immediate: true });\n\n // Clear token cache when component unmounts to prevent memory leaks\n onUnmounted(() => {\n tokenCache.clear();\n });\n\n return {\n debouncedInternalSearch,\n filteredOptions,\n internalSearch: readonly(internalSearch),\n justOpened, // eslint-disable-line @rotki/composable-return-readonly -- written by focus.ts onInputFocused and component setValue\n textValueToProperValue: (val: any, returnObjectOverride: boolean = false) => textValueToProperValue(val, {\n keyAttr: toValue(opts.keyAttr),\n returnObject: returnObjectOverride || toValue(opts.returnObject),\n textAttr: toValue(opts.textAttr),\n }),\n updateInternalSearch,\n };\n}\n"],"mappings":";;;;;AAmCA,SAAgB,sBACd,SACA,aACA,MACoC;CACpC,MAAM,iBAAiB,WAAmB,EAAE;CAC5C,MAAM,0BAA0B,aAAa,gBAAgB,EAAE;CAC/D,MAAM,aAAa,WAAoB,KAAK;CAG5C,MAAM,iBAAiB;CACvB,MAAM,6BAAa,IAAI,IAAoB;CAC3C,MAAM,sBAAsB,SAAyB;EACnD,MAAM,SAAS,WAAW,IAAI,IAAI;EAClC,IAAI,WAAW,KAAA,GACb,OAAO;EAET,IAAI,WAAW,QAAQ,gBAAgB;GACrC,MAAM,SAAS,WAAW,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;GACxC,IAAI,WAAW,KAAA,GACb,WAAW,OAAO,MAAM;EAC5B;EAEA,MAAM,QAAQ,aAAa,IAAI;EAC/B,WAAW,IAAI,MAAM,KAAK;EAC1B,OAAO;CACT;;;;;;CAOA,MAAM,gBAAgB,MAAa,YAA4D;EAC7F,IAAI,CAAC,SACH,OAAO,KAAA;EAET,IAAI,OAAO,YAAY,YACrB,OAAO,QAAQ,IAAI;EAErB,OAAO,OAAQ,OAAe,YAAY,EAAE;CAC9C;CAEA,MAAM,kBAAkB,eAAwB;EAC9C,MAAM,SAAS,MAAI,uBAAuB;EAC1C,MAAM,eAAe,QAAQ,OAAO;EAGpC,IADiB,QAAQ,KAAK,QAC1B,KAAY,CAAC,UAAU,MAAI,UAAU,GACvC,OAAO;EAET,MAAM,UAAU,QAAQ,KAAK,OAAO;EACpC,MAAM,WAAW,QAAQ,KAAK,QAAQ;EACtC,MAAM,SAAS,QAAQ,KAAK,MAAM;EAClC,MAAM,UAAU,QAAQ,KAAK,OAAO;EACpC,MAAM,2BAA2B,QAAQ,KAAK,wBAAwB;EAGtE,MAAM,cAAc,mBAAmB,MAAM;EAE7C,MAAM,WAAW,SACb,aAAa,QAAO,SAAQ,OAAO,MAAM,QAAQ,aAAa,MAAM,OAAO,CAAC,CAAC,IAC7E,aAAa,QAAQ,SAAS;GAC5B,IAAI,CAAC,MACH,OAAO;GAET,MAAM,WAAqB,CAAC,mBAAmB,UAAU,OAAQ,KAAa,QAAQ,IAAI,KAAK,SAAS,CAAC,CAAC;GAE1G,IAAI,YAAY,OAAO,SAAS,UAC9B,SAAS,KAAK,mBAAmB,OAAQ,KAAa,SAAS,CAAC,CAAC;GAGnE,IAAI,4BAA4B,SAAS;IACvC,MAAM,QAAQ,aAAa,MAAM,OAAO;IACxC,IAAI,OACF,SAAS,KAAK,mBAAmB,KAAK,CAAC;GAC3C;GAEA,OAAO,SAAS,MAAK,YAAW,QAAQ,SAAS,WAAW,CAAC;EAC/D,CAAC;EAEL,MAAM,cAAc,QAAQ,KAAK,WAAW;EAC5C,MAAM,kBAAkB,QAAQ,KAAK,eAAe;EACpD,IAAI,CAAC,eAAe,mBAAmB,CAAC,QACtC,OAAO;EAaT,IAT8B,SAAS,MAAM,SAAS;GACpD,IAAI,CAAC,MACH,OAAO;GAIT,QADY,WAAY,KAAa,YAAY,KAAK,SAAS,OAChD;EACjB,CAEI,GACF,OAAO;EAGT,OAAO,CAAC,uBAAuB,QAAQ;GACrC;GACA,cAAc,QAAQ,KAAK,YAAY;GACvC;EACF,CAAC,GAAG,GAAG,QAAQ;CACjB,CAAC;CAED,SAAS,uBAAuB,KAAU,SAA2F;EACnI,MAAM,EAAE,SAAS,cAAc,aAAa;EAC5C,IAAI,CAAC,WAAW,cACd,OAAO;EAET,OAAO;IACJ,UAAU;GACX,GACE,WACI,GAAG,WAAW,IAAI,IAClB,CAAC;EAET;CACF;CAEA,SAAS,qBAAqB,QAAgB,IAAU;EACtD,MAAI,aAAa,KAAK;EACtB,MAAI,gBAAgB,KAAK;CAC3B;CAEA,MAAM,cAAc,WAAW;EAC7B,MAAI,gBAAgB,MAAM;CAC5B,GAAG,EAAE,WAAW,KAAK,CAAC;CAGtB,kBAAkB;EAChB,WAAW,MAAM;CACnB,CAAC;CAED,OAAO;EACL;EACA;EACA,gBAAgB,SAAS,cAAc;EACvC;EACA,yBAAyB,KAAU,uBAAgC,UAAU,uBAAuB,KAAK;GACvG,SAAS,QAAQ,KAAK,OAAO;GAC7B,cAAc,wBAAwB,QAAQ,KAAK,YAAY;GAC/D,UAAU,QAAQ,KAAK,QAAQ;EACjC,CAAC;EACD;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"value.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/value.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';\nimport { get, set } from '@vueuse/shared';\nimport { assert } from '@/utils/assert';\n\nexport interface UseAutoCompleteValueOptions<TItem> {\n /** The property used as the unique identifier for each item. */\n keyAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** Whether to return the full item object instead of just the key. */\n returnObject?: MaybeRefOrGetter<boolean>;\n /** Whether custom (free-text) values are allowed. */\n customValue?: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteValueReturn<TItem> {\n value: ComputedRef<TItem[]>;\n setSelected: (selected: TItem[]) => void;\n /** Resolves the current model value against an arbitrary options list. */\n resolveIn: (options: TItem[]) => TItem[];\n}\n\nexport interface UseAutoCompleteValueDeps<TItem> {\n getIdentifier: (item: TItem) => any;\n getText: (item: TItem) => string | undefined;\n textValueToProperValue: (val: any, returnObject?: boolean) => TItem;\n shouldApplyValueAsSearch: MaybeRefOrGetter<boolean>;\n isOpen: MaybeRefOrGetter<boolean>;\n multiple: MaybeRefOrGetter<boolean>;\n updateInternalSearch: (value?: string) => void;\n}\n\nexport function useAutoCompleteValue<TValue, TItem>(\n modelValue: Ref<TValue | undefined>,\n options: MaybeRefOrGetter<TItem[]>,\n opts: UseAutoCompleteValueOptions<TItem>,\n deps: UseAutoCompleteValueDeps<TItem>,\n): UseAutoCompleteValueReturn<TItem> {\n function buildOptionsMap(optionsData: TItem[]): Map<any, TItem> {\n const map = new Map<any, TItem>();\n for (const item of optionsData) {\n map.set(deps.getIdentifier(item), item);\n }\n return map;\n }\n\n // Create maps for O(1) lookup performance\n const optionsMap = computed<Map<any, TItem>>(() => buildOptionsMap(toValue(options)));\n\n function convertModelValueToArray(modelValueData: TValue | undefined): any[] {\n if (modelValueData === null || modelValueData === undefined)\n return [];\n return Array.isArray(modelValueData) ? modelValueData : [modelValueData];\n }\n\n function filterValues(\n valueArray: any[],\n optionsMapData: Map<any, TItem>,\n customValue: boolean,\n returnObject: boolean,\n getKey: (val: any) => any,\n ): TItem[] {\n const filtered: TItem[] = [];\n for (const val of valueArray) {\n const inOptions = optionsMapData.get(getKey(val));\n if (inOptions !== undefined)\n filtered.push(inOptions);\n else if (customValue)\n filtered.push(deps.textValueToProperValue(val, returnObject));\n }\n return filtered;\n }\n\n function processReturnObjectValue(\n modelValueData: TValue | undefined,\n optionsMapData: Map<any, TItem>,\n returnObject: boolean,\n customValue: boolean,\n ): TItem[] {\n const multipleValue = Array.isArray(modelValueData);\n const valueArray = convertModelValueToArray(modelValueData);\n const filtered = filterValues(valueArray, optionsMapData, customValue, returnObject, val => deps.getIdentifier(val));\n\n if (multipleValue || filtered.length === 0)\n return filtered;\n\n const val = filtered[0];\n assert(val !== undefined && val !== null);\n return [val];\n }\n\n function processStandardValue(\n modelValueData: TValue | undefined,\n optionsMapData: Map<any, TItem>,\n returnObject: boolean,\n customValue: boolean,\n ): TItem[] {\n const valueArray = convertModelValueToArray(modelValueData);\n return filterValues(valueArray, optionsMapData, customValue, returnObject, val => val);\n }\n\n function onUpdateModelValue(value: TValue | undefined): void {\n set(modelValue, value);\n }\n\n function setSelected(selected: TItem[]): void {\n const keyAttr = toValue(opts.keyAttr);\n const returnObject = toValue(opts.returnObject);\n const selection = keyAttr && !returnObject ? selected.map(item => item[keyAttr]) : selected;\n\n if (toValue(deps.multiple))\n return onUpdateModelValue(selection as TValue);\n\n if (selection.length === 0)\n return onUpdateModelValue(undefined);\n\n return onUpdateModelValue(selection[0] as TValue);\n }\n\n function resolveAgainst(optionsMapData: Map<any, TItem>): TItem[] {\n const modelValueData = get(modelValue);\n const keyAttr = toValue(opts.keyAttr);\n const returnObject = toValue(opts.returnObject) ?? false;\n const customValue = toValue(opts.customValue) ?? false;\n\n if (keyAttr && returnObject)\n return processReturnObjectValue(modelValueData, optionsMapData, returnObject, customValue);\n\n return processStandardValue(modelValueData, optionsMapData, returnObject, customValue);\n }\n\n function resolveIn(optionsData: TItem[]): TItem[] {\n return resolveAgainst(buildOptionsMap(optionsData));\n }\n\n const value = computed<TItem[]>({\n get: () => resolveAgainst(get(optionsMap)),\n set: (selected: TItem[]): void => {\n setSelected(selected);\n },\n });\n\n //
|
|
1
|
+
{"version":3,"file":"value.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/value.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';\nimport { get, set } from '@vueuse/shared';\nimport { assert } from '@/utils/assert';\n\nexport interface UseAutoCompleteValueOptions<TItem> {\n /** The property used as the unique identifier for each item. */\n keyAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** Whether to return the full item object instead of just the key. */\n returnObject?: MaybeRefOrGetter<boolean>;\n /** Whether custom (free-text) values are allowed. */\n customValue?: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteValueReturn<TItem> {\n value: ComputedRef<TItem[]>;\n setSelected: (selected: TItem[]) => void;\n /** Resolves the current model value against an arbitrary options list. */\n resolveIn: (options: TItem[]) => TItem[];\n}\n\nexport interface UseAutoCompleteValueDeps<TItem> {\n getIdentifier: (item: TItem) => any;\n getText: (item: TItem) => string | undefined;\n textValueToProperValue: (val: any, returnObject?: boolean) => TItem;\n shouldApplyValueAsSearch: MaybeRefOrGetter<boolean>;\n isOpen: MaybeRefOrGetter<boolean>;\n multiple: MaybeRefOrGetter<boolean>;\n updateInternalSearch: (value?: string) => void;\n}\n\nexport function useAutoCompleteValue<TValue, TItem>(\n modelValue: Ref<TValue | undefined>,\n options: MaybeRefOrGetter<TItem[]>,\n opts: UseAutoCompleteValueOptions<TItem>,\n deps: UseAutoCompleteValueDeps<TItem>,\n): UseAutoCompleteValueReturn<TItem> {\n function buildOptionsMap(optionsData: TItem[]): Map<any, TItem> {\n const map = new Map<any, TItem>();\n for (const item of optionsData) {\n map.set(deps.getIdentifier(item), item);\n }\n return map;\n }\n\n // Create maps for O(1) lookup performance\n const optionsMap = computed<Map<any, TItem>>(() => buildOptionsMap(toValue(options)));\n\n function convertModelValueToArray(modelValueData: TValue | undefined): any[] {\n if (modelValueData === null || modelValueData === undefined)\n return [];\n return Array.isArray(modelValueData) ? modelValueData : [modelValueData];\n }\n\n function filterValues(\n valueArray: any[],\n optionsMapData: Map<any, TItem>,\n customValue: boolean,\n returnObject: boolean,\n getKey: (val: any) => any,\n ): TItem[] {\n const filtered: TItem[] = [];\n for (const val of valueArray) {\n const inOptions = optionsMapData.get(getKey(val));\n if (inOptions !== undefined)\n filtered.push(inOptions);\n else if (customValue)\n filtered.push(deps.textValueToProperValue(val, returnObject));\n }\n return filtered;\n }\n\n function processReturnObjectValue(\n modelValueData: TValue | undefined,\n optionsMapData: Map<any, TItem>,\n returnObject: boolean,\n customValue: boolean,\n ): TItem[] {\n const multipleValue = Array.isArray(modelValueData);\n const valueArray = convertModelValueToArray(modelValueData);\n const filtered = filterValues(valueArray, optionsMapData, customValue, returnObject, val => deps.getIdentifier(val));\n\n if (multipleValue || filtered.length === 0)\n return filtered;\n\n const val = filtered[0];\n assert(val !== undefined && val !== null);\n return [val];\n }\n\n function processStandardValue(\n modelValueData: TValue | undefined,\n optionsMapData: Map<any, TItem>,\n returnObject: boolean,\n customValue: boolean,\n ): TItem[] {\n const valueArray = convertModelValueToArray(modelValueData);\n return filterValues(valueArray, optionsMapData, customValue, returnObject, val => val);\n }\n\n function onUpdateModelValue(value: TValue | undefined): void {\n set(modelValue, value);\n }\n\n function setSelected(selected: TItem[]): void {\n const keyAttr = toValue(opts.keyAttr);\n const returnObject = toValue(opts.returnObject);\n const selection = keyAttr && !returnObject ? selected.map(item => item[keyAttr]) : selected;\n\n if (toValue(deps.multiple))\n return onUpdateModelValue(selection as TValue);\n\n if (selection.length === 0)\n return onUpdateModelValue(undefined);\n\n return onUpdateModelValue(selection[0] as TValue);\n }\n\n function resolveAgainst(optionsMapData: Map<any, TItem>): TItem[] {\n const modelValueData = get(modelValue);\n const keyAttr = toValue(opts.keyAttr);\n const returnObject = toValue(opts.returnObject) ?? false;\n const customValue = toValue(opts.customValue) ?? false;\n\n if (keyAttr && returnObject)\n return processReturnObjectValue(modelValueData, optionsMapData, returnObject, customValue);\n\n return processStandardValue(modelValueData, optionsMapData, returnObject, customValue);\n }\n\n function resolveIn(optionsData: TItem[]): TItem[] {\n return resolveAgainst(buildOptionsMap(optionsData));\n }\n\n const value = computed<TItem[]>({\n get: () => resolveAgainst(get(optionsMap)),\n set: (selected: TItem[]): void => {\n setSelected(selected);\n },\n });\n\n // Watches `value` rather than `modelValue`, so the search text resyncs once late `options` resolve it\n watch([value, () => toValue(deps.isOpen)], () => {\n if (toValue(deps.isOpen) || !toValue(deps.shouldApplyValueAsSearch))\n return;\n\n const currentValue = get(value);\n if (toValue(deps.multiple) || currentValue.length === 0) {\n deps.updateInternalSearch();\n }\n else {\n const firstItem = currentValue[0];\n assert(firstItem !== undefined && firstItem !== null);\n deps.updateInternalSearch(deps.getText(firstItem));\n }\n }, { immediate: true });\n\n return {\n resolveIn,\n setSelected,\n value,\n };\n}\n"],"mappings":"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"}
|
|
@@ -110,6 +110,7 @@ function useCategoryPicker(options) {
|
|
|
110
110
|
if (value === void 0) return false;
|
|
111
111
|
return getIdentifier(item) === value;
|
|
112
112
|
}
|
|
113
|
+
/** Points the rail at the selected item's category, so it shows on open. */
|
|
113
114
|
function syncActiveToSelection() {
|
|
114
115
|
const value = get(modelValue);
|
|
115
116
|
if (value === void 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-category-picker.js","names":[],"sources":["../../../../src/composables/forms/category-picker/use-category-picker.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport { type KeyOfType, useDropdownOptionProperty } from '@/composables/dropdown-menu';\n\n/**\n * A resolved category and the items that belong to it.\n */\nexport interface CategoryGroup<TItem> {\n category: string;\n items: TItem[];\n}\n\n/**\n * A single entry in the category rail. `category` is `null` for the synthetic\n * \"All\" pseudo-category, which aggregates every currently visible item.\n */\nexport interface CategoryRailEntry {\n category: string | null;\n label: string;\n count: number;\n}\n\n/**\n * A row rendered in the detail pane. Item rows carry a running `index` used for\n * `aria-activedescendant`; header rows are visual separators shown in the\n * flattened \"All\" view and never receive focus.\n */\nexport type DetailRow<TItem>\n = | { type: 'header'; category: string }\n | { type: 'item'; item: TItem; index: number };\n\nexport interface UseCategoryPickerOptions<TValue, TItem> {\n /** The full catalogue of selectable items. */\n items: MaybeRefOrGetter<TItem[]>;\n /** Resolve an item's category label. */\n categoryOf: (item: TItem) => string;\n /** Property whose value becomes the model value. */\n keyAttr?: KeyOfType<TItem, TValue extends (infer U)[] ? U : TValue>;\n /** Property (or getter) that produces an item's display text. */\n textAttr?: keyof TItem | ((item: TItem) => string);\n /** The current search query. */\n search: Ref<string>;\n /** Whether the search query is applied. */\n searchable: MaybeRefOrGetter<boolean>;\n /** Custom predicate receiving the resolved category as the third argument. */\n filter?: MaybeRefOrGetter<((item: TItem, query: string, category: string) => boolean) | undefined>;\n /** Whether the synthetic \"All\" pseudo-category is offered. */\n showAll: MaybeRefOrGetter<boolean>;\n /** Label used for the \"All\" pseudo-category. */\n allLabel: MaybeRefOrGetter<string>;\n /** The picker's current selection. */\n modelValue: Ref<TValue | undefined>;\n}\n\nexport interface UseCategoryPickerReturn<TItem> {\n getText: (item: TItem) => string | undefined;\n getIdentifier: (item: TItem) => any;\n filteredGroups: Ref<CategoryGroup<TItem>[]>;\n railEntries: Ref<CategoryRailEntry[]>;\n activeCategory: Readonly<Ref<string | null>>;\n detailGroups: Ref<CategoryGroup<TItem>[]>;\n detailRows: Ref<DetailRow<TItem>[]>;\n detailItems: Ref<TItem[]>;\n isEmpty: Ref<boolean>;\n setActiveCategory: (category: string | null) => void;\n syncActiveToSelection: () => void;\n isSelected: (item: TItem) => boolean;\n categoryOf: (item: TItem) => string;\n}\n\n/**\n * Owns the grouping, filtering and selection state for `RuiCategoryPicker`.\n *\n * The component keeps DOM concerns (focus, keyboard, scrolling); this composable\n * keeps the data: which categories exist, which survive the current search, and\n * which items belong in the detail pane for the active category.\n */\nexport function useCategoryPicker<TValue, TItem>(\n options: UseCategoryPickerOptions<TValue, TItem>,\n): UseCategoryPickerReturn<TItem> {\n const { allLabel, categoryOf, filter, items, keyAttr, modelValue, search, searchable, showAll, textAttr } = options;\n\n const { getIdentifier, getText } = useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n });\n\n function defaultFilter(item: TItem, query: string, category: string): boolean {\n const needle = query.toLowerCase();\n const text = (getText(item) ?? '').toLowerCase();\n return text.includes(needle) || category.toLowerCase().includes(needle);\n }\n\n // All items grouped by category, preserving first-seen category order.\n const allGroups = computed<CategoryGroup<TItem>[]>(() => {\n const map = new Map<string, TItem[]>();\n for (const item of toValue(items)) {\n const category = categoryOf(item);\n const bucket = map.get(category);\n if (bucket)\n bucket.push(item);\n else\n map.set(category, [item]);\n }\n return Array.from(map, ([category, groupItems]) => ({ category, items: groupItems }));\n });\n\n const query = computed<string>(() => get(search).trim());\n\n const filteredGroups = computed<CategoryGroup<TItem>[]>(() => {\n const currentQuery = get(query);\n if (!toValue(searchable) || !currentQuery)\n return get(allGroups);\n\n const filterFn = toValue(filter) ?? defaultFilter;\n return get(allGroups)\n .map(group => ({\n category: group.category,\n items: group.items.filter(item => filterFn(item, currentQuery, group.category)),\n }))\n .filter(group => group.items.length > 0);\n });\n\n const railEntries = computed<CategoryRailEntry[]>(() => {\n const groups = get(filteredGroups);\n const entries: CategoryRailEntry[] = [];\n\n if (toValue(showAll)) {\n const total = groups.reduce((sum, group) => sum + group.items.length, 0);\n entries.push({ category: null, count: total, label: toValue(allLabel) });\n }\n\n for (const group of groups)\n entries.push({ category: group.category, count: group.items.length, label: group.category });\n\n return entries;\n });\n\n const activeCategory = shallowRef<string | null>(null);\n\n function firstCategory(): string | null {\n return get(filteredGroups)[0]?.category ?? null;\n }\n\n function fallbackCategory(): string | null {\n return toValue(showAll) ? null : firstCategory();\n }\n\n function setActiveCategory(category: string | null): void {\n set(activeCategory, category);\n }\n\n // Keep the active category valid as the search narrows the rail. If the\n // active category disappears, fall back to \"All\" (when shown) or the first\n // remaining category.\n watch(filteredGroups, (groups) => {\n const active = get(activeCategory);\n if (active === null)\n return;\n if (!groups.some(group => group.category === active))\n set(activeCategory, fallbackCategory());\n });\n\n // When the user starts typing, surface matches across every category so the\n // top hit is global rather than scoped to whatever category was active.\n watch(query, (current, previous) => {\n if (current && !previous && toValue(showAll))\n set(activeCategory, null);\n });\n\n const detailGroups = computed<CategoryGroup<TItem>[]>(() => {\n const groups = get(filteredGroups);\n const active = get(activeCategory);\n if (active === null)\n return groups;\n const match = groups.find(group => group.category === active);\n return match ? [match] : [];\n });\n\n const detailItems = computed<TItem[]>(() => get(detailGroups).flatMap(group => group.items));\n\n const detailRows = computed<DetailRow<TItem>[]>(() => {\n const groups = get(detailGroups);\n const flattened = get(activeCategory) === null && groups.length > 1;\n const rows: DetailRow<TItem>[] = [];\n let index = 0;\n for (const group of groups) {\n if (flattened)\n rows.push({ type: 'header', category: group.category });\n for (const item of group.items)\n rows.push({ index: index++, item, type: 'item' });\n }\n return rows;\n });\n\n const isEmpty = computed<boolean>(() => get(detailItems).length === 0);\n\n function isSelected(item: TItem): boolean {\n const value = get(modelValue);\n if (value === undefined)\n return false;\n return getIdentifier(item) === value;\n }\n\n // Point the rail at the selected item's category so it is visible on open.\n function syncActiveToSelection(): void {\n const value = get(modelValue);\n if (value === undefined) {\n set(activeCategory, fallbackCategory());\n return;\n }\n const selected = toValue(items).find(item => getIdentifier(item) === value);\n set(activeCategory, selected ? categoryOf(selected) : fallbackCategory());\n }\n\n return {\n activeCategory: readonly(activeCategory),\n categoryOf,\n detailGroups,\n detailItems,\n detailRows,\n filteredGroups,\n getIdentifier,\n getText,\n isEmpty,\n isSelected,\n railEntries,\n setActiveCategory,\n syncActiveToSelection,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-category-picker.js","names":[],"sources":["../../../../src/composables/forms/category-picker/use-category-picker.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport { type KeyOfType, useDropdownOptionProperty } from '@/composables/dropdown-menu';\n\n/**\n * A resolved category and the items that belong to it.\n */\nexport interface CategoryGroup<TItem> {\n category: string;\n items: TItem[];\n}\n\n/**\n * A single entry in the category rail. `category` is `null` for the synthetic\n * \"All\" pseudo-category, which aggregates every currently visible item.\n */\nexport interface CategoryRailEntry {\n category: string | null;\n label: string;\n count: number;\n}\n\n/**\n * A row rendered in the detail pane. Item rows carry a running `index` used for\n * `aria-activedescendant`; header rows are visual separators shown in the\n * flattened \"All\" view and never receive focus.\n */\nexport type DetailRow<TItem>\n = | { type: 'header'; category: string }\n | { type: 'item'; item: TItem; index: number };\n\nexport interface UseCategoryPickerOptions<TValue, TItem> {\n /** The full catalogue of selectable items. */\n items: MaybeRefOrGetter<TItem[]>;\n /** Resolve an item's category label. */\n categoryOf: (item: TItem) => string;\n /** Property whose value becomes the model value. */\n keyAttr?: KeyOfType<TItem, TValue extends (infer U)[] ? U : TValue>;\n /** Property (or getter) that produces an item's display text. */\n textAttr?: keyof TItem | ((item: TItem) => string);\n /** The current search query. */\n search: Ref<string>;\n /** Whether the search query is applied. */\n searchable: MaybeRefOrGetter<boolean>;\n /** Custom predicate receiving the resolved category as the third argument. */\n filter?: MaybeRefOrGetter<((item: TItem, query: string, category: string) => boolean) | undefined>;\n /** Whether the synthetic \"All\" pseudo-category is offered. */\n showAll: MaybeRefOrGetter<boolean>;\n /** Label used for the \"All\" pseudo-category. */\n allLabel: MaybeRefOrGetter<string>;\n /** The picker's current selection. */\n modelValue: Ref<TValue | undefined>;\n}\n\nexport interface UseCategoryPickerReturn<TItem> {\n getText: (item: TItem) => string | undefined;\n getIdentifier: (item: TItem) => any;\n filteredGroups: Ref<CategoryGroup<TItem>[]>;\n railEntries: Ref<CategoryRailEntry[]>;\n activeCategory: Readonly<Ref<string | null>>;\n detailGroups: Ref<CategoryGroup<TItem>[]>;\n detailRows: Ref<DetailRow<TItem>[]>;\n detailItems: Ref<TItem[]>;\n isEmpty: Ref<boolean>;\n setActiveCategory: (category: string | null) => void;\n syncActiveToSelection: () => void;\n isSelected: (item: TItem) => boolean;\n categoryOf: (item: TItem) => string;\n}\n\n/**\n * Owns the grouping, filtering and selection state for `RuiCategoryPicker`.\n *\n * The component keeps DOM concerns (focus, keyboard, scrolling); this composable\n * keeps the data: which categories exist, which survive the current search, and\n * which items belong in the detail pane for the active category.\n */\nexport function useCategoryPicker<TValue, TItem>(\n options: UseCategoryPickerOptions<TValue, TItem>,\n): UseCategoryPickerReturn<TItem> {\n const { allLabel, categoryOf, filter, items, keyAttr, modelValue, search, searchable, showAll, textAttr } = options;\n\n const { getIdentifier, getText } = useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n });\n\n function defaultFilter(item: TItem, query: string, category: string): boolean {\n const needle = query.toLowerCase();\n const text = (getText(item) ?? '').toLowerCase();\n return text.includes(needle) || category.toLowerCase().includes(needle);\n }\n\n // All items grouped by category, preserving first-seen category order.\n const allGroups = computed<CategoryGroup<TItem>[]>(() => {\n const map = new Map<string, TItem[]>();\n for (const item of toValue(items)) {\n const category = categoryOf(item);\n const bucket = map.get(category);\n if (bucket)\n bucket.push(item);\n else\n map.set(category, [item]);\n }\n return Array.from(map, ([category, groupItems]) => ({ category, items: groupItems }));\n });\n\n const query = computed<string>(() => get(search).trim());\n\n const filteredGroups = computed<CategoryGroup<TItem>[]>(() => {\n const currentQuery = get(query);\n if (!toValue(searchable) || !currentQuery)\n return get(allGroups);\n\n const filterFn = toValue(filter) ?? defaultFilter;\n return get(allGroups)\n .map(group => ({\n category: group.category,\n items: group.items.filter(item => filterFn(item, currentQuery, group.category)),\n }))\n .filter(group => group.items.length > 0);\n });\n\n const railEntries = computed<CategoryRailEntry[]>(() => {\n const groups = get(filteredGroups);\n const entries: CategoryRailEntry[] = [];\n\n if (toValue(showAll)) {\n const total = groups.reduce((sum, group) => sum + group.items.length, 0);\n entries.push({ category: null, count: total, label: toValue(allLabel) });\n }\n\n for (const group of groups)\n entries.push({ category: group.category, count: group.items.length, label: group.category });\n\n return entries;\n });\n\n const activeCategory = shallowRef<string | null>(null);\n\n function firstCategory(): string | null {\n return get(filteredGroups)[0]?.category ?? null;\n }\n\n function fallbackCategory(): string | null {\n return toValue(showAll) ? null : firstCategory();\n }\n\n function setActiveCategory(category: string | null): void {\n set(activeCategory, category);\n }\n\n // A category the search narrows away falls back to \"All\", where it is shown, or the first remaining one\n watch(filteredGroups, (groups) => {\n const active = get(activeCategory);\n if (active === null)\n return;\n if (!groups.some(group => group.category === active))\n set(activeCategory, fallbackCategory());\n });\n\n // Typing searches every category, so the top hit is global rather than scoped to the active one\n watch(query, (current, previous) => {\n if (current && !previous && toValue(showAll))\n set(activeCategory, null);\n });\n\n const detailGroups = computed<CategoryGroup<TItem>[]>(() => {\n const groups = get(filteredGroups);\n const active = get(activeCategory);\n if (active === null)\n return groups;\n const match = groups.find(group => group.category === active);\n return match ? [match] : [];\n });\n\n const detailItems = computed<TItem[]>(() => get(detailGroups).flatMap(group => group.items));\n\n const detailRows = computed<DetailRow<TItem>[]>(() => {\n const groups = get(detailGroups);\n const flattened = get(activeCategory) === null && groups.length > 1;\n const rows: DetailRow<TItem>[] = [];\n let index = 0;\n for (const group of groups) {\n if (flattened)\n rows.push({ type: 'header', category: group.category });\n for (const item of group.items)\n rows.push({ index: index++, item, type: 'item' });\n }\n return rows;\n });\n\n const isEmpty = computed<boolean>(() => get(detailItems).length === 0);\n\n function isSelected(item: TItem): boolean {\n const value = get(modelValue);\n if (value === undefined)\n return false;\n return getIdentifier(item) === value;\n }\n\n /** Points the rail at the selected item's category, so it shows on open. */\n function syncActiveToSelection(): void {\n const value = get(modelValue);\n if (value === undefined) {\n set(activeCategory, fallbackCategory());\n return;\n }\n const selected = toValue(items).find(item => getIdentifier(item) === value);\n set(activeCategory, selected ? categoryOf(selected) : fallbackCategory());\n }\n\n return {\n activeCategory: readonly(activeCategory),\n categoryOf,\n detailGroups,\n detailItems,\n detailRows,\n filteredGroups,\n getIdentifier,\n getText,\n isEmpty,\n isSelected,\n railEntries,\n setActiveCategory,\n syncActiveToSelection,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ShallowRef } from 'vue';
|
|
2
2
|
export interface PrependAppendWidth {
|
|
3
|
-
prependWidth:
|
|
4
|
-
appendWidth:
|
|
3
|
+
prependWidth: Readonly<ShallowRef<string>>;
|
|
4
|
+
appendWidth: Readonly<ShallowRef<string>>;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Tracks how much room a field's prepend and append regions take.
|
|
8
|
+
*
|
|
9
|
+
* Each is measured by its outer border-box width, so a caller gets the whole
|
|
10
|
+
* space the region occupies, both paddings included. The earlier
|
|
11
|
+
* `contentRect.width + contentRect.left` form added padding-left but dropped
|
|
12
|
+
* padding-right, so a prepend slot styled with `pr-3` alone reported 12px
|
|
13
|
+
* short and the floated label landed under the icon's trailing padding
|
|
14
|
+
* instead of aligned with the input text.
|
|
15
|
+
*
|
|
16
|
+
* @param prepend - the prepend region's element
|
|
17
|
+
* @param append - the append region's element
|
|
18
|
+
* @param offset - extra width to add to the prepend measurement
|
|
19
|
+
* @returns both widths, in px, as CSS lengths
|
|
20
|
+
*/
|
|
6
21
|
export declare function usePrependAppendWidth(prepend: Readonly<ShallowRef<HTMLDivElement | null>>, append: Readonly<ShallowRef<HTMLDivElement | null>>, offset?: number): PrependAppendWidth;
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
import { assert } from "../../utils/assert.js";
|
|
2
|
-
import { shallowRef } from "vue";
|
|
2
|
+
import { readonly, shallowRef } from "vue";
|
|
3
3
|
import { useResizeObserver } from "@vueuse/core";
|
|
4
4
|
import { get as get$1, set as set$1 } from "@vueuse/shared";
|
|
5
5
|
//#region src/composables/forms/use-prepend-append-width.ts
|
|
6
|
+
/**
|
|
7
|
+
* Tracks how much room a field's prepend and append regions take.
|
|
8
|
+
*
|
|
9
|
+
* Each is measured by its outer border-box width, so a caller gets the whole
|
|
10
|
+
* space the region occupies, both paddings included. The earlier
|
|
11
|
+
* `contentRect.width + contentRect.left` form added padding-left but dropped
|
|
12
|
+
* padding-right, so a prepend slot styled with `pr-3` alone reported 12px
|
|
13
|
+
* short and the floated label landed under the icon's trailing padding
|
|
14
|
+
* instead of aligned with the input text.
|
|
15
|
+
*
|
|
16
|
+
* @param prepend - the prepend region's element
|
|
17
|
+
* @param append - the append region's element
|
|
18
|
+
* @param offset - extra width to add to the prepend measurement
|
|
19
|
+
* @returns both widths, in px, as CSS lengths
|
|
20
|
+
*/
|
|
6
21
|
function usePrependAppendWidth(prepend, append, offset = 0) {
|
|
7
22
|
const prependWidth = shallowRef("0px");
|
|
8
23
|
const appendWidth = shallowRef("0px");
|
|
@@ -17,8 +32,8 @@ function usePrependAppendWidth(prepend, append, offset = 0) {
|
|
|
17
32
|
set$1(appendWidth, `${target.offsetWidth + offset}px`);
|
|
18
33
|
});
|
|
19
34
|
return {
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
appendWidth: readonly(appendWidth),
|
|
36
|
+
prependWidth: readonly(prependWidth)
|
|
22
37
|
};
|
|
23
38
|
}
|
|
24
39
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-prepend-append-width.js","names":[],"sources":["../../../src/composables/forms/use-prepend-append-width.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"use-prepend-append-width.js","names":[],"sources":["../../../src/composables/forms/use-prepend-append-width.ts"],"sourcesContent":["import type { ShallowRef } from 'vue';\nimport { assert } from '@/utils/assert';\n\nexport interface PrependAppendWidth {\n prependWidth: Readonly<ShallowRef<string>>;\n appendWidth: Readonly<ShallowRef<string>>;\n}\n\n/**\n * Tracks how much room a field's prepend and append regions take.\n *\n * Each is measured by its outer border-box width, so a caller gets the whole\n * space the region occupies, both paddings included. The earlier\n * `contentRect.width + contentRect.left` form added padding-left but dropped\n * padding-right, so a prepend slot styled with `pr-3` alone reported 12px\n * short and the floated label landed under the icon's trailing padding\n * instead of aligned with the input text.\n *\n * @param prepend - the prepend region's element\n * @param append - the append region's element\n * @param offset - extra width to add to the prepend measurement\n * @returns both widths, in px, as CSS lengths\n */\nexport function usePrependAppendWidth(\n prepend: Readonly<ShallowRef<HTMLDivElement | null>>,\n append: Readonly<ShallowRef<HTMLDivElement | null>>,\n offset: number = 0,\n): PrependAppendWidth {\n const prependWidth = shallowRef<string>('0px');\n const appendWidth = shallowRef<string>('0px');\n\n useResizeObserver(prepend, () => {\n const target = get(prepend);\n assert(target);\n set(prependWidth, `${target.offsetWidth + offset}px`);\n });\n\n useResizeObserver(append, () => {\n const target = get(append);\n assert(target);\n set(appendWidth, `${target.offsetWidth + offset}px`);\n });\n\n return {\n appendWidth: readonly(appendWidth),\n prependWidth: readonly(prependWidth),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,sBACd,SACA,QACA,SAAiB,GACG;CACpB,MAAM,eAAe,WAAmB,KAAK;CAC7C,MAAM,cAAc,WAAmB,KAAK;CAE5C,kBAAkB,eAAe;EAC/B,MAAM,SAAS,MAAI,OAAO;EAC1B,OAAO,MAAM;EACb,MAAI,cAAc,GAAG,OAAO,cAAc,OAAO,GAAG;CACtD,CAAC;CAED,kBAAkB,cAAc;EAC9B,MAAM,SAAS,MAAI,MAAM;EACzB,OAAO,MAAM;EACb,MAAI,aAAa,GAAG,OAAO,cAAc,OAAO,GAAG;CACrD,CAAC;CAED,OAAO;EACL,aAAa,SAAS,WAAW;EACjC,cAAc,SAAS,YAAY;CACrC;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { useBreakpoint } from '
|
|
2
|
-
export { useIcons } from '
|
|
3
|
-
export {
|
|
1
|
+
export { useBreakpoint } from './breakpoint.js';
|
|
2
|
+
export { useIcons } from './icons.js';
|
|
3
|
+
export { resetOverlayStack, useDismissableOverlay, useOverlayStack, type UseOverlayStackReturn, } from './overlay-stack.js';
|
|
4
|
+
export { useRotkiTheme } from './theme.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useIcons } from "./icons.js";
|
|
2
2
|
import { useRotkiTheme } from "./theme.js";
|
|
3
|
+
import { resetOverlayStack, useDismissableOverlay, useOverlayStack } from "./overlay-stack.js";
|
|
3
4
|
import { useBreakpoint } from "./breakpoint.js";
|
|
4
|
-
export { useBreakpoint, useIcons, useRotkiTheme };
|
|
5
|
+
export { resetOverlayStack, useBreakpoint, useDismissableOverlay, useIcons, useOverlayStack, useRotkiTheme };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
export interface UseOverlayStackReturn {
|
|
3
|
+
/**
|
|
4
|
+
* Whether any layer is still showing. Counts what is up rather than what is
|
|
5
|
+
* registered, since a layer that was asked to dismiss stays listed until its
|
|
6
|
+
* own open state says otherwise.
|
|
7
|
+
*/
|
|
8
|
+
hasOverlay: ComputedRef<boolean>;
|
|
9
|
+
/**
|
|
10
|
+
* Asks the topmost layer still showing to dismiss itself, and reports whether
|
|
11
|
+
* there was one. The caller needs that answer to tell a gesture it handled
|
|
12
|
+
* from one it has to let through.
|
|
13
|
+
*
|
|
14
|
+
* Nothing is removed here. A layer leaves only when its own open state says
|
|
15
|
+
* so, because dismissing is a request the layer may decline: a persistent
|
|
16
|
+
* dialog refuses outright, and a dirty form may raise a discard prompt and
|
|
17
|
+
* stay up. Dropping the layer here would deregister something still covering
|
|
18
|
+
* the page, and the next gesture would sail past it.
|
|
19
|
+
*
|
|
20
|
+
* A layer that declines still counts as handled, so the gesture is swallowed
|
|
21
|
+
* rather than passed through to whatever is underneath.
|
|
22
|
+
*/
|
|
23
|
+
dismissTop: () => boolean;
|
|
24
|
+
/** Adds a layer on top. Returns the handle it is removed with. */
|
|
25
|
+
register: (isOpen: () => boolean, dismiss: () => void) => number;
|
|
26
|
+
unregister: (id: number) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare function useOverlayStack(): UseOverlayStackReturn;
|
|
29
|
+
/**
|
|
30
|
+
* Declares something as a layer the stack should be able to take down.
|
|
31
|
+
*
|
|
32
|
+
* RuiDialog does this for itself, and RuiBottomSheet through it. Anything else
|
|
33
|
+
* covering the page - a custom panel, a wrapper around RuiMenu - opts in here.
|
|
34
|
+
*
|
|
35
|
+
* @param open - whether the layer is showing; the registration follows it, so the
|
|
36
|
+
* stack ends up ordered by when layers opened rather than when they were built
|
|
37
|
+
* @param dismiss - what the gesture should do, which is whatever the layer's own
|
|
38
|
+
* close control does. It may decline, and the layer then stays in the stack, so
|
|
39
|
+
* the gesture keeps being swallowed for as long as the layer is up. Deciding
|
|
40
|
+
* inside `dismiss` rather than by dropping out of `open` matters: a dialog that
|
|
41
|
+
* turns persistent partway through its life would otherwise leave the stack
|
|
42
|
+
* exactly when the gesture costs most.
|
|
43
|
+
*/
|
|
44
|
+
export declare function useDismissableOverlay(open: MaybeRefOrGetter<boolean>, dismiss: () => void): void;
|
|
45
|
+
/**
|
|
46
|
+
* Empties the stack.
|
|
47
|
+
*
|
|
48
|
+
* The stack outlives any component, and the unit project runs on a pool that
|
|
49
|
+
* shares one module registry across the files in a worker, so without this a
|
|
50
|
+
* layer left behind by one spec is still listed in the next.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resetOverlayStack(): void;
|