@nexxtmove/ui 2.6.0 → 2.8.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/editor/molecules/EditorColor/EditorColor.vue.d.ts +7 -5
- package/dist/components/editor/molecules/EditorColor/_ColorField.vue.d.ts +4 -1
- package/dist/components/organisms/ColorPicker/ColorPicker.vue.d.ts +3 -1
- package/dist/index.js +95 -172
- package/dist/nuxt.js +0 -1
- package/package.json +38 -36
- package/src/attribute-contract.test.ts +151 -0
- package/src/components/atoms/AnimatedNumber/AnimatedNumber.stories.ts +36 -0
- package/src/components/atoms/AnimatedNumber/AnimatedNumber.test.ts +21 -0
- package/src/components/atoms/Avatar/Avatar.stories.ts +122 -0
- package/src/components/atoms/Avatar/Avatar.test.ts +134 -0
- package/src/components/atoms/Button/Button.stories.ts +290 -0
- package/src/components/atoms/Button/Button.test.ts +406 -0
- package/src/components/atoms/Card/Card.stories.ts +45 -0
- package/src/components/atoms/Card/Card.test.ts +46 -0
- package/src/components/atoms/Checkbox/Checkbox.stories.ts +35 -0
- package/src/components/atoms/Checkbox/Checkbox.test.ts +55 -0
- package/src/components/atoms/Chip/Chip.stories.ts +274 -0
- package/src/components/atoms/Chip/Chip.test.ts +230 -0
- package/src/components/atoms/EnergyLabel/EnergyLabel.stories.ts +189 -0
- package/src/components/atoms/EnergyLabel/EnergyLabel.test.ts +100 -0
- package/src/components/atoms/FloatingPanel/FloatingPanel.stories.ts +677 -0
- package/src/components/atoms/FloatingPanel/FloatingPanel.test.ts +864 -0
- package/src/components/atoms/Icon/Icon.stories.ts +63 -0
- package/src/components/atoms/Icon/Icon.test.ts +89 -0
- package/src/components/atoms/Loader/Loader.stories.ts +36 -0
- package/src/components/atoms/Loader/Loader.test.ts +40 -0
- package/src/components/atoms/PickerItem/PickerItem.stories.ts +172 -0
- package/src/components/atoms/PickerItem/PickerItem.test.ts +142 -0
- package/src/components/atoms/PickerPreview/PickerPreview.stories.ts +183 -0
- package/src/components/atoms/PickerPreview/PickerPreview.test.ts +137 -0
- package/src/components/atoms/PresenceIndicator/PresenceIndicator.stories.ts +21 -0
- package/src/components/atoms/PropertyListing/PropertyListing.stories.ts +38 -0
- package/src/components/atoms/PropertyListing/PropertyListing.test.ts +46 -0
- package/src/components/atoms/SelectableOption/SelectableOption.stories.ts +131 -0
- package/src/components/atoms/SelectableOption/SelectableOption.test.ts +96 -0
- package/src/components/atoms/Skeleton/Skeleton.stories.ts +27 -0
- package/src/components/atoms/Skeleton/Skeleton.test.ts +28 -0
- package/src/components/atoms/Slider/Slider.stories.ts +151 -0
- package/src/components/atoms/Slider/Slider.test.ts +191 -0
- package/src/components/atoms/Squircle/Squircle.stories.ts +114 -0
- package/src/components/atoms/Squircle/Squircle.test.ts +70 -0
- package/src/components/atoms/Switch/Switch.stories.ts +91 -0
- package/src/components/atoms/Switch/Switch.test.ts +183 -0
- package/src/components/atoms/Tooltip/Tooltip.stories.ts +158 -0
- package/src/components/atoms/Tooltip/Tooltip.test.ts +134 -0
- package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.stories.ts +124 -0
- package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.test.ts +464 -0
- package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.stories.ts +266 -0
- package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.test.ts +421 -0
- package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.stories.ts +365 -0
- package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.test.ts +484 -0
- package/src/components/editor/composables/useRadioGrid.test.ts +261 -0
- package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.stories.ts +73 -0
- package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.test.ts +189 -0
- package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.stories.ts +309 -0
- package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.test.ts +359 -0
- package/src/components/editor/molecules/EditorAnchor/EditorAnchor.stories.ts +138 -0
- package/src/components/editor/molecules/EditorAnchor/EditorAnchor.test.ts +344 -0
- package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.stories.ts +87 -0
- package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.test.ts +262 -0
- package/src/components/editor/molecules/EditorBlur/EditorBlur.stories.ts +115 -0
- package/src/components/editor/molecules/EditorBlur/EditorBlur.test.ts +243 -0
- package/src/components/editor/molecules/EditorBorder/EditorBorder.stories.ts +187 -0
- package/src/components/editor/molecules/EditorBorder/EditorBorder.test.ts +456 -0
- package/src/components/editor/molecules/EditorColor/EditorColor.stories.ts +633 -0
- package/src/components/editor/molecules/EditorColor/EditorColor.test.ts +776 -0
- package/src/components/editor/molecules/EditorColor/EditorColor.vue +7 -5
- package/src/components/editor/molecules/EditorColor/EditorColorGradient.test.ts +832 -0
- package/src/components/editor/molecules/EditorColor/_ColorField.vue +20 -15
- package/src/components/editor/molecules/EditorColor/gradientClass.test.ts +303 -0
- package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.stories.ts +72 -0
- package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.test.ts +124 -0
- package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.stories.ts +46 -0
- package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.test.ts +97 -0
- package/src/components/editor/molecules/EditorFontSize/EditorFontSize.stories.ts +248 -0
- package/src/components/editor/molecules/EditorFontSize/EditorFontSize.test.ts +288 -0
- package/src/components/editor/molecules/EditorGap/EditorGap.stories.ts +129 -0
- package/src/components/editor/molecules/EditorGap/EditorGap.test.ts +253 -0
- package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.stories.ts +68 -0
- package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.test.ts +150 -0
- package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.stories.ts +71 -0
- package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.test.ts +161 -0
- package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.stories.ts +204 -0
- package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.test.ts +238 -0
- package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.stories.ts +257 -0
- package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.test.ts +286 -0
- package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.stories.ts +135 -0
- package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.test.ts +230 -0
- package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.stories.ts +154 -0
- package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.test.ts +112 -0
- package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.stories.ts +206 -0
- package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.test.ts +332 -0
- package/src/components/editor/molecules/EditorPadding/EditorPadding.stories.ts +374 -0
- package/src/components/editor/molecules/EditorPadding/EditorPadding.test.ts +712 -0
- package/src/components/editor/molecules/EditorRadius/EditorRadius.stories.ts +64 -0
- package/src/components/editor/molecules/EditorRadius/EditorRadius.test.ts +137 -0
- package/src/components/editor/molecules/EditorShadow/EditorShadow.stories.ts +103 -0
- package/src/components/editor/molecules/EditorShadow/EditorShadow.test.ts +168 -0
- package/src/components/editor/molecules/EditorSize/EditorSize.stories.ts +84 -0
- package/src/components/editor/molecules/EditorSize/EditorSize.test.ts +253 -0
- package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.stories.ts +49 -0
- package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.test.ts +43 -0
- package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.stories.ts +69 -0
- package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.test.ts +155 -0
- package/src/components/molecules/Announcement/Announcement.stories.ts +224 -0
- package/src/components/molecules/Announcement/Announcement.test.ts +161 -0
- package/src/components/molecules/ContactInfoCard/ContactInfoCard.stories.ts +99 -0
- package/src/components/molecules/ContactInfoCard/ContactInfoCard.test.ts +70 -0
- package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.stories.ts +148 -0
- package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.test.ts +271 -0
- package/src/components/molecules/DoughnutChart/DoughnutChart.stories.ts +45 -0
- package/src/components/molecules/DoughnutChart/DoughnutChart.test.ts +205 -0
- package/src/components/molecules/InfoBlock/InfoBlock.stories.ts +84 -0
- package/src/components/molecules/InfoBlock/InfoBlock.test.ts +101 -0
- package/src/components/molecules/InputField/InputField.stories.ts +117 -0
- package/src/components/molecules/InputField/InputField.test.ts +138 -0
- package/src/components/molecules/InputSelect/InputSelect.stories.ts +116 -0
- package/src/components/molecules/InputSelect/InputSelect.test.ts +127 -0
- package/src/components/molecules/ModalFooter/ModalFooter.stories.ts +204 -0
- package/src/components/molecules/ModalFooter/ModalFooter.test.ts +276 -0
- package/src/components/molecules/PageCard/PageCard.stories.ts +100 -0
- package/src/components/molecules/PageCard/PageCard.test.ts +91 -0
- package/src/components/molecules/PageContainer/PageContainer.stories.ts +90 -0
- package/src/components/molecules/PageContainer/PageContainer.test.ts +50 -0
- package/src/components/molecules/PageMockup/PageMockup.stories.ts +38 -0
- package/src/components/molecules/PageMockup/PageMockup.test.ts +20 -0
- package/src/components/molecules/PageTypeTile/PageTypeTile.stories.ts +63 -0
- package/src/components/molecules/PageTypeTile/PageTypeTile.test.ts +41 -0
- package/src/components/molecules/Pagination/Pagination.stories.ts +72 -0
- package/src/components/molecules/Pagination/Pagination.test.ts +130 -0
- package/src/components/molecules/PickerGroup/PickerGroup.stories.ts +90 -0
- package/src/components/molecules/PickerGroup/PickerGroup.test.ts +145 -0
- package/src/components/molecules/PickerList/PickerList.stories.ts +436 -0
- package/src/components/molecules/PickerList/PickerList.test.ts +870 -0
- package/src/components/molecules/PlaceholderInput/PlaceholderInput.stories.ts +48 -0
- package/src/components/molecules/PlaceholderInput/PlaceholderInput.test.ts +107 -0
- package/src/components/molecules/PropertyCard/PropertyCard.stories.ts +46 -0
- package/src/components/molecules/PropertyCard/PropertyCard.test.ts +59 -0
- package/src/components/molecules/Select/Select.stories.ts +264 -0
- package/src/components/molecules/Select/Select.test.ts +315 -0
- package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.stories.ts +84 -0
- package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.test.ts +103 -0
- package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.stories.ts +11 -0
- package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.test.ts +38 -0
- package/src/components/molecules/SocialIcons/SocialIcons.stories.ts +28 -0
- package/src/components/molecules/SocialIcons/SocialIcons.test.ts +58 -0
- package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.stories.ts +11 -0
- package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.test.ts +116 -0
- package/src/components/molecules/SocialMediaType/SocialMediaType.stories.ts +37 -0
- package/src/components/molecules/SocialMediaType/SocialMediaType.test.ts +126 -0
- package/src/components/molecules/Source/Source.stories.ts +35 -0
- package/src/components/molecules/Source/Source.test.ts +45 -0
- package/src/components/molecules/TabbedContent/TabbedContent.stories.ts +96 -0
- package/src/components/molecules/TabbedContent/TabbedContent.test.ts +109 -0
- package/src/components/molecules/Tabs/Tabs.stories.ts +230 -0
- package/src/components/molecules/Tabs/Tabs.test.ts +280 -0
- package/src/components/molecules/TemplateCard/TemplateCard.stories.ts +327 -0
- package/src/components/molecules/TemplateCard/TemplateCard.test.ts +339 -0
- package/src/components/molecules/Textarea/Textarea.stories.ts +216 -0
- package/src/components/molecules/Textarea/Textarea.test.ts +191 -0
- package/src/components/molecules/TimelineEvent/TimelineEvent.stories.ts +319 -0
- package/src/components/molecules/TimelineEvent/TimelineEvent.test.ts +224 -0
- package/src/components/molecules/TimelineLanes/TimelineLanes.stories.ts +29 -0
- package/src/components/molecules/TimelineLanes/TimelineLanes.test.ts +30 -0
- package/src/components/molecules/Toast/Toast.stories.ts +110 -0
- package/src/components/molecules/Toast/Toast.test.ts +103 -0
- package/src/components/molecules/ToggleGroup/ToggleGroup.stories.ts +297 -0
- package/src/components/molecules/ToggleGroup/ToggleGroup.test.ts +578 -0
- package/src/components/molecules/Tree/Tree.stories.ts +884 -0
- package/src/components/molecules/Tree/Tree.test.ts +1247 -0
- package/src/components/molecules/Tree/tree-drop.test.ts +223 -0
- package/src/components/organisms/Calendar/Calendar.stories.ts +108 -0
- package/src/components/organisms/Calendar/Calendar.test.ts +279 -0
- package/src/components/organisms/Calendar/_CalendarDayView.test.ts +104 -0
- package/src/components/organisms/Calendar/_CalendarHeader.test.ts +86 -0
- package/src/components/organisms/Calendar/_CalendarMonthView.test.ts +52 -0
- package/src/components/organisms/Calendar/_CalendarTimePicker.test.ts +89 -0
- package/src/components/organisms/Calendar/_CalendarYearView.test.ts +56 -0
- package/src/components/organisms/ColorPicker/ColorPicker.stories.ts +229 -0
- package/src/components/organisms/ColorPicker/ColorPicker.test.ts +696 -0
- package/src/components/organisms/ColorPicker/ColorPicker.vue +12 -3
- package/src/components/organisms/ColorPicker/gradient.test.ts +67 -0
- package/src/components/organisms/ColorPicker/gradientGeometry.test.ts +206 -0
- package/src/components/organisms/Combobox/Combobox.stories.ts +234 -0
- package/src/components/organisms/Combobox/Combobox.test.ts +512 -0
- package/src/components/organisms/Combobox/Combobox.vue +1 -1
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.stories.ts +158 -0
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.test.ts +524 -0
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.vue +1 -1
- package/src/components/organisms/CountrySelect/CountrySelect.stories.ts +139 -0
- package/src/components/organisms/CountrySelect/CountrySelect.test.ts +149 -0
- package/src/components/organisms/DatePicker/DatePicker.stories.ts +163 -0
- package/src/components/organisms/DatePicker/DatePicker.test.ts +214 -0
- package/src/components/organisms/DropdownButton/DropdownButton.stories.ts +123 -0
- package/src/components/organisms/DropdownButton/DropdownButton.test.ts +379 -0
- package/src/components/organisms/FontPicker/FontPicker.stories.ts +476 -0
- package/src/components/organisms/FontPicker/FontPicker.test.ts +873 -0
- package/src/components/organisms/Header/Header.stories.ts +75 -0
- package/src/components/organisms/Header/Header.test.ts +233 -0
- package/src/components/organisms/IconPicker/IconPicker.stories.ts +734 -0
- package/src/components/organisms/IconPicker/IconPicker.test.ts +669 -0
- package/src/components/organisms/IconPicker/_IconPickerGrid.test.ts +184 -0
- package/src/components/organisms/IconPicker/_IconPickerRail.test.ts +102 -0
- package/src/components/organisms/IconPicker/useIconPickerNavigation.test.ts +215 -0
- package/src/components/organisms/Modal/Modal.stories.ts +350 -0
- package/src/components/organisms/Modal/Modal.test.ts +275 -0
- package/src/components/organisms/PickerPanel/PickerPanel.stories.ts +452 -0
- package/src/components/organisms/PickerPanel/PickerPanel.test.ts +358 -0
- package/src/components/organisms/ProgressBar/ProgressBar.stories.ts +100 -0
- package/src/components/organisms/ProgressBar/ProgressBar.test.ts +417 -0
- package/src/components/organisms/ReferenceCard/ReferenceCard.stories.ts +191 -0
- package/src/components/organisms/ReferenceCard/ReferenceCard.test.ts +165 -0
- package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.stories.ts +65 -0
- package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.test.ts +466 -0
- package/src/components/organisms/StepperHeader/StepperHeader.stories.ts +91 -0
- package/src/components/organisms/StepperHeader/StepperHeader.test.ts +279 -0
- package/src/components/organisms/Table/Table.stories.ts +332 -0
- package/src/components/organisms/Table/Table.test.ts +320 -0
- package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.stories.ts +198 -0
- package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.test.ts +283 -0
- package/src/components/organisms/TimelineTrack/TimelineTrack.stories.ts +120 -0
- package/src/components/organisms/TimelineTrack/TimelineTrack.test.ts +91 -0
- package/src/components/organisms/Toaster/Toaster.stories.ts +51 -0
- package/src/components/organisms/Toaster/Toaster.test.ts +75 -0
- package/src/components/organisms/VideoControls/VideoControls.stories.ts +792 -0
- package/src/components/organisms/VideoControls/VideoControls.test.ts +1056 -0
- package/src/components/organisms/VideoPlayer/VideoPlayer.stories.ts +327 -0
- package/src/components/organisms/VideoPlayer/VideoPlayer.test.ts +439 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import PageContainer from './PageContainer.vue'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Molecules/PageContainer',
|
|
7
|
+
component: PageContainer,
|
|
8
|
+
} satisfies Meta<typeof PageContainer>
|
|
9
|
+
|
|
10
|
+
type Story = StoryObj<typeof PageContainer>
|
|
11
|
+
|
|
12
|
+
const contentBlock = `
|
|
13
|
+
<div class="rounded-lg border border-gray-200 bg-gray-50 p-8 text-center">
|
|
14
|
+
Content
|
|
15
|
+
</div>
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
export const Default: Story = {
|
|
19
|
+
render: (args) => ({
|
|
20
|
+
components: { PageContainer },
|
|
21
|
+
setup: () => ({ args }),
|
|
22
|
+
template: `
|
|
23
|
+
<div class="h-96">
|
|
24
|
+
<PageContainer v-bind="args">${contentBlock}</PageContainer>
|
|
25
|
+
</div>
|
|
26
|
+
`,
|
|
27
|
+
}),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Every step of the width scale, from xs up to full (the app's maximum width). */
|
|
31
|
+
export const Widths: Story = {
|
|
32
|
+
render: () => ({
|
|
33
|
+
components: { PageContainer },
|
|
34
|
+
setup: () => ({
|
|
35
|
+
widths: [
|
|
36
|
+
'xs',
|
|
37
|
+
'sm',
|
|
38
|
+
'md',
|
|
39
|
+
'lg',
|
|
40
|
+
'xl',
|
|
41
|
+
'2xl',
|
|
42
|
+
'3xl',
|
|
43
|
+
'4xl',
|
|
44
|
+
'5xl',
|
|
45
|
+
'6xl',
|
|
46
|
+
'7xl',
|
|
47
|
+
'8xl',
|
|
48
|
+
'full',
|
|
49
|
+
],
|
|
50
|
+
}),
|
|
51
|
+
template: `
|
|
52
|
+
<div class="flex flex-col gap-2">
|
|
53
|
+
<div v-for="width in widths" :key="width" class="h-32">
|
|
54
|
+
<PageContainer :max-width="width">
|
|
55
|
+
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4 text-center">
|
|
56
|
+
{{ width }}
|
|
57
|
+
</div>
|
|
58
|
+
</PageContainer>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
`,
|
|
62
|
+
}),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The sidebar slot slides in and out from the right edge. */
|
|
66
|
+
export const WithSidebar: Story = {
|
|
67
|
+
render: () => ({
|
|
68
|
+
components: { PageContainer },
|
|
69
|
+
setup: () => ({ open: ref(true) }),
|
|
70
|
+
template: `
|
|
71
|
+
<div class="flex h-96 flex-col">
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
class="button button-primary mb-4 self-start rounded-lg"
|
|
75
|
+
@click="open = !open"
|
|
76
|
+
>
|
|
77
|
+
Toggle sidebar
|
|
78
|
+
</button>
|
|
79
|
+
<PageContainer max-width="3xl">
|
|
80
|
+
${contentBlock}
|
|
81
|
+
<template v-if="open" #sidebar>
|
|
82
|
+
<div class="rounded-lg border border-gray-200 bg-gray-50 p-8 text-center">
|
|
83
|
+
Sidebar
|
|
84
|
+
</div>
|
|
85
|
+
</template>
|
|
86
|
+
</PageContainer>
|
|
87
|
+
</div>
|
|
88
|
+
`,
|
|
89
|
+
}),
|
|
90
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import PageContainer from './PageContainer.vue'
|
|
4
|
+
|
|
5
|
+
const WIDTHS = {
|
|
6
|
+
xs: 'max-w-xs',
|
|
7
|
+
sm: 'max-w-sm',
|
|
8
|
+
md: 'max-w-md',
|
|
9
|
+
lg: 'max-w-lg',
|
|
10
|
+
xl: 'max-w-xl',
|
|
11
|
+
'2xl': 'max-w-2xl',
|
|
12
|
+
'3xl': 'max-w-3xl',
|
|
13
|
+
'4xl': 'max-w-4xl',
|
|
14
|
+
'5xl': 'max-w-5xl',
|
|
15
|
+
'6xl': 'max-w-6xl',
|
|
16
|
+
'7xl': 'max-w-7xl',
|
|
17
|
+
'8xl': 'max-w-8xl',
|
|
18
|
+
full: 'max-w-full-width',
|
|
19
|
+
} as const
|
|
20
|
+
|
|
21
|
+
describe('PageContainer', () => {
|
|
22
|
+
it('renders a single-root div', () => {
|
|
23
|
+
const wrapper = mount(PageContainer)
|
|
24
|
+
|
|
25
|
+
expect(wrapper.element.tagName).toBe('DIV')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('centers the content at max-w-7xl by default', () => {
|
|
29
|
+
const wrapper = mount(PageContainer, { slots: { default: '<p>content</p>' } })
|
|
30
|
+
|
|
31
|
+
expect(wrapper.find('.mx-auto').classes()).toContain('max-w-7xl')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it.each(Object.entries(WIDTHS))('maps maxWidth %s to %s', (maxWidth, expected) => {
|
|
35
|
+
const wrapper = mount(PageContainer, {
|
|
36
|
+
props: { maxWidth: maxWidth as keyof typeof WIDTHS },
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
expect(wrapper.find('.mx-auto').classes()).toContain(expected)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('renders the sidebar only when the slot is filled', () => {
|
|
43
|
+
const withSidebar = mount(PageContainer, { slots: { sidebar: '<p>side</p>' } })
|
|
44
|
+
const withoutSidebar = mount(PageContainer)
|
|
45
|
+
|
|
46
|
+
expect(withSidebar.find('aside').exists()).toBe(true)
|
|
47
|
+
expect(withSidebar.find('aside').text()).toBe('side')
|
|
48
|
+
expect(withoutSidebar.find('aside').exists()).toBe(false)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import PageMockup, { PAGE_MOCKUP_TYPES } from './PageMockup.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Molecules/Page Mockup',
|
|
6
|
+
component: PageMockup,
|
|
7
|
+
} satisfies Meta<typeof PageMockup>
|
|
8
|
+
|
|
9
|
+
type Story = StoryObj<typeof PageMockup>
|
|
10
|
+
|
|
11
|
+
export const Default: Story = {
|
|
12
|
+
args: { type: 'about' },
|
|
13
|
+
render: (args) => ({
|
|
14
|
+
components: { PageMockup },
|
|
15
|
+
setup() {
|
|
16
|
+
return { args }
|
|
17
|
+
},
|
|
18
|
+
template:
|
|
19
|
+
'<div class="w-80 rounded-xl border border-gray-200 p-3"><PageMockup v-bind="args" /></div>',
|
|
20
|
+
}),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const AllTypes: Story = {
|
|
24
|
+
render: () => ({
|
|
25
|
+
components: { PageMockup },
|
|
26
|
+
setup() {
|
|
27
|
+
return { types: PAGE_MOCKUP_TYPES }
|
|
28
|
+
},
|
|
29
|
+
template: `
|
|
30
|
+
<div class="grid max-w-3xl grid-cols-2 gap-4">
|
|
31
|
+
<div v-for="type in types" :key="type" class="rounded-xl border border-gray-200 p-3">
|
|
32
|
+
<PageMockup :type="type" />
|
|
33
|
+
<p class="mt-2 small-semibold text-gray-700">{{ type }}</p>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
`,
|
|
37
|
+
}),
|
|
38
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import PageMockup, { PAGE_MOCKUP_TYPES } from './PageMockup.vue'
|
|
4
|
+
|
|
5
|
+
describe('PageMockup', () => {
|
|
6
|
+
it.each(PAGE_MOCKUP_TYPES)('renders a decorative svg for %s', (type) => {
|
|
7
|
+
const wrapper = mount(PageMockup, { props: { type } })
|
|
8
|
+
|
|
9
|
+
expect(wrapper.element.tagName).toBe('svg')
|
|
10
|
+
expect(wrapper.attributes('aria-hidden')).toBe('true')
|
|
11
|
+
expect(wrapper.findAll('rect').length).toBeGreaterThan(4)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('draws a different sketch per type', () => {
|
|
15
|
+
const about = mount(PageMockup, { props: { type: 'about' } }).html()
|
|
16
|
+
const reviews = mount(PageMockup, { props: { type: 'reviews' } }).html()
|
|
17
|
+
|
|
18
|
+
expect(about).not.toBe(reviews)
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import PageTypeTile from './PageTypeTile.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Molecules/Page Type Tile',
|
|
6
|
+
component: PageTypeTile,
|
|
7
|
+
} satisfies Meta<typeof PageTypeTile>
|
|
8
|
+
|
|
9
|
+
type Story = StoryObj<typeof PageTypeTile>
|
|
10
|
+
|
|
11
|
+
export const Default: Story = {
|
|
12
|
+
args: {
|
|
13
|
+
label: "USP's",
|
|
14
|
+
icon: 'briefcase',
|
|
15
|
+
},
|
|
16
|
+
render: (args) => ({
|
|
17
|
+
components: { PageTypeTile },
|
|
18
|
+
setup() {
|
|
19
|
+
return { args }
|
|
20
|
+
},
|
|
21
|
+
template: '<div class="max-w-36"><PageTypeTile v-bind="args" draggable="true" /></div>',
|
|
22
|
+
}),
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const Dragging: Story = {
|
|
26
|
+
args: {
|
|
27
|
+
label: 'Courtage',
|
|
28
|
+
icon: 'piggy-bank',
|
|
29
|
+
dragging: true,
|
|
30
|
+
},
|
|
31
|
+
render: (args) => ({
|
|
32
|
+
components: { PageTypeTile },
|
|
33
|
+
setup() {
|
|
34
|
+
return { args }
|
|
35
|
+
},
|
|
36
|
+
template: '<div class="max-w-36"><PageTypeTile v-bind="args" /></div>',
|
|
37
|
+
}),
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const Grid: Story = {
|
|
41
|
+
render: () => ({
|
|
42
|
+
components: { PageTypeTile },
|
|
43
|
+
setup() {
|
|
44
|
+
const tiles = [
|
|
45
|
+
{ label: 'Welkomstpagina', icon: 'hand-wave' },
|
|
46
|
+
{ label: 'Over ons', icon: 'users' },
|
|
47
|
+
{ label: 'Waarde-indicatie', icon: 'circle-euro' },
|
|
48
|
+
{ label: "USP's", icon: 'briefcase' },
|
|
49
|
+
{ label: 'Courtage', icon: 'piggy-bank' },
|
|
50
|
+
{ label: 'Referentiewoningen', icon: 'house' },
|
|
51
|
+
{ label: 'Klantbeoordelingen', icon: 'star' },
|
|
52
|
+
{ label: 'Overige pagina', icon: 'file-lines' },
|
|
53
|
+
] as const
|
|
54
|
+
|
|
55
|
+
return { tiles }
|
|
56
|
+
},
|
|
57
|
+
template: `
|
|
58
|
+
<div class="grid max-w-xs grid-cols-2 gap-3">
|
|
59
|
+
<PageTypeTile v-for="tile in tiles" :key="tile.label" v-bind="tile" draggable="true" />
|
|
60
|
+
</div>
|
|
61
|
+
`,
|
|
62
|
+
}),
|
|
63
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import PageTypeTile from './PageTypeTile.vue'
|
|
4
|
+
|
|
5
|
+
describe('PageTypeTile', () => {
|
|
6
|
+
it('renders a button with the label and icon', () => {
|
|
7
|
+
const wrapper = mount(PageTypeTile, { props: { label: "USP's", icon: 'briefcase' } })
|
|
8
|
+
|
|
9
|
+
expect(wrapper.element.tagName).toBe('BUTTON')
|
|
10
|
+
expect(wrapper.attributes('type')).toBe('button')
|
|
11
|
+
expect(wrapper.text()).toBe("USP's")
|
|
12
|
+
expect(wrapper.find('.fa-briefcase').exists()).toBe(true)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('emits select on click', async () => {
|
|
16
|
+
const wrapper = mount(PageTypeTile, { props: { label: "USP's", icon: 'briefcase' } })
|
|
17
|
+
|
|
18
|
+
await wrapper.trigger('click')
|
|
19
|
+
|
|
20
|
+
expect(wrapper.emitted('select')).toHaveLength(1)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('draws the blue border while dragging', () => {
|
|
24
|
+
const dragging = mount(PageTypeTile, {
|
|
25
|
+
props: { label: "USP's", icon: 'briefcase', dragging: true },
|
|
26
|
+
})
|
|
27
|
+
const idle = mount(PageTypeTile, { props: { label: "USP's", icon: 'briefcase' } })
|
|
28
|
+
|
|
29
|
+
expect(dragging.classes()).toContain('border-cornflower-blue-500')
|
|
30
|
+
expect(idle.classes()).toContain('border-gray-200')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('passes attributes through, so the consumer can make it draggable', () => {
|
|
34
|
+
const wrapper = mount(PageTypeTile, {
|
|
35
|
+
props: { label: "USP's", icon: 'briefcase' },
|
|
36
|
+
attrs: { draggable: 'true' },
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
expect(wrapper.attributes('draggable')).toBe('true')
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
3
|
+
import Pagination from './Pagination.vue'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Molecules/Pagination',
|
|
7
|
+
component: Pagination,
|
|
8
|
+
args: {
|
|
9
|
+
total: 100,
|
|
10
|
+
itemsPerPage: 10,
|
|
11
|
+
siblingCount: 1,
|
|
12
|
+
page: 1,
|
|
13
|
+
showEdges: true,
|
|
14
|
+
},
|
|
15
|
+
} satisfies Meta<typeof Pagination>
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj<typeof Pagination>
|
|
18
|
+
|
|
19
|
+
export const Default: Story = {}
|
|
20
|
+
|
|
21
|
+
export const MidPage: Story = {
|
|
22
|
+
args: {
|
|
23
|
+
page: 5,
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const FewPages: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
total: 30,
|
|
30
|
+
page: 2,
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const LotsOfPages: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
total: 2054,
|
|
37
|
+
page: 1,
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const NoEdges: Story = {
|
|
42
|
+
args: {
|
|
43
|
+
showEdges: false,
|
|
44
|
+
page: 5,
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const Disabled: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
page: 5,
|
|
51
|
+
disabled: true,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const Playground: Story = {
|
|
56
|
+
render: (args) => ({
|
|
57
|
+
components: { Pagination },
|
|
58
|
+
setup() {
|
|
59
|
+
const currentPage = ref(args.page ?? 1)
|
|
60
|
+
return { args, currentPage }
|
|
61
|
+
},
|
|
62
|
+
template: `
|
|
63
|
+
<div class="flex flex-col items-center gap-4">
|
|
64
|
+
<p class="text-gray-700 body-normal">Current page: <strong>{{ currentPage }}</strong></p>
|
|
65
|
+
<Pagination v-bind="args" v-model:page="currentPage" />
|
|
66
|
+
</div>
|
|
67
|
+
`,
|
|
68
|
+
}),
|
|
69
|
+
args: {
|
|
70
|
+
total: 100,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import Pagination from './Pagination.vue'
|
|
4
|
+
|
|
5
|
+
const stubs = { NexxtIcon: { template: '<span />' } }
|
|
6
|
+
|
|
7
|
+
const mountPagination = (props = {}) =>
|
|
8
|
+
mount(Pagination, {
|
|
9
|
+
props: { total: 100, ...props },
|
|
10
|
+
global: { stubs },
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe('Pagination', () => {
|
|
14
|
+
describe('rendering', () => {
|
|
15
|
+
it('renders without crashing', () => {
|
|
16
|
+
const wrapper = mountPagination()
|
|
17
|
+
expect(wrapper.exists()).toBe(true)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('renders page number buttons', () => {
|
|
21
|
+
const wrapper = mountPagination()
|
|
22
|
+
expect(wrapper.findAll('button').length).toBeGreaterThan(0)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('renders the correct page buttons for a small page count', () => {
|
|
26
|
+
const wrapper = mountPagination({ total: 30, itemsPerPage: 10 })
|
|
27
|
+
const pageButtons = wrapper
|
|
28
|
+
.findAll('button')
|
|
29
|
+
.filter((b) => ['1', '2', '3'].includes(b.text()))
|
|
30
|
+
expect(pageButtons.length).toBe(3)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('does not render pages beyond the total', () => {
|
|
34
|
+
const wrapper = mountPagination({ total: 30, itemsPerPage: 10 })
|
|
35
|
+
const page4 = wrapper.findAll('button').find((b) => b.text() === '4')
|
|
36
|
+
expect(page4).toBeUndefined()
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('shows ellipsis when there are many pages', () => {
|
|
40
|
+
const wrapper = mountPagination({ total: 100, itemsPerPage: 10 })
|
|
41
|
+
expect(wrapper.html()).toContain('…')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('does not show ellipsis when all pages fit', () => {
|
|
45
|
+
const wrapper = mountPagination({ total: 30, itemsPerPage: 10 })
|
|
46
|
+
expect(wrapper.html()).not.toContain('…')
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('page model', () => {
|
|
51
|
+
it('defaults to page 1 as the active page', () => {
|
|
52
|
+
const wrapper = mountPagination()
|
|
53
|
+
const page1 = wrapper.findAll('button').find((b) => b.text() === '1')
|
|
54
|
+
expect(page1?.attributes('data-selected')).toBeDefined()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('sets the active page from the page prop', () => {
|
|
58
|
+
const wrapper = mountPagination({ total: 30, itemsPerPage: 10, page: 3 })
|
|
59
|
+
const page3 = wrapper.findAll('button').find((b) => b.text() === '3')
|
|
60
|
+
expect(page3?.attributes('data-selected')).toBeDefined()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('only marks one page as active at a time', () => {
|
|
64
|
+
const wrapper = mountPagination({ total: 30, itemsPerPage: 10, page: 2 })
|
|
65
|
+
const selectedButtons = wrapper.findAll('button[data-selected]')
|
|
66
|
+
expect(selectedButtons.length).toBe(1)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('emits update:page when a page button is clicked', async () => {
|
|
70
|
+
const wrapper = mountPagination({ total: 30, itemsPerPage: 10 })
|
|
71
|
+
const page2 = wrapper.findAll('button').find((b) => b.text() === '2')
|
|
72
|
+
await page2?.trigger('click')
|
|
73
|
+
expect(wrapper.emitted('update:page')).toBeTruthy()
|
|
74
|
+
expect(wrapper.emitted('update:page')?.[0]).toEqual([2])
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('props', () => {
|
|
79
|
+
it('respects itemsPerPage when calculating total pages', () => {
|
|
80
|
+
const wrapper = mountPagination({ total: 20, itemsPerPage: 5 })
|
|
81
|
+
const pageButtons = wrapper
|
|
82
|
+
.findAll('button')
|
|
83
|
+
.filter((b) => ['1', '2', '3', '4'].includes(b.text()))
|
|
84
|
+
expect(pageButtons.length).toBe(4)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('shows more sibling pages with a higher siblingCount', () => {
|
|
88
|
+
const wrapperLow = mountPagination({ total: 100, itemsPerPage: 10, page: 5, siblingCount: 1 })
|
|
89
|
+
const wrapperHigh = mountPagination({
|
|
90
|
+
total: 100,
|
|
91
|
+
itemsPerPage: 10,
|
|
92
|
+
page: 5,
|
|
93
|
+
siblingCount: 3,
|
|
94
|
+
})
|
|
95
|
+
expect(wrapperHigh.findAll('button').length).toBeGreaterThan(
|
|
96
|
+
wrapperLow.findAll('button').length,
|
|
97
|
+
)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
describe('disabled', () => {
|
|
102
|
+
it('applies opacity-50 and pointer-events-none to the list when disabled', () => {
|
|
103
|
+
const wrapper = mountPagination({ disabled: true })
|
|
104
|
+
const list = wrapper.find('.opacity-50')
|
|
105
|
+
expect(list.exists()).toBe(true)
|
|
106
|
+
expect(list.classes()).toContain('pointer-events-none')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('does not apply opacity-50 when not disabled', () => {
|
|
110
|
+
const wrapper = mountPagination({ disabled: false })
|
|
111
|
+
expect(wrapper.find('.opacity-50').exists()).toBe(false)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('sets disabled attribute on nav buttons when disabled', () => {
|
|
115
|
+
const wrapper = mountPagination({ disabled: true, page: 5, total: 100 })
|
|
116
|
+
// All nav and page buttons should carry disabled
|
|
117
|
+
const allButtons = wrapper.findAll('button')
|
|
118
|
+
const disabledButtons = allButtons.filter((b) => b.attributes('disabled') !== undefined)
|
|
119
|
+
expect(disabledButtons.length).toBe(allButtons.length)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('does not set disabled on page buttons when not disabled', () => {
|
|
123
|
+
const wrapper = mountPagination({ disabled: false, total: 30, itemsPerPage: 10, page: 2 })
|
|
124
|
+
const pageButtons = wrapper
|
|
125
|
+
.findAll('button')
|
|
126
|
+
.filter((b) => ['1', '2', '3'].includes(b.text()))
|
|
127
|
+
pageButtons.forEach((b) => expect(b.attributes('disabled')).toBeUndefined())
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test'
|
|
3
|
+
import { ref } from 'vue'
|
|
4
|
+
import PickerItem from '../../atoms/PickerItem/PickerItem.vue'
|
|
5
|
+
import PickerGroup from './PickerGroup.vue'
|
|
6
|
+
|
|
7
|
+
/** A group sits in a listbox; outside one axe reports the options' missing parent. */
|
|
8
|
+
const LISTBOX_CLASSES =
|
|
9
|
+
'group/listbox flex w-66 flex-col gap-0.5 rounded-xl border border-gray-200 bg-white p-2 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-cornflower-blue-500'
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
title: 'Components/Molecules/PickerGroup',
|
|
13
|
+
component: PickerGroup,
|
|
14
|
+
args: { label: 'Media', collapsible: true },
|
|
15
|
+
} satisfies Meta<typeof PickerGroup>
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj<typeof PickerGroup>
|
|
18
|
+
|
|
19
|
+
const renderGroup = (initiallyOpen: boolean) => (args: Story['args']) => ({
|
|
20
|
+
components: { PickerGroup, PickerItem },
|
|
21
|
+
setup: () => ({ args, open: ref(initiallyOpen), classes: LISTBOX_CLASSES }),
|
|
22
|
+
template: `
|
|
23
|
+
<div role="listbox" aria-label="Onderdelen" tabindex="0" :class="classes">
|
|
24
|
+
<PickerGroup v-bind="args" v-model:open="open">
|
|
25
|
+
<PickerItem id="group-image" label="Afbeelding" icon="image" highlighted />
|
|
26
|
+
<PickerItem id="group-video" label="Video" icon="video" />
|
|
27
|
+
<PickerItem id="group-gallery" label="Galerij" icon="images" />
|
|
28
|
+
</PickerGroup>
|
|
29
|
+
<PickerGroup label="Basis" :collapsible="args.collapsible">
|
|
30
|
+
<PickerItem id="group-title" label="Titel" icon="heading" />
|
|
31
|
+
</PickerGroup>
|
|
32
|
+
</div>
|
|
33
|
+
`,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const groupOf = (canvasElement: HTMLElement) =>
|
|
37
|
+
canvasElement.querySelector<HTMLElement>('[role="group"]')!
|
|
38
|
+
|
|
39
|
+
/** Click the heading to fold; the chevron turns and the options leave the DOM after 120ms. */
|
|
40
|
+
export const Open: Story = {
|
|
41
|
+
render: renderGroup(true),
|
|
42
|
+
play: async ({ canvasElement }) => {
|
|
43
|
+
const canvas = within(canvasElement)
|
|
44
|
+
const listbox = canvas.getByRole('listbox')
|
|
45
|
+
const group = groupOf(canvasElement)
|
|
46
|
+
const heading = group.querySelector<HTMLElement>('[role="presentation"]')!
|
|
47
|
+
|
|
48
|
+
await expect(group).toHaveAttribute('aria-expanded', 'true')
|
|
49
|
+
await expect(document.getElementById(group.getAttribute('aria-labelledby')!)).toHaveTextContent(
|
|
50
|
+
'Media',
|
|
51
|
+
)
|
|
52
|
+
await expect(heading).not.toHaveAttribute('tabindex')
|
|
53
|
+
await expect(heading.querySelector('button, a')).toBeNull()
|
|
54
|
+
|
|
55
|
+
listbox.focus()
|
|
56
|
+
await userEvent.click(heading)
|
|
57
|
+
|
|
58
|
+
await expect(group).toHaveAttribute('aria-expanded', 'false')
|
|
59
|
+
await waitFor(() => expect(group.querySelectorAll('[role="option"]')).toHaveLength(0))
|
|
60
|
+
// the heading is no tab stop and prevents the mousedown, so focus stays on the listbox
|
|
61
|
+
await expect(listbox).toHaveFocus()
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const Closed: Story = {
|
|
66
|
+
render: renderGroup(false),
|
|
67
|
+
play: async ({ canvasElement }) => {
|
|
68
|
+
const group = groupOf(canvasElement)
|
|
69
|
+
|
|
70
|
+
await expect(group).toHaveAttribute('aria-expanded', 'false')
|
|
71
|
+
await expect(group.querySelectorAll('[role="option"]')).toHaveLength(0)
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The heading is a plain label: no chevron, no hover tint, no `aria-expanded`. */
|
|
76
|
+
export const NotCollapsible: Story = {
|
|
77
|
+
args: { collapsible: false },
|
|
78
|
+
render: renderGroup(true),
|
|
79
|
+
play: async ({ canvasElement }) => {
|
|
80
|
+
const group = groupOf(canvasElement)
|
|
81
|
+
const heading = group.querySelector<HTMLElement>('[role="presentation"]')!
|
|
82
|
+
|
|
83
|
+
await expect(group).not.toHaveAttribute('aria-expanded')
|
|
84
|
+
await expect(group).toHaveAttribute('aria-labelledby')
|
|
85
|
+
await expect(heading.querySelector('i')).toBeNull()
|
|
86
|
+
|
|
87
|
+
await userEvent.click(heading)
|
|
88
|
+
await expect(group.querySelectorAll('[role="option"]')).toHaveLength(3)
|
|
89
|
+
},
|
|
90
|
+
}
|