@adyen/bento-mcp 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/assets/components/dashed-underline/dashed-underline.vue +1 -1
- package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.types.ts +1 -1
- package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.vue +1 -1
- package/dist/assets/components/date-picker/composables/use-date-picker-single-calendar-text.types.ts +1 -1
- package/dist/assets/components/date-picker/date-picker.vue +1 -1
- package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.vue +1 -1
- package/dist/assets/components/date-time-picker/date-time-picker.docs.mdx +129 -0
- package/dist/assets/components/date-time-picker/date-time-picker.stories.ts +1 -0
- package/dist/assets/components/date-time-picker/date-time-picker.types.ts +1 -0
- package/dist/assets/components/date-time-picker/date-time-picker.vue +1 -0
- package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.vue +1 -1
- package/dist/assets/components/dropdown/components/dropdown-small-textbox/dropdown-small-textbox.vue +1 -1
- package/dist/assets/components/dropdown/dropdown.vue +1 -1
- package/dist/assets/components/file-uploader/file-uploader.vue +1 -1
- package/dist/assets/components/input-field/input-field.vue +1 -1
- package/dist/assets/components/internal/info-icon-with-popover/info-icon-with-popover.vue +1 -1
- package/dist/assets/components/link/link.vue +1 -1
- package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.stories.ts +1 -1
- package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.vue +1 -1
- package/dist/assets/components/navigation-menu/components/navigation-menu-item/navigation-menu-item.stories.ts +1 -1
- package/dist/assets/components/navigation-menu/components/navigation-menu-item/navigation-menu-item.vue +1 -1
- package/dist/assets/components/navigation-menu/navigation-menu.docs.mdx +7 -43
- package/dist/assets/components/navigation-menu/navigation-menu.stories.ts +1 -1
- package/dist/assets/components/navigation-menu/navigation-menu.types.ts +1 -1
- package/dist/assets/components/navigation-menu/navigation-menu.vue +1 -1
- package/dist/assets/components/popover/popover.docs.mdx +74 -15
- package/dist/assets/components/popover/popover.stories.ts +1 -1
- package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.types.ts +1 -1
- package/dist/assets/components.json +1 -0
- package/dist/assets/composables/use-bento-delayed-hover/use-bento-delayed-hover.docs.mdx +73 -0
- package/dist/assets/composables/use-bento-delayed-hover/use-bento-delayed-hover.stories.ts +1 -0
- package/dist/assets/index.ts +1 -1
- package/dist/assets/usage.json +8 -7
- package/dist/main.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BentoNavigationMenu from './navigation-menu.vue'; import BentoNavigationMenuItem from './components/navigation-menu-item/navigation-menu-item.vue'; import BentoNavigationMenuGroup from './components/navigation-menu-group/navigation-menu-group.vue'; import { BentoButton } from '@/components/button'; import type { Meta, StoryObj } from '@storybook/vue'; import StarIcon from '@adyen/ui-assets-icons-16/vue/star'; import StarFilledIcon from '@adyen/ui-assets-icons-16/vue/star-filled'; import SearchIcon from '@adyen/ui-assets-icons-16/vue/search'; import NavHomeIcon from '@adyen/ui-assets-icons-16/vue/nav-home'; import NavPaymentsIcon from '@adyen/ui-assets-icons-16/vue/nav-payments'; import NavReportsIcon from '@adyen/ui-assets-icons-16/vue/nav-reports'; import NavSettingsIcon from '@adyen/ui-assets-icons-16/vue/nav-settings'; import NavAccountHoldersIcon from '@adyen/ui-assets-icons-16/vue/nav-account-holders'; import { ref } from 'vue'; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import NavigationMenuEverythingBagelExample from './__tests__/navigation-menu-everything-bagel-example.vue?raw'; import NavigationMenuSimpleListExample from './__tests__/navigation-menu-simple-list-example.vue?raw'; export default { title: 'Navigation Menu', component: BentoNavigationMenu, argTypes: { default: { control: false, table: { type: { summary: 'Navigation items and groups' }, }, }, headerActions: { control: false, table: { type: { summary: 'Action buttons' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoNavigationMenu>; export const EverythingBagel: Story = { render: (_args, { argTypes }) => ({ components: { BentoNavigationMenu, BentoNavigationMenuItem, BentoNavigationMenuGroup, BentoButton, StarIcon, StarFilledIcon, SearchIcon, NavHomeIcon, NavPaymentsIcon, NavReportsIcon, NavSettingsIcon, NavAccountHoldersIcon, }, props: Object.keys(argTypes), setup(props) { const activePage = ref('home'); const paymentsExpanded = ref(true); const favorites = ref({}); const toggleFavorite = (value: string) => { favorites.value = { ...favorites.value, [value]: !favorites.value[value] }; }; const onExpandAll = () => action('expand-all')(); const onCollapseAll = () => action('collapse-all')(); return { activePage, paymentsExpanded, favorites, toggleFavorite, onExpandAll, onCollapseAll, args: isVue2 ? props : _args, }; }, template: ` <div style="width: 248px;"> <bento-navigation-menu v-bind="args" :active-page="activePage" @update:active-page="activePage = $event" @expand-all="onExpandAll" @collapse-all="onCollapseAll"> <template #headerActions> <bento-button variant="tertiary-with-background"> <template #iconLeft> <search-icon svg-title="Search" /> </template> </bento-button> </template> <bento-navigation-menu-item value="home" label="Home" :link="{ to: '#home', isNotRouting: true }" > <template #icon> <nav-home-icon /> </template> </bento-navigation-menu-item> <bento-navigation-menu-group label="Payments" :is-expanded="paymentsExpanded" @update:is-expanded="paymentsExpanded = $event" > <template #icon> <nav-payments-icon /> </template> <bento-navigation-menu-item nested value="payments" label="Payments" :link="{ to: '#payments', isNotRouting: true }" :always-show-actions="!!favorites.payments || activePage === 'payments'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('payments')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.payments" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="preauth" label="Pre-authorized" :link="{ to: '#preauth', isNotRouting: true }" :always-show-actions="!!favorites.preauth || activePage === 'preauth'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('preauth')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.preauth" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="links" label="Payment links" :link="{ to: '#links', isNotRouting: true }" :always-show-actions="!!favorites.links || activePage === 'links'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('links')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.links" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="methods" label="Payment methods" :link="{ to: '#methods', isNotRouting: true }" :always-show-actions="!!favorites.methods || activePage === 'methods'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('methods')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.methods" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> </bento-navigation-menu-group> <bento-navigation-menu-group label="Reports" > <template #icon> <nav-reports-icon /> </template> <bento-navigation-menu-item nested value="analytics" label="Analytics" :link="{ to: '#analytics', isNotRouting: true }" :always-show-actions="!!favorites.analytics || activePage === 'analytics'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('analytics')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.analytics" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="transactions" label="Transactions" :link="{ to: '#transactions', isNotRouting: true }" :always-show-actions="!!favorites.transactions || activePage === 'transactions'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('transactions')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.transactions" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> </bento-navigation-menu-group> <bento-navigation-menu-item value="settings" label="Settings" :link="{ to: '#settings', isNotRouting: true }" :always-show-actions="!!favorites.settings || activePage === 'settings'" > <template #icon> <nav-settings-icon /> </template> <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('settings')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.settings" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item value="profile" label="Profile" :link="{ to: '#profile', isNotRouting: true }" :always-show-actions="!!favorites.profile || activePage === 'profile'" > <template #icon> <nav-account-holders-icon /> </template> <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('profile')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.profile" svg-title="Remove from favorites" /> <star-icon v-else svg-title="Add to favorites" /> </template> </bento-button> </template> </bento-navigation-menu-item> </bento-navigation-menu> </div> `, }), args: { label: 'Pages', showExpandAllButton: true, }, parameters: storybookDocsParameter(NavigationMenuEverythingBagelExample), }; export const SimpleList: Story = { render: (_args, { argTypes }) => ({ components: { BentoNavigationMenu, BentoNavigationMenuItem, StarIcon, }, props: Object.keys(argTypes), setup(props) { const activePage = ref('home'); return { activePage, args: isVue2 ? props : _args }; }, template: ` <div style="width: 248px;"> <bento-navigation-menu v-bind="args" :active-page="activePage" @update:active-page="activePage = $event"> <bento-navigation-menu-item value="home" label="Home" :link="{ to: '#home', isNotRouting: true }" /> <bento-navigation-menu-item value="analytics" label="Analytics" :link="{ to: '#analytics', isNotRouting: true }" /> <bento-navigation-menu-item value="settings" label="Settings" :link="{ to: '#settings', isNotRouting: true }" /> <bento-navigation-menu-item value="profile" label="Profile" :link="{ to: '#profile', isNotRouting: true }" /> </bento-navigation-menu> </div> `, }), args: { label: 'Pages', }, parameters: storybookDocsParameter(NavigationMenuSimpleListExample), };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { type Ref } from 'vue'; export interface BentoNavigationMenuProps { /** * Label text for the navigation menu header */ label?: string; /** * Whether to show the expand/collapse all button */ showExpandAllButton?: boolean; /** * The value of the currently active navigation item */ activePage?: string; } /** * @private */ export interface BentoNavigationMenuGroupRegistration { id: string; setOpen: (open: boolean) => void; getIsOpen: () => boolean; } /** * @private */ export interface BentoNavigationMenuState { registerGroup: (groupId: string, setOpen: (open: boolean) => void, getIsOpen: () => boolean) => void; unregisterGroup: (groupId: string) => void; activePage: Ref<string | undefined>; updateActivePage: (value: string) => void; }
|
|
1
|
+
import { type Ref } from 'vue'; export interface BentoNavigationMenuProps { /** * Label text for the navigation menu header */ label?: string; /** * Whether to show the expand/collapse all button */ showExpandAllButton?: boolean; /** * The value of the currently active navigation item */ activePage?: string; } export interface BentoNavigationMenuEmits { /** * Emits update event when active page is changed */ (e: 'update:active-page', value: string): void; /** * Emits event when expand all button is clicked */ (e: 'expand-all'): void; /** * Emits event when collapse all button is clicked */ (e: 'collapse-all'): void; } /** * @private */ export interface BentoNavigationMenuGroupRegistration { id: string; setOpen: (open: boolean) => void; getIsOpen: () => boolean; } /** * @private */ export interface BentoNavigationMenuState { registerGroup: (groupId: string, setOpen: (open: boolean) => void, getIsOpen: () => boolean) => void; unregisterGroup: (groupId: string) => void; activePage: Ref<string | undefined>; updateActivePage: (value: string) => void; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<template> <nav class="b-navigation-menu" :aria-labelledby="label ? titleId : undefined"> <div v-if="showHeader" class="b-navigation-menu__header"> <bento-typography v-if="label" :id="titleId" el="p" variant="caption" stronger class="b-navigation-menu__title" > {{ label }} </bento-typography> <div class="b-navigation-menu__actions-container"> <div v-if="hasSlot('headerActions')" class="b-navigation-menu__actions"> <slot name="headerActions" /> </div> <bento-button v-if="computedShowExpandAll" v-bento-tooltip-directive="expandButtonLabel" variant="tertiary-with-background" :aria-label="expandButtonLabel" @click="toggleAllGroups" > <template #iconLeft> <menu-collapse-icon v-if="allExpanded" /> <menu-expand-icon v-else /> </template> </bento-button> </div> </div> <ul class="b-navigation-menu__content"> <slot /> </ul> </nav> </template> <script setup lang="ts"> import { computed, provide, ref, toRef, useSlots } from 'vue'; import { BentoTypography } from '@/components/typography'; import { BentoButton } from '@/components/button'; import MenuCollapseIcon from '@adyen/ui-assets-icons-16/vue/menu-collapse'; import MenuExpandIcon from '@adyen/ui-assets-icons-16/vue/menu-expand'; import { useHasSlot } from '@/composables'; import { BentoTooltipDirective as vBentoTooltipDirective } from '@/directives/tooltip'; import { generateUid } from '@/core/utils/ts'; import { useI18n } from '@/utils/ts/i18n'; import type { BentoNavigationMenuGroupRegistration, BentoNavigationMenuProps, BentoNavigationMenuState, } from './navigation-menu.types'; import { NAVIGATION_MENU_STATE_INJECTION_KEY } from './navigation-menu.keys'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults(defineProps<BentoNavigationMenuProps>(), { label: undefined, showExpandAllButton: false, activePage: undefined, }); const emit = defineEmits<
|
|
1
|
+
<template> <nav class="b-navigation-menu" :aria-labelledby="label ? titleId : undefined"> <div v-if="showHeader" class="b-navigation-menu__header"> <bento-typography v-if="label" :id="titleId" el="p" variant="caption" stronger class="b-navigation-menu__title" > {{ label }} </bento-typography> <div class="b-navigation-menu__actions-container"> <div v-if="hasSlot('headerActions')" class="b-navigation-menu__actions"> <slot name="headerActions" /> </div> <bento-button v-if="computedShowExpandAll" v-bento-tooltip-directive="expandButtonLabel" variant="tertiary-with-background" :aria-label="expandButtonLabel" @click="toggleAllGroups" > <template #iconLeft> <menu-collapse-icon v-if="allExpanded" aria-hidden="true" /> <menu-expand-icon v-else aria-hidden="true" /> </template> </bento-button> </div> </div> <ul class="b-navigation-menu__content"> <slot /> </ul> </nav> </template> <script setup lang="ts"> import { computed, provide, ref, toRef, useSlots } from 'vue'; import { BentoTypography } from '@/components/typography'; import { BentoButton } from '@/components/button'; import MenuCollapseIcon from '@adyen/ui-assets-icons-16/vue/menu-collapse'; import MenuExpandIcon from '@adyen/ui-assets-icons-16/vue/menu-expand'; import { useHasSlot } from '@/composables'; import { BentoTooltipDirective as vBentoTooltipDirective } from '@/directives/tooltip'; import { generateUid } from '@/core/utils/ts'; import { useI18n } from '@/utils/ts/i18n'; import type { BentoNavigationMenuEmits, BentoNavigationMenuGroupRegistration, BentoNavigationMenuProps, BentoNavigationMenuState, } from './navigation-menu.types'; import { NAVIGATION_MENU_STATE_INJECTION_KEY } from './navigation-menu.keys'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults(defineProps<BentoNavigationMenuProps>(), { label: undefined, showExpandAllButton: false, activePage: undefined, }); const emit = defineEmits<BentoNavigationMenuEmits>(); const slots = useSlots(); const hasSlot = useHasSlot(slots); const titleId = generateUid('navigation-menu-title'); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const groups = ref<Array<BentoNavigationMenuGroupRegistration>>([]); const registerGroup = (groupId: string, setOpen: (open: boolean) => void, getIsOpen: () => boolean) => { groups.value.push({ id: groupId, setOpen, getIsOpen }); }; const unregisterGroup = (groupId: string) => { groups.value = groups.value.filter(g => g.id !== groupId); }; const allExpanded = computed(() => groups.value.length > 0 && groups.value.every(group => group.getIsOpen())); const computedShowExpandAll = computed(() => groups.value.length > 0 && props.showExpandAllButton); const showHeader = computed(() => props.label || hasSlot('headerActions') || computedShowExpandAll.value); const expandButtonLabel = computed(() => (allExpanded.value ? t('hideAllPages') : t('showAllPages'))); const toggleAllGroups = () => { const shouldExpand = !allExpanded.value; groups.value.forEach(({ setOpen }) => setOpen(shouldExpand)); if (shouldExpand) { emit('expand-all'); } else { emit('collapse-all'); } }; const updateActivePage = (value: string) => { emit('update:active-page', value); }; provide<BentoNavigationMenuState>(NAVIGATION_MENU_STATE_INJECTION_KEY, { registerGroup, unregisterGroup, activePage: toRef(props, 'activePage'), updateActivePage, }); </script> <script lang="ts"> /** * Navigation menu container component with optional header and action buttons. * * @usage * import { BentoNavigationMenu, BentoNavigationMenuItem, BentoNavigationMenuGroup } from '@adyen/bento-vue2'; * * export default { * components: { BentoNavigationMenu, BentoNavigationMenuItem, BentoNavigationMenuGroup }, * template: ` * <bento-navigation-menu label="Pages" active-page="home"> * <template #headerActions> * <button>Search</button> * </template> * <bento-navigation-menu-item value="home" label="Home" :link="{ to: '/home' }"> * <template #icon><home-icon /></template> * </bento-navigation-menu-item> * <bento-navigation-menu-group label="Settings"> * <template #icon><folder-icon /></template> * <bento-navigation-menu-item nested value="general" label="General" :link="{ to: '/settings/general' }" /> * </bento-navigation-menu-group> * </bento-navigation-menu> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./navigation-menu.scss" />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Canvas, Story, Meta } from '@storybook/blocks';
|
|
1
|
+
import { Canvas, Source, Story, Meta } from '@storybook/blocks';
|
|
2
2
|
import * as ComponentStories from './popover.stories';
|
|
3
3
|
|
|
4
4
|
<Meta of={ComponentStories} />
|
|
@@ -14,8 +14,8 @@ control or interactive area.
|
|
|
14
14
|
|
|
15
15
|
Use popover when you need:
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
17
|
+
- Provide a piece of non-critical extra information (informative, educative).
|
|
18
|
+
- Provide contextual to trigger functionality.
|
|
19
19
|
|
|
20
20
|
### Do not use
|
|
21
21
|
|
|
@@ -36,11 +36,11 @@ Using the `title` prop and `headerIcon` slot we can create a header for the Popo
|
|
|
36
36
|
Using the `actions` prop we can provide an array of action objects (see the Button Actions story). The `actionsLayout`
|
|
37
37
|
prop can be used to define the layout of buttons and can take up one of the following values:
|
|
38
38
|
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
39
|
+
- `'buttons-end'`
|
|
40
|
+
- `'fill-container'`
|
|
41
|
+
- `'space-between'`
|
|
42
|
+
- `'vertical-stack'`
|
|
43
|
+
- `'buttons-start'`
|
|
44
44
|
|
|
45
45
|
### Image
|
|
46
46
|
|
|
@@ -48,6 +48,65 @@ prop can be used to define the layout of buttons and can take up one of the foll
|
|
|
48
48
|
|
|
49
49
|
Using the `image` slot you can set a header image.
|
|
50
50
|
|
|
51
|
+
### Triggering on hover
|
|
52
|
+
|
|
53
|
+
<Canvas of={ComponentStories.OnHover} />
|
|
54
|
+
|
|
55
|
+
The popover can be opened on hover by using the `useBentoDelayedHover` composable. It returns the `isOpen` ref, the
|
|
56
|
+
individual handlers (`open`, `close`), and a `hoverEvents` object that bundles them as `mouseenter`/`mouseleave`/
|
|
57
|
+
`focusin`/`focusout` listeners. Mouse and focus events are handled, so the popover also opens when the trigger receives
|
|
58
|
+
keyboard focus, and a small closing delay is applied to prevent flickering when the user moves the cursor or focus from
|
|
59
|
+
the trigger to the popover content.
|
|
60
|
+
|
|
61
|
+
Bind the handlers on the trigger via `v-on="hoverEvents"`:
|
|
62
|
+
|
|
63
|
+
<Source
|
|
64
|
+
format={'html'}
|
|
65
|
+
dark
|
|
66
|
+
code={`
|
|
67
|
+
<span ref="triggerRef" v-on="hoverEvents">Hover me</span>
|
|
68
|
+
`}
|
|
69
|
+
/>
|
|
70
|
+
|
|
71
|
+
When the popover is **NOT** a descendant of the trigger element (for example, rendered as a sibling or teleported
|
|
72
|
+
elsewhere in the DOM), also bind `hoverEvents` on the popover so that hovering or focusing its content keeps it open:
|
|
73
|
+
|
|
74
|
+
<Source
|
|
75
|
+
format={'html'}
|
|
76
|
+
dark
|
|
77
|
+
code={`
|
|
78
|
+
<span ref="triggerRef" v-on="hoverEvents">Hover me</span>
|
|
79
|
+
|
|
80
|
+
<bento-popover v-on="hoverEvents" :open="isOpen" :target-element="triggerRef">
|
|
81
|
+
Popover content
|
|
82
|
+
</bento-popover>
|
|
83
|
+
`}
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
When the popover is rendered as a descendant of the trigger element, this is not necessary — the trigger's own
|
|
87
|
+
`mouseleave` will not fire while the cursor is over its descendants.
|
|
88
|
+
|
|
89
|
+
> **Vue 2 only:** when binding on a Vue component (e.g. `bento-button` or `bento-popover`) rather than a native HTML
|
|
90
|
+
> element, `v-on` with object syntax does not attach the listeners to the underlying DOM element — the `.native`
|
|
91
|
+
> modifier is required for that, and it cannot be combined with the object form of `v-on`. To work around this, either
|
|
92
|
+
> wrap the component in a native element and use `v-on="hoverEvents"` on the wrapper, or break the object up and bind
|
|
93
|
+
> the handlers individually with `.native`. Neither workaround is needed in Vue 3, where listeners on a component
|
|
94
|
+
> automatically fall through to the root element.
|
|
95
|
+
|
|
96
|
+
<Source
|
|
97
|
+
format={'html'}
|
|
98
|
+
dark
|
|
99
|
+
code={`
|
|
100
|
+
<!-- Option A: wrap in a native element -->
|
|
101
|
+
<span v-on="hoverEvents" tabindex="0">
|
|
102
|
+
<bento-tag ref="triggerRef" label="Hover me" />
|
|
103
|
+
</span>
|
|
104
|
+
|
|
105
|
+
<!-- Option B: bind events individually with .native -->
|
|
106
|
+
|
|
107
|
+
<bento-tag ref="triggerRef" label="Hover me" tabindex="0" @mouseenter.native="open" @mouseleave.native="close"
|
|
108
|
+
@focusin.native="open" @focusout.native="close" /> `} />
|
|
109
|
+
|
|
51
110
|
## Accessibility 🚧
|
|
52
111
|
|
|
53
112
|
NOTE: The focus trap within the popover does not function as it should right now, this issue is currently being worked
|
|
@@ -71,12 +130,12 @@ documentation provided.
|
|
|
71
130
|
|
|
72
131
|
#### Please note that:
|
|
73
132
|
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
|
|
133
|
+
- The element that shows and hides the content has role button, e.g. use the `BentoButton` component.
|
|
134
|
+
- When the Popover is visible, the element with role button has `aria-expanded` set to `true`. When the content area is
|
|
135
|
+
hidden, it is set to `false`.
|
|
136
|
+
- When the Popover is visible, the popover needs to be identified by an `id` and the trigger element with role button
|
|
137
|
+
needs to have `aria-controls` set to the popover `id`. When the popover is hidden, the `aria-controls` attribute needs
|
|
138
|
+
to be set to `null`.
|
|
80
139
|
|
|
81
140
|
| ARIA attribute | is automatic? | fallback used | manual override |
|
|
82
141
|
| --------------- | ------------------------------------------------------------------------ | ------------- | --------------- |
|
|
@@ -86,4 +145,4 @@ documentation provided.
|
|
|
86
145
|
|
|
87
146
|
## Resources
|
|
88
147
|
|
|
89
|
-
-
|
|
148
|
+
- [Figma link](https://www.figma.com/file/uLabwF3243jdMDsNSP7U9I/branch/xxUamzpDM5NlukATVD9JFT/Bento---Components?type=design&node-id=1913%3A27764&mode=design&t=cY18II3hTxXGJeoI-1)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { onMounted, ref, watch } from 'vue'; import { isVue2 } from 'vue-demi'; import { type Meta, type StoryObj } from '@storybook/vue'; import { storybookDocsParameter } from '../../utils/ts/storybook'; import { action } from '@storybook/addon-actions'; import { BentoButton, BentoButtonActionsLayoutBasic } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { BentoPopoverImage } from './components/popover-image'; import BentoPopover from './popover.vue'; import InfoFilledIcon from '@adyen/ui-assets-icons-16/vue/info-filled'; import { BentoPopoverPositions } from './popover.types'; import { popoverImageSrcStub } from '../../__tests__/img-stub.json'; import './popover.stories.scss?module'; const DEFAULT_TEXT = 'Add your text here'; const TITLE_TEXT = 'Title'; const IMAGE_SRC = popoverImageSrcStub; const IMAGE_ALT = 'Example image'; const ID = 'popover-id'; const ACTIONS = [ { title: 'Primary', event: () => action('Primary')(), }, { title: 'Secondary', event: () => action('Secondary')(), }, ]; const DEFAULT_PROPS = { position: 'bottom-start', disableFocusTrap: true, default: DEFAULT_TEXT, }; export default { title: 'Popover', component: BentoPopover, parameters: { layout: 'centered', }, argTypes: { // Slots default: { defaultValue: '', description: 'Popover content', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text' }, }, headerIcon: { defaultValue: '', description: 'Vue Icon from the library @adyen/ui-assets-icons-16.', table: { type: { summary: 'VNode[]' }, }, control: { disable: true }, }, image: { defaultValue: '', description: 'Popover image container', table: { type: { summary: 'BentoPopoverImage' }, }, control: { disable: true }, }, // Enum props actionsLayout: { options: Object.values(BentoButtonActionsLayoutBasic), mapping: BentoButtonActionsLayoutBasic, control: { type: 'select', }, }, position: { options: Object.values(BentoPopoverPositions), mapping: BentoPopoverPositions, control: { type: 'select', }, }, }, } as Meta; type Story = StoryObj<typeof BentoPopover>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoTypography, }, props: Object.keys(argTypes), template: ` <div class="b-popover-story--default"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @placement="onPlacementUpdate" > <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); const onPlacementUpdate = action('placement'); return { // Values args, isOpen, targetElement, // Methods onPlacementUpdate, show, togglePopover, }; }, }), args: { ...DEFAULT_PROPS, id: ID }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" position="bottom-start" :targetElement="targetElement" > <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), }; export const WithHeader: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoTypography, InfoFilledIcon, }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); const dismissPopover = () => { action('dismiss')(); isOpen.value = false; }; onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); return { // Values args, isOpen, targetElement, // Methods togglePopover, show, dismissPopover, }; }, template: ` <div class="b-popover-story--with-header"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @dismiss="dismissPopover" > <template #headerIcon> <info-filled-icon /> </template> <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, }), args: { ...DEFAULT_PROPS, title: TITLE_TEXT, id: ID }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" title="${TITLE_TEXT}" position="bottom-start" :targetElement="targetElement" @dismiss="dismissPopover" > <template #headerIcon> <info-filled-icon /> </template> <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), }; export const WithActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoTypography, InfoFilledIcon, }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); const dismissPopover = () => { action('dismiss')(); isOpen.value = false; }; onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); return { // Values args, isOpen, targetElement, // Methods togglePopover, show, dismissPopover, }; }, template: ` <div class="b-popover-story--with-actions"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @dismiss="dismissPopover" > <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, }), args: { ...DEFAULT_PROPS, title: TITLE_TEXT, actions: ACTIONS, id: ID, }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" title="${TITLE_TEXT}" :actions="[ { title: 'Primary', event: () => action('Primary')(), }, { title: 'Secondary', event: () => action('Secondary')(), }, ]" position="bottom-start" :targetElement="targetElement" @dismiss="dismissPopover" > <template #headerIcon> <info-filled-icon /> </template> <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), }; export const WithImage: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoPopoverImage, BentoTypography, InfoFilledIcon, }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); const dismissPopover = () => { action('dismiss')(); isOpen.value = false; }; onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); return { // Values args, isOpen, targetElement, // Methods togglePopover, show, dismissPopover, }; }, template: ` <div class="b-popover-story--with-image"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @dismiss="dismissPopover" > <template #image> <bento-popover-image src="${IMAGE_SRC}" alt="${IMAGE_ALT}" /> </template> <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, }), args: { ...DEFAULT_PROPS, title: TITLE_TEXT, actions: ACTIONS, id: ID, }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" title="${TITLE_TEXT}" :actions="[ { title: 'Primary', event: () => action('Primary')(), }, { title: 'Secondary', event: () => action('Secondary')(), }, ]" position="bottom-start" :targetElement="targetElement" @dismiss="dismissPopover" > <template #image> <bento-popover-image src="${IMAGE_SRC}" alt="${IMAGE_ALT}" /> </template> <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), };
|
|
1
|
+
import { onMounted, ref, watch } from 'vue'; import { isVue2 } from 'vue-demi'; import { type Meta, type StoryObj } from '@storybook/vue'; import { storybookDocsParameter } from '../../utils/ts/storybook'; import { action } from '@storybook/addon-actions'; import { BentoButton, BentoButtonActionsLayoutBasic } from '@/components/button'; import { BentoLink } from '@/components/link'; import { BentoTag } from '@/components/tag'; import { BentoTypography } from '@/components/typography'; import { useBentoDelayedHover } from '@/composables'; import { BentoPopoverImage } from './components/popover-image'; import BentoPopover from './popover.vue'; import InfoFilledIcon from '@adyen/ui-assets-icons-16/vue/info-filled'; import { BentoPopoverPositions } from './popover.types'; import { popoverImageSrcStub } from '../../__tests__/img-stub.json'; import BentoDelayedHoverExample from '@/composables/use-bento-delayed-hover/__tests__/use-bento-delayed-hover-example.vue?raw'; import './popover.stories.scss?module'; const DEFAULT_TEXT = 'Add your text here'; const TITLE_TEXT = 'Title'; const IMAGE_SRC = popoverImageSrcStub; const IMAGE_ALT = 'Example image'; const ID = 'popover-id'; const ACTIONS = [ { title: 'Primary', event: () => action('Primary')(), }, { title: 'Secondary', event: () => action('Secondary')(), }, ]; const DEFAULT_PROPS = { position: 'bottom-start', disableFocusTrap: true, default: DEFAULT_TEXT, }; export default { title: 'Popover', component: BentoPopover, parameters: { layout: 'centered', }, argTypes: { // Slots default: { defaultValue: '', description: 'Popover content', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text' }, }, headerIcon: { defaultValue: '', description: 'Vue Icon from the library @adyen/ui-assets-icons-16.', table: { type: { summary: 'VNode[]' }, }, control: { disable: true }, }, image: { defaultValue: '', description: 'Popover image container', table: { type: { summary: 'BentoPopoverImage' }, }, control: { disable: true }, }, // Enum props actionsLayout: { options: Object.values(BentoButtonActionsLayoutBasic), mapping: BentoButtonActionsLayoutBasic, control: { type: 'select', }, }, position: { options: Object.values(BentoPopoverPositions), mapping: BentoPopoverPositions, control: { type: 'select', }, }, }, } as Meta; type Story = StoryObj<typeof BentoPopover>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoTypography, }, props: Object.keys(argTypes), template: ` <div class="b-popover-story--default"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @placement="onPlacementUpdate" > <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); const onPlacementUpdate = action('placement'); return { // Values args, isOpen, targetElement, // Methods onPlacementUpdate, show, togglePopover, }; }, }), args: { ...DEFAULT_PROPS, id: ID }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" position="bottom-start" :targetElement="targetElement" > <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), }; export const WithHeader: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoTypography, InfoFilledIcon, }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); const dismissPopover = () => { action('dismiss')(); isOpen.value = false; }; onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); return { // Values args, isOpen, targetElement, // Methods togglePopover, show, dismissPopover, }; }, template: ` <div class="b-popover-story--with-header"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @dismiss="dismissPopover" > <template #headerIcon> <info-filled-icon /> </template> <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, }), args: { ...DEFAULT_PROPS, title: TITLE_TEXT, id: ID }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" title="${TITLE_TEXT}" position="bottom-start" :targetElement="targetElement" @dismiss="dismissPopover" > <template #headerIcon> <info-filled-icon /> </template> <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), }; export const WithActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoTypography, InfoFilledIcon, }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); const dismissPopover = () => { action('dismiss')(); isOpen.value = false; }; onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); return { // Values args, isOpen, targetElement, // Methods togglePopover, show, dismissPopover, }; }, template: ` <div class="b-popover-story--with-actions"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @dismiss="dismissPopover" > <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, }), args: { ...DEFAULT_PROPS, title: TITLE_TEXT, actions: ACTIONS, id: ID, }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" title="${TITLE_TEXT}" :actions="[ { title: 'Primary', event: () => action('Primary')(), }, { title: 'Secondary', event: () => action('Secondary')(), }, ]" position="bottom-start" :targetElement="targetElement" @dismiss="dismissPopover" > <template #headerIcon> <info-filled-icon /> </template> <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), }; export const OnHover: Story = { render: (_args, { argTypes }) => ({ components: { BentoLink, BentoPopover, BentoTag, BentoTypography, }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const triggerElement = ref(null); const { isOpen, open, close, hoverEvents } = useBentoDelayedHover(); return { args, isOpen, open, close, triggerElement, hoverEvents, }; }, template: ` <div class="b-popover-story--on-hover"> <bento-tag ref="triggerElement" label="Hover over me" tabindex="0" :aria-expanded="isOpen.toString()" aria-controls="${ID}" @mouseenter.native="open" @mouseleave.native="close" @focusin.native="open" @focusout.native="close" /> <span v-on="hoverEvents"> <bento-popover v-if="triggerElement" :open="isOpen" v-bind="args" :target-element="triggerElement" role="tooltip" disable-focus-trap > <bento-typography el="span"> {{ args.default }} <bento-link to="https://www.adyen.com/" external> Learn more here </bento-link> </bento-typography> </bento-popover> </span> </div> `, }), args: { ...DEFAULT_PROPS, id: ID }, parameters: storybookDocsParameter(BentoDelayedHoverExample), }; export const WithImage: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton, BentoPopover, BentoPopoverImage, BentoTypography, InfoFilledIcon, }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const isOpen = ref(false); const targetElement = ref(null); const togglePopover = () => { isOpen.value = !isOpen.value; }; watch( () => args.open, (val: boolean) => { isOpen.value = val; } ); const show = () => action('input'); const dismissPopover = () => { action('dismiss')(); isOpen.value = false; }; onMounted(() => (isOpen.value = args.open === undefined ? true : args.open)); return { // Values args, isOpen, targetElement, // Methods togglePopover, show, dismissPopover, }; }, template: ` <div class="b-popover-story--with-image"> <bento-popover v-if="targetElement" :open="isOpen" v-bind="args" :targetElement="targetElement" @dismiss="dismissPopover" > <template #image> <bento-popover-image src="${IMAGE_SRC}" alt="${IMAGE_ALT}" /> </template> <bento-typography el="span"> {{args.default}} </bento-typography> </bento-popover> <bento-button ref="targetElement" @click="togglePopover" :aria-expanded="isOpen" aria-controls="${ID}" > Open popover </bento-button> </div> `, }), args: { ...DEFAULT_PROPS, title: TITLE_TEXT, actions: ACTIONS, id: ID, }, parameters: storybookDocsParameter(` <div> <bento-popover v-if="targetElement" id="${ID}" :open="isOpen" title="${TITLE_TEXT}" :actions="[ { title: 'Primary', event: () => action('Primary')(), }, { title: 'Secondary', event: () => action('Secondary')(), }, ]" position="bottom-start" :targetElement="targetElement" @dismiss="dismissPopover" > <template #image> <bento-popover-image src="${IMAGE_SRC}" alt="${IMAGE_ALT}" /> </template> <bento-typography el="span"> ${DEFAULT_TEXT} </bento-typography> </bento-popover> <bento-button ref="targetElement" :aria-expanded="isOpen" @click="togglePopover" aria-controls="${ID}" > Open popover </bento-button> </div> `), };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { type GridLayoutColumnWidth } from '@/internal'; import type { BentoSelectionCardItem, BentoSelectionCardModelValue } from '
|
|
1
|
+
import { type GridLayoutColumnWidth } from '@/internal'; import type { BentoSelectionCardItem, BentoSelectionCardModelValue } from '../../selection-card.types'; import { type FormField, type FormFieldEmits } from '../../../../types/form-field'; export type BentoSelectionCardGroupVariant = 'checkbox' | 'radio'; export type BentoSelectionCardGroupLayout = 'horizontal' | 'vertical'; export type BentoSelectionCardGroupItemsPerRow = GridLayoutColumnWidth; export type BentoSelectionCardGroupEmits = FormFieldEmits<BentoSelectionCardModelValue>; export interface BentoSelectionCardGroupProps extends FormField { /** * The form id the selection card group is associated with. Defaults to null, as a selection card group can also be * used standalone. * @default null */ formId?: string; /** * Shows/hides the group label. * @default null */ hideLabel?: boolean; /** * The selection card group's layout. It can be vertical or horizontal. Defaults to vertical. * @values horizontal, vertical * @default vertical */ layout?: BentoSelectionCardGroupLayout; /** * The selection card group's items. */ items: Array<BentoSelectionCardItem>; /** * Sets the responsive number of items rendered in each row. * @default undefined */ itemsPerRow?: BentoSelectionCardGroupItemsPerRow; /** * Determines the initially selected value of the group. Corresponds to the BentoSelectionCardItem's value. * @default null */ modelValue?: BentoSelectionCardModelValue; /** * Renders the cards with a checkbox or a radio input. Selection logic will also apply in accordance. * @values checkbox, radio * @default checkbox */ variant?: BentoSelectionCardGroupVariant; }
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Canvas, Meta, Source } from '@storybook/blocks';
|
|
2
|
+
import * as useBentoDelayedHoverStories from './use-bento-delayed-hover.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={useBentoDelayedHoverStories} />
|
|
5
|
+
|
|
6
|
+
# useBentoDelayedHover
|
|
7
|
+
|
|
8
|
+
A composable that provides the logic to open and close an element on hover and focus with a closing delay.
|
|
9
|
+
|
|
10
|
+
<Canvas of={useBentoDelayedHoverStories.Default} />
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
`useBentoDelayedHover` returns an object with:
|
|
15
|
+
|
|
16
|
+
- `isOpen` — a `ref<boolean>` tracking the open state.
|
|
17
|
+
- `open` / `close` — individual handlers to open or close immediately / after the delay.
|
|
18
|
+
- `hoverEvents` — an object bundling `mouseenter`, `mouseleave`, `focusin`, and `focusout` handlers, ready to be spread
|
|
19
|
+
with `v-on`.
|
|
20
|
+
|
|
21
|
+
Bind `hoverEvents` on the trigger element:
|
|
22
|
+
|
|
23
|
+
<Source
|
|
24
|
+
format={'html'}
|
|
25
|
+
dark
|
|
26
|
+
code={`
|
|
27
|
+
<span ref="triggerRef" v-on="hoverEvents">Hover me</span>
|
|
28
|
+
`}
|
|
29
|
+
/>
|
|
30
|
+
|
|
31
|
+
When the content is **not** a descendant of the trigger (e.g. rendered as a sibling or teleported elsewhere in the DOM),
|
|
32
|
+
also bind `hoverEvents` on a wrapper around the content so that hovering or focusing it cancels the pending close:
|
|
33
|
+
|
|
34
|
+
<Source
|
|
35
|
+
format={'html'}
|
|
36
|
+
dark
|
|
37
|
+
code={`
|
|
38
|
+
<span ref="triggerRef" v-on="hoverEvents">Hover me</span>
|
|
39
|
+
|
|
40
|
+
<span v-on="hoverEvents">
|
|
41
|
+
<bento-popover :open="isOpen" :target-element="triggerRef">
|
|
42
|
+
Popover content
|
|
43
|
+
</bento-popover>
|
|
44
|
+
</span>
|
|
45
|
+
`}
|
|
46
|
+
/>
|
|
47
|
+
|
|
48
|
+
> **Vue 2 only:** `v-on` with object syntax does not attach listeners to the underlying DOM element of a Vue component —
|
|
49
|
+
> the `.native` modifier is required, but it cannot be combined with the object form of `v-on`. Either wrap the
|
|
50
|
+
> component in a native element and use `v-on="hoverEvents"` on the wrapper, or bind the handlers individually with
|
|
51
|
+
> `.native`:
|
|
52
|
+
|
|
53
|
+
<Source
|
|
54
|
+
format={'html'}
|
|
55
|
+
dark
|
|
56
|
+
code={`
|
|
57
|
+
<!-- Option A: wrap in a native element -->
|
|
58
|
+
<span v-on="hoverEvents" tabindex="0">
|
|
59
|
+
<bento-tag ref="triggerRef" label="Hover me" />
|
|
60
|
+
</span>
|
|
61
|
+
|
|
62
|
+
<!-- Option B: bind events individually with .native -->
|
|
63
|
+
|
|
64
|
+
<bento-tag ref="triggerRef" label="Hover me" tabindex="0" @mouseenter.native="open" @mouseleave.native="close"
|
|
65
|
+
@focusin.native="open" @focusout.native="close" /> `} />
|
|
66
|
+
|
|
67
|
+
## Delay
|
|
68
|
+
|
|
69
|
+
A small closing delay (200 ms by default) is applied when the cursor or focus leaves the trigger. This prevents the
|
|
70
|
+
content from flickering when the user moves between the trigger and the content. The delay can be customised by passing
|
|
71
|
+
a value in milliseconds:
|
|
72
|
+
|
|
73
|
+
<Source language={'ts'} dark code={`const { isOpen, open, close, hoverEvents } = useBentoDelayedHover(400);`} />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue'; import { ref } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { BentoLink } from '@/components/link'; import { BentoPopover } from '@/components/popover'; import { BentoTag } from '@/components/tag'; import { BentoTypography } from '@/components/typography'; import { useBentoDelayedHover } from './use-bento-delayed-hover'; import UseBentoDelayedHoverExample from './__tests__/use-bento-delayed-hover-example.vue?raw'; const meta: Meta = { title: 'useBentoDelayedHover', }; export default meta; export const Default: StoryObj = { render: () => ({ components: { BentoLink, BentoPopover, BentoTag, BentoTypography }, setup() { const triggerElement = ref(null); const { isOpen, open, close, hoverEvents } = useBentoDelayedHover(); return { isOpen, open, close, triggerElement, hoverEvents }; }, template: ` <div> <bento-tag ref="triggerElement" label="Hover over me" tabindex="0" :aria-expanded="isOpen.toString()" aria-controls="delayed-hover-popover" @mouseenter.native="open" @mouseleave.native="close" @focusin.native="open" @focusout.native="close" /> <span v-on="hoverEvents"> <bento-popover v-if="triggerElement" id="delayed-hover-popover" :open="isOpen" :target-element="triggerElement" role="tooltip" disable-focus-trap > <bento-typography el="span"> Add your text here <bento-link to="https://www.adyen.com/" external>Learn more here</bento-link> </bento-typography> </bento-popover> </span> </div> `, }), parameters: storybookDocsParameter(UseBentoDelayedHoverExample), };
|
package/dist/assets/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import BentoVue from './install'; export * from './components/accordion'; export * from './components/action-bar'; export * from './components/ai-tag'; export * from './components/alert'; export * from './components/anchor-scroller'; export * from './components/avatar'; export * from './components/button'; export * from './components/dashed-underline'; export * from './components/data-grid'; export * from './components/card'; export * from './components/date-picker'; export * from './components/date-range-picker'; export * from './components/draggable'; export * from './components/draggable/components/draggable-handle'; export * from './components/drawer'; export * from './components/dropdown'; export * from './components/checkbox'; export * from './components/chip'; export * from './components/click-outside'; export * from './components/code-snippet'; export * from './components/country'; export * from './components/currency'; export * from './components/date'; export * from './components/divider'; export * from './components/empty-state'; export * from './components/file-uploader'; export * from './components/filter-bar'; export * from './components/form-layout'; export * from './components/header-with-views'; export * from './components/image'; export * from './components/info-icon'; export * from './components/input-field'; export * from './components/input-field-password'; export * from './components/input-field-phone-number'; export * from './components/input-time'; export * from './components/inspector'; export * from './components/layout'; export * from './components/list'; export * from './components/loading-indicator'; export * from './components/link'; export * from './components/menu'; export * from './components/modal'; export * from './components/modal-fullscreen'; export * from './components/navigation-menu'; export * from './components/header'; export * from './components/pagination'; export * from './components/payment-method'; export * from './components/popover'; export * from './components/promo-banner'; export * from './components/radio-group'; export * from './components/rich-text-editor'; export * from './components/search-bar'; export * from './components/secondary-nav'; export * from './components/selection-card'; export * from './components/segmented-control'; export * from './components/sidepanel'; export * from './components/status'; export * from './components/stepper'; export * from './components/structured-list'; export * from './components/summary-grid'; export * from './components/tabs'; export * from './components/tag'; export * from './components/textarea'; export * from './components/timeline'; export * from './components/toast'; export * from './components/toggle'; export * from './components/tutorial'; export * from './components/typography'; // Export Composables export * from './composables/use-bento-base-filter'; export * from './composables/use-bento-currency'; export * from './composables/use-bento-theme'; export * from './composables/use-bento-toast-controller'; export * from './composables/use-click-outside'; export * from './composables/use-form-validate'; // Export Templates export * from './templates/dashboard-template'; export * from './templates/data-grid-template'; // Export Types export * from './types'; // Export Directives export * from './directives'; // AdlVue Plugin export default BentoVue; export { BentoTheme } from './install';
|
|
1
|
+
import BentoVue from './install'; export * from './components/accordion'; export * from './components/action-bar'; export * from './components/ai-tag'; export * from './components/alert'; export * from './components/anchor-scroller'; export * from './components/avatar'; export * from './components/button'; export * from './components/dashed-underline'; export * from './components/data-grid'; export * from './components/card'; export * from './components/date-picker'; export * from './components/date-range-picker'; export * from './components/date-time-picker'; export * from './components/draggable'; export * from './components/draggable/components/draggable-handle'; export * from './components/drawer'; export * from './components/dropdown'; export * from './components/checkbox'; export * from './components/chip'; export * from './components/click-outside'; export * from './components/code-snippet'; export * from './components/country'; export * from './components/currency'; export * from './components/date'; export * from './components/divider'; export * from './components/empty-state'; export * from './components/file-uploader'; export * from './components/filter-bar'; export * from './components/form-layout'; export * from './components/header-with-views'; export * from './components/image'; export * from './components/info-icon'; export * from './components/input-field'; export * from './components/input-field-password'; export * from './components/input-field-phone-number'; export * from './components/input-time'; export * from './components/inspector'; export * from './components/layout'; export * from './components/list'; export * from './components/loading-indicator'; export * from './components/link'; export * from './components/menu'; export * from './components/modal'; export * from './components/modal-fullscreen'; export * from './components/navigation-menu'; export * from './components/header'; export * from './components/pagination'; export * from './components/payment-method'; export * from './components/popover'; export * from './components/promo-banner'; export * from './components/radio-group'; export * from './components/rich-text-editor'; export * from './components/search-bar'; export * from './components/secondary-nav'; export * from './components/selection-card'; export * from './components/segmented-control'; export * from './components/sidepanel'; export * from './components/status'; export * from './components/stepper'; export * from './components/structured-list'; export * from './components/summary-grid'; export * from './components/tabs'; export * from './components/tag'; export * from './components/textarea'; export * from './components/timeline'; export * from './components/toast'; export * from './components/toggle'; export * from './components/tutorial'; export * from './components/typography'; // Export Composables export * from './composables/use-bento-base-filter'; export * from './composables/use-bento-currency'; export * from './composables/use-bento-theme'; export * from './composables/use-bento-toast-controller'; export * from './composables/use-click-outside'; export * from './composables/use-form-validate'; export * from './composables/use-bento-delayed-hover'; // Export Templates export * from './templates/dashboard-template'; export * from './templates/data-grid-template'; // Export Types export * from './types'; // Export Directives export * from './directives'; // AdlVue Plugin export default BentoVue; export { BentoTheme } from './install';
|