@rotki/ui-library 2.27.0 → 3.0.0-beta.2
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 +36 -15
- package/dist/components/accordions/accordion/RuiAccordion.js.map +1 -1
- package/dist/components/accordions/accordion/RuiAccordion.vue.d.ts +0 -4
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js +9 -10
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/accordions/accordions/RuiAccordions.js.map +1 -1
- package/dist/components/accordions/accordions/RuiAccordions.vue_vue_type_script_setup_true_lang.js +16 -3
- package/dist/components/accordions/accordions/RuiAccordions.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/alerts/RuiAlert.js.map +1 -1
- package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js +43 -212
- package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/avatars/RuiAvatar.js.map +1 -1
- package/dist/components/avatars/RuiAvatar.vue_vue_type_script_setup_true_lang.js +22 -32
- 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 +6 -0
- package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js +17 -13
- package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/avatars/avatar-props.d.ts +16 -3
- package/dist/components/avatars/avatar-props.js +42 -5
- package/dist/components/avatars/avatar-props.js.map +1 -1
- package/dist/components/buttons/button/RuiButton.js.map +1 -1
- package/dist/components/buttons/button/RuiButton.vue.d.ts +0 -1
- package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js +39 -26
- package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/buttons/button/button-props.d.ts +0 -2
- package/dist/components/buttons/button/button-props.js +5 -5
- package/dist/components/buttons/button/button-props.js.map +1 -1
- package/dist/components/buttons/button/button-styles.d.ts +4 -1
- package/dist/components/buttons/button/button-styles.js +136 -55
- 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 +8 -2
- package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js +66 -97
- package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/buttons/button-group/button-group-context.d.ts +28 -0
- package/dist/components/buttons/button-group/button-group-context.js +22 -0
- package/dist/components/buttons/button-group/button-group-context.js.map +1 -0
- package/dist/components/calendar/RuiCalendar.js.map +1 -1
- package/dist/components/calendar/RuiCalendar.vue_vue_type_script_setup_true_lang.js +6 -3
- 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 +12 -8
- package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/calendar/RuiCalendarHeader.js.map +1 -1
- package/dist/components/calendar/RuiCalendarHeader.vue_vue_type_script_setup_true_lang.js +21 -22
- 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_vue_type_script_setup_true_lang.js +17 -21
- package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cards/RuiCard.js.map +1 -1
- package/dist/components/cards/RuiCard.vue.d.ts +0 -3
- package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js +31 -19
- package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cards/RuiCardHeader.js.map +1 -1
- package/dist/components/cards/RuiCardHeader.vue_vue_type_script_setup_true_lang.js +13 -25
- package/dist/components/cards/RuiCardHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/chips/RuiChip.js.map +1 -1
- package/dist/components/chips/RuiChip.vue.d.ts +5 -2
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js +127 -78
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/chips/chip-props.d.ts +2 -0
- package/dist/components/chips/chip-props.js +5 -3
- package/dist/components/chips/chip-props.js.map +1 -1
- package/dist/components/color-picker/RuiColorBoard.js.map +1 -1
- package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js +5 -5
- 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 +1 -1
- package/dist/components/color-picker/RuiColorHue.js.map +1 -1
- package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorInput.js.map +1 -1
- package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js +46 -36
- package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorPicker.js.map +1 -1
- package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js +4 -5
- 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 +3 -2
- package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +81 -80
- 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.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePickerMenu.vue_vue_type_script_setup_true_lang.js +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.js.map +1 -1
- package/dist/components/date-time-picker/RuiTimezoneSelect.vue.d.ts +4 -3
- package/dist/components/date-time-picker/RuiTimezoneSelect.vue_vue_type_script_setup_true_lang.js +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 +128 -219
- package/dist/components/date-time-picker/date-time-picker-styles.js +1 -2
- package/dist/components/date-time-picker/date-time-picker-styles.js.map +1 -1
- package/dist/components/date-time-picker/use-date-bounds.js +1 -1
- package/dist/components/date-time-picker/use-date-time-selection.js +65 -66
- package/dist/components/date-time-picker/use-date-time-selection.js.map +1 -1
- package/dist/components/date-time-picker/use-input-handler.js +1 -1
- package/dist/components/date-time-picker/use-keyboard-handler.js +29 -30
- package/dist/components/date-time-picker/use-keyboard-handler.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 +1 -68
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +203 -198
- 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.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue.d.ts +2 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue_vue_type_script_setup_true_lang.js +8 -3
- package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue.d.ts +4 -0
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js +24 -10
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/auto-complete-props.d.ts +66 -0
- package/dist/components/forms/auto-complete/auto-complete-styles.d.ts +128 -218
- package/dist/components/forms/auto-complete/auto-complete-styles.js +4 -2
- package/dist/components/forms/auto-complete/auto-complete-styles.js.map +1 -1
- package/dist/components/forms/category-picker/RuiCategoryPicker.js.map +1 -1
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue.d.ts +3 -6
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js +154 -154
- 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 +83 -232
- package/dist/components/forms/category-picker/category-picker-styles.js +20 -26
- package/dist/components/forms/category-picker/category-picker-styles.js.map +1 -1
- package/dist/components/forms/check-control-styles.d.ts +61 -2
- package/dist/components/forms/check-control-styles.js +53 -46
- package/dist/components/forms/check-control-styles.js.map +1 -1
- package/dist/components/forms/checkbox/RuiCheckbox.js.map +1 -1
- package/dist/components/forms/checkbox/RuiCheckbox.vue_vue_type_script_setup_true_lang.js +32 -19
- 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.js.map +1 -1
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue_vue_type_script_setup_true_lang.js +4 -4
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/field-defaults/RuiFieldDefaults.js +7 -0
- package/dist/components/forms/field-defaults/RuiFieldDefaults.js.map +1 -0
- package/dist/components/forms/field-defaults/RuiFieldDefaults.vue.d.ts +16 -0
- package/dist/components/forms/field-defaults/RuiFieldDefaults.vue_vue_type_script_setup_true_lang.js +18 -0
- package/dist/components/forms/field-defaults/RuiFieldDefaults.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/forms/field-label/RuiFieldLabel.js +7 -0
- package/dist/components/forms/field-label/RuiFieldLabel.js.map +1 -0
- package/dist/components/forms/field-label/RuiFieldLabel.vue.d.ts +17 -0
- package/dist/components/forms/field-label/RuiFieldLabel.vue_vue_type_script_setup_true_lang.js +57 -0
- package/dist/components/forms/field-label/RuiFieldLabel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- 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 +56 -35
- 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.js.map +1 -1
- package/dist/components/forms/radio-button/radio/RuiRadio.vue_vue_type_script_setup_true_lang.js +14 -15
- 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 +3 -3
- 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.js.map +1 -1
- package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue_vue_type_script_setup_true_lang.js +6 -6
- 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 +3 -12
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +61 -56
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/select/RuiSimpleSelect.js.map +1 -1
- package/dist/components/forms/select/RuiSimpleSelect.vue.d.ts +0 -1
- package/dist/components/forms/select/RuiSimpleSelect.vue_vue_type_script_setup_true_lang.js +13 -20
- 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 +99 -221
- package/dist/components/forms/select/menu-select-styles.js +1 -4
- package/dist/components/forms/select/menu-select-styles.js.map +1 -1
- package/dist/components/forms/slider/RuiSlider.js.map +1 -1
- package/dist/components/forms/slider/RuiSlider.vue.d.ts +0 -4
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js +129 -106
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/slider/slider-styles.d.ts +40 -40
- package/dist/components/forms/slider/slider-styles.js +67 -109
- package/dist/components/forms/slider/slider-styles.js.map +1 -1
- package/dist/components/forms/switch/RuiSwitch.js.map +1 -1
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js +33 -45
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-area/RuiTextArea.js.map +1 -1
- package/dist/components/forms/text-area/RuiTextArea.vue.d.ts +3 -2
- package/dist/components/forms/text-area/RuiTextArea.vue_vue_type_script_setup_true_lang.js +138 -117
- 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 +41 -115
- package/dist/components/forms/text-area/text-area-styles.js +34 -194
- package/dist/components/forms/text-area/text-area-styles.js.map +1 -1
- package/dist/components/forms/text-field/RuiTextField.js.map +1 -1
- package/dist/components/forms/text-field/RuiTextField.vue.d.ts +5 -2
- package/dist/components/forms/text-field/RuiTextField.vue_vue_type_script_setup_true_lang.js +112 -105
- 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 -145
- package/dist/components/forms/text-field/text-field-styles.js +24 -267
- package/dist/components/forms/text-field/text-field-styles.js.map +1 -1
- package/dist/components/forms/text-input-styles.d.ts +98 -229
- package/dist/components/forms/text-input-styles.js +63 -193
- package/dist/components/forms/text-input-styles.js.map +1 -1
- package/dist/components/helpers/RuiFormTextDetail.js.map +1 -1
- package/dist/components/helpers/RuiFormTextDetail.vue.d.ts +11 -1
- package/dist/components/helpers/RuiFormTextDetail.vue_vue_type_script_setup_true_lang.js +5 -5
- 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 +7 -4
- package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/index.d.ts +5 -3
- package/dist/components/index.js +4 -3
- package/dist/components/loaders/RuiSkeletonBase.js.map +1 -1
- package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js +6 -5
- package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/loaders/RuiSkeletonLoader.js.map +1 -1
- package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/logos/RuiLogo.js.map +1 -1
- package/dist/components/logos/RuiLogo.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/logos/RuiLogo.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/badge/RuiBadge.js.map +1 -1
- package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js +76 -48
- package/dist/components/overlays/badge/RuiBadge.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 +3 -2
- package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js +17 -13
- 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.d.ts +9 -7
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +33 -29
- 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.d.ts +6 -2
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js +49 -25
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/notification/RuiNotification.js.map +1 -1
- package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js +7 -8
- package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/tooltip/RuiTooltip.js.map +1 -1
- package/dist/components/overlays/tooltip/RuiTooltip.vue.d.ts +0 -5
- package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js +17 -11
- 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 +5 -12
- package/dist/components/overlays/tooltip/tooltip-styles.js +11 -18
- package/dist/components/overlays/tooltip/tooltip-styles.js.map +1 -1
- package/dist/components/progress/RuiProgress.js.map +1 -1
- package/dist/components/progress/RuiProgress.vue.d.ts +4 -0
- package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js +73 -47
- package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/RuiFooterStepper.js.map +1 -1
- package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js +28 -29
- 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.d.ts +0 -4
- package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js +36 -29
- package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/RuiStepperIcon.js.map +1 -1
- package/dist/components/steppers/RuiStepperIcon.vue.d.ts +2 -0
- package/dist/components/steppers/RuiStepperIcon.vue_vue_type_script_setup_true_lang.js +47 -47
- 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 +3 -6
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +85 -67
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiExpandButton.js.map +1 -1
- package/dist/components/tables/RuiExpandButton.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/components/tables/RuiExpandButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTable.js.map +1 -1
- package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js +8 -5
- package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableEmptyState.js.map +1 -1
- package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableHead.js.map +1 -1
- package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js +89 -67
- package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTablePagination.js.map +1 -1
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +9 -12
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js +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 +3 -3
- 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 +8 -4
- package/dist/components/tables/data-table/RuiDataTableGroupRow.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_vue_type_script_setup_true_lang.js +2 -2
- 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_vue_type_script_setup_true_lang.js +47 -8
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table-styles.d.ts +24 -0
- package/dist/components/tables/data-table-styles.js +35 -20
- package/dist/components/tables/data-table-styles.js.map +1 -1
- package/dist/components/tables/table_no_data_placeholder.js +1 -1
- package/dist/components/tables/table_no_data_placeholder.js.map +1 -1
- package/dist/components/tables/table_no_data_placeholder_dark.js +1 -1
- package/dist/components/tables/table_no_data_placeholder_dark.js.map +1 -1
- package/dist/components/tables/use-pagination-navigation.js +1 -1
- package/dist/components/tabs/tab/RuiTab.js.map +1 -1
- package/dist/components/tabs/tab/RuiTab.vue.d.ts +2 -5
- package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js +95 -69
- package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tab/use-tab-link.js +1 -1
- package/dist/components/tabs/tab-item/RuiTabItem.js.map +1 -1
- package/dist/components/tabs/tab-item/RuiTabItem.vue.d.ts +0 -1
- package/dist/components/tabs/tab-item/RuiTabItem.vue_vue_type_script_setup_true_lang.js +5 -11
- 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_vue_type_script_setup_true_lang.js +8 -13
- package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tab-props.d.ts +7 -1
- package/dist/components/tabs/tab-props.js +7 -1
- package/dist/components/tabs/tab-props.js.map +1 -1
- package/dist/components/tabs/tabs/RuiTabs.js.map +1 -1
- package/dist/components/tabs/tabs/RuiTabs.vue.d.ts +2 -1
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js +188 -43
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tabs/use-tab-indicator.d.ts +27 -0
- package/dist/components/tabs/tabs/use-tab-indicator.js +67 -0
- package/dist/components/tabs/tabs/use-tab-indicator.js.map +1 -0
- package/dist/components/tabs/tabs/use-tab-keyboard.d.ts +17 -0
- package/dist/components/tabs/tabs/use-tab-keyboard.js +57 -0
- package/dist/components/tabs/tabs/use-tab-keyboard.js.map +1 -0
- package/dist/components/tabs/tabs/use-tab-routing.js +1 -2
- package/dist/components/tabs/tabs/use-tab-routing.js.map +1 -1
- package/dist/components/tabs/tabs/use-tab-scroll.js +15 -15
- package/dist/components/tabs/tabs/use-tab-scroll.js.map +1 -1
- package/dist/components/time-picker/RuiTimePicker.js.map +1 -1
- package/dist/components/time-picker/RuiTimePicker.vue_vue_type_script_setup_true_lang.js +95 -93
- 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 +18 -0
- package/dist/components/time-picker/time-picker-styles.js +16 -10
- package/dist/components/time-picker/time-picker-styles.js.map +1 -1
- package/dist/composables/breakpoint.js +3 -3
- package/dist/composables/breakpoint.js.map +1 -1
- package/dist/composables/defaults/field.d.ts +22 -0
- package/dist/composables/defaults/field.js +29 -0
- package/dist/composables/defaults/field.js.map +1 -0
- package/dist/composables/dropdown-menu.d.ts +23 -11
- package/dist/composables/dropdown-menu.js +44 -34
- package/dist/composables/dropdown-menu.js.map +1 -1
- package/dist/composables/floating.d.ts +1 -3
- package/dist/composables/floating.js +16 -13
- package/dist/composables/floating.js.map +1 -1
- package/dist/composables/forms/auto-complete/chips.d.ts +22 -0
- package/dist/composables/forms/auto-complete/chips.js +42 -0
- package/dist/composables/forms/auto-complete/chips.js.map +1 -0
- package/dist/composables/forms/auto-complete/combobox.d.ts +25 -0
- package/dist/composables/forms/auto-complete/combobox.js +35 -0
- package/dist/composables/forms/auto-complete/combobox.js.map +1 -0
- package/dist/composables/forms/auto-complete/focus.d.ts +5 -2
- package/dist/composables/forms/auto-complete/focus.js +44 -19
- package/dist/composables/forms/auto-complete/focus.js.map +1 -1
- package/dist/composables/forms/auto-complete/index.d.ts +3 -0
- package/dist/composables/forms/auto-complete/keyboard-navigation.d.ts +8 -1
- package/dist/composables/forms/auto-complete/keyboard-navigation.js +49 -21
- package/dist/composables/forms/auto-complete/keyboard-navigation.js.map +1 -1
- package/dist/composables/forms/auto-complete/search.js +6 -7
- package/dist/composables/forms/auto-complete/search.js.map +1 -1
- package/dist/composables/forms/auto-complete/selection.d.ts +37 -0
- package/dist/composables/forms/auto-complete/selection.js +60 -0
- package/dist/composables/forms/auto-complete/selection.js.map +1 -0
- package/dist/composables/forms/auto-complete/value.js +20 -1
- package/dist/composables/forms/auto-complete/value.js.map +1 -1
- package/dist/composables/forms/category-picker/use-category-picker.js +1 -1
- package/dist/composables/forms/use-prepend-append-width.js +6 -6
- package/dist/composables/forms/use-prepend-append-width.js.map +1 -1
- package/dist/composables/keyboard-scroll.d.ts +17 -0
- package/dist/composables/keyboard-scroll.js +58 -0
- package/dist/composables/keyboard-scroll.js.map +1 -0
- package/dist/composables/overlay-stack.js +1 -1
- package/dist/composables/sticky-header.d.ts +8 -0
- package/dist/composables/sticky-header.js +21 -10
- package/dist/composables/sticky-header.js.map +1 -1
- package/dist/composables/tables/data-table/columns.js +1 -1
- package/dist/composables/tables/data-table/expansion.js +1 -1
- package/dist/composables/tables/data-table/grouping.js +27 -28
- package/dist/composables/tables/data-table/grouping.js.map +1 -1
- package/dist/composables/tables/data-table/page-scroll.d.ts +32 -0
- package/dist/composables/tables/data-table/page-scroll.js +144 -0
- package/dist/composables/tables/data-table/page-scroll.js.map +1 -0
- package/dist/composables/tables/data-table/pagination.js +1 -1
- package/dist/composables/tables/data-table/selection.js +37 -38
- package/dist/composables/tables/data-table/selection.js.map +1 -1
- package/dist/composables/tables/data-table/sort.js +1 -1
- package/dist/composables/theme.js +12 -12
- package/dist/composables/theme.js.map +1 -1
- package/dist/composables/timeout-manager.js +1 -1
- package/dist/consts/colors.d.ts +4 -0
- package/dist/consts/colors.js +1 -37
- package/dist/consts/colors.js.map +1 -1
- package/dist/consts/tokens.d.ts +56 -0
- package/dist/consts/tokens.js +46 -0
- package/dist/consts/tokens.js.map +1 -0
- package/dist/consts/typography.d.ts +51 -18
- package/dist/index.d.ts +7 -2
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/library-icons.json +0 -10
- package/dist/style.css +5629 -4678
- package/dist/styles/colors.css +315 -0
- package/dist/styles/tokens.css +50 -0
- package/dist/tailwind.css +145 -0
- package/dist/theme/theme.css +403 -0
- package/dist/theme.css +403 -0
- package/dist/types/dom.d.ts +9 -0
- package/dist/types/theme.d.ts +2 -3
- package/dist/types/theme.js.map +1 -1
- package/dist/utils/form-text-detail.js +1 -1
- package/dist/utils/helpers.d.ts +0 -8
- package/dist/utils/helpers.js +1 -2
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/tv.js +13 -21
- package/dist/utils/tv.js.map +1 -1
- package/dist/vendor/@vueuse/core/dist/index.js +1577 -0
- package/dist/vendor/@vueuse/core/dist/index.js.map +1 -0
- package/dist/vendor/@vueuse/shared/dist/index.js +563 -0
- package/dist/vendor/@vueuse/shared/dist/index.js.map +1 -0
- package/dist/vite-plugin/index.js +5 -6
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/web-types.json +278 -403
- package/package.json +17 -19
- package/dist/components/icons/LazyIcon.vue.d.ts +0 -8
- package/dist/components/steppers/RuiStepperCustomIcon.js +0 -7
- package/dist/components/steppers/RuiStepperCustomIcon.js.map +0 -1
- package/dist/components/steppers/RuiStepperCustomIcon.vue.d.ts +0 -8
- package/dist/components/steppers/RuiStepperCustomIcon.vue_vue_type_script_setup_true_lang.js +0 -43
- package/dist/components/steppers/RuiStepperCustomIcon.vue_vue_type_script_setup_true_lang.js.map +0 -1
- package/dist/composables/colors/common.d.ts +0 -20
- package/dist/composables/colors/index.d.ts +0 -3
- package/dist/composables/colors/text-input.d.ts +0 -27
- package/dist/composables/forms/use-label-with-quote.d.ts +0 -2
- package/dist/composables/popper.d.ts +0 -16
- package/dist/composables/popper.js +0 -23
- package/dist/composables/popper.js.map +0 -1
- package/dist/consts/forms/auto-complete/index.d.ts +0 -4
- package/dist/theme/index.d.ts +0 -5
- package/dist/theme/index.js +0 -162
- package/dist/theme/index.js.map +0 -1
- package/dist/utils/forms/auto-complete/index.d.ts +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
2
|
+
import { ref, toValue, watch } from "vue";
|
|
3
3
|
//#region src/composables/forms/auto-complete/keyboard-navigation.ts
|
|
4
4
|
function useAutoCompleteKeyboardNavigation(options, deps) {
|
|
5
5
|
const focusedValueIndex = ref(-1);
|
|
@@ -88,36 +88,64 @@ function useAutoCompleteKeyboardNavigation(options, deps) {
|
|
|
88
88
|
event.preventDefault();
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Removes the selected value. Alt with it, where custom values are accepted, puts the value's
|
|
93
|
+
* text back in the search instead of dropping it.
|
|
94
|
+
*
|
|
95
|
+
* @param event - the Backspace or Delete press
|
|
96
|
+
* @param item - the value the highlighted chip stands for
|
|
97
|
+
*/
|
|
98
|
+
function removeSelectedValue(event, item) {
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
set(focusedValueIndex, -1);
|
|
101
|
+
deps.removeValue(item);
|
|
102
|
+
if (event.altKey && toValue(options.customValue)) deps.updateInternalSearch(deps.getText(item) ?? "");
|
|
103
|
+
}
|
|
104
|
+
/** Backspace or Delete with nothing typed: steps onto the last value, or drops it outright. */
|
|
105
|
+
function deleteFromEmptySearch(value) {
|
|
106
|
+
if (!toValue(options.multiple)) {
|
|
107
|
+
deps.clear();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (toValue(options.chips)) {
|
|
111
|
+
set(focusedValueIndex, value.length - 1);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const lastItem = value.at(-1);
|
|
115
|
+
if (lastItem !== void 0) deps.removeValue(lastItem);
|
|
116
|
+
}
|
|
117
|
+
function onInputDeletePressed(event) {
|
|
93
118
|
const value = get(deps.value);
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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();
|
|
119
|
+
const selected = value[get(focusedValueIndex)];
|
|
120
|
+
if (selected !== void 0) {
|
|
121
|
+
removeSelectedValue(event, selected);
|
|
122
|
+
return;
|
|
104
123
|
}
|
|
124
|
+
if (!get(deps.internalSearch) && value.length > 0) deleteFromEmptySearch(value);
|
|
125
|
+
}
|
|
126
|
+
function onInputKeydown(event) {
|
|
127
|
+
if (get(focusedValueIndex) === -1) return;
|
|
128
|
+
if (![
|
|
129
|
+
"Backspace",
|
|
130
|
+
"Delete",
|
|
131
|
+
"ArrowLeft",
|
|
132
|
+
"ArrowRight",
|
|
133
|
+
"Alt",
|
|
134
|
+
"AltGraph",
|
|
135
|
+
"Control",
|
|
136
|
+
"Meta",
|
|
137
|
+
"Shift"
|
|
138
|
+
].includes(event.key)) set(focusedValueIndex, -1);
|
|
105
139
|
}
|
|
106
140
|
watch(deps.value, () => {
|
|
107
141
|
setValueFocus(-1);
|
|
108
142
|
});
|
|
109
|
-
watch(focusedValueIndex, async (index) => {
|
|
110
|
-
const multiple = toValue(options.multiple);
|
|
111
|
-
if (index === -1 || !multiple) return;
|
|
112
|
-
await nextTick(() => {
|
|
113
|
-
(get(deps.activator)?.querySelector(`[data-index="${index}"]`))?.focus();
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
143
|
return {
|
|
117
144
|
focusedValueIndex,
|
|
118
145
|
moveSelectedValueHighlight,
|
|
119
146
|
onEnter,
|
|
120
147
|
onInputDeletePressed,
|
|
148
|
+
onInputKeydown,
|
|
121
149
|
onTab,
|
|
122
150
|
setValueFocus
|
|
123
151
|
};
|
|
@@ -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 /**\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
|
+
{"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 updateInternalSearch: (value?: string) => void;\n activator: Ref<HTMLElement | undefined> | TemplateRef<HTMLElement>;\n}\n\nexport interface UseAutoCompleteKeyboardNavigationReturn {\n /**\n * The selected value (a chip) that Backspace or Delete would remove, -1 for none. It is only\n * drawn as selected: focus stays in the input, where no browser shortcut takes the key.\n */\n focusedValueIndex: Ref<number>;\n moveSelectedValueHighlight: (event: KeyboardEvent, next: boolean) => void;\n onEnter: (event: KeyboardEvent) => void;\n onTab: (event: KeyboardEvent) => void;\n onInputDeletePressed: (event: KeyboardEvent) => void;\n /** Drops the value selection on any key that does not act on it. */\n onInputKeydown: (event: KeyboardEvent) => 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 /**\n * Removes the selected value. Alt with it, where custom values are accepted, puts the value's\n * text back in the search instead of dropping it.\n *\n * @param event - the Backspace or Delete press\n * @param item - the value the highlighted chip stands for\n */\n function removeSelectedValue(event: KeyboardEvent, item: TItem): void {\n event.preventDefault();\n set(focusedValueIndex, -1);\n deps.removeValue(item);\n if (event.altKey && toValue(options.customValue))\n deps.updateInternalSearch(deps.getText(item) ?? '');\n }\n\n /** Backspace or Delete with nothing typed: steps onto the last value, or drops it outright. */\n function deleteFromEmptySearch(value: TItem[]): void {\n if (!toValue(options.multiple)) {\n deps.clear();\n return;\n }\n if (toValue(options.chips)) {\n set(focusedValueIndex, value.length - 1);\n return;\n }\n const lastItem = value.at(-1);\n if (lastItem !== undefined)\n deps.removeValue(lastItem);\n }\n\n function onInputDeletePressed(event: KeyboardEvent): void {\n const value = get(deps.value);\n const selected = value[get(focusedValueIndex)];\n if (selected !== undefined) {\n removeSelectedValue(event, selected);\n return;\n }\n\n if (!get(deps.internalSearch) && value.length > 0)\n deleteFromEmptySearch(value);\n }\n\n function onInputKeydown(event: KeyboardEvent): void {\n if (get(focusedValueIndex) === -1)\n return;\n // a modifier pressed on its own (the Alt of Alt + Backspace) keeps the selection for the key it modifies\n const keepsSelection = ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Alt', 'AltGraph', 'Control', 'Meta', 'Shift'].includes(event.key);\n if (!keepsSelection)\n set(focusedValueIndex, -1);\n }\n\n // Watch value changes to reset focused index\n watch(deps.value, () => {\n setValueFocus(-1);\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 onInputKeydown,\n onTab,\n setValueFocus,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { get, refDebounced, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { getTextToken } from "../../../utils/helpers.js";
|
|
2
3
|
import { computed, onUnmounted, readonly, shallowRef, toValue, watch } from "vue";
|
|
3
|
-
import { refDebounced } from "@vueuse/core";
|
|
4
|
-
import { get as get$1, set as set$1 } from "@vueuse/shared";
|
|
5
4
|
//#region src/composables/forms/auto-complete/search.ts
|
|
6
5
|
function useAutoCompleteSearch(options, searchModel, opts) {
|
|
7
6
|
const internalSearch = shallowRef("");
|
|
@@ -31,9 +30,9 @@ function useAutoCompleteSearch(options, searchModel, opts) {
|
|
|
31
30
|
return String(item?.[groupBy] ?? "");
|
|
32
31
|
};
|
|
33
32
|
const filteredOptions = computed(() => {
|
|
34
|
-
const search = get
|
|
33
|
+
const search = get(debouncedInternalSearch);
|
|
35
34
|
const optionsValue = toValue(options);
|
|
36
|
-
if (toValue(opts.noFilter) || !search || get
|
|
35
|
+
if (toValue(opts.noFilter) || !search || get(justOpened)) return optionsValue;
|
|
37
36
|
const keyAttr = toValue(opts.keyAttr);
|
|
38
37
|
const textAttr = toValue(opts.textAttr);
|
|
39
38
|
const filter = toValue(opts.filter);
|
|
@@ -72,11 +71,11 @@ function useAutoCompleteSearch(options, searchModel, opts) {
|
|
|
72
71
|
};
|
|
73
72
|
}
|
|
74
73
|
function updateInternalSearch(value = "") {
|
|
75
|
-
set
|
|
76
|
-
set
|
|
74
|
+
set(searchModel, value);
|
|
75
|
+
set(internalSearch, value);
|
|
77
76
|
}
|
|
78
77
|
watch(searchModel, (search) => {
|
|
79
|
-
set
|
|
78
|
+
set(internalSearch, search);
|
|
80
79
|
}, { immediate: true });
|
|
81
80
|
onUnmounted(() => {
|
|
82
81
|
tokenCache.clear();
|
|
@@ -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 // 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":"
|
|
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":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ComputedRef, Ref } from 'vue';
|
|
2
|
+
export interface UseAutoCompleteSelectionDeps<TItem> {
|
|
3
|
+
value: Ref<TItem[]>;
|
|
4
|
+
multiple: ComputedRef<boolean>;
|
|
5
|
+
/** Whether a single pick shows its text in the input, rather than a slot or chip drawing it. */
|
|
6
|
+
shouldApplyValueAsSearch: ComputedRef<boolean>;
|
|
7
|
+
isOpen: Ref<boolean>;
|
|
8
|
+
searchInputFocused: Ref<boolean>;
|
|
9
|
+
internalSearch: Ref<string>;
|
|
10
|
+
/** The item's place in the selection, -1 when it is not picked. */
|
|
11
|
+
itemIndexInValue: (item: TItem) => number;
|
|
12
|
+
getText: (item: TItem) => string | undefined;
|
|
13
|
+
textValueToProperValue: (text: string) => TItem;
|
|
14
|
+
updateInternalSearch: (value?: string) => void;
|
|
15
|
+
/** Keeps focus on the input after a pick, showing the value rather than an empty search. */
|
|
16
|
+
settleOnInput: () => void;
|
|
17
|
+
/** Empties the model: an empty list when several values are picked, undefined otherwise. */
|
|
18
|
+
resetModel: () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface UseAutoCompleteSelectionReturn<TItem> {
|
|
21
|
+
/**
|
|
22
|
+
* Picks an item, or drops it when several values are picked and it already is one.
|
|
23
|
+
* `skipRefocused` leaves focus where it is, for a value set from typed text.
|
|
24
|
+
*/
|
|
25
|
+
setValue: (item: TItem, skipRefocused?: boolean) => Promise<void>;
|
|
26
|
+
/** Turns the typed search into a value, where custom values are accepted. */
|
|
27
|
+
setSearchAsValue: () => void;
|
|
28
|
+
clear: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The changes to the auto-complete's selection: picking or dropping an item, taking the typed text
|
|
32
|
+
* as a value, and clearing, with the search and focus that follow each.
|
|
33
|
+
*
|
|
34
|
+
* @param deps - the selection state and the operations it calls
|
|
35
|
+
* @returns the selection operations
|
|
36
|
+
*/
|
|
37
|
+
export declare function useAutoCompleteSelection<TItem>(deps: UseAutoCompleteSelectionDeps<TItem>): UseAutoCompleteSelectionReturn<TItem>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
2
|
+
import { nextTick } from "vue";
|
|
3
|
+
//#region src/composables/forms/auto-complete/selection.ts
|
|
4
|
+
/**
|
|
5
|
+
* The changes to the auto-complete's selection: picking or dropping an item, taking the typed text
|
|
6
|
+
* as a value, and clearing, with the search and focus that follow each.
|
|
7
|
+
*
|
|
8
|
+
* @param deps - the selection state and the operations it calls
|
|
9
|
+
* @returns the selection operations
|
|
10
|
+
*/
|
|
11
|
+
function useAutoCompleteSelection(deps) {
|
|
12
|
+
function toggleInSelection(item) {
|
|
13
|
+
const newValue = [...get(deps.value)];
|
|
14
|
+
const indexInValue = deps.itemIndexInValue(item);
|
|
15
|
+
if (indexInValue === -1) {
|
|
16
|
+
deps.updateInternalSearch();
|
|
17
|
+
newValue.push(item);
|
|
18
|
+
} else newValue.splice(indexInValue, 1);
|
|
19
|
+
set(deps.value, newValue);
|
|
20
|
+
}
|
|
21
|
+
function replaceSelection(item) {
|
|
22
|
+
if (get(deps.shouldApplyValueAsSearch)) deps.updateInternalSearch(deps.getText(item));
|
|
23
|
+
else deps.updateInternalSearch();
|
|
24
|
+
set(deps.value, [item]);
|
|
25
|
+
}
|
|
26
|
+
async function setValue(item, skipRefocused = false) {
|
|
27
|
+
if (get(deps.multiple)) {
|
|
28
|
+
toggleInSelection(item);
|
|
29
|
+
if (!skipRefocused) set(deps.searchInputFocused, true);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
replaceSelection(item);
|
|
33
|
+
if (skipRefocused) {
|
|
34
|
+
set(deps.isOpen, false);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
deps.settleOnInput();
|
|
38
|
+
await nextTick(() => {
|
|
39
|
+
set(deps.isOpen, false);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function setSearchAsValue() {
|
|
43
|
+
const searchToBeValue = get(deps.internalSearch);
|
|
44
|
+
if (!searchToBeValue) return;
|
|
45
|
+
setValue(deps.textValueToProperValue(searchToBeValue), true);
|
|
46
|
+
}
|
|
47
|
+
function clear() {
|
|
48
|
+
deps.updateInternalSearch();
|
|
49
|
+
deps.resetModel();
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
clear,
|
|
53
|
+
setSearchAsValue,
|
|
54
|
+
setValue
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { useAutoCompleteSelection };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/selection.ts"],"sourcesContent":["import type { ComputedRef, Ref } from 'vue';\n\nexport interface UseAutoCompleteSelectionDeps<TItem> {\n value: Ref<TItem[]>;\n multiple: ComputedRef<boolean>;\n /** Whether a single pick shows its text in the input, rather than a slot or chip drawing it. */\n shouldApplyValueAsSearch: ComputedRef<boolean>;\n isOpen: Ref<boolean>;\n searchInputFocused: Ref<boolean>;\n internalSearch: Ref<string>;\n /** The item's place in the selection, -1 when it is not picked. */\n itemIndexInValue: (item: TItem) => number;\n getText: (item: TItem) => string | undefined;\n textValueToProperValue: (text: string) => TItem;\n updateInternalSearch: (value?: string) => void;\n /** Keeps focus on the input after a pick, showing the value rather than an empty search. */\n settleOnInput: () => void;\n /** Empties the model: an empty list when several values are picked, undefined otherwise. */\n resetModel: () => void;\n}\n\nexport interface UseAutoCompleteSelectionReturn<TItem> {\n /**\n * Picks an item, or drops it when several values are picked and it already is one.\n * `skipRefocused` leaves focus where it is, for a value set from typed text.\n */\n setValue: (item: TItem, skipRefocused?: boolean) => Promise<void>;\n /** Turns the typed search into a value, where custom values are accepted. */\n setSearchAsValue: () => void;\n clear: () => void;\n}\n\n/**\n * The changes to the auto-complete's selection: picking or dropping an item, taking the typed text\n * as a value, and clearing, with the search and focus that follow each.\n *\n * @param deps - the selection state and the operations it calls\n * @returns the selection operations\n */\nexport function useAutoCompleteSelection<TItem>(deps: UseAutoCompleteSelectionDeps<TItem>): UseAutoCompleteSelectionReturn<TItem> {\n function toggleInSelection(item: TItem): void {\n const newValue = [...get(deps.value)];\n const indexInValue = deps.itemIndexInValue(item);\n if (indexInValue === -1) {\n deps.updateInternalSearch();\n newValue.push(item);\n }\n else {\n newValue.splice(indexInValue, 1);\n }\n set(deps.value, newValue);\n }\n\n function replaceSelection(item: TItem): void {\n if (get(deps.shouldApplyValueAsSearch))\n deps.updateInternalSearch(deps.getText(item));\n else deps.updateInternalSearch();\n set(deps.value, [item]);\n }\n\n async function setValue(item: TItem, skipRefocused = false): Promise<void> {\n if (get(deps.multiple)) {\n toggleInSelection(item);\n if (!skipRefocused)\n set(deps.searchInputFocused, true);\n return;\n }\n\n replaceSelection(item);\n if (skipRefocused) {\n set(deps.isOpen, false);\n return;\n }\n // focus stays on the combobox, which keeps showing the value just picked\n deps.settleOnInput();\n await nextTick(() => {\n set(deps.isOpen, false);\n });\n }\n\n function setSearchAsValue(): void {\n const searchToBeValue = get(deps.internalSearch);\n if (!searchToBeValue)\n return;\n\n setValue(deps.textValueToProperValue(searchToBeValue), true);\n }\n\n function clear(): void {\n deps.updateInternalSearch();\n deps.resetModel();\n }\n\n return { clear, setSearchAsValue, setValue };\n}\n"],"mappings":";;;;;;;;;;AAuCA,SAAgB,yBAAgC,MAAkF;CAChI,SAAS,kBAAkB,MAAmB;EAC5C,MAAM,WAAW,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC;EACpC,MAAM,eAAe,KAAK,iBAAiB,IAAI;EAC/C,IAAI,iBAAiB,IAAI;GACvB,KAAK,qBAAqB;GAC1B,SAAS,KAAK,IAAI;EACpB,OAEE,SAAS,OAAO,cAAc,CAAC;EAEjC,IAAI,KAAK,OAAO,QAAQ;CAC1B;CAEA,SAAS,iBAAiB,MAAmB;EAC3C,IAAI,IAAI,KAAK,wBAAwB,GACnC,KAAK,qBAAqB,KAAK,QAAQ,IAAI,CAAC;OACzC,KAAK,qBAAqB;EAC/B,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC;CACxB;CAEA,eAAe,SAAS,MAAa,gBAAgB,OAAsB;EACzE,IAAI,IAAI,KAAK,QAAQ,GAAG;GACtB,kBAAkB,IAAI;GACtB,IAAI,CAAC,eACH,IAAI,KAAK,oBAAoB,IAAI;GACnC;EACF;EAEA,iBAAiB,IAAI;EACrB,IAAI,eAAe;GACjB,IAAI,KAAK,QAAQ,KAAK;GACtB;EACF;EAEA,KAAK,cAAc;EACnB,MAAM,eAAe;GACnB,IAAI,KAAK,QAAQ,KAAK;EACxB,CAAC;CACH;CAEA,SAAS,mBAAyB;EAChC,MAAM,kBAAkB,IAAI,KAAK,cAAc;EAC/C,IAAI,CAAC,iBACH;EAEF,SAAS,KAAK,uBAAuB,eAAe,GAAG,IAAI;CAC7D;CAEA,SAAS,QAAc;EACrB,KAAK,qBAAqB;EAC1B,KAAK,WAAW;CAClB;CAEA,OAAO;EAAE;EAAO;EAAkB;CAAS;AAC7C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assert } from "../../../utils/assert.js";
|
|
2
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
3
|
+
import { isEqual } from "../../../utils/is-equal.js";
|
|
2
4
|
import { computed, toValue, watch } from "vue";
|
|
3
|
-
import { get, set } from "@vueuse/shared";
|
|
4
5
|
//#region src/composables/forms/auto-complete/value.ts
|
|
5
6
|
function useAutoCompleteValue(modelValue, options, opts, deps) {
|
|
6
7
|
function buildOptionsMap(optionsData) {
|
|
@@ -71,6 +72,24 @@ function useAutoCompleteValue(modelValue, options, opts, deps) {
|
|
|
71
72
|
deps.updateInternalSearch(deps.getText(firstItem));
|
|
72
73
|
}
|
|
73
74
|
}, { immediate: true });
|
|
75
|
+
/**
|
|
76
|
+
* Reconciles the selection against a new set of options, comparing by
|
|
77
|
+
* reference before by value so an unchanged list costs nothing.
|
|
78
|
+
*
|
|
79
|
+
* Only a selection the previous options could resolve is reconciled: a value
|
|
80
|
+
* that was already unresolvable is one the consumer set before its options
|
|
81
|
+
* arrived, since an async list starts empty, and clearing it here would
|
|
82
|
+
* discard a legitimate value.
|
|
83
|
+
*
|
|
84
|
+
* @param curr - the new options
|
|
85
|
+
* @param old - the options before them
|
|
86
|
+
*/
|
|
87
|
+
function onOptionsChanged(curr, old) {
|
|
88
|
+
if (curr === old || toValue(opts.customValue) || isEqual(curr, old)) return;
|
|
89
|
+
if (!toValue(deps.multiple) && resolveIn(old).length === 0) return;
|
|
90
|
+
setSelected(get(value));
|
|
91
|
+
}
|
|
92
|
+
watch(() => toValue(options), onOptionsChanged);
|
|
74
93
|
return {
|
|
75
94
|
resolveIn,
|
|
76
95
|
setSelected,
|
|
@@ -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 // 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":"
|
|
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';\nimport { isEqual } from '@/utils/is-equal';\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 /**\n * Reconciles the selection against a new set of options, comparing by\n * reference before by value so an unchanged list costs nothing.\n *\n * Only a selection the previous options could resolve is reconciled: a value\n * that was already unresolvable is one the consumer set before its options\n * arrived, since an async list starts empty, and clearing it here would\n * discard a legitimate value.\n *\n * @param curr - the new options\n * @param old - the options before them\n */\n function onOptionsChanged(curr: TItem[], old: TItem[]): void {\n if (curr === old || toValue(opts.customValue) || isEqual(curr, old))\n return;\n\n if (!toValue(deps.multiple) && resolveIn(old).length === 0)\n return;\n\n setSelected(get(value));\n }\n\n watch(() => toValue(options), onOptionsChanged);\n\n return {\n resolveIn,\n setSelected,\n value,\n };\n}\n"],"mappings":";;;;;AA+BA,SAAgB,qBACd,YACA,SACA,MACA,MACmC;CACnC,SAAS,gBAAgB,aAAuC;EAC9D,MAAM,sBAAM,IAAI,IAAgB;EAChC,KAAK,MAAM,QAAQ,aACjB,IAAI,IAAI,KAAK,cAAc,IAAI,GAAG,IAAI;EAExC,OAAO;CACT;CAGA,MAAM,aAAa,eAAgC,gBAAgB,QAAQ,OAAO,CAAC,CAAC;CAEpF,SAAS,yBAAyB,gBAA2C;EAC3E,IAAI,mBAAmB,QAAQ,mBAAmB,KAAA,GAChD,OAAO,CAAC;EACV,OAAO,MAAM,QAAQ,cAAc,IAAI,iBAAiB,CAAC,cAAc;CACzE;CAEA,SAAS,aACP,YACA,gBACA,aACA,cACA,QACS;EACT,MAAM,WAAoB,CAAC;EAC3B,KAAK,MAAM,OAAO,YAAY;GAC5B,MAAM,YAAY,eAAe,IAAI,OAAO,GAAG,CAAC;GAChD,IAAI,cAAc,KAAA,GAChB,SAAS,KAAK,SAAS;QACpB,IAAI,aACP,SAAS,KAAK,KAAK,uBAAuB,KAAK,YAAY,CAAC;EAChE;EACA,OAAO;CACT;CAEA,SAAS,yBACP,gBACA,gBACA,cACA,aACS;EACT,MAAM,gBAAgB,MAAM,QAAQ,cAAc;EAElD,MAAM,WAAW,aADE,yBAAyB,cACd,GAAY,gBAAgB,aAAa,eAAc,QAAO,KAAK,cAAc,GAAG,CAAC;EAEnH,IAAI,iBAAiB,SAAS,WAAW,GACvC,OAAO;EAET,MAAM,MAAM,SAAS;EACrB,OAAO,QAAQ,KAAA,KAAa,QAAQ,IAAI;EACxC,OAAO,CAAC,GAAG;CACb;CAEA,SAAS,qBACP,gBACA,gBACA,cACA,aACS;EAET,OAAO,aADY,yBAAyB,cACxB,GAAY,gBAAgB,aAAa,eAAc,QAAO,GAAG;CACvF;CAEA,SAAS,mBAAmB,OAAiC;EAC3D,IAAI,YAAY,KAAK;CACvB;CAEA,SAAS,YAAY,UAAyB;EAC5C,MAAM,UAAU,QAAQ,KAAK,OAAO;EACpC,MAAM,eAAe,QAAQ,KAAK,YAAY;EAC9C,MAAM,YAAY,WAAW,CAAC,eAAe,SAAS,KAAI,SAAQ,KAAK,QAAQ,IAAI;EAEnF,IAAI,QAAQ,KAAK,QAAQ,GACvB,OAAO,mBAAmB,SAAmB;EAE/C,IAAI,UAAU,WAAW,GACvB,OAAO,mBAAmB,KAAA,CAAS;EAErC,OAAO,mBAAmB,UAAU,EAAY;CAClD;CAEA,SAAS,eAAe,gBAA0C;EAChE,MAAM,iBAAiB,IAAI,UAAU;EACrC,MAAM,UAAU,QAAQ,KAAK,OAAO;EACpC,MAAM,eAAe,QAAQ,KAAK,YAAY,KAAK;EACnD,MAAM,cAAc,QAAQ,KAAK,WAAW,KAAK;EAEjD,IAAI,WAAW,cACb,OAAO,yBAAyB,gBAAgB,gBAAgB,cAAc,WAAW;EAE3F,OAAO,qBAAqB,gBAAgB,gBAAgB,cAAc,WAAW;CACvF;CAEA,SAAS,UAAU,aAA+B;EAChD,OAAO,eAAe,gBAAgB,WAAW,CAAC;CACpD;CAEA,MAAM,QAAQ,SAAkB;EAC9B,WAAW,eAAe,IAAI,UAAU,CAAC;EACzC,MAAM,aAA4B;GAChC,YAAY,QAAQ;EACtB;CACF,CAAC;CAGD,MAAM,CAAC,aAAa,QAAQ,KAAK,MAAM,CAAC,SAAS;EAC/C,IAAI,QAAQ,KAAK,MAAM,KAAK,CAAC,QAAQ,KAAK,wBAAwB,GAChE;EAEF,MAAM,eAAe,IAAI,KAAK;EAC9B,IAAI,QAAQ,KAAK,QAAQ,KAAK,aAAa,WAAW,GACpD,KAAK,qBAAqB;OAEvB;GACH,MAAM,YAAY,aAAa;GAC/B,OAAO,cAAc,KAAA,KAAa,cAAc,IAAI;GACpD,KAAK,qBAAqB,KAAK,QAAQ,SAAS,CAAC;EACnD;CACF,GAAG,EAAE,WAAW,KAAK,CAAC;;;;;;;;;;;;;CActB,SAAS,iBAAiB,MAAe,KAAoB;EAC3D,IAAI,SAAS,OAAO,QAAQ,KAAK,WAAW,KAAK,QAAQ,MAAM,GAAG,GAChE;EAEF,IAAI,CAAC,QAAQ,KAAK,QAAQ,KAAK,UAAU,GAAG,CAAC,CAAC,WAAW,GACvD;EAEF,YAAY,IAAI,KAAK,CAAC;CACxB;CAEA,YAAY,QAAQ,OAAO,GAAG,gBAAgB;CAE9C,OAAO;EACL;EACA;EACA;CACF;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { useDropdownOptionProperty } from "../../dropdown-menu.js";
|
|
2
3
|
import { computed, readonly, shallowRef, toValue, watch } from "vue";
|
|
3
|
-
import { get, set } from "@vueuse/shared";
|
|
4
4
|
//#region src/composables/forms/category-picker/use-category-picker.ts
|
|
5
5
|
/**
|
|
6
6
|
* Owns the grouping, filtering and selection state for `RuiCategoryPicker`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assert } from "../../utils/assert.js";
|
|
2
|
+
import { get, set } from "../../vendor/@vueuse/shared/dist/index.js";
|
|
3
|
+
import { useResizeObserver } from "../../vendor/@vueuse/core/dist/index.js";
|
|
2
4
|
import { readonly, shallowRef } from "vue";
|
|
3
|
-
import { useResizeObserver } from "@vueuse/core";
|
|
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
6
|
/**
|
|
7
7
|
* Tracks how much room a field's prepend and append regions take.
|
|
@@ -22,14 +22,14 @@ function usePrependAppendWidth(prepend, append, offset = 0) {
|
|
|
22
22
|
const prependWidth = shallowRef("0px");
|
|
23
23
|
const appendWidth = shallowRef("0px");
|
|
24
24
|
useResizeObserver(prepend, () => {
|
|
25
|
-
const target = get
|
|
25
|
+
const target = get(prepend);
|
|
26
26
|
assert(target);
|
|
27
|
-
set
|
|
27
|
+
set(prependWidth, `${target.offsetWidth + offset}px`);
|
|
28
28
|
});
|
|
29
29
|
useResizeObserver(append, () => {
|
|
30
|
-
const target = get
|
|
30
|
+
const target = get(append);
|
|
31
31
|
assert(target);
|
|
32
|
-
set
|
|
32
|
+
set(appendWidth, `${target.offsetWidth + offset}px`);
|
|
33
33
|
});
|
|
34
34
|
return {
|
|
35
35
|
appendWidth: readonly(appendWidth),
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,IAAI,OAAO;EAC1B,OAAO,MAAM;EACb,IAAI,cAAc,GAAG,OAAO,cAAc,OAAO,GAAG;CACtD,CAAC;CAED,kBAAkB,cAAc;EAC9B,MAAM,SAAS,IAAI,MAAM;EACzB,OAAO,MAAM;EACb,IAAI,aAAa,GAAG,OAAO,cAAc,OAAO,GAAG;CACrD,CAAC;CAED,OAAO;EACL,aAAa,SAAS,WAAW;EACjC,cAAc,SAAS,YAAY;CACrC;AACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ComputedRef, Ref } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a box scrolls while holding nothing a keyboard user can reach, the case WCAG 2.1.1 and
|
|
4
|
+
* axe's scrollable-region-focusable rule cover: the arrow keys only scroll what has focus.
|
|
5
|
+
*
|
|
6
|
+
* @param element - the scrolling box
|
|
7
|
+
* @returns true when the box overflows and has no focusable content
|
|
8
|
+
*/
|
|
9
|
+
export declare function needsOwnFocus(element: HTMLElement): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Makes a scrolling box a tab stop while, and only while, it overflows with nothing focusable
|
|
12
|
+
* inside, so keyboard users can scroll it without a stray tab stop on every box that fits.
|
|
13
|
+
*
|
|
14
|
+
* @param target - the scrolling box
|
|
15
|
+
* @returns the `tabindex` to bind on the box: 0 when it needs focus, otherwise undefined
|
|
16
|
+
*/
|
|
17
|
+
export declare function useKeyboardScroll(target: Readonly<Ref<HTMLElement | null | undefined>>): ComputedRef<0 | undefined>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { get, set } from "../vendor/@vueuse/shared/dist/index.js";
|
|
2
|
+
import { useMutationObserver, useResizeObserver } from "../vendor/@vueuse/core/dist/index.js";
|
|
3
|
+
import { computed, onMounted, shallowRef } from "vue";
|
|
4
|
+
//#region src/composables/keyboard-scroll.ts
|
|
5
|
+
/** What a keyboard user can tab to inside a scrolling box, and so scroll it by. */
|
|
6
|
+
var FOCUSABLE = [
|
|
7
|
+
"a[href]",
|
|
8
|
+
"button:not([disabled])",
|
|
9
|
+
"input:not([disabled]):not([type=hidden])",
|
|
10
|
+
"select:not([disabled])",
|
|
11
|
+
"textarea:not([disabled])",
|
|
12
|
+
"[tabindex]:not([tabindex=\"-1\"])"
|
|
13
|
+
].join(",");
|
|
14
|
+
/**
|
|
15
|
+
* Whether a box scrolls while holding nothing a keyboard user can reach, the case WCAG 2.1.1 and
|
|
16
|
+
* axe's scrollable-region-focusable rule cover: the arrow keys only scroll what has focus.
|
|
17
|
+
*
|
|
18
|
+
* @param element - the scrolling box
|
|
19
|
+
* @returns true when the box overflows and has no focusable content
|
|
20
|
+
*/
|
|
21
|
+
function needsOwnFocus(element) {
|
|
22
|
+
return (element.scrollWidth > element.clientWidth + 1 || element.scrollHeight > element.clientHeight + 1) && element.querySelector(FOCUSABLE) === null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Makes a scrolling box a tab stop while, and only while, it overflows with nothing focusable
|
|
26
|
+
* inside, so keyboard users can scroll it without a stray tab stop on every box that fits.
|
|
27
|
+
*
|
|
28
|
+
* @param target - the scrolling box
|
|
29
|
+
* @returns the `tabindex` to bind on the box: 0 when it needs focus, otherwise undefined
|
|
30
|
+
*/
|
|
31
|
+
function useKeyboardScroll(target) {
|
|
32
|
+
const focusable = shallowRef(false);
|
|
33
|
+
let scheduled = false;
|
|
34
|
+
function update() {
|
|
35
|
+
scheduled = false;
|
|
36
|
+
const element = get(target);
|
|
37
|
+
set(focusable, element ? needsOwnFocus(element) : false);
|
|
38
|
+
}
|
|
39
|
+
/** Reading the scroll sizes forces layout, so a burst of resizes and mutations is checked once a frame. */
|
|
40
|
+
function schedule() {
|
|
41
|
+
if (scheduled) return;
|
|
42
|
+
scheduled = true;
|
|
43
|
+
requestAnimationFrame(update);
|
|
44
|
+
}
|
|
45
|
+
onMounted(update);
|
|
46
|
+
useResizeObserver(target, schedule);
|
|
47
|
+
useMutationObserver(target, schedule, {
|
|
48
|
+
childList: true,
|
|
49
|
+
subtree: true,
|
|
50
|
+
attributes: true,
|
|
51
|
+
attributeFilter: ["disabled", "tabindex"]
|
|
52
|
+
});
|
|
53
|
+
return computed(() => get(focusable) ? 0 : void 0);
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { needsOwnFocus, useKeyboardScroll };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=keyboard-scroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard-scroll.js","names":[],"sources":["../../src/composables/keyboard-scroll.ts"],"sourcesContent":["import type { ComputedRef, Ref } from 'vue';\nimport { useMutationObserver, useResizeObserver } from '@vueuse/core';\n\n/** What a keyboard user can tab to inside a scrolling box, and so scroll it by. */\nconst FOCUSABLE = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled]):not([type=hidden])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\n/**\n * Whether a box scrolls while holding nothing a keyboard user can reach, the case WCAG 2.1.1 and\n * axe's scrollable-region-focusable rule cover: the arrow keys only scroll what has focus.\n *\n * @param element - the scrolling box\n * @returns true when the box overflows and has no focusable content\n */\nexport function needsOwnFocus(element: HTMLElement): boolean {\n const overflows = element.scrollWidth > element.clientWidth + 1 || element.scrollHeight > element.clientHeight + 1;\n return overflows && element.querySelector(FOCUSABLE) === null;\n}\n\n/**\n * Makes a scrolling box a tab stop while, and only while, it overflows with nothing focusable\n * inside, so keyboard users can scroll it without a stray tab stop on every box that fits.\n *\n * @param target - the scrolling box\n * @returns the `tabindex` to bind on the box: 0 when it needs focus, otherwise undefined\n */\nexport function useKeyboardScroll(target: Readonly<Ref<HTMLElement | null | undefined>>): ComputedRef<0 | undefined> {\n const focusable = shallowRef<boolean>(false);\n let scheduled = false;\n\n function update(): void {\n scheduled = false;\n const element = get(target);\n set(focusable, element ? needsOwnFocus(element) : false);\n }\n\n /** Reading the scroll sizes forces layout, so a burst of resizes and mutations is checked once a frame. */\n function schedule(): void {\n if (scheduled)\n return;\n scheduled = true;\n requestAnimationFrame(update);\n }\n\n // the first check runs at mount, so the box is reachable from its first render, not a frame later\n onMounted(update);\n useResizeObserver(target, schedule);\n // the box keeps its size while its content grows or swaps, which changes whether it overflows\n useMutationObserver(target, schedule, { childList: true, subtree: true, attributes: true, attributeFilter: ['disabled', 'tabindex'] });\n\n return computed<0 | undefined>(() => (get(focusable) ? 0 : undefined));\n}\n"],"mappings":";;;;;AAIA,IAAM,YAAY;CAChB;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,GAAG;;;;;;;;AASV,SAAgB,cAAc,SAA+B;CAE3D,QADkB,QAAQ,cAAc,QAAQ,cAAc,KAAK,QAAQ,eAAe,QAAQ,eAAe,MAC7F,QAAQ,cAAc,SAAS,MAAM;AAC3D;;;;;;;;AASA,SAAgB,kBAAkB,QAAmF;CACnH,MAAM,YAAY,WAAoB,KAAK;CAC3C,IAAI,YAAY;CAEhB,SAAS,SAAe;EACtB,YAAY;EACZ,MAAM,UAAU,IAAI,MAAM;EAC1B,IAAI,WAAW,UAAU,cAAc,OAAO,IAAI,KAAK;CACzD;;CAGA,SAAS,WAAiB;EACxB,IAAI,WACF;EACF,YAAY;EACZ,sBAAsB,MAAM;CAC9B;CAGA,UAAU,MAAM;CAChB,kBAAkB,QAAQ,QAAQ;CAElC,oBAAoB,QAAQ,UAAU;EAAE,WAAW;EAAM,SAAS;EAAM,YAAY;EAAM,iBAAiB,CAAC,YAAY,UAAU;CAAE,CAAC;CAErI,OAAO,eAA+B,IAAI,SAAS,IAAI,IAAI,KAAA,CAAU;AACvE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { get, set } from "../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { computed, onScopeDispose, ref, toValue, watch } from "vue";
|
|
2
|
-
import { get, set } from "@vueuse/shared";
|
|
3
3
|
//#region src/composables/overlay-stack.ts
|
|
4
4
|
/**
|
|
5
5
|
* Module scoped rather than per call. Layers stack in the window, not in a
|
|
@@ -5,6 +5,14 @@ export interface UseStickyTableHeaderRefs {
|
|
|
5
5
|
interface UseStickyTableHeaderReturn {
|
|
6
6
|
stick: Readonly<Ref<boolean>>;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Whether an element becomes the containing block of its `position: fixed`
|
|
10
|
+
* descendants. The individual `translate`, `rotate` and `scale` properties
|
|
11
|
+
* count like `transform`: Tailwind 4 writes its translate utilities to
|
|
12
|
+
* `translate`, so a dialog centred with `-translate-x-1/2` leaves `transform`
|
|
13
|
+
* at `none`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createsFixedContainingBlock(style: CSSStyleDeclaration): boolean;
|
|
8
16
|
/**
|
|
9
17
|
* Setup sticky table header
|
|
10
18
|
*/
|