@rotki/ui-library 3.1.7 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordions/accordion/RuiAccordion.js.map +1 -1
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/accordions/accordion/accordion-styles.d.ts +1 -0
- package/dist/components/accordions/accordion/accordion-styles.js +7 -0
- package/dist/components/accordions/accordion/accordion-styles.js.map +1 -0
- package/dist/components/alerts/RuiAlert.js.map +1 -1
- package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js +1 -65
- package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/alerts/alert-styles.d.ts +145 -0
- package/dist/components/alerts/alert-styles.js +70 -0
- package/dist/components/alerts/alert-styles.js.map +1 -0
- package/dist/components/avatars/RuiAvatar.js.map +1 -1
- package/dist/components/avatars/RuiAvatar.vue_vue_type_script_setup_true_lang.js +1 -38
- 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_vue_type_script_setup_true_lang.js +1 -13
- package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/avatars/avatar-group-styles.d.ts +49 -0
- package/dist/components/avatars/avatar-group-styles.js +18 -0
- package/dist/components/avatars/avatar-group-styles.js.map +1 -0
- package/dist/components/avatars/avatar-styles.d.ts +181 -0
- package/dist/components/avatars/avatar-styles.js +43 -0
- package/dist/components/avatars/avatar-styles.js.map +1 -0
- package/dist/components/buttons/button-group/RuiButtonGroup.js.map +1 -1
- package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js +2 -138
- 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-styles.d.ts +142 -0
- package/dist/components/buttons/button-group/button-group-styles.js +143 -0
- package/dist/components/buttons/button-group/button-group-styles.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 +1 -8
- 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 +2 -22
- package/dist/components/calendar/RuiCalendarGrid.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 +3 -14
- package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/calendar/calendar-grid-styles.d.ts +43 -0
- package/dist/components/calendar/calendar-grid-styles.js +26 -0
- package/dist/components/calendar/calendar-grid-styles.js.map +1 -0
- package/dist/components/calendar/calendar-menu-styles.d.ts +34 -0
- package/dist/components/calendar/calendar-menu-styles.js +17 -0
- package/dist/components/calendar/calendar-menu-styles.js.map +1 -0
- package/dist/components/calendar/calendar-styles.d.ts +16 -0
- package/dist/components/calendar/calendar-styles.js +13 -0
- package/dist/components/calendar/calendar-styles.js.map +1 -0
- package/dist/components/cards/RuiCard.js.map +1 -1
- package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js +3 -58
- 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 +2 -20
- package/dist/components/cards/RuiCardHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cards/card-header-styles.d.ts +46 -0
- package/dist/components/cards/card-header-styles.js +24 -0
- package/dist/components/cards/card-header-styles.js.map +1 -0
- package/dist/components/cards/card-styles.d.ts +175 -0
- package/dist/components/cards/card-styles.js +62 -0
- package/dist/components/cards/card-styles.js.map +1 -0
- package/dist/components/chips/RuiChip.js.map +1 -1
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js +2 -241
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/chips/chip-styles.d.ts +223 -0
- package/dist/components/chips/chip-styles.js +246 -0
- package/dist/components/chips/chip-styles.js.map +1 -0
- package/dist/components/color-picker/RuiColorBoard.js.map +1 -1
- package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js.map +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 +3 -3
- package/dist/components/color-picker/RuiColorHue.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 +3 -3
- package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/color-board-styles.d.ts +1 -0
- package/dist/components/color-picker/color-board-styles.js +7 -0
- package/dist/components/color-picker/color-board-styles.js.map +1 -0
- package/dist/components/color-picker/color-hue-styles.d.ts +1 -0
- package/dist/components/color-picker/color-hue-styles.js +7 -0
- package/dist/components/color-picker/color-hue-styles.js.map +1 -0
- package/dist/components/color-picker/color-picker-styles.d.ts +1 -0
- package/dist/components/color-picker/color-picker-styles.js +7 -0
- package/dist/components/color-picker/color-picker-styles.js.map +1 -0
- package/dist/components/forms/field-label/RuiFieldLabel.js.map +1 -1
- package/dist/components/forms/field-label/RuiFieldLabel.vue_vue_type_script_setup_true_lang.js +1 -11
- package/dist/components/forms/field-label/RuiFieldLabel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/field-label/field-label-styles.d.ts +43 -0
- package/dist/components/forms/field-label/field-label-styles.js +16 -0
- package/dist/components/forms/field-label/field-label-styles.js.map +1 -0
- package/dist/components/forms/select/RuiSimpleSelect.js.map +1 -1
- package/dist/components/forms/select/RuiSimpleSelect.vue_vue_type_script_setup_true_lang.js +2 -11
- package/dist/components/forms/select/RuiSimpleSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/select/simple-select-styles.d.ts +2 -0
- package/dist/components/forms/select/simple-select-styles.js +15 -0
- package/dist/components/forms/select/simple-select-styles.js.map +1 -0
- package/dist/components/forms/switch/RuiSwitch.js.map +1 -1
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js +1 -126
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/switch/switch-styles.d.ts +151 -0
- package/dist/components/forms/switch/switch-styles.js +131 -0
- package/dist/components/forms/switch/switch-styles.js.map +1 -0
- package/dist/components/icons/RuiIcon.js.map +1 -1
- package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js +2 -28
- package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/icons/icon-styles.d.ts +44 -0
- package/dist/components/icons/icon-styles.js +33 -0
- package/dist/components/icons/icon-styles.js.map +1 -0
- package/dist/components/loaders/RuiSkeletonBase.js.map +1 -1
- package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js +2 -12
- 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 +3 -13
- package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/loaders/skeleton-base-styles.d.ts +25 -0
- package/dist/components/loaders/skeleton-base-styles.js +16 -0
- package/dist/components/loaders/skeleton-base-styles.js.map +1 -0
- package/dist/components/loaders/skeleton-loader-styles.d.ts +37 -0
- package/dist/components/loaders/skeleton-loader-styles.js +18 -0
- package/dist/components/loaders/skeleton-loader-styles.js.map +1 -0
- package/dist/components/overlays/badge/RuiBadge.js.map +1 -1
- package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js +1 -83
- package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/badge/badge-styles.d.ts +193 -0
- package/dist/components/overlays/badge/badge-styles.js +88 -0
- package/dist/components/overlays/badge/badge-styles.js.map +1 -0
- package/dist/components/overlays/dialog/RuiDialog.js.map +1 -1
- package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js +3 -14
- package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/dialog/dialog-styles.d.ts +40 -0
- package/dist/components/overlays/dialog/dialog-styles.js +18 -0
- package/dist/components/overlays/dialog/dialog-styles.js.map +1 -0
- package/dist/components/overlays/menu/RuiMenu.js.map +1 -1
- package/dist/components/overlays/menu/RuiMenu.vue.d.ts +9 -0
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +113 -58
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/menu/menu-styles.d.ts +58 -0
- package/dist/components/overlays/menu/menu-styles.js +25 -0
- package/dist/components/overlays/menu/menu-styles.js.map +1 -0
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.js.map +1 -1
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js +4 -69
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/navigation-drawer/navigation-drawer-styles.d.ts +76 -0
- package/dist/components/overlays/navigation-drawer/navigation-drawer-styles.js +72 -0
- package/dist/components/overlays/navigation-drawer/navigation-drawer-styles.js.map +1 -0
- package/dist/components/overlays/notification/RuiNotification.js.map +1 -1
- package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/notification/notification-styles.d.ts +1 -0
- package/dist/components/overlays/notification/notification-styles.js +7 -0
- package/dist/components/overlays/notification/notification-styles.js.map +1 -0
- package/dist/components/overlays/tooltip/RuiTooltip.js.map +1 -1
- package/dist/components/overlays/tooltip/RuiTooltip.vue.d.ts +4 -2
- package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js +42 -25
- package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/tooltip/tooltip-styles.d.ts +2 -0
- package/dist/components/overlays/tooltip/tooltip-styles.js +3 -1
- 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_vue_type_script_setup_true_lang.js +1 -133
- package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/progress/progress-styles.d.ts +181 -0
- package/dist/components/progress/progress-styles.js +139 -0
- package/dist/components/progress/progress-styles.js.map +1 -0
- package/dist/components/steppers/RuiFooterStepper.js.map +1 -1
- package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js +3 -13
- package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/RuiStepper.js.map +1 -1
- package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js +4 -94
- 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_vue_type_script_setup_true_lang.js +2 -34
- package/dist/components/steppers/RuiStepperIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/steppers/footer-stepper-styles.d.ts +28 -0
- package/dist/components/steppers/footer-stepper-styles.js +16 -0
- package/dist/components/steppers/footer-stepper-styles.js.map +1 -0
- package/dist/components/steppers/stepper-icon-styles.d.ts +60 -0
- package/dist/components/steppers/stepper-icon-styles.js +39 -0
- package/dist/components/steppers/stepper-icon-styles.js.map +1 -0
- package/dist/components/steppers/stepper-styles.d.ts +202 -0
- package/dist/components/steppers/stepper-styles.js +98 -0
- package/dist/components/steppers/stepper-styles.js.map +1 -0
- package/dist/components/tables/RuiTable.js.map +1 -1
- package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js +1 -32
- 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 -15
- package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableErrorState.js.map +1 -1
- package/dist/components/tables/RuiTableErrorState.vue_vue_type_script_setup_true_lang.js +2 -5
- package/dist/components/tables/RuiTableErrorState.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 +1 -34
- package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableLoadingState.js.map +1 -1
- package/dist/components/tables/RuiTableLoadingState.vue_vue_type_script_setup_true_lang.js +1 -8
- package/dist/components/tables/RuiTableLoadingState.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 +1 -30
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/table-empty-state-styles.d.ts +43 -0
- package/dist/components/tables/table-empty-state-styles.js +20 -0
- package/dist/components/tables/table-empty-state-styles.js.map +1 -0
- package/dist/components/tables/table-error-state-styles.d.ts +36 -0
- package/dist/components/tables/table-error-state-styles.js +15 -0
- package/dist/components/tables/table-error-state-styles.js.map +1 -0
- package/dist/components/tables/table-head-styles.d.ts +91 -0
- package/dist/components/tables/table-head-styles.js +39 -0
- package/dist/components/tables/table-head-styles.js.map +1 -0
- package/dist/components/tables/table-loading-state-styles.d.ts +34 -0
- package/dist/components/tables/table-loading-state-styles.js +13 -0
- package/dist/components/tables/table-loading-state-styles.js.map +1 -0
- package/dist/components/tables/table-pagination-styles.d.ts +82 -0
- package/dist/components/tables/table-pagination-styles.js +35 -0
- package/dist/components/tables/table-pagination-styles.js.map +1 -0
- package/dist/components/tables/table-styles.d.ts +62 -0
- package/dist/components/tables/table-styles.js +37 -0
- package/dist/components/tables/table-styles.js.map +1 -0
- package/dist/components/tabs/tab/RuiTab.js.map +1 -1
- package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js +3 -84
- package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tab/tab-styles.d.ts +153 -0
- package/dist/components/tabs/tab/tab-styles.js +89 -0
- package/dist/components/tabs/tab/tab-styles.js.map +1 -0
- package/dist/components/tabs/tabs/RuiTabs.js.map +1 -1
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js +2 -137
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tabs/tabs-styles.d.ts +168 -0
- package/dist/components/tabs/tabs/tabs-styles.js +142 -0
- package/dist/components/tabs/tabs/tabs-styles.js.map +1 -0
- package/dist/composables/floating.d.ts +3 -1
- package/dist/composables/floating.js +8 -9
- package/dist/composables/floating.js.map +1 -1
- package/dist/icons/icons_1.d.ts +1 -1
- package/dist/icons/icons_1.js +10 -9
- package/dist/icons/icons_1.js.map +1 -1
- package/dist/icons/icons_2.d.ts +1 -1
- package/dist/icons/icons_2.js +9 -11
- package/dist/icons/icons_2.js.map +1 -1
- package/dist/icons/icons_3.d.ts +1 -1
- package/dist/icons/icons_3.js +11 -5
- package/dist/icons/icons_3.js.map +1 -1
- package/dist/icons/icons_4.d.ts +1 -1
- package/dist/icons/icons_4.js +5 -10
- package/dist/icons/icons_4.js.map +1 -1
- package/dist/icons/icons_5.d.ts +1 -0
- package/dist/icons/icons_5.js +10 -1
- package/dist/icons/icons_5.js.map +1 -1
- package/dist/icons/index.d.ts +1 -1
- package/dist/icons/index.js +7 -6
- package/dist/icons/index.js.map +1 -1
- package/dist/index.js +6 -6
- package/dist/utils/form-text-detail.d.ts +2 -0
- package/dist/utils/form-text-detail.js +5 -1
- package/dist/utils/form-text-detail.js.map +1 -1
- package/dist/web-types.json +11 -1
- package/package.json +1 -1
package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDialog.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_useModel","_openBlock","_createElementBlock","_normalizeProps","_guardReactiveProps","_unref","_renderSlot","_createBlock","_Teleport","_mergeProps","_withKeys","_createVNode","_Transition","_withCtx","_normalizeClass","_withModifiers","_createCommentVNode","_normalizeStyle"],"sources":["../../../../src/components/overlays/dialog/RuiDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { DialogSize } from '@/consts/tokens';\nimport type { VueClassValue } from '@/types/class-value';\nimport { ButtonGroupBoundary } from '@/components/buttons/button-group/button-group-context';\nimport { useDismissableOverlay } from '@/composables/overlay-stack';\nimport { useTimeoutManager } from '@/composables/timeout-manager';\nimport { getNonRootAttrs, getRootAttrs, transformPropsUnit } from '@/utils/helpers';\nimport { cn, tv } from '@/utils/tv';\n\nexport interface RuiDialogClassNames {\n root?: VueClassValue;\n content?: VueClassValue;\n}\n\nexport interface DialogProps {\n persistent?: boolean;\n width?: string | number;\n maxWidth?: string | number;\n /** A preset max width, `--rui-dialog-<size>`; an explicit `maxWidth` wins */\n size?: DialogSize;\n bottomSheet?: boolean;\n classNames?: RuiDialogClassNames;\n zIndex?: string | number;\n ariaLabel?: string;\n}\n\ndefineOptions({\n name: 'RuiDialog',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<boolean>({ default: false });\n\nconst {\n persistent = false,\n width = '98%',\n maxWidth,\n size,\n bottomSheet = false,\n classNames,\n zIndex = 'var(--rui-z-dialog)',\n ariaLabel,\n} = defineProps<DialogProps>();\n\nconst emit = defineEmits<{\n 'closed': [];\n 'click:outside': [];\n 'click:esc': [];\n /**\n * The overlay stack asked this dialog to go, which is what a back gesture\n * reaches it as. Closes unless persistent, like escape does, so a dialog that\n * has to ask before discarding should bind `persistent` and answer here.\n */\n 'dismiss': [];\n}>();\n\ndefineSlots<{\n activator?: (props: { attrs: { onClick: () => void }; isOpen: boolean }) => any;\n default?: (props: { isOpen: boolean; close: () => void }) => any;\n}>();\n\nconst transitioning = ref<boolean>(false);\nconst contentRef = useTemplateRef<HTMLDivElement>('contentRef');\n\nconst leaveTimeout = useTimeoutManager();\n\nconst alive = computed<boolean>(() => get(modelValue) || get(transitioning));\n\nconst style = computed<{ width: string | undefined; maxWidth: string | undefined }>(() => ({\n width: transformPropsUnit(width),\n maxWidth: transformPropsUnit(maxWidth) ?? (size ? `var(--rui-dialog-${size})` : undefined),\n}));\n\nconst dialog = tv({\n slots: {\n root: 'fixed inset-0',\n overlay: 'absolute inset-0 backdrop-blur-sm bg-rui-neutral-950/40 dark:bg-black/60',\n content: 'absolute left-1/2 bottom-0 -translate-x-1/2 outline-hidden overflow-y-auto max-h-(--rui-dialog-max-height)',\n },\n variants: {\n /*\n * The corners match a RuiCard's, the usual content, which the box clips while it scrolls.\n * A sheet sits on the screen's bottom edge, so its content's bottom corners are squared.\n */\n bottomSheet: {\n true: { content: 'rounded-t-rui-card shadow-rui-drawer *:rounded-b-none' },\n false: { content: 'top-1/2 -translate-y-1/2 bottom-auto rounded-rui-card shadow-rui-menu' },\n },\n },\n defaultVariants: { bottomSheet: false },\n});\n\nconst ui = computed<ReturnType<typeof dialog>>(() => dialog({ bottomSheet }));\n\nconst dialogAttrs: { onClick: () => void } = {\n onClick: toggle,\n};\n\nconst contentTransition = computed<Record<string, string>>(() => {\n if (!bottomSheet) {\n return {\n enterFromClass: 'opacity-0 scale-95',\n enterActiveClass: 'transition-all ease-out duration-200',\n enterToClass: 'opacity-100 scale-100',\n leaveFromClass: 'opacity-100 scale-100',\n leaveActiveClass: 'transition-all ease-in duration-150',\n leaveToClass: 'opacity-0 scale-95',\n };\n }\n\n return {\n enterFromClass: 'translate-y-full',\n enterActiveClass: 'transition-transform ease-out duration-300',\n enterToClass: 'translate-y-0',\n leaveFromClass: 'translate-y-0',\n leaveActiveClass: 'transition-transform ease-in duration-200',\n leaveToClass: 'translate-y-full',\n };\n});\n\nfunction toggle(): void {\n set(modelValue, !get(modelValue));\n}\n\nfunction close(): void {\n set(modelValue, false);\n}\n\n/**\n * Closes on Escape unless persistent, and reports the press as `click:esc`.\n *\n * @remarks\n * An Escape that arrives while an IME is composing belongs to the IME, which\n * cancels the candidate with it. The dialog leaves that key alone entirely: no\n * close, no `click:esc`, and no `stopPropagation`, so a search field inside the\n * dialog does not lose the dialog mid-word.\n */\nfunction onEscKeydown(event: KeyboardEvent): void {\n if (event.isComposing)\n return;\n\n event.stopPropagation();\n if (!persistent) {\n close();\n }\n emit('click:esc');\n}\n\nfunction onClickOutside(): void {\n if (!persistent) {\n close();\n }\n emit('click:outside');\n}\n\nfunction onDismiss(): void {\n if (!persistent) {\n close();\n }\n emit('dismiss');\n}\n\n/**\n * Registration follows `modelValue` alone, never `persistent`: a dialog that\n * turns persistent partway through its life has to stay in the stack and refuse\n * in `onDismiss`, or the gesture starts passing through exactly once there is\n * work to lose. A dialog playing its leave transition is already on its way out\n * and does not hold the stack.\n */\nuseDismissableOverlay(modelValue, onDismiss);\n\nfunction onLeaveComplete(): void {\n leaveTimeout.clear();\n if (get(transitioning)) {\n set(transitioning, false);\n emit('closed');\n }\n}\n\nwatch(modelValue, (value) => {\n if (!value) {\n set(transitioning, true);\n // Safety fallback if transitionend is not detected\n leaveTimeout.create(onLeaveComplete, 400);\n }\n});\n\nwatch(contentRef, (ref) => {\n if (ref) {\n nextTick(() => ref.focus());\n }\n else {\n onLeaveComplete();\n }\n});\n</script>\n\n<template>\n <div v-bind=\"getRootAttrs($attrs)\">\n <slot\n name=\"activator\"\n v-bind=\"{ attrs: dialogAttrs, isOpen: modelValue }\"\n />\n <Teleport to=\"body\">\n <div\n v-if=\"alive\"\n :class=\"ui.root({ class: cn(classNames?.root) })\"\n :style=\"{ zIndex }\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"ariaLabel\"\n tabindex=\"0\"\n v-bind=\"getNonRootAttrs($attrs)\"\n @keydown.esc=\"onEscKeydown($event)\"\n >\n <Transition\n enter-from-class=\"opacity-0\"\n enter-active-class=\"transition-opacity ease-out duration-200\"\n enter-to-class=\"opacity-100\"\n leave-from-class=\"opacity-100\"\n leave-active-class=\"transition-opacity ease-in duration-150\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"modelValue\"\n data-id=\"overlay\"\n :class=\"ui.overlay()\"\n @click.stop=\"onClickOutside()\"\n />\n </Transition>\n <Transition\n v-bind=\"contentTransition\"\n @after-leave=\"onLeaveComplete()\"\n >\n <div\n v-if=\"modelValue\"\n ref=\"contentRef\"\n data-id=\"content\"\n :style=\"style\"\n tabindex=\"0\"\n :data-bottom-sheet=\"bottomSheet || undefined\"\n :class=\"ui.content({ class: cn(classNames?.content) })\"\n >\n <ButtonGroupBoundary>\n <slot v-bind=\"{ isOpen: modelValue, close }\" />\n </ButtonGroupBoundary>\n </div>\n </Transition>\n </div>\n </Teleport>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RuiDialog.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_useModel","_openBlock","_createElementBlock","_normalizeProps","_guardReactiveProps","_unref","_renderSlot","_createBlock","_Teleport","_mergeProps","_withKeys","_createVNode","_Transition","_withCtx","_normalizeClass","_withModifiers","_createCommentVNode","_normalizeStyle"],"sources":["../../../../src/components/overlays/dialog/RuiDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { DialogSize } from '@/consts/tokens';\nimport type { VueClassValue } from '@/types/class-value';\nimport { ButtonGroupBoundary } from '@/components/buttons/button-group/button-group-context';\nimport { useDismissableOverlay } from '@/composables/overlay-stack';\nimport { useTimeoutManager } from '@/composables/timeout-manager';\nimport { getNonRootAttrs, getRootAttrs, transformPropsUnit } from '@/utils/helpers';\nimport { cn } from '@/utils/tv';\nimport { dialogStyles } from './dialog-styles';\n\nexport interface RuiDialogClassNames {\n root?: VueClassValue;\n content?: VueClassValue;\n}\n\nexport interface DialogProps {\n persistent?: boolean;\n width?: string | number;\n maxWidth?: string | number;\n /** A preset max width, `--rui-dialog-<size>`; an explicit `maxWidth` wins */\n size?: DialogSize;\n bottomSheet?: boolean;\n classNames?: RuiDialogClassNames;\n zIndex?: string | number;\n ariaLabel?: string;\n}\n\ndefineOptions({\n name: 'RuiDialog',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<boolean>({ default: false });\n\nconst {\n persistent = false,\n width = '98%',\n maxWidth,\n size,\n bottomSheet = false,\n classNames,\n zIndex = 'var(--rui-z-dialog)',\n ariaLabel,\n} = defineProps<DialogProps>();\n\nconst emit = defineEmits<{\n 'closed': [];\n 'click:outside': [];\n 'click:esc': [];\n /**\n * The overlay stack asked this dialog to go, which is what a back gesture\n * reaches it as. Closes unless persistent, like escape does, so a dialog that\n * has to ask before discarding should bind `persistent` and answer here.\n */\n 'dismiss': [];\n}>();\n\ndefineSlots<{\n activator?: (props: { attrs: { onClick: () => void }; isOpen: boolean }) => any;\n default?: (props: { isOpen: boolean; close: () => void }) => any;\n}>();\n\nconst transitioning = ref<boolean>(false);\nconst contentRef = useTemplateRef<HTMLDivElement>('contentRef');\n\nconst leaveTimeout = useTimeoutManager();\n\nconst alive = computed<boolean>(() => get(modelValue) || get(transitioning));\n\nconst style = computed<{ width: string | undefined; maxWidth: string | undefined }>(() => ({\n width: transformPropsUnit(width),\n maxWidth: transformPropsUnit(maxWidth) ?? (size ? `var(--rui-dialog-${size})` : undefined),\n}));\n\nconst ui = computed<ReturnType<typeof dialogStyles>>(() => dialogStyles({ bottomSheet }));\n\nconst dialogAttrs: { onClick: () => void } = {\n onClick: toggle,\n};\n\nconst contentTransition = computed<Record<string, string>>(() => {\n if (!bottomSheet) {\n return {\n enterFromClass: 'opacity-0 scale-95',\n enterActiveClass: 'transition-all ease-out duration-200',\n enterToClass: 'opacity-100 scale-100',\n leaveFromClass: 'opacity-100 scale-100',\n leaveActiveClass: 'transition-all ease-in duration-150',\n leaveToClass: 'opacity-0 scale-95',\n };\n }\n\n return {\n enterFromClass: 'translate-y-full',\n enterActiveClass: 'transition-transform ease-out duration-300',\n enterToClass: 'translate-y-0',\n leaveFromClass: 'translate-y-0',\n leaveActiveClass: 'transition-transform ease-in duration-200',\n leaveToClass: 'translate-y-full',\n };\n});\n\nfunction toggle(): void {\n set(modelValue, !get(modelValue));\n}\n\nfunction close(): void {\n set(modelValue, false);\n}\n\n/**\n * Closes on Escape unless persistent, and reports the press as `click:esc`.\n *\n * @remarks\n * An Escape that arrives while an IME is composing belongs to the IME, which\n * cancels the candidate with it. The dialog leaves that key alone entirely: no\n * close, no `click:esc`, and no `stopPropagation`, so a search field inside the\n * dialog does not lose the dialog mid-word.\n */\nfunction onEscKeydown(event: KeyboardEvent): void {\n if (event.isComposing)\n return;\n\n event.stopPropagation();\n if (!persistent) {\n close();\n }\n emit('click:esc');\n}\n\nfunction onClickOutside(): void {\n if (!persistent) {\n close();\n }\n emit('click:outside');\n}\n\nfunction onDismiss(): void {\n if (!persistent) {\n close();\n }\n emit('dismiss');\n}\n\n/**\n * Registration follows `modelValue` alone, never `persistent`: a dialog that\n * turns persistent partway through its life has to stay in the stack and refuse\n * in `onDismiss`, or the gesture starts passing through exactly once there is\n * work to lose. A dialog playing its leave transition is already on its way out\n * and does not hold the stack.\n */\nuseDismissableOverlay(modelValue, onDismiss);\n\nfunction onLeaveComplete(): void {\n leaveTimeout.clear();\n if (get(transitioning)) {\n set(transitioning, false);\n emit('closed');\n }\n}\n\nwatch(modelValue, (value) => {\n if (!value) {\n set(transitioning, true);\n // Safety fallback if transitionend is not detected\n leaveTimeout.create(onLeaveComplete, 400);\n }\n});\n\nwatch(contentRef, (ref) => {\n if (ref) {\n nextTick(() => ref.focus());\n }\n else {\n onLeaveComplete();\n }\n});\n</script>\n\n<template>\n <div v-bind=\"getRootAttrs($attrs)\">\n <slot\n name=\"activator\"\n v-bind=\"{ attrs: dialogAttrs, isOpen: modelValue }\"\n />\n <Teleport to=\"body\">\n <div\n v-if=\"alive\"\n :class=\"ui.root({ class: cn(classNames?.root) })\"\n :style=\"{ zIndex }\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"ariaLabel\"\n tabindex=\"0\"\n v-bind=\"getNonRootAttrs($attrs)\"\n @keydown.esc=\"onEscKeydown($event)\"\n >\n <Transition\n enter-from-class=\"opacity-0\"\n enter-active-class=\"transition-opacity ease-out duration-200\"\n enter-to-class=\"opacity-100\"\n leave-from-class=\"opacity-100\"\n leave-active-class=\"transition-opacity ease-in duration-150\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"modelValue\"\n data-id=\"overlay\"\n :class=\"ui.overlay()\"\n @click.stop=\"onClickOutside()\"\n />\n </Transition>\n <Transition\n v-bind=\"contentTransition\"\n @after-leave=\"onLeaveComplete()\"\n >\n <div\n v-if=\"modelValue\"\n ref=\"contentRef\"\n data-id=\"content\"\n :style=\"style\"\n tabindex=\"0\"\n :data-bottom-sheet=\"bottomSheet || undefined\"\n :class=\"ui.content({ class: cn(classNames?.content) })\"\n >\n <ButtonGroupBoundary>\n <slot v-bind=\"{ isOpen: modelValue, close }\" />\n </ButtonGroupBoundary>\n </div>\n </Transition>\n </div>\n </Teleport>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const dialogStyles: import("tailwind-variants").TVReturnType<{
|
|
2
|
+
bottomSheet: {
|
|
3
|
+
true: {
|
|
4
|
+
content: string;
|
|
5
|
+
};
|
|
6
|
+
false: {
|
|
7
|
+
content: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
}, {
|
|
11
|
+
root: string;
|
|
12
|
+
overlay: string;
|
|
13
|
+
content: string;
|
|
14
|
+
}, undefined, {
|
|
15
|
+
bottomSheet: {
|
|
16
|
+
true: {
|
|
17
|
+
content: string;
|
|
18
|
+
};
|
|
19
|
+
false: {
|
|
20
|
+
content: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}, {
|
|
24
|
+
root: string;
|
|
25
|
+
overlay: string;
|
|
26
|
+
content: string;
|
|
27
|
+
}, import("tailwind-variants").TVReturnTypeLike<{
|
|
28
|
+
bottomSheet: {
|
|
29
|
+
true: {
|
|
30
|
+
content: string;
|
|
31
|
+
};
|
|
32
|
+
false: {
|
|
33
|
+
content: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}, {
|
|
37
|
+
root: string;
|
|
38
|
+
overlay: string;
|
|
39
|
+
content: string;
|
|
40
|
+
}>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { tv } from "../../../utils/tv.js";
|
|
2
|
+
//#region src/components/overlays/dialog/dialog-styles.ts
|
|
3
|
+
var dialogStyles = tv({
|
|
4
|
+
slots: {
|
|
5
|
+
root: "fixed inset-0",
|
|
6
|
+
overlay: "absolute inset-0 backdrop-blur-sm bg-rui-neutral-950/40 dark:bg-black/60",
|
|
7
|
+
content: "absolute left-1/2 bottom-0 -translate-x-1/2 outline-hidden overflow-y-auto max-h-(--rui-dialog-max-height)"
|
|
8
|
+
},
|
|
9
|
+
variants: { bottomSheet: {
|
|
10
|
+
true: { content: "rounded-t-rui-card shadow-rui-drawer *:rounded-b-none" },
|
|
11
|
+
false: { content: "top-1/2 -translate-y-1/2 bottom-auto rounded-rui-card shadow-rui-menu" }
|
|
12
|
+
} },
|
|
13
|
+
defaultVariants: { bottomSheet: false }
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { dialogStyles };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=dialog-styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-styles.js","names":[],"sources":["../../../../src/components/overlays/dialog/dialog-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\nexport const dialogStyles = tv({\n slots: {\n root: 'fixed inset-0',\n overlay: 'absolute inset-0 backdrop-blur-sm bg-rui-neutral-950/40 dark:bg-black/60',\n content: 'absolute left-1/2 bottom-0 -translate-x-1/2 outline-hidden overflow-y-auto max-h-(--rui-dialog-max-height)',\n },\n variants: {\n /*\n * The corners match a RuiCard's, the usual content, which the box clips while it scrolls.\n * A sheet sits on the screen's bottom edge, so its content's bottom corners are squared.\n */\n bottomSheet: {\n true: { content: 'rounded-t-rui-card shadow-rui-drawer *:rounded-b-none' },\n false: { content: 'top-1/2 -translate-y-1/2 bottom-auto rounded-rui-card shadow-rui-menu' },\n },\n },\n defaultVariants: { bottomSheet: false },\n});\n"],"mappings":";;AAEA,IAAa,eAAe,GAAG;CAC7B,OAAO;EACL,MAAM;EACN,SAAS;EACT,SAAS;CACX;CACA,UAAU,EAKR,aAAa;EACX,MAAM,EAAE,SAAS,wDAAwD;EACzE,OAAO,EAAE,SAAS,wEAAwE;CAC5F,EACF;CACA,iBAAiB,EAAE,aAAa,MAAM;AACxC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiMenu.js","names":["_sfc_main"],"sources":["../../../../src/components/overlays/menu/RuiMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { VueClassValue } from '@/types/class-value';\nimport { ButtonGroupBoundary } from '@/components/buttons/button-group/button-group-context';\nimport RuiFormTextDetail from '@/components/helpers/RuiFormTextDetail.vue';\nimport { type FloatingOptions, useFloating } from '@/composables/floating';\nimport { type FormDetails, useFormTextDetail } from '@/utils/form-text-detail';\nimport { cn, tv } from '@/utils/tv';\n\ninterface BaseMenuAttrs { onMouseover?: () => void; onMouseleave?: () => void }\n\n/**\n * What the activator slot binds onto its trigger. The ARIA keys belong on an\n * element that can carry them (a button, link or combobox), never on a plain\n * `div`; an activator that sets its own ARIA takes `activatorHandlers(attrs)`.\n */\ninterface MenuAttrs extends BaseMenuAttrs {\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n}\n\nexport interface RuiMenuClassNames {\n root?: VueClassValue;\n wrapper?: VueClassValue;\n menu?: VueClassValue;\n /** Overrides applied to the popover content box (e.g. to drop its default padding). */\n content?: VueClassValue;\n /** Overrides applied to the hint and messages under the activator. */\n details?: VueClassValue;\n}\n\n/**\n * Roles a popover container may take. These are the values `aria-haspopup`\n * accepts, which keeps the activator and the popover in agreement.\n */\nexport type RuiMenuRole = 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';\n\nexport interface MenuProps {\n openOnHover?: boolean;\n fullWidth?: boolean;\n disabled?: boolean;\n openDelay?: number;\n closeDelay?: number;\n options?: FloatingOptions;\n classNames?: RuiMenuClassNames;\n closeOnContentClick?: boolean;\n persistOnActivatorClick?: boolean;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n showDetails?: boolean;\n /** With `showDetails`: `reserve` keeps the line while empty (default), `auto` takes no space until there is a message. */\n details?: Exclude<FormDetails, 'hidden'>;\n dense?: boolean;\n /**\n * Keeps the menu open through the interactions that would otherwise dismiss\n * it: a click outside and an Escape press. A programmatic close (`v-model`\n * set to `false`) still applies.\n */\n persistent?: boolean;\n disableAutoFocus?: boolean;\n /**\n * Optional external element to anchor the menu to, instead of the\n * activator slot's wrapper. When set, the menu's position is computed\n * against this element.\n */\n anchorEl?: HTMLElement;\n /**\n * Role of the teleported popover. Defaults to `menu`, which is correct when\n * the content is made of `menuitem`s. Set it to `listbox` (or `tree`, `grid`,\n * `dialog`) when the content follows a different ARIA model, e.g. a selection\n * list opened by a `combobox`. The activator's `aria-haspopup` follows it.\n */\n role?: RuiMenuRole;\n /**\n * Accessible name of the teleported popover. A `dialog` popover needs one;\n * the other roles take it from their activator or options.\n */\n menuLabel?: string;\n}\n\ndefineOptions({\n name: 'RuiMenu',\n});\n\nconst modelValue = defineModel<boolean>({ default: false });\n\nconst {\n openOnHover = false,\n disabled = false,\n fullWidth = false,\n openDelay = 0,\n closeDelay = 0,\n options,\n classNames,\n closeOnContentClick = false,\n persistOnActivatorClick = false,\n hint,\n errorMessages = [],\n successMessages = [],\n showDetails = false,\n details = 'reserve',\n dense = false,\n persistent = false,\n disableAutoFocus = false,\n anchorEl,\n role = 'menu',\n menuLabel,\n} = defineProps<MenuProps>();\n\ndefineSlots<{\n activator?: (props: {\n // An inline type literal, so callers can pass it on as `Record<string, unknown>`\n attrs: {\n 'onMouseover'?: () => void;\n 'onMouseleave'?: () => void;\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n };\n open: boolean;\n disabled: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n default?: (props: { width: number }) => any;\n /** Rendered above the activator, outside the element the menu positions against. */\n label?: () => any;\n}>();\n\nconst click = ref<boolean>(false);\nconst menuContent = useTemplateRef<HTMLElement>('menuContent');\nconst menuId = useId();\n\nconst FOCUSABLE_ELEMENTS_SELECTOR =\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\nconst {\n reference: activator,\n popover: menu,\n open,\n visible,\n currentPlacement,\n leavePending,\n onLeavePending,\n onOpen,\n onClose,\n onLeaveComplete,\n updatePosition,\n} = useFloating(\n () => options ?? {},\n () => disabled,\n () => openDelay,\n () => closeDelay,\n () => anchorEl,\n);\n\nconst { width } = useElementSize(activator);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst menuStyles = tv({\n slots: {\n wrapper: 'relative inline-flex max-w-full',\n popover: 'w-max z-rui-menu',\n // a hairline edge keeps the popup apart from a surface of nearly the same shade in dark mode\n content: 'rounded-rui-panel overflow-hidden shadow-rui-menu bg-rui-menu border border-rui-divider text-rui-text focus:outline-hidden p-1',\n details: '',\n },\n variants: {\n fullWidth: {\n true: { wrapper: 'w-full' },\n },\n dense: {\n true: { details: 'px-2' },\n false: { details: 'px-4' },\n },\n },\n defaultVariants: { fullWidth: false, dense: false },\n});\n\nconst ui = computed<ReturnType<typeof menuStyles>>(() => menuStyles({\n fullWidth,\n dense,\n}));\n\n// `aria-haspopup=\"true\"` means `\"menu\"`, and the default keeps emitting `true` for existing callers\nconst ariaHasPopup = computed<RuiMenuRole | 'true'>(() => role === 'menu' ? 'true' : role);\n\n/**\n * The activator attributes.\n *\n * This and the computed below it must return the same object shape from every\n * branch. Otherwise vue-tsc infers the slot's `attrs` type as a discriminated\n * union where each key is either all defined or all undefined, which breaks\n * consumer code typing its own `attrs` handler with individually optional\n * keys.\n */\nconst baseMenuAttrs = computed<BaseMenuAttrs>(() => {\n const clickVal = get(click);\n return {\n onMouseover: disabled\n ? undefined\n : () => {\n if (openOnHover)\n onOpen();\n },\n onMouseleave: disabled\n ? undefined\n : () => {\n if (openOnHover && !clickVal)\n onClose();\n },\n };\n});\n\nconst menuAttrs = computed<MenuAttrs>(() => ({\n ...get(baseMenuAttrs),\n 'onClick': disabled ? undefined : checkClick,\n 'aria-haspopup': get(ariaHasPopup),\n 'aria-expanded': get(open),\n // Only while the popover is in the DOM, so the reference never points at a missing element\n 'aria-controls': get(visible) ? menuId : undefined,\n}));\n\n/**\n * Moves focus into the open menu without scrolling the page. A menu taller than the space below its\n * activator would otherwise make the browser scroll the whole document to reveal the focused\n * container, sliding the page out from under the activator.\n */\nfunction focusOnContent() {\n const content = get(menuContent);\n if (!content)\n return;\n\n content.focus({ preventScroll: true });\n}\n\nfunction focusMenu(): void {\n if (disableAutoFocus)\n return;\n\n nextTick(() => focusOnContent());\n}\n\n/** Hands focus back to the activator on close, likewise without scrolling to it. */\nfunction focusOnActivator() {\n const activatorEl = get(activator);\n if (!activatorEl) {\n return;\n }\n const focusableEl = activatorEl.querySelector<HTMLElement>(FOCUSABLE_ELEMENTS_SELECTOR);\n if (focusableEl) {\n focusableEl.focus({ preventScroll: true });\n }\n}\n\nfunction onLeave(event?: KeyboardEvent): void {\n if (!get(open))\n return;\n onClose();\n set(click, false);\n event?.stopPropagation();\n\n // Return focus to activator when menu closes\n if (disableAutoFocus) {\n return;\n }\n\n nextTick(() => focusOnActivator());\n}\n\n/**\n * `persistent` blocks the outside interactions that would close the menu, and\n * Escape is one of them, which is how `RuiDialog` and `RuiBottomSheet` already\n * read it. The guard sits here rather than in `onLeave`, because `onLeave`\n * also runs for a programmatic close through `v-model`, which must keep\n * working.\n *\n * A persistent menu leaves the key alone instead of swallowing it, so an inner\n * popover can close on Escape while the menu stays open, and an ancestor still\n * sees a key nothing consumed.\n *\n * Escape is swallowed only while the menu is open and not persistent\n * (`onLeave` stops the event itself); a closed or persistent menu must let it\n * through, or a consumer that closes its own editor on Escape never sees the\n * key. The root element listens for it.\n *\n * An Escape that arrives while an IME is composing belongs to the IME, which\n * cancels the candidate with it, so the menu leaves it alone the same way: a\n * search field inside the menu would otherwise lose the whole menu mid-word.\n */\nfunction onEscape(event: KeyboardEvent): void {\n if (persistent || event.isComposing)\n return;\n\n onLeave(event);\n}\n\nfunction checkClick(): void {\n if (get(open) && get(click)) {\n if (!persistOnActivatorClick)\n onLeave();\n }\n else {\n onOpen();\n set(click, true);\n }\n}\n\nwatch(modelValue, (value) => {\n if (get(open) === value)\n return;\n\n if (value) {\n onOpen();\n set(click, true);\n }\n else {\n onLeave();\n }\n});\n\nwatch(open, (open) => {\n set(modelValue, open);\n if (open) {\n focusMenu();\n }\n});\n\nonClickOutside(menu, () => {\n if (get(open) && !persistent)\n onLeave();\n}, { ignore: [activator] });\n</script>\n\n<template>\n <div\n :class=\"classNames?.root\"\n @keydown.esc=\"onEscape($event)\"\n >\n <slot name=\"label\" />\n <div\n ref=\"activator\"\n :class=\"ui.wrapper({ class: cn(classNames?.wrapper) })\"\n :data-menu-disabled=\"disabled\"\n >\n <slot\n name=\"activator\"\n v-bind=\"{ attrs: menuAttrs, open, disabled, hasError, hasSuccess }\"\n />\n </div>\n <Teleport\n v-if=\"!disabled\"\n to=\"body\"\n >\n <div\n v-if=\"visible\"\n :id=\"menuId\"\n ref=\"menu\"\n :class=\"ui.popover({ class: cn(classNames?.menu) })\"\n :role=\"role\"\n :aria-label=\"menuLabel\"\n :data-placement=\"currentPlacement\"\n @click=\"closeOnContentClick ? onLeave() : undefined\"\n @keydown.esc=\"onEscape($event)\"\n >\n <TransitionGroup\n enter-active-class=\"transition ease-out duration-200\"\n enter-from-class=\"opacity-0 translate-y-1\"\n enter-to-class=\"opacity-100 translate-y-0\"\n leave-active-class=\"transition ease-in duration-150\"\n leave-from-class=\"opacity-100 translate-y-0\"\n leave-to-class=\"opacity-0 translate-y-1\"\n @before-enter=\"updatePosition()\"\n @after-leave=\"leavePending ? onLeaveComplete() : undefined\"\n @before-leave=\"onLeavePending()\"\n >\n <div\n v-if=\"open\"\n ref=\"menuContent\"\n key=\"menu\"\n data-id=\"content\"\n :class=\"ui.content({ class: cn(classNames?.content) })\"\n tabindex=\"-1\"\n v-bind=\"baseMenuAttrs\"\n >\n <ButtonGroupBoundary>\n <slot v-bind=\"{ width }\" />\n </ButtonGroupBoundary>\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n <RuiFormTextDetail\n v-if=\"showDetails\"\n :details=\"details\"\n :class=\"ui.details({ class: cn(classNames?.details) })\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n />\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RuiMenu.js","names":["_sfc_main"],"sources":["../../../../src/components/overlays/menu/RuiMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Reactive, Ref, WatchHandle } from 'vue';\nimport type { VueClassValue } from '@/types/class-value';\nimport { ButtonGroupBoundary } from '@/components/buttons/button-group/button-group-context';\nimport RuiFormTextDetail from '@/components/helpers/RuiFormTextDetail.vue';\nimport { type FloatingOptions, useFloating, type UseFloatingReturn } from '@/composables/floating';\nimport { containsMessage, type FormDetails } from '@/utils/form-text-detail';\nimport { cn } from '@/utils/tv';\nimport { menuStyles } from './menu-styles';\n\ninterface BaseMenuAttrs { onMouseover?: () => void; onMouseleave?: () => void }\n\n/**\n * What the activator slot binds onto its trigger. The ARIA keys belong on an\n * element that can carry them (a button, link or combobox), never on a plain\n * `div`; an activator that sets its own ARIA takes `activatorHandlers(attrs)`.\n */\ninterface MenuAttrs extends BaseMenuAttrs {\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n}\n\nexport interface RuiMenuClassNames {\n root?: VueClassValue;\n wrapper?: VueClassValue;\n menu?: VueClassValue;\n /** Overrides applied to the popover content box (e.g. to drop its default padding). */\n content?: VueClassValue;\n /** Overrides applied to the hint and messages under the activator. */\n details?: VueClassValue;\n}\n\n/**\n * Roles a popover container may take. These are the values `aria-haspopup`\n * accepts, which keeps the activator and the popover in agreement.\n */\nexport type RuiMenuRole = 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';\n\nexport interface MenuProps {\n openOnHover?: boolean;\n fullWidth?: boolean;\n disabled?: boolean;\n openDelay?: number;\n closeDelay?: number;\n options?: FloatingOptions;\n classNames?: RuiMenuClassNames;\n closeOnContentClick?: boolean;\n persistOnActivatorClick?: boolean;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n showDetails?: boolean;\n /** With `showDetails`: `reserve` keeps the line while empty (default), `auto` takes no space until there is a message. */\n details?: Exclude<FormDetails, 'hidden'>;\n dense?: boolean;\n /**\n * Keeps the menu open through the interactions that would otherwise dismiss\n * it: a click outside and an Escape press. A programmatic close (`v-model`\n * set to `false`) still applies.\n */\n persistent?: boolean;\n disableAutoFocus?: boolean;\n /**\n * Optional external element to anchor the menu to, instead of the\n * activator slot's wrapper. When set, the menu's position is computed\n * against this element.\n */\n anchorEl?: HTMLElement;\n /**\n * Role of the teleported popover. Defaults to `menu`, which is correct when\n * the content is made of `menuitem`s. Set it to `listbox` (or `tree`, `grid`,\n * `dialog`) when the content follows a different ARIA model, e.g. a selection\n * list opened by a `combobox`. The activator's `aria-haspopup` follows it.\n */\n role?: RuiMenuRole;\n /**\n * Accessible name of the teleported popover. A `dialog` popover needs one;\n * the other roles take it from their activator or options.\n */\n menuLabel?: string;\n /**\n * Defers the popover's setup (its positioning, the activator's size\n * observer and the click-outside listeners) to first use: a click or a\n * context menu on the activator, a hover with `openOnHover`, or the model\n * turning `true`. Until then the menu renders its root, the wrapper and the\n * activator, the same elements it keeps afterwards, so a table with a menu\n * on every row pays for the menus that are opened. Read at mount.\n */\n lazy?: boolean;\n}\n\n/** What the menu sets up at mount, or on first use when `lazy`, with its refs unwrapped. */\ntype MenuSetup = Reactive<{\n floating: UseFloatingReturn;\n width: Readonly<Ref<number>>;\n}>;\n\ndefineOptions({\n name: 'RuiMenu',\n});\n\nconst modelValue = defineModel<boolean>({ default: false });\n\nconst {\n openOnHover = false,\n disabled = false,\n fullWidth = false,\n openDelay = 0,\n closeDelay = 0,\n options,\n classNames,\n closeOnContentClick = false,\n persistOnActivatorClick = false,\n hint,\n errorMessages = [],\n successMessages = [],\n showDetails = false,\n details = 'reserve',\n dense = false,\n persistent = false,\n disableAutoFocus = false,\n anchorEl,\n role = 'menu',\n menuLabel,\n lazy = false,\n} = defineProps<MenuProps>();\n\ndefineSlots<{\n activator?: (props: {\n // An inline type literal, so callers can pass it on as `Record<string, unknown>`\n attrs: {\n 'onMouseover'?: () => void;\n 'onMouseleave'?: () => void;\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n };\n open: boolean;\n disabled: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n default?: (props: { width: number }) => any;\n /** Rendered above the activator, outside the element the menu positions against. */\n label?: () => any;\n}>();\n\nconst click = ref<boolean>(false);\nconst activator = useTemplateRef<HTMLElement>('activator');\nconst menu = useTemplateRef<HTMLElement>('menu');\nconst menuContent = useTemplateRef<HTMLElement>('menuContent');\nconst menuId = useId();\nconst instance = getCurrentInstance();\n// Owned by this component, so whatever the setup starts stops on unmount even when it ran after mount\nconst setupScope = effectScope();\nconst menuSetup = shallowRef<MenuSetup>();\nlet stopSetUpOnModel: WatchHandle | undefined;\n\nconst FOCUSABLE_ELEMENTS_SELECTOR =\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\n// Only the two flags, not the formatted lists useFormTextDetail builds, since a table may hold hundreds of menus\nconst hasError = computed<boolean>(() => containsMessage(errorMessages));\nconst hasSuccess = computed<boolean>(() => containsMessage(successMessages));\n\nconst ui = computed<ReturnType<typeof menuStyles>>(() => menuStyles({\n fullWidth,\n dense,\n}));\n\nconst open = computed<boolean>(() => get(menuSetup)?.floating.open ?? false);\nconst visible = computed<boolean>(() => get(menuSetup)?.floating.visible ?? false);\n\n/**\n * The activator attributes.\n *\n * This and the computed below it must return the same object shape from every\n * branch. Otherwise vue-tsc infers the slot's `attrs` type as a discriminated\n * union where each key is either all defined or all undefined, which breaks\n * consumer code typing its own `attrs` handler with individually optional\n * keys.\n */\nconst baseMenuAttrs = computed<BaseMenuAttrs>(() => {\n const clickVal = get(click);\n return {\n onMouseover: disabled\n ? undefined\n : () => {\n if (openOnHover)\n setUp()?.onOpen();\n },\n onMouseleave: disabled\n ? undefined\n : () => {\n if (openOnHover && !clickVal)\n activeFloating()?.onClose();\n },\n };\n});\n\nconst menuAttrs = computed<MenuAttrs>(() => ({\n ...get(baseMenuAttrs),\n 'onClick': disabled ? undefined : checkClick,\n // `aria-haspopup=\"true\"` means `\"menu\"`, and the default keeps emitting `true` for existing callers\n 'aria-haspopup': role === 'menu' ? 'true' : role,\n 'aria-expanded': get(open),\n // Only while the popover is in the DOM, so the reference never points at a missing element\n 'aria-controls': get(visible) ? menuId : undefined,\n}));\n\n/**\n * Sets a lazy menu up on its first use, on the wrapper so that it covers an\n * activator that opens the menu through the model rather than through\n * `attrs`. Hover and focus are left out: a cursor resting over a scrolling\n * table or Tab moving down it would set up every row it passes. They stay\n * after setup, where `setUp` only hands back what it already made.\n */\nconst firstUseListeners = { click: setUp, contextmenu: setUp };\n\n/**\n * Sets the popover up once and hands back its floating state. It runs at\n * mount, or for a `lazy` menu on first use, which can be after mount and\n * inside another component's lifecycle hook, so what it starts must not\n * attach itself to the current instance.\n */\nfunction setUp(): MenuSetup['floating'] | undefined {\n if (setupScope.active && !get(menuSetup)) {\n set(menuSetup, setupScope.run(createSetup));\n stopSetUpOnModel?.();\n }\n return activeFloating();\n}\n\n/**\n * The floating state while the menu is alive. An event can still reach the\n * activator after unmount, and must not start timers on a stopped menu.\n */\nfunction activeFloating(): MenuSetup['floating'] | undefined {\n return setupScope.active ? get(menuSetup)?.floating : undefined;\n}\n\n/** An element's content-box width, the box its resize observer reports. */\nfunction contentWidth(element: HTMLElement | null): number {\n if (!element)\n return 0;\n\n const style = getComputedStyle(element);\n const edges = [style.paddingLeft, style.paddingRight, style.borderLeftWidth, style.borderRightWidth];\n return edges.reduce((width, edge) => width - (Number.parseFloat(edge) || 0), element.offsetWidth);\n}\n\nfunction createSetup(): MenuSetup {\n const floating = useFloating(\n () => options ?? {},\n () => disabled,\n () => openDelay,\n () => closeDelay,\n () => anchorEl ?? get(activator) ?? undefined,\n menu,\n );\n\n const width = shallowRef<number>(0);\n const readWidth = (): void => set(width, contentWidth(get(activator)));\n useResizeObserver(activator, ([entry]) => {\n if (entry)\n set(width, entry.contentRect.width);\n });\n // Only the menu's own setup waits for its mount; a later one may run inside another component's hook\n if (instance?.isMounted)\n readWidth();\n else\n onMounted(readWidth);\n\n // Immediate, so a model that is already `true` at setup opens the menu\n watch(modelValue, (value) => {\n if (get(floating.open) === value)\n return;\n\n if (value) {\n floating.onOpen();\n set(click, true);\n }\n else {\n onLeave();\n }\n }, { immediate: true });\n\n watch(floating.open, (isOpen) => {\n set(modelValue, isOpen);\n if (isOpen) {\n focusMenu();\n }\n });\n\n onClickOutside(menu, () => {\n if (get(floating.open) && !persistent)\n onLeave();\n }, { ignore: [activator] });\n\n return reactive({ floating, width });\n}\n\n/**\n * Moves focus into the open menu without scrolling the page. A menu taller than the space below its\n * activator would otherwise make the browser scroll the whole document to reveal the focused\n * container, sliding the page out from under the activator.\n */\nfunction focusOnContent() {\n const content = get(menuContent);\n if (!content)\n return;\n\n content.focus({ preventScroll: true });\n}\n\nfunction focusMenu(): void {\n if (disableAutoFocus)\n return;\n\n nextTick(() => focusOnContent());\n}\n\n/** Hands focus back to the activator on close, likewise without scrolling to it. */\nfunction focusOnActivator() {\n const activatorEl = get(activator);\n if (!activatorEl) {\n return;\n }\n const focusableEl = activatorEl.querySelector<HTMLElement>(FOCUSABLE_ELEMENTS_SELECTOR);\n if (focusableEl) {\n focusableEl.focus({ preventScroll: true });\n }\n}\n\nfunction onLeave(event?: KeyboardEvent): void {\n const floating = activeFloating();\n if (!floating?.open)\n return;\n floating.onClose();\n set(click, false);\n event?.stopPropagation();\n\n // Return focus to activator when menu closes\n if (disableAutoFocus) {\n return;\n }\n\n nextTick(() => focusOnActivator());\n}\n\n/**\n * `persistent` blocks the outside interactions that would close the menu, and\n * Escape is one of them, which is how `RuiDialog` and `RuiBottomSheet` already\n * read it. The guard sits here rather than in `onLeave`, because `onLeave`\n * also runs for a programmatic close through `v-model`, which must keep\n * working.\n *\n * A persistent menu leaves the key alone instead of swallowing it, so an inner\n * popover can close on Escape while the menu stays open, and an ancestor still\n * sees a key nothing consumed.\n *\n * Escape is swallowed only while the menu is open and not persistent\n * (`onLeave` stops the event itself); a closed or persistent menu must let it\n * through, or a consumer that closes its own editor on Escape never sees the\n * key. The root element listens for it.\n *\n * An Escape that arrives while an IME is composing belongs to the IME, which\n * cancels the candidate with it, so the menu leaves it alone the same way: a\n * search field inside the menu would otherwise lose the whole menu mid-word.\n */\nfunction onEscape(event: KeyboardEvent): void {\n if (persistent || event.isComposing)\n return;\n\n onLeave(event);\n}\n\nfunction checkClick(): void {\n const floating = setUp();\n if (!floating)\n return;\n\n if (floating.open && get(click)) {\n if (!persistOnActivatorClick)\n onLeave();\n }\n else {\n floating.onOpen();\n set(click, true);\n }\n}\n\n// The setup's own watcher opens it; a disabled menu stays closed and unset, as an eager one stays closed\nif (!lazy || (get(modelValue) && !disabled)) {\n setUp();\n}\nelse {\n stopSetUpOnModel = watch(modelValue, (value) => {\n if (value && !disabled)\n setUp();\n });\n}\n</script>\n\n<template>\n <div\n :class=\"classNames?.root\"\n @keydown.esc=\"onEscape($event)\"\n >\n <slot name=\"label\" />\n <div\n ref=\"activator\"\n :class=\"ui.wrapper({ class: cn(classNames?.wrapper) })\"\n :data-menu-disabled=\"disabled\"\n v-on=\"lazy && !disabled ? firstUseListeners : {}\"\n >\n <slot\n name=\"activator\"\n v-bind=\"{ attrs: menuAttrs, open, disabled, hasError, hasSuccess }\"\n />\n </div>\n <Teleport\n v-if=\"!disabled && menuSetup\"\n to=\"body\"\n >\n <div\n v-if=\"visible\"\n :id=\"menuId\"\n ref=\"menu\"\n :class=\"ui.popover({ class: cn(classNames?.menu) })\"\n :role=\"role\"\n :aria-label=\"menuLabel\"\n :data-placement=\"menuSetup.floating.currentPlacement\"\n @click=\"closeOnContentClick ? onLeave() : undefined\"\n @keydown.esc=\"onEscape($event)\"\n >\n <TransitionGroup\n enter-active-class=\"transition ease-out duration-200\"\n enter-from-class=\"opacity-0 translate-y-1\"\n enter-to-class=\"opacity-100 translate-y-0\"\n leave-active-class=\"transition ease-in duration-150\"\n leave-from-class=\"opacity-100 translate-y-0\"\n leave-to-class=\"opacity-0 translate-y-1\"\n @before-enter=\"menuSetup?.floating.updatePosition()\"\n @after-leave=\"menuSetup?.floating.leavePending ? menuSetup.floating.onLeaveComplete() : undefined\"\n @before-leave=\"menuSetup?.floating.onLeavePending()\"\n >\n <div\n v-if=\"open\"\n ref=\"menuContent\"\n key=\"menu\"\n data-id=\"content\"\n :class=\"ui.content({ class: cn(classNames?.content) })\"\n tabindex=\"-1\"\n v-bind=\"baseMenuAttrs\"\n >\n <ButtonGroupBoundary>\n <slot v-bind=\"{ width: menuSetup.width }\" />\n </ButtonGroupBoundary>\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n <RuiFormTextDetail\n v-if=\"showDetails\"\n :details=\"details\"\n :class=\"ui.details({ class: cn(classNames?.details) })\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n />\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -57,6 +57,15 @@ export interface MenuProps {
|
|
|
57
57
|
* the other roles take it from their activator or options.
|
|
58
58
|
*/
|
|
59
59
|
menuLabel?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Defers the popover's setup (its positioning, the activator's size
|
|
62
|
+
* observer and the click-outside listeners) to first use: a click or a
|
|
63
|
+
* context menu on the activator, a hover with `openOnHover`, or the model
|
|
64
|
+
* turning `true`. Until then the menu renders its root, the wrapper and the
|
|
65
|
+
* activator, the same elements it keeps afterwards, so a table with a menu
|
|
66
|
+
* on every row pays for the menus that are opened. Read at mount.
|
|
67
|
+
*/
|
|
68
|
+
lazy?: boolean;
|
|
60
69
|
}
|
|
61
70
|
type __VLS_Props = MenuProps;
|
|
62
71
|
type __VLS_Slots = {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
2
|
-
import { onClickOutside,
|
|
3
|
-
import { cn
|
|
2
|
+
import { onClickOutside, useResizeObserver } from "../../../vendor/@vueuse/core/dist/index.js";
|
|
3
|
+
import { cn } from "../../../utils/tv.js";
|
|
4
4
|
import { ButtonGroupBoundary } from "../../buttons/button-group/button-group-context.js";
|
|
5
|
-
import {
|
|
5
|
+
import { containsMessage } from "../../../utils/form-text-detail.js";
|
|
6
6
|
import RuiFormTextDetail_default from "../../helpers/RuiFormTextDetail.js";
|
|
7
7
|
import { useFloating } from "../../../composables/floating.js";
|
|
8
|
-
import {
|
|
8
|
+
import { menuStyles } from "./menu-styles.js";
|
|
9
|
+
import { Teleport, TransitionGroup, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, effectScope, getCurrentInstance, guardReactiveProps, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, onMounted, openBlock, reactive, ref, renderSlot, shallowRef, toHandlers, unref, useId, useModel, useTemplateRef, watch, withCtx, withKeys } from "vue";
|
|
9
10
|
//#region src/components/overlays/menu/RuiMenu.vue?vue&type=script&setup=true&lang.ts
|
|
10
11
|
var _hoisted_1 = ["data-menu-disabled"];
|
|
11
12
|
var _hoisted_2 = [
|
|
@@ -65,7 +66,11 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
65
66
|
},
|
|
66
67
|
anchorEl: {},
|
|
67
68
|
role: { default: "menu" },
|
|
68
|
-
menuLabel: {}
|
|
69
|
+
menuLabel: {},
|
|
70
|
+
lazy: {
|
|
71
|
+
type: Boolean,
|
|
72
|
+
default: false
|
|
73
|
+
}
|
|
69
74
|
}, {
|
|
70
75
|
"modelValue": {
|
|
71
76
|
type: Boolean,
|
|
@@ -77,35 +82,22 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
77
82
|
setup(__props) {
|
|
78
83
|
const modelValue = useModel(__props, "modelValue");
|
|
79
84
|
const click = ref(false);
|
|
85
|
+
const activator = useTemplateRef("activator");
|
|
86
|
+
const menu = useTemplateRef("menu");
|
|
80
87
|
const menuContent = useTemplateRef("menuContent");
|
|
81
88
|
const menuId = useId();
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
popover: "w-max z-rui-menu",
|
|
89
|
-
content: "rounded-rui-panel overflow-hidden shadow-rui-menu bg-rui-menu border border-rui-divider text-rui-text focus:outline-hidden p-1",
|
|
90
|
-
details: ""
|
|
91
|
-
},
|
|
92
|
-
variants: {
|
|
93
|
-
fullWidth: { true: { wrapper: "w-full" } },
|
|
94
|
-
dense: {
|
|
95
|
-
true: { details: "px-2" },
|
|
96
|
-
false: { details: "px-4" }
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
defaultVariants: {
|
|
100
|
-
fullWidth: false,
|
|
101
|
-
dense: false
|
|
102
|
-
}
|
|
103
|
-
});
|
|
89
|
+
const instance = getCurrentInstance();
|
|
90
|
+
const setupScope = effectScope();
|
|
91
|
+
const menuSetup = shallowRef();
|
|
92
|
+
let stopSetUpOnModel;
|
|
93
|
+
const hasError = computed(() => containsMessage(__props.errorMessages));
|
|
94
|
+
const hasSuccess = computed(() => containsMessage(__props.successMessages));
|
|
104
95
|
const ui = computed(() => menuStyles({
|
|
105
96
|
fullWidth: __props.fullWidth,
|
|
106
97
|
dense: __props.dense
|
|
107
98
|
}));
|
|
108
|
-
const
|
|
99
|
+
const open = computed(() => get(menuSetup)?.floating.open ?? false);
|
|
100
|
+
const visible = computed(() => get(menuSetup)?.floating.visible ?? false);
|
|
109
101
|
/**
|
|
110
102
|
* The activator attributes.
|
|
111
103
|
*
|
|
@@ -119,21 +111,91 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
119
111
|
const clickVal = get(click);
|
|
120
112
|
return {
|
|
121
113
|
onMouseover: __props.disabled ? void 0 : () => {
|
|
122
|
-
if (__props.openOnHover) onOpen();
|
|
114
|
+
if (__props.openOnHover) setUp()?.onOpen();
|
|
123
115
|
},
|
|
124
116
|
onMouseleave: __props.disabled ? void 0 : () => {
|
|
125
|
-
if (__props.openOnHover && !clickVal) onClose();
|
|
117
|
+
if (__props.openOnHover && !clickVal) activeFloating()?.onClose();
|
|
126
118
|
}
|
|
127
119
|
};
|
|
128
120
|
});
|
|
129
121
|
const menuAttrs = computed(() => ({
|
|
130
122
|
...get(baseMenuAttrs),
|
|
131
123
|
"onClick": __props.disabled ? void 0 : checkClick,
|
|
132
|
-
"aria-haspopup":
|
|
124
|
+
"aria-haspopup": __props.role === "menu" ? "true" : __props.role,
|
|
133
125
|
"aria-expanded": get(open),
|
|
134
126
|
"aria-controls": get(visible) ? menuId : void 0
|
|
135
127
|
}));
|
|
136
128
|
/**
|
|
129
|
+
* Sets a lazy menu up on its first use, on the wrapper so that it covers an
|
|
130
|
+
* activator that opens the menu through the model rather than through
|
|
131
|
+
* `attrs`. Hover and focus are left out: a cursor resting over a scrolling
|
|
132
|
+
* table or Tab moving down it would set up every row it passes. They stay
|
|
133
|
+
* after setup, where `setUp` only hands back what it already made.
|
|
134
|
+
*/
|
|
135
|
+
const firstUseListeners = {
|
|
136
|
+
click: setUp,
|
|
137
|
+
contextmenu: setUp
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Sets the popover up once and hands back its floating state. It runs at
|
|
141
|
+
* mount, or for a `lazy` menu on first use, which can be after mount and
|
|
142
|
+
* inside another component's lifecycle hook, so what it starts must not
|
|
143
|
+
* attach itself to the current instance.
|
|
144
|
+
*/
|
|
145
|
+
function setUp() {
|
|
146
|
+
if (setupScope.active && !get(menuSetup)) {
|
|
147
|
+
set(menuSetup, setupScope.run(createSetup));
|
|
148
|
+
stopSetUpOnModel?.();
|
|
149
|
+
}
|
|
150
|
+
return activeFloating();
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The floating state while the menu is alive. An event can still reach the
|
|
154
|
+
* activator after unmount, and must not start timers on a stopped menu.
|
|
155
|
+
*/
|
|
156
|
+
function activeFloating() {
|
|
157
|
+
return setupScope.active ? get(menuSetup)?.floating : void 0;
|
|
158
|
+
}
|
|
159
|
+
/** An element's content-box width, the box its resize observer reports. */
|
|
160
|
+
function contentWidth(element) {
|
|
161
|
+
if (!element) return 0;
|
|
162
|
+
const style = getComputedStyle(element);
|
|
163
|
+
return [
|
|
164
|
+
style.paddingLeft,
|
|
165
|
+
style.paddingRight,
|
|
166
|
+
style.borderLeftWidth,
|
|
167
|
+
style.borderRightWidth
|
|
168
|
+
].reduce((width, edge) => width - (Number.parseFloat(edge) || 0), element.offsetWidth);
|
|
169
|
+
}
|
|
170
|
+
function createSetup() {
|
|
171
|
+
const floating = useFloating(() => __props.options ?? {}, () => __props.disabled, () => __props.openDelay, () => __props.closeDelay, () => __props.anchorEl ?? get(activator) ?? void 0, menu);
|
|
172
|
+
const width = shallowRef(0);
|
|
173
|
+
const readWidth = () => set(width, contentWidth(get(activator)));
|
|
174
|
+
useResizeObserver(activator, ([entry]) => {
|
|
175
|
+
if (entry) set(width, entry.contentRect.width);
|
|
176
|
+
});
|
|
177
|
+
if (instance?.isMounted) readWidth();
|
|
178
|
+
else onMounted(readWidth);
|
|
179
|
+
watch(modelValue, (value) => {
|
|
180
|
+
if (get(floating.open) === value) return;
|
|
181
|
+
if (value) {
|
|
182
|
+
floating.onOpen();
|
|
183
|
+
set(click, true);
|
|
184
|
+
} else onLeave();
|
|
185
|
+
}, { immediate: true });
|
|
186
|
+
watch(floating.open, (isOpen) => {
|
|
187
|
+
set(modelValue, isOpen);
|
|
188
|
+
if (isOpen) focusMenu();
|
|
189
|
+
});
|
|
190
|
+
onClickOutside(menu, () => {
|
|
191
|
+
if (get(floating.open) && !__props.persistent) onLeave();
|
|
192
|
+
}, { ignore: [activator] });
|
|
193
|
+
return reactive({
|
|
194
|
+
floating,
|
|
195
|
+
width
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
137
199
|
* Moves focus into the open menu without scrolling the page. A menu taller than the space below its
|
|
138
200
|
* activator would otherwise make the browser scroll the whole document to reveal the focused
|
|
139
201
|
* container, sliding the page out from under the activator.
|
|
@@ -155,8 +217,9 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
155
217
|
if (focusableEl) focusableEl.focus({ preventScroll: true });
|
|
156
218
|
}
|
|
157
219
|
function onLeave(event) {
|
|
158
|
-
|
|
159
|
-
|
|
220
|
+
const floating = activeFloating();
|
|
221
|
+
if (!floating?.open) return;
|
|
222
|
+
floating.onClose();
|
|
160
223
|
set(click, false);
|
|
161
224
|
event?.stopPropagation();
|
|
162
225
|
if (__props.disableAutoFocus) return;
|
|
@@ -187,46 +250,38 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
187
250
|
onLeave(event);
|
|
188
251
|
}
|
|
189
252
|
function checkClick() {
|
|
190
|
-
|
|
253
|
+
const floating = setUp();
|
|
254
|
+
if (!floating) return;
|
|
255
|
+
if (floating.open && get(click)) {
|
|
191
256
|
if (!__props.persistOnActivatorClick) onLeave();
|
|
192
257
|
} else {
|
|
193
|
-
onOpen();
|
|
258
|
+
floating.onOpen();
|
|
194
259
|
set(click, true);
|
|
195
260
|
}
|
|
196
261
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (value)
|
|
200
|
-
onOpen();
|
|
201
|
-
set(click, true);
|
|
202
|
-
} else onLeave();
|
|
203
|
-
});
|
|
204
|
-
watch(open, (open) => {
|
|
205
|
-
set(modelValue, open);
|
|
206
|
-
if (open) focusMenu();
|
|
262
|
+
if (!__props.lazy || get(modelValue) && !__props.disabled) setUp();
|
|
263
|
+
else stopSetUpOnModel = watch(modelValue, (value) => {
|
|
264
|
+
if (value && !__props.disabled) setUp();
|
|
207
265
|
});
|
|
208
|
-
onClickOutside(menu, () => {
|
|
209
|
-
if (get(open) && !__props.persistent) onLeave();
|
|
210
|
-
}, { ignore: [activator] });
|
|
211
266
|
return (_ctx, _cache) => {
|
|
212
267
|
return openBlock(), createElementBlock("div", {
|
|
213
268
|
class: normalizeClass(__props.classNames?.root),
|
|
214
269
|
onKeydown: _cache[5] || (_cache[5] = withKeys(($event) => onEscape($event), ["esc"]))
|
|
215
270
|
}, [
|
|
216
271
|
renderSlot(_ctx.$slots, "label"),
|
|
217
|
-
createElementVNode("div", {
|
|
272
|
+
createElementVNode("div", mergeProps({
|
|
218
273
|
ref_key: "activator",
|
|
219
274
|
ref: activator,
|
|
220
|
-
class:
|
|
275
|
+
class: unref(ui).wrapper({ class: unref(cn)(__props.classNames?.wrapper) }),
|
|
221
276
|
"data-menu-disabled": __props.disabled
|
|
222
|
-
}, [renderSlot(_ctx.$slots, "activator", normalizeProps(guardReactiveProps({
|
|
277
|
+
}, toHandlers(__props.lazy && !__props.disabled ? firstUseListeners : {}, true)), [renderSlot(_ctx.$slots, "activator", normalizeProps(guardReactiveProps({
|
|
223
278
|
attrs: unref(menuAttrs),
|
|
224
279
|
open: unref(open),
|
|
225
280
|
disabled: __props.disabled,
|
|
226
281
|
hasError: unref(hasError),
|
|
227
282
|
hasSuccess: unref(hasSuccess)
|
|
228
|
-
})))],
|
|
229
|
-
!__props.disabled ? (openBlock(), createBlock(Teleport, {
|
|
283
|
+
})))], 16, _hoisted_1),
|
|
284
|
+
!__props.disabled && unref(menuSetup) ? (openBlock(), createBlock(Teleport, {
|
|
230
285
|
key: 0,
|
|
231
286
|
to: "body"
|
|
232
287
|
}, [unref(visible) ? (openBlock(), createElementBlock("div", {
|
|
@@ -237,7 +292,7 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
237
292
|
class: normalizeClass(unref(ui).popover({ class: unref(cn)(__props.classNames?.menu) })),
|
|
238
293
|
role: __props.role,
|
|
239
294
|
"aria-label": __props.menuLabel,
|
|
240
|
-
"data-placement": unref(currentPlacement
|
|
295
|
+
"data-placement": unref(menuSetup).floating.currentPlacement,
|
|
241
296
|
onClick: _cache[3] || (_cache[3] = ($event) => __props.closeOnContentClick ? onLeave() : void 0),
|
|
242
297
|
onKeydown: _cache[4] || (_cache[4] = withKeys(($event) => onEscape($event), ["esc"]))
|
|
243
298
|
}, [createVNode(TransitionGroup, {
|
|
@@ -247,9 +302,9 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
247
302
|
"leave-active-class": "transition ease-in duration-150",
|
|
248
303
|
"leave-from-class": "opacity-100 translate-y-0",
|
|
249
304
|
"leave-to-class": "opacity-0 translate-y-1",
|
|
250
|
-
onBeforeEnter: _cache[0] || (_cache[0] = ($event) => unref(updatePosition
|
|
251
|
-
onAfterLeave: _cache[1] || (_cache[1] = ($event) => unref(leavePending
|
|
252
|
-
onBeforeLeave: _cache[2] || (_cache[2] = ($event) => unref(onLeavePending
|
|
305
|
+
onBeforeEnter: _cache[0] || (_cache[0] = ($event) => unref(menuSetup)?.floating.updatePosition()),
|
|
306
|
+
onAfterLeave: _cache[1] || (_cache[1] = ($event) => unref(menuSetup)?.floating.leavePending ? unref(menuSetup).floating.onLeaveComplete() : void 0),
|
|
307
|
+
onBeforeLeave: _cache[2] || (_cache[2] = ($event) => unref(menuSetup)?.floating.onLeavePending())
|
|
253
308
|
}, {
|
|
254
309
|
default: withCtx(() => [unref(open) ? (openBlock(), createElementBlock("div", mergeProps({
|
|
255
310
|
ref_key: "menuContent",
|
|
@@ -259,7 +314,7 @@ var RuiMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
259
314
|
class: unref(ui).content({ class: unref(cn)(__props.classNames?.content) }),
|
|
260
315
|
tabindex: "-1"
|
|
261
316
|
}, unref(baseMenuAttrs)), [createVNode(unref(ButtonGroupBoundary), null, {
|
|
262
|
-
default: withCtx(() => [renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps({ width: unref(width
|
|
317
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps({ width: unref(menuSetup).width })))]),
|
|
263
318
|
_: 3
|
|
264
319
|
})], 16)) : createCommentVNode("", true)]),
|
|
265
320
|
_: 3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiMenu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_normalizeClass","_withKeys","_renderSlot","_createElementVNode","_unref","_normalizeProps","_guardReactiveProps","_createBlock","_Teleport","_createVNode","_TransitionGroup","_withCtx","_mergeProps","_createCommentVNode","RuiFormTextDetail"],"sources":["../../../../src/components/overlays/menu/RuiMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { VueClassValue } from '@/types/class-value';\nimport { ButtonGroupBoundary } from '@/components/buttons/button-group/button-group-context';\nimport RuiFormTextDetail from '@/components/helpers/RuiFormTextDetail.vue';\nimport { type FloatingOptions, useFloating } from '@/composables/floating';\nimport { type FormDetails, useFormTextDetail } from '@/utils/form-text-detail';\nimport { cn, tv } from '@/utils/tv';\n\ninterface BaseMenuAttrs { onMouseover?: () => void; onMouseleave?: () => void }\n\n/**\n * What the activator slot binds onto its trigger. The ARIA keys belong on an\n * element that can carry them (a button, link or combobox), never on a plain\n * `div`; an activator that sets its own ARIA takes `activatorHandlers(attrs)`.\n */\ninterface MenuAttrs extends BaseMenuAttrs {\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n}\n\nexport interface RuiMenuClassNames {\n root?: VueClassValue;\n wrapper?: VueClassValue;\n menu?: VueClassValue;\n /** Overrides applied to the popover content box (e.g. to drop its default padding). */\n content?: VueClassValue;\n /** Overrides applied to the hint and messages under the activator. */\n details?: VueClassValue;\n}\n\n/**\n * Roles a popover container may take. These are the values `aria-haspopup`\n * accepts, which keeps the activator and the popover in agreement.\n */\nexport type RuiMenuRole = 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';\n\nexport interface MenuProps {\n openOnHover?: boolean;\n fullWidth?: boolean;\n disabled?: boolean;\n openDelay?: number;\n closeDelay?: number;\n options?: FloatingOptions;\n classNames?: RuiMenuClassNames;\n closeOnContentClick?: boolean;\n persistOnActivatorClick?: boolean;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n showDetails?: boolean;\n /** With `showDetails`: `reserve` keeps the line while empty (default), `auto` takes no space until there is a message. */\n details?: Exclude<FormDetails, 'hidden'>;\n dense?: boolean;\n /**\n * Keeps the menu open through the interactions that would otherwise dismiss\n * it: a click outside and an Escape press. A programmatic close (`v-model`\n * set to `false`) still applies.\n */\n persistent?: boolean;\n disableAutoFocus?: boolean;\n /**\n * Optional external element to anchor the menu to, instead of the\n * activator slot's wrapper. When set, the menu's position is computed\n * against this element.\n */\n anchorEl?: HTMLElement;\n /**\n * Role of the teleported popover. Defaults to `menu`, which is correct when\n * the content is made of `menuitem`s. Set it to `listbox` (or `tree`, `grid`,\n * `dialog`) when the content follows a different ARIA model, e.g. a selection\n * list opened by a `combobox`. The activator's `aria-haspopup` follows it.\n */\n role?: RuiMenuRole;\n /**\n * Accessible name of the teleported popover. A `dialog` popover needs one;\n * the other roles take it from their activator or options.\n */\n menuLabel?: string;\n}\n\ndefineOptions({\n name: 'RuiMenu',\n});\n\nconst modelValue = defineModel<boolean>({ default: false });\n\nconst {\n openOnHover = false,\n disabled = false,\n fullWidth = false,\n openDelay = 0,\n closeDelay = 0,\n options,\n classNames,\n closeOnContentClick = false,\n persistOnActivatorClick = false,\n hint,\n errorMessages = [],\n successMessages = [],\n showDetails = false,\n details = 'reserve',\n dense = false,\n persistent = false,\n disableAutoFocus = false,\n anchorEl,\n role = 'menu',\n menuLabel,\n} = defineProps<MenuProps>();\n\ndefineSlots<{\n activator?: (props: {\n // An inline type literal, so callers can pass it on as `Record<string, unknown>`\n attrs: {\n 'onMouseover'?: () => void;\n 'onMouseleave'?: () => void;\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n };\n open: boolean;\n disabled: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n default?: (props: { width: number }) => any;\n /** Rendered above the activator, outside the element the menu positions against. */\n label?: () => any;\n}>();\n\nconst click = ref<boolean>(false);\nconst menuContent = useTemplateRef<HTMLElement>('menuContent');\nconst menuId = useId();\n\nconst FOCUSABLE_ELEMENTS_SELECTOR =\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\nconst {\n reference: activator,\n popover: menu,\n open,\n visible,\n currentPlacement,\n leavePending,\n onLeavePending,\n onOpen,\n onClose,\n onLeaveComplete,\n updatePosition,\n} = useFloating(\n () => options ?? {},\n () => disabled,\n () => openDelay,\n () => closeDelay,\n () => anchorEl,\n);\n\nconst { width } = useElementSize(activator);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst menuStyles = tv({\n slots: {\n wrapper: 'relative inline-flex max-w-full',\n popover: 'w-max z-rui-menu',\n // a hairline edge keeps the popup apart from a surface of nearly the same shade in dark mode\n content: 'rounded-rui-panel overflow-hidden shadow-rui-menu bg-rui-menu border border-rui-divider text-rui-text focus:outline-hidden p-1',\n details: '',\n },\n variants: {\n fullWidth: {\n true: { wrapper: 'w-full' },\n },\n dense: {\n true: { details: 'px-2' },\n false: { details: 'px-4' },\n },\n },\n defaultVariants: { fullWidth: false, dense: false },\n});\n\nconst ui = computed<ReturnType<typeof menuStyles>>(() => menuStyles({\n fullWidth,\n dense,\n}));\n\n// `aria-haspopup=\"true\"` means `\"menu\"`, and the default keeps emitting `true` for existing callers\nconst ariaHasPopup = computed<RuiMenuRole | 'true'>(() => role === 'menu' ? 'true' : role);\n\n/**\n * The activator attributes.\n *\n * This and the computed below it must return the same object shape from every\n * branch. Otherwise vue-tsc infers the slot's `attrs` type as a discriminated\n * union where each key is either all defined or all undefined, which breaks\n * consumer code typing its own `attrs` handler with individually optional\n * keys.\n */\nconst baseMenuAttrs = computed<BaseMenuAttrs>(() => {\n const clickVal = get(click);\n return {\n onMouseover: disabled\n ? undefined\n : () => {\n if (openOnHover)\n onOpen();\n },\n onMouseleave: disabled\n ? undefined\n : () => {\n if (openOnHover && !clickVal)\n onClose();\n },\n };\n});\n\nconst menuAttrs = computed<MenuAttrs>(() => ({\n ...get(baseMenuAttrs),\n 'onClick': disabled ? undefined : checkClick,\n 'aria-haspopup': get(ariaHasPopup),\n 'aria-expanded': get(open),\n // Only while the popover is in the DOM, so the reference never points at a missing element\n 'aria-controls': get(visible) ? menuId : undefined,\n}));\n\n/**\n * Moves focus into the open menu without scrolling the page. A menu taller than the space below its\n * activator would otherwise make the browser scroll the whole document to reveal the focused\n * container, sliding the page out from under the activator.\n */\nfunction focusOnContent() {\n const content = get(menuContent);\n if (!content)\n return;\n\n content.focus({ preventScroll: true });\n}\n\nfunction focusMenu(): void {\n if (disableAutoFocus)\n return;\n\n nextTick(() => focusOnContent());\n}\n\n/** Hands focus back to the activator on close, likewise without scrolling to it. */\nfunction focusOnActivator() {\n const activatorEl = get(activator);\n if (!activatorEl) {\n return;\n }\n const focusableEl = activatorEl.querySelector<HTMLElement>(FOCUSABLE_ELEMENTS_SELECTOR);\n if (focusableEl) {\n focusableEl.focus({ preventScroll: true });\n }\n}\n\nfunction onLeave(event?: KeyboardEvent): void {\n if (!get(open))\n return;\n onClose();\n set(click, false);\n event?.stopPropagation();\n\n // Return focus to activator when menu closes\n if (disableAutoFocus) {\n return;\n }\n\n nextTick(() => focusOnActivator());\n}\n\n/**\n * `persistent` blocks the outside interactions that would close the menu, and\n * Escape is one of them, which is how `RuiDialog` and `RuiBottomSheet` already\n * read it. The guard sits here rather than in `onLeave`, because `onLeave`\n * also runs for a programmatic close through `v-model`, which must keep\n * working.\n *\n * A persistent menu leaves the key alone instead of swallowing it, so an inner\n * popover can close on Escape while the menu stays open, and an ancestor still\n * sees a key nothing consumed.\n *\n * Escape is swallowed only while the menu is open and not persistent\n * (`onLeave` stops the event itself); a closed or persistent menu must let it\n * through, or a consumer that closes its own editor on Escape never sees the\n * key. The root element listens for it.\n *\n * An Escape that arrives while an IME is composing belongs to the IME, which\n * cancels the candidate with it, so the menu leaves it alone the same way: a\n * search field inside the menu would otherwise lose the whole menu mid-word.\n */\nfunction onEscape(event: KeyboardEvent): void {\n if (persistent || event.isComposing)\n return;\n\n onLeave(event);\n}\n\nfunction checkClick(): void {\n if (get(open) && get(click)) {\n if (!persistOnActivatorClick)\n onLeave();\n }\n else {\n onOpen();\n set(click, true);\n }\n}\n\nwatch(modelValue, (value) => {\n if (get(open) === value)\n return;\n\n if (value) {\n onOpen();\n set(click, true);\n }\n else {\n onLeave();\n }\n});\n\nwatch(open, (open) => {\n set(modelValue, open);\n if (open) {\n focusMenu();\n }\n});\n\nonClickOutside(menu, () => {\n if (get(open) && !persistent)\n onLeave();\n}, { ignore: [activator] });\n</script>\n\n<template>\n <div\n :class=\"classNames?.root\"\n @keydown.esc=\"onEscape($event)\"\n >\n <slot name=\"label\" />\n <div\n ref=\"activator\"\n :class=\"ui.wrapper({ class: cn(classNames?.wrapper) })\"\n :data-menu-disabled=\"disabled\"\n >\n <slot\n name=\"activator\"\n v-bind=\"{ attrs: menuAttrs, open, disabled, hasError, hasSuccess }\"\n />\n </div>\n <Teleport\n v-if=\"!disabled\"\n to=\"body\"\n >\n <div\n v-if=\"visible\"\n :id=\"menuId\"\n ref=\"menu\"\n :class=\"ui.popover({ class: cn(classNames?.menu) })\"\n :role=\"role\"\n :aria-label=\"menuLabel\"\n :data-placement=\"currentPlacement\"\n @click=\"closeOnContentClick ? onLeave() : undefined\"\n @keydown.esc=\"onEscape($event)\"\n >\n <TransitionGroup\n enter-active-class=\"transition ease-out duration-200\"\n enter-from-class=\"opacity-0 translate-y-1\"\n enter-to-class=\"opacity-100 translate-y-0\"\n leave-active-class=\"transition ease-in duration-150\"\n leave-from-class=\"opacity-100 translate-y-0\"\n leave-to-class=\"opacity-0 translate-y-1\"\n @before-enter=\"updatePosition()\"\n @after-leave=\"leavePending ? onLeaveComplete() : undefined\"\n @before-leave=\"onLeavePending()\"\n >\n <div\n v-if=\"open\"\n ref=\"menuContent\"\n key=\"menu\"\n data-id=\"content\"\n :class=\"ui.content({ class: cn(classNames?.content) })\"\n tabindex=\"-1\"\n v-bind=\"baseMenuAttrs\"\n >\n <ButtonGroupBoundary>\n <slot v-bind=\"{ width }\" />\n </ButtonGroupBoundary>\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n <RuiFormTextDetail\n v-if=\"showDetails\"\n :details=\"details\"\n :class=\"ui.details({ class: cn(classNames?.details) })\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RuiMenu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_normalizeClass","_withKeys","_renderSlot","_createElementVNode","_mergeProps","_unref","_toHandlers","_normalizeProps","_guardReactiveProps","_createBlock","_Teleport","_createVNode","_TransitionGroup","_withCtx","_createCommentVNode","RuiFormTextDetail"],"sources":["../../../../src/components/overlays/menu/RuiMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Reactive, Ref, WatchHandle } from 'vue';\nimport type { VueClassValue } from '@/types/class-value';\nimport { ButtonGroupBoundary } from '@/components/buttons/button-group/button-group-context';\nimport RuiFormTextDetail from '@/components/helpers/RuiFormTextDetail.vue';\nimport { type FloatingOptions, useFloating, type UseFloatingReturn } from '@/composables/floating';\nimport { containsMessage, type FormDetails } from '@/utils/form-text-detail';\nimport { cn } from '@/utils/tv';\nimport { menuStyles } from './menu-styles';\n\ninterface BaseMenuAttrs { onMouseover?: () => void; onMouseleave?: () => void }\n\n/**\n * What the activator slot binds onto its trigger. The ARIA keys belong on an\n * element that can carry them (a button, link or combobox), never on a plain\n * `div`; an activator that sets its own ARIA takes `activatorHandlers(attrs)`.\n */\ninterface MenuAttrs extends BaseMenuAttrs {\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n}\n\nexport interface RuiMenuClassNames {\n root?: VueClassValue;\n wrapper?: VueClassValue;\n menu?: VueClassValue;\n /** Overrides applied to the popover content box (e.g. to drop its default padding). */\n content?: VueClassValue;\n /** Overrides applied to the hint and messages under the activator. */\n details?: VueClassValue;\n}\n\n/**\n * Roles a popover container may take. These are the values `aria-haspopup`\n * accepts, which keeps the activator and the popover in agreement.\n */\nexport type RuiMenuRole = 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';\n\nexport interface MenuProps {\n openOnHover?: boolean;\n fullWidth?: boolean;\n disabled?: boolean;\n openDelay?: number;\n closeDelay?: number;\n options?: FloatingOptions;\n classNames?: RuiMenuClassNames;\n closeOnContentClick?: boolean;\n persistOnActivatorClick?: boolean;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n showDetails?: boolean;\n /** With `showDetails`: `reserve` keeps the line while empty (default), `auto` takes no space until there is a message. */\n details?: Exclude<FormDetails, 'hidden'>;\n dense?: boolean;\n /**\n * Keeps the menu open through the interactions that would otherwise dismiss\n * it: a click outside and an Escape press. A programmatic close (`v-model`\n * set to `false`) still applies.\n */\n persistent?: boolean;\n disableAutoFocus?: boolean;\n /**\n * Optional external element to anchor the menu to, instead of the\n * activator slot's wrapper. When set, the menu's position is computed\n * against this element.\n */\n anchorEl?: HTMLElement;\n /**\n * Role of the teleported popover. Defaults to `menu`, which is correct when\n * the content is made of `menuitem`s. Set it to `listbox` (or `tree`, `grid`,\n * `dialog`) when the content follows a different ARIA model, e.g. a selection\n * list opened by a `combobox`. The activator's `aria-haspopup` follows it.\n */\n role?: RuiMenuRole;\n /**\n * Accessible name of the teleported popover. A `dialog` popover needs one;\n * the other roles take it from their activator or options.\n */\n menuLabel?: string;\n /**\n * Defers the popover's setup (its positioning, the activator's size\n * observer and the click-outside listeners) to first use: a click or a\n * context menu on the activator, a hover with `openOnHover`, or the model\n * turning `true`. Until then the menu renders its root, the wrapper and the\n * activator, the same elements it keeps afterwards, so a table with a menu\n * on every row pays for the menus that are opened. Read at mount.\n */\n lazy?: boolean;\n}\n\n/** What the menu sets up at mount, or on first use when `lazy`, with its refs unwrapped. */\ntype MenuSetup = Reactive<{\n floating: UseFloatingReturn;\n width: Readonly<Ref<number>>;\n}>;\n\ndefineOptions({\n name: 'RuiMenu',\n});\n\nconst modelValue = defineModel<boolean>({ default: false });\n\nconst {\n openOnHover = false,\n disabled = false,\n fullWidth = false,\n openDelay = 0,\n closeDelay = 0,\n options,\n classNames,\n closeOnContentClick = false,\n persistOnActivatorClick = false,\n hint,\n errorMessages = [],\n successMessages = [],\n showDetails = false,\n details = 'reserve',\n dense = false,\n persistent = false,\n disableAutoFocus = false,\n anchorEl,\n role = 'menu',\n menuLabel,\n lazy = false,\n} = defineProps<MenuProps>();\n\ndefineSlots<{\n activator?: (props: {\n // An inline type literal, so callers can pass it on as `Record<string, unknown>`\n attrs: {\n 'onMouseover'?: () => void;\n 'onMouseleave'?: () => void;\n 'onClick'?: () => void;\n 'aria-haspopup': RuiMenuRole | 'true';\n 'aria-expanded': boolean;\n 'aria-controls'?: string;\n };\n open: boolean;\n disabled: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n default?: (props: { width: number }) => any;\n /** Rendered above the activator, outside the element the menu positions against. */\n label?: () => any;\n}>();\n\nconst click = ref<boolean>(false);\nconst activator = useTemplateRef<HTMLElement>('activator');\nconst menu = useTemplateRef<HTMLElement>('menu');\nconst menuContent = useTemplateRef<HTMLElement>('menuContent');\nconst menuId = useId();\nconst instance = getCurrentInstance();\n// Owned by this component, so whatever the setup starts stops on unmount even when it ran after mount\nconst setupScope = effectScope();\nconst menuSetup = shallowRef<MenuSetup>();\nlet stopSetUpOnModel: WatchHandle | undefined;\n\nconst FOCUSABLE_ELEMENTS_SELECTOR =\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\n// Only the two flags, not the formatted lists useFormTextDetail builds, since a table may hold hundreds of menus\nconst hasError = computed<boolean>(() => containsMessage(errorMessages));\nconst hasSuccess = computed<boolean>(() => containsMessage(successMessages));\n\nconst ui = computed<ReturnType<typeof menuStyles>>(() => menuStyles({\n fullWidth,\n dense,\n}));\n\nconst open = computed<boolean>(() => get(menuSetup)?.floating.open ?? false);\nconst visible = computed<boolean>(() => get(menuSetup)?.floating.visible ?? false);\n\n/**\n * The activator attributes.\n *\n * This and the computed below it must return the same object shape from every\n * branch. Otherwise vue-tsc infers the slot's `attrs` type as a discriminated\n * union where each key is either all defined or all undefined, which breaks\n * consumer code typing its own `attrs` handler with individually optional\n * keys.\n */\nconst baseMenuAttrs = computed<BaseMenuAttrs>(() => {\n const clickVal = get(click);\n return {\n onMouseover: disabled\n ? undefined\n : () => {\n if (openOnHover)\n setUp()?.onOpen();\n },\n onMouseleave: disabled\n ? undefined\n : () => {\n if (openOnHover && !clickVal)\n activeFloating()?.onClose();\n },\n };\n});\n\nconst menuAttrs = computed<MenuAttrs>(() => ({\n ...get(baseMenuAttrs),\n 'onClick': disabled ? undefined : checkClick,\n // `aria-haspopup=\"true\"` means `\"menu\"`, and the default keeps emitting `true` for existing callers\n 'aria-haspopup': role === 'menu' ? 'true' : role,\n 'aria-expanded': get(open),\n // Only while the popover is in the DOM, so the reference never points at a missing element\n 'aria-controls': get(visible) ? menuId : undefined,\n}));\n\n/**\n * Sets a lazy menu up on its first use, on the wrapper so that it covers an\n * activator that opens the menu through the model rather than through\n * `attrs`. Hover and focus are left out: a cursor resting over a scrolling\n * table or Tab moving down it would set up every row it passes. They stay\n * after setup, where `setUp` only hands back what it already made.\n */\nconst firstUseListeners = { click: setUp, contextmenu: setUp };\n\n/**\n * Sets the popover up once and hands back its floating state. It runs at\n * mount, or for a `lazy` menu on first use, which can be after mount and\n * inside another component's lifecycle hook, so what it starts must not\n * attach itself to the current instance.\n */\nfunction setUp(): MenuSetup['floating'] | undefined {\n if (setupScope.active && !get(menuSetup)) {\n set(menuSetup, setupScope.run(createSetup));\n stopSetUpOnModel?.();\n }\n return activeFloating();\n}\n\n/**\n * The floating state while the menu is alive. An event can still reach the\n * activator after unmount, and must not start timers on a stopped menu.\n */\nfunction activeFloating(): MenuSetup['floating'] | undefined {\n return setupScope.active ? get(menuSetup)?.floating : undefined;\n}\n\n/** An element's content-box width, the box its resize observer reports. */\nfunction contentWidth(element: HTMLElement | null): number {\n if (!element)\n return 0;\n\n const style = getComputedStyle(element);\n const edges = [style.paddingLeft, style.paddingRight, style.borderLeftWidth, style.borderRightWidth];\n return edges.reduce((width, edge) => width - (Number.parseFloat(edge) || 0), element.offsetWidth);\n}\n\nfunction createSetup(): MenuSetup {\n const floating = useFloating(\n () => options ?? {},\n () => disabled,\n () => openDelay,\n () => closeDelay,\n () => anchorEl ?? get(activator) ?? undefined,\n menu,\n );\n\n const width = shallowRef<number>(0);\n const readWidth = (): void => set(width, contentWidth(get(activator)));\n useResizeObserver(activator, ([entry]) => {\n if (entry)\n set(width, entry.contentRect.width);\n });\n // Only the menu's own setup waits for its mount; a later one may run inside another component's hook\n if (instance?.isMounted)\n readWidth();\n else\n onMounted(readWidth);\n\n // Immediate, so a model that is already `true` at setup opens the menu\n watch(modelValue, (value) => {\n if (get(floating.open) === value)\n return;\n\n if (value) {\n floating.onOpen();\n set(click, true);\n }\n else {\n onLeave();\n }\n }, { immediate: true });\n\n watch(floating.open, (isOpen) => {\n set(modelValue, isOpen);\n if (isOpen) {\n focusMenu();\n }\n });\n\n onClickOutside(menu, () => {\n if (get(floating.open) && !persistent)\n onLeave();\n }, { ignore: [activator] });\n\n return reactive({ floating, width });\n}\n\n/**\n * Moves focus into the open menu without scrolling the page. A menu taller than the space below its\n * activator would otherwise make the browser scroll the whole document to reveal the focused\n * container, sliding the page out from under the activator.\n */\nfunction focusOnContent() {\n const content = get(menuContent);\n if (!content)\n return;\n\n content.focus({ preventScroll: true });\n}\n\nfunction focusMenu(): void {\n if (disableAutoFocus)\n return;\n\n nextTick(() => focusOnContent());\n}\n\n/** Hands focus back to the activator on close, likewise without scrolling to it. */\nfunction focusOnActivator() {\n const activatorEl = get(activator);\n if (!activatorEl) {\n return;\n }\n const focusableEl = activatorEl.querySelector<HTMLElement>(FOCUSABLE_ELEMENTS_SELECTOR);\n if (focusableEl) {\n focusableEl.focus({ preventScroll: true });\n }\n}\n\nfunction onLeave(event?: KeyboardEvent): void {\n const floating = activeFloating();\n if (!floating?.open)\n return;\n floating.onClose();\n set(click, false);\n event?.stopPropagation();\n\n // Return focus to activator when menu closes\n if (disableAutoFocus) {\n return;\n }\n\n nextTick(() => focusOnActivator());\n}\n\n/**\n * `persistent` blocks the outside interactions that would close the menu, and\n * Escape is one of them, which is how `RuiDialog` and `RuiBottomSheet` already\n * read it. The guard sits here rather than in `onLeave`, because `onLeave`\n * also runs for a programmatic close through `v-model`, which must keep\n * working.\n *\n * A persistent menu leaves the key alone instead of swallowing it, so an inner\n * popover can close on Escape while the menu stays open, and an ancestor still\n * sees a key nothing consumed.\n *\n * Escape is swallowed only while the menu is open and not persistent\n * (`onLeave` stops the event itself); a closed or persistent menu must let it\n * through, or a consumer that closes its own editor on Escape never sees the\n * key. The root element listens for it.\n *\n * An Escape that arrives while an IME is composing belongs to the IME, which\n * cancels the candidate with it, so the menu leaves it alone the same way: a\n * search field inside the menu would otherwise lose the whole menu mid-word.\n */\nfunction onEscape(event: KeyboardEvent): void {\n if (persistent || event.isComposing)\n return;\n\n onLeave(event);\n}\n\nfunction checkClick(): void {\n const floating = setUp();\n if (!floating)\n return;\n\n if (floating.open && get(click)) {\n if (!persistOnActivatorClick)\n onLeave();\n }\n else {\n floating.onOpen();\n set(click, true);\n }\n}\n\n// The setup's own watcher opens it; a disabled menu stays closed and unset, as an eager one stays closed\nif (!lazy || (get(modelValue) && !disabled)) {\n setUp();\n}\nelse {\n stopSetUpOnModel = watch(modelValue, (value) => {\n if (value && !disabled)\n setUp();\n });\n}\n</script>\n\n<template>\n <div\n :class=\"classNames?.root\"\n @keydown.esc=\"onEscape($event)\"\n >\n <slot name=\"label\" />\n <div\n ref=\"activator\"\n :class=\"ui.wrapper({ class: cn(classNames?.wrapper) })\"\n :data-menu-disabled=\"disabled\"\n v-on=\"lazy && !disabled ? firstUseListeners : {}\"\n >\n <slot\n name=\"activator\"\n v-bind=\"{ attrs: menuAttrs, open, disabled, hasError, hasSuccess }\"\n />\n </div>\n <Teleport\n v-if=\"!disabled && menuSetup\"\n to=\"body\"\n >\n <div\n v-if=\"visible\"\n :id=\"menuId\"\n ref=\"menu\"\n :class=\"ui.popover({ class: cn(classNames?.menu) })\"\n :role=\"role\"\n :aria-label=\"menuLabel\"\n :data-placement=\"menuSetup.floating.currentPlacement\"\n @click=\"closeOnContentClick ? onLeave() : undefined\"\n @keydown.esc=\"onEscape($event)\"\n >\n <TransitionGroup\n enter-active-class=\"transition ease-out duration-200\"\n enter-from-class=\"opacity-0 translate-y-1\"\n enter-to-class=\"opacity-100 translate-y-0\"\n leave-active-class=\"transition ease-in duration-150\"\n leave-from-class=\"opacity-100 translate-y-0\"\n leave-to-class=\"opacity-0 translate-y-1\"\n @before-enter=\"menuSetup?.floating.updatePosition()\"\n @after-leave=\"menuSetup?.floating.leavePending ? menuSetup.floating.onLeaveComplete() : undefined\"\n @before-leave=\"menuSetup?.floating.onLeavePending()\"\n >\n <div\n v-if=\"open\"\n ref=\"menuContent\"\n key=\"menu\"\n data-id=\"content\"\n :class=\"ui.content({ class: cn(classNames?.content) })\"\n tabindex=\"-1\"\n v-bind=\"baseMenuAttrs\"\n >\n <ButtonGroupBoundary>\n <slot v-bind=\"{ width: menuSetup.width }\" />\n </ButtonGroupBoundary>\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n <RuiFormTextDetail\n v-if=\"showDetails\"\n :details=\"details\"\n :class=\"ui.details({ class: cn(classNames?.details) })\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|