@nexxtmove/ui 2.6.0 → 2.7.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/index.js +49 -126
- 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 +563 -0
- package/src/components/editor/molecules/EditorColor/EditorColor.test.ts +689 -0
- package/src/components/editor/molecules/EditorColor/EditorColorGradient.test.ts +793 -0
- 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 +638 -0
- 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,578 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import type { IconName } from '@awesome.me/kit-37b149f3ef/icons'
|
|
4
|
+
import ToggleGroup from './ToggleGroup.vue'
|
|
5
|
+
import type { NexxtToggleGroupOption } from './ToggleGroup.vue'
|
|
6
|
+
|
|
7
|
+
const labelOptions = [
|
|
8
|
+
{ value: 'week', label: 'Week' },
|
|
9
|
+
{ value: 'month', label: 'Month' },
|
|
10
|
+
{ value: 'year', label: 'Year' },
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
const iconOptions = [
|
|
14
|
+
{ value: 'list', icon: 'list' as IconName },
|
|
15
|
+
{ value: 'grid', icon: 'grid-2' as IconName },
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
const tooltipOptions = [
|
|
19
|
+
{ value: 'list', icon: 'list' as IconName, tooltip: 'List view' },
|
|
20
|
+
{ value: 'grid', icon: 'grid-2' as IconName, tooltip: 'Grid view' },
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
Object.defineProperty(document, 'fonts', {
|
|
25
|
+
value: { ready: Promise.resolve() },
|
|
26
|
+
configurable: true,
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe('ToggleGroup', () => {
|
|
31
|
+
it('renders a button for each option', () => {
|
|
32
|
+
const wrapper = mount(ToggleGroup, {
|
|
33
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
expect(wrapper.findAll('button')).toHaveLength(labelOptions.length)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('renders option labels', () => {
|
|
40
|
+
const wrapper = mount(ToggleGroup, {
|
|
41
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const buttons = wrapper.findAll('button')
|
|
45
|
+
expect(buttons[0].text()).toBe('Week')
|
|
46
|
+
expect(buttons[1].text()).toBe('Month')
|
|
47
|
+
expect(buttons[2].text()).toBe('Year')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('renders option icons', () => {
|
|
51
|
+
const wrapper = mount(ToggleGroup, {
|
|
52
|
+
props: { options: iconOptions, modelValue: 'list' },
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// each icon appears in both the button layer and the overlay layer
|
|
56
|
+
expect(wrapper.findAll('i')).toHaveLength(iconOptions.length * 2)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('renders both icon and label when both are set', () => {
|
|
60
|
+
const combined = [
|
|
61
|
+
{ value: 'list', icon: 'list' as IconName, label: 'List' },
|
|
62
|
+
{ value: 'grid', icon: 'grid-2' as IconName, label: 'Grid' },
|
|
63
|
+
]
|
|
64
|
+
const wrapper = mount(ToggleGroup, {
|
|
65
|
+
props: { options: combined, modelValue: 'list' },
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// icons in both layers
|
|
69
|
+
expect(wrapper.findAll('i')).toHaveLength(combined.length * 2)
|
|
70
|
+
// labels in both layers
|
|
71
|
+
expect(wrapper.findAll('span.extra-small-semibold')).toHaveLength(combined.length * 2)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('renders the label prop above the buttons', () => {
|
|
75
|
+
const wrapper = mount(ToggleGroup, {
|
|
76
|
+
props: { options: labelOptions, modelValue: 'week', label: 'Period' },
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
expect(wrapper.find('label').text()).toBe('Period')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('hides the label visually but keeps it as the name with labelHidden', () => {
|
|
83
|
+
const wrapper = mount(ToggleGroup, {
|
|
84
|
+
props: { options: labelOptions, modelValue: 'week', label: 'Period', labelHidden: true },
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const label = wrapper.get('label')
|
|
88
|
+
const labelledBy = wrapper.get('[role="toolbar"]').attributes('aria-labelledby')
|
|
89
|
+
expect(label.classes()).toContain('sr-only')
|
|
90
|
+
expect(labelledBy).toBe(label.attributes('id'))
|
|
91
|
+
expect(label.text()).toBe('Period')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('shows the label by default', () => {
|
|
95
|
+
const wrapper = mount(ToggleGroup, {
|
|
96
|
+
props: { options: labelOptions, modelValue: 'week', label: 'Period' },
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
expect(wrapper.get('label').classes()).not.toContain('sr-only')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('does not render a label element when label prop is omitted', () => {
|
|
103
|
+
const wrapper = mount(ToggleGroup, {
|
|
104
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
expect(wrapper.find('label').exists()).toBe(false)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('emits update:modelValue with the clicked option value', async () => {
|
|
111
|
+
const wrapper = mount(ToggleGroup, {
|
|
112
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
await wrapper.findAll('button')[1].trigger('click')
|
|
116
|
+
|
|
117
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
118
|
+
expect(wrapper.emitted('update:modelValue')![0]).toEqual(['month'])
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// Not typography but contrast: gray-500 on the gray-100 track is about 1.6:1
|
|
122
|
+
// and reads as disabled; gray-700 reaches AA for the labels and 3:1 for icons.
|
|
123
|
+
it('draws unselected options in gray-700, gray-900 on hover', () => {
|
|
124
|
+
const wrapper = mount(ToggleGroup, {
|
|
125
|
+
props: { options: [...labelOptions.slice(0, 1), ...tooltipOptions], modelValue: 'week' },
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
wrapper.findAll('button').forEach((button) => {
|
|
129
|
+
expect(button.classes()).toEqual(
|
|
130
|
+
expect.arrayContaining(['text-gray-700', 'hover:text-gray-900']),
|
|
131
|
+
)
|
|
132
|
+
expect(button.classes()).not.toContain('text-gray-500')
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('renders the slider pill', () => {
|
|
137
|
+
const wrapper = mount(ToggleGroup, {
|
|
138
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
expect(wrapper.find('.bg-white.absolute').exists()).toBe(true)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('renders a tooltip when the tooltip property is set', () => {
|
|
145
|
+
const wrapper = mount(ToggleGroup, {
|
|
146
|
+
props: { options: tooltipOptions, modelValue: 'list' },
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// reka-ui TooltipProvider is rendered when tooltip is present
|
|
150
|
+
expect(wrapper.findComponent({ name: 'TooltipProvider' }).exists()).toBe(true)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('names an icon-only button with its tooltip, so axe finds discernible text', () => {
|
|
154
|
+
const wrapper = mount(ToggleGroup, {
|
|
155
|
+
props: { options: tooltipOptions, modelValue: 'list' },
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const buttons = wrapper.findAll('button')
|
|
159
|
+
expect(buttons[0].attributes('aria-label')).toBe('List view')
|
|
160
|
+
expect(buttons[1].attributes('aria-label')).toBe('Grid view')
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('leaves a visible label as the accessible name instead of the tooltip', () => {
|
|
164
|
+
const labelledTooltipOptions = [
|
|
165
|
+
{ value: 'list', icon: 'list' as IconName, label: 'List', tooltip: 'Show as a list' },
|
|
166
|
+
]
|
|
167
|
+
const wrapper = mount(ToggleGroup, {
|
|
168
|
+
props: { options: labelledTooltipOptions, modelValue: 'list' },
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
expect(wrapper.find('button').attributes('aria-label')).toBeUndefined()
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('names an icon-only button with ariaLabel when there is no tooltip', () => {
|
|
175
|
+
const ariaLabelOptions = [
|
|
176
|
+
{ value: 'list', icon: 'list' as IconName, ariaLabel: 'List view' },
|
|
177
|
+
{ value: 'grid', icon: 'grid-2' as IconName, ariaLabel: 'Grid view' },
|
|
178
|
+
]
|
|
179
|
+
const wrapper = mount(ToggleGroup, {
|
|
180
|
+
props: { options: ariaLabelOptions, modelValue: 'list' },
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
const buttons = wrapper.findAll('button')
|
|
184
|
+
expect(buttons[0].attributes('aria-label')).toBe('List view')
|
|
185
|
+
expect(buttons[1].attributes('aria-label')).toBe('Grid view')
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('prefers ariaLabel over the tooltip fallback', () => {
|
|
189
|
+
const bothOptions = [
|
|
190
|
+
{
|
|
191
|
+
value: 'list',
|
|
192
|
+
icon: 'list' as IconName,
|
|
193
|
+
tooltip: 'Show as a list',
|
|
194
|
+
ariaLabel: 'List view',
|
|
195
|
+
},
|
|
196
|
+
]
|
|
197
|
+
const wrapper = mount(ToggleGroup, {
|
|
198
|
+
props: { options: bothOptions, modelValue: 'list' },
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
expect(wrapper.find('button').attributes('aria-label')).toBe('List view')
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('does not render a tooltip when the tooltip property is not set', () => {
|
|
205
|
+
const wrapper = mount(ToggleGroup, {
|
|
206
|
+
props: { options: iconOptions, modelValue: 'list' },
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
expect(wrapper.findComponent({ name: 'TooltipProvider' }).exists()).toBe(false)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
it('does not render a tooltip for options without a tooltip alongside ones that have one', () => {
|
|
213
|
+
const mixedOptions = [
|
|
214
|
+
{ value: 'list', icon: 'list' as IconName, tooltip: 'List view' },
|
|
215
|
+
{ value: 'grid', icon: 'grid-2' as IconName },
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
const wrapper = mount(ToggleGroup, {
|
|
219
|
+
props: { options: mixedOptions, modelValue: 'list' },
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
expect(wrapper.findAllComponents({ name: 'TooltipProvider' })).toHaveLength(1)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('applies flex-1 to buttons when equalWidth is true (default)', () => {
|
|
226
|
+
const wrapper = mount(ToggleGroup, {
|
|
227
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
const buttons = wrapper.findAll('button')
|
|
231
|
+
buttons.forEach((btn) => expect(btn.classes()).toContain('flex-1'))
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('does not apply flex-1 to buttons when equalWidth is false', () => {
|
|
235
|
+
const wrapper = mount(ToggleGroup, {
|
|
236
|
+
props: { options: labelOptions, modelValue: 'week', equalWidth: false },
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
const buttons = wrapper.findAll('button')
|
|
240
|
+
buttons.forEach((btn) => expect(btn.classes()).not.toContain('flex-1'))
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
it('applies flex-wrap to the container when equalWidth is false', () => {
|
|
244
|
+
const wrapper = mount(ToggleGroup, {
|
|
245
|
+
props: { options: labelOptions, modelValue: 'week', equalWidth: false },
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
expect(wrapper.find('.flex-wrap').exists()).toBe(true)
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('does not apply flex-wrap to the container when equalWidth is true (default)', () => {
|
|
252
|
+
const wrapper = mount(ToggleGroup, {
|
|
253
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
expect(wrapper.find('.flex-wrap').exists()).toBe(false)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('applies the default active color class to overlay spans when activeClass is not set', () => {
|
|
260
|
+
const wrapper = mount(ToggleGroup, {
|
|
261
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
const overlaySpans = wrapper.findAll('[aria-hidden="true"] span[class*="rounded-lg"]')
|
|
265
|
+
overlaySpans.forEach((span) => expect(span.classes()).toContain('text-cornflower-blue-600'))
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
it('applies a custom activeClass to the matching overlay span', () => {
|
|
269
|
+
const colorOptions = [
|
|
270
|
+
{ value: 'buy', label: 'Buy', activeClass: 'text-green-600' },
|
|
271
|
+
{ value: 'rent', label: 'Rent', activeClass: 'text-orange-500' },
|
|
272
|
+
]
|
|
273
|
+
const wrapper = mount(ToggleGroup, {
|
|
274
|
+
props: { options: colorOptions, modelValue: 'buy' },
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
const overlaySpans = wrapper.findAll('[aria-hidden="true"] span[class*="rounded-lg"]')
|
|
278
|
+
expect(overlaySpans[0].classes()).toContain('text-green-600')
|
|
279
|
+
expect(overlaySpans[0].classes()).not.toContain('text-cornflower-blue-600')
|
|
280
|
+
expect(overlaySpans[1].classes()).toContain('text-orange-500')
|
|
281
|
+
expect(overlaySpans[1].classes()).not.toContain('text-cornflower-blue-600')
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
describe('option slot', () => {
|
|
285
|
+
const slots = {
|
|
286
|
+
option: `<template #option="{ option, selected }">
|
|
287
|
+
<b data-testid="custom" :data-value="option.value" :data-selected="String(selected)" />
|
|
288
|
+
</template>`,
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
it('replaces the default icon and label in both layers', () => {
|
|
292
|
+
const wrapper = mount(ToggleGroup, {
|
|
293
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
294
|
+
slots,
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
// Once on the button, once in the overlay that shows the active colour.
|
|
298
|
+
expect(wrapper.findAll('[data-testid="custom"]')).toHaveLength(labelOptions.length * 2)
|
|
299
|
+
wrapper.findAll('button').forEach((button) => expect(button.text()).toBe(''))
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
it('passes the option and whether it is the selected one', () => {
|
|
303
|
+
const wrapper = mount(ToggleGroup, {
|
|
304
|
+
props: { options: labelOptions, modelValue: 'month' },
|
|
305
|
+
slots,
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
const onButtons = wrapper
|
|
309
|
+
.findAll('button [data-testid="custom"]')
|
|
310
|
+
.map((el) => [el.attributes('data-value'), el.attributes('data-selected')])
|
|
311
|
+
expect(onButtons).toEqual([
|
|
312
|
+
['week', 'false'],
|
|
313
|
+
['month', 'true'],
|
|
314
|
+
['year', 'false'],
|
|
315
|
+
])
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it('renders inside a tooltip trigger too, and keeps the option names', () => {
|
|
319
|
+
const wrapper = mount(ToggleGroup, {
|
|
320
|
+
props: { options: tooltipOptions, modelValue: 'list' },
|
|
321
|
+
slots,
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
const buttons = wrapper.findAll('button')
|
|
325
|
+
expect(buttons.map((button) => button.find('[data-testid="custom"]').exists())).toEqual([
|
|
326
|
+
true,
|
|
327
|
+
true,
|
|
328
|
+
])
|
|
329
|
+
expect(buttons.map((button) => button.attributes('aria-label'))).toEqual([
|
|
330
|
+
'List view',
|
|
331
|
+
'Grid view',
|
|
332
|
+
])
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
it('still selects on click', async () => {
|
|
336
|
+
const wrapper = mount(ToggleGroup, {
|
|
337
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
338
|
+
slots,
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
await wrapper.findAll('button')[2].trigger('click')
|
|
342
|
+
|
|
343
|
+
expect(wrapper.emitted('update:modelValue')).toEqual([['year']])
|
|
344
|
+
})
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
describe('keyboard (roving tabindex)', () => {
|
|
348
|
+
const keyed = (modelValue: string, options: NexxtToggleGroupOption[] = labelOptions) =>
|
|
349
|
+
mount(ToggleGroup, { props: { options, modelValue }, attachTo: document.body })
|
|
350
|
+
|
|
351
|
+
const tabindexes = (wrapper: ReturnType<typeof keyed>) =>
|
|
352
|
+
wrapper.findAll('button').map((button) => button.attributes('tabindex'))
|
|
353
|
+
|
|
354
|
+
const press = async (wrapper: ReturnType<typeof keyed>, key: string) => {
|
|
355
|
+
const target = document.activeElement as HTMLElement
|
|
356
|
+
target.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }))
|
|
357
|
+
await wrapper.vm.$nextTick()
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const focused = (wrapper: ReturnType<typeof keyed>) =>
|
|
361
|
+
wrapper.findAll('button').findIndex((button) => button.element === document.activeElement)
|
|
362
|
+
|
|
363
|
+
it('makes the selected option the only tab stop', () => {
|
|
364
|
+
const wrapper = keyed('month')
|
|
365
|
+
|
|
366
|
+
expect(tabindexes(wrapper)).toEqual(['-1', '0', '-1'])
|
|
367
|
+
wrapper.unmount()
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
it('makes the first option the tab stop when nothing is selected', () => {
|
|
371
|
+
const wrapper = keyed('none-of-them')
|
|
372
|
+
|
|
373
|
+
expect(tabindexes(wrapper)).toEqual(['0', '-1', '-1'])
|
|
374
|
+
wrapper.unmount()
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('moves the tab stop with the selection', async () => {
|
|
378
|
+
const wrapper = keyed('week')
|
|
379
|
+
|
|
380
|
+
await wrapper.setProps({ modelValue: 'year' })
|
|
381
|
+
|
|
382
|
+
expect(tabindexes(wrapper)).toEqual(['-1', '-1', '0'])
|
|
383
|
+
wrapper.unmount()
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('moves focus with the arrow keys and wraps at both ends', async () => {
|
|
387
|
+
const wrapper = keyed('week')
|
|
388
|
+
;(wrapper.findAll('button')[0].element as HTMLElement).focus()
|
|
389
|
+
|
|
390
|
+
await press(wrapper, 'ArrowRight')
|
|
391
|
+
expect(focused(wrapper)).toBe(1)
|
|
392
|
+
await press(wrapper, 'ArrowDown')
|
|
393
|
+
expect(focused(wrapper)).toBe(2)
|
|
394
|
+
await press(wrapper, 'ArrowRight')
|
|
395
|
+
expect(focused(wrapper)).toBe(0)
|
|
396
|
+
await press(wrapper, 'ArrowLeft')
|
|
397
|
+
expect(focused(wrapper)).toBe(2)
|
|
398
|
+
await press(wrapper, 'ArrowUp')
|
|
399
|
+
expect(focused(wrapper)).toBe(1)
|
|
400
|
+
wrapper.unmount()
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
it('jumps to the first and last option with Home and End', async () => {
|
|
404
|
+
const wrapper = keyed('month')
|
|
405
|
+
;(wrapper.findAll('button')[1].element as HTMLElement).focus()
|
|
406
|
+
|
|
407
|
+
await press(wrapper, 'End')
|
|
408
|
+
expect(focused(wrapper)).toBe(2)
|
|
409
|
+
await press(wrapper, 'Home')
|
|
410
|
+
expect(focused(wrapper)).toBe(0)
|
|
411
|
+
wrapper.unmount()
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
it('selects nothing when focus moves', async () => {
|
|
415
|
+
const wrapper = keyed('week')
|
|
416
|
+
;(wrapper.findAll('button')[0].element as HTMLElement).focus()
|
|
417
|
+
|
|
418
|
+
await press(wrapper, 'ArrowRight')
|
|
419
|
+
await press(wrapper, 'End')
|
|
420
|
+
|
|
421
|
+
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
|
422
|
+
wrapper.unmount()
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
it('carries the tab stop along while focus moves, and hands it back on leaving', async () => {
|
|
426
|
+
const outside = document.createElement('button')
|
|
427
|
+
document.body.append(outside)
|
|
428
|
+
const wrapper = keyed('week')
|
|
429
|
+
;(wrapper.findAll('button')[0].element as HTMLElement).focus()
|
|
430
|
+
|
|
431
|
+
await press(wrapper, 'ArrowRight')
|
|
432
|
+
// Shift+Tab from here must leave the group, not land on the selected option.
|
|
433
|
+
expect(tabindexes(wrapper)).toEqual(['-1', '0', '-1'])
|
|
434
|
+
|
|
435
|
+
outside.focus()
|
|
436
|
+
await wrapper.vm.$nextTick()
|
|
437
|
+
expect(tabindexes(wrapper)).toEqual(['0', '-1', '-1'])
|
|
438
|
+
|
|
439
|
+
wrapper.unmount()
|
|
440
|
+
outside.remove()
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
it('prevents the default of the keys it handles, so the panel does not scroll', () => {
|
|
444
|
+
const wrapper = keyed('week')
|
|
445
|
+
const button = wrapper.findAll('button')[0].element as HTMLElement
|
|
446
|
+
button.focus()
|
|
447
|
+
|
|
448
|
+
const arrow = new KeyboardEvent('keydown', {
|
|
449
|
+
key: 'ArrowDown',
|
|
450
|
+
bubbles: true,
|
|
451
|
+
cancelable: true,
|
|
452
|
+
})
|
|
453
|
+
const tab = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true })
|
|
454
|
+
button.dispatchEvent(arrow)
|
|
455
|
+
button.dispatchEvent(tab)
|
|
456
|
+
|
|
457
|
+
expect(arrow.defaultPrevented).toBe(true)
|
|
458
|
+
expect(tab.defaultPrevented).toBe(false)
|
|
459
|
+
wrapper.unmount()
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
// Enter and Space reach the button natively as a click; jsdom does not
|
|
463
|
+
// synthesise that click, so the click is what is asserted here and the
|
|
464
|
+
// real keys are played in the KeyboardNavigation story.
|
|
465
|
+
it('selects on the button click that Enter and Space produce', async () => {
|
|
466
|
+
const wrapper = keyed('week')
|
|
467
|
+
;(wrapper.findAll('button')[0].element as HTMLElement).focus()
|
|
468
|
+
await press(wrapper, 'ArrowRight')
|
|
469
|
+
|
|
470
|
+
await wrapper.findAll('button')[focused(wrapper)].trigger('click')
|
|
471
|
+
|
|
472
|
+
expect(wrapper.emitted('update:modelValue')).toEqual([['month']])
|
|
473
|
+
wrapper.unmount()
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
it('works the same for options with tooltips', async () => {
|
|
477
|
+
const wrapper = keyed('list', tooltipOptions)
|
|
478
|
+
expect(tabindexes(wrapper)).toEqual(['0', '-1'])
|
|
479
|
+
;(wrapper.findAll('button')[0].element as HTMLElement).focus()
|
|
480
|
+
|
|
481
|
+
await press(wrapper, 'ArrowRight')
|
|
482
|
+
|
|
483
|
+
expect(focused(wrapper)).toBe(1)
|
|
484
|
+
wrapper.unmount()
|
|
485
|
+
})
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
describe('semantics', () => {
|
|
489
|
+
const pressed = (wrapper: ReturnType<typeof mount>) =>
|
|
490
|
+
wrapper.findAll('button').map((button) => button.attributes('aria-pressed'))
|
|
491
|
+
|
|
492
|
+
it('marks the selected option pressed and the others not', () => {
|
|
493
|
+
const wrapper = mount(ToggleGroup, { props: { options: labelOptions, modelValue: 'month' } })
|
|
494
|
+
|
|
495
|
+
expect(pressed(wrapper)).toEqual(['false', 'true', 'false'])
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
it('follows a change of the model from outside', async () => {
|
|
499
|
+
const wrapper = mount(ToggleGroup, { props: { options: labelOptions, modelValue: 'month' } })
|
|
500
|
+
|
|
501
|
+
await wrapper.setProps({ modelValue: 'year' })
|
|
502
|
+
|
|
503
|
+
expect(pressed(wrapper)).toEqual(['false', 'false', 'true'])
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
it('follows a click', async () => {
|
|
507
|
+
const wrapper = mount(ToggleGroup, {
|
|
508
|
+
props: {
|
|
509
|
+
options: labelOptions,
|
|
510
|
+
modelValue: 'week',
|
|
511
|
+
'onUpdate:modelValue': (value: string) => wrapper.setProps({ modelValue: value }),
|
|
512
|
+
},
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
await wrapper.findAll('button')[2].trigger('click')
|
|
516
|
+
|
|
517
|
+
expect(pressed(wrapper)).toEqual(['false', 'false', 'true'])
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
it('marks every option not pressed when nothing is selected', () => {
|
|
521
|
+
const wrapper = mount(ToggleGroup, { props: { options: labelOptions, modelValue: '' } })
|
|
522
|
+
|
|
523
|
+
expect(pressed(wrapper)).toEqual(['false', 'false', 'false'])
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
it('puts aria-pressed on options with a tooltip and with the option slot', () => {
|
|
527
|
+
const withTooltip = mount(ToggleGroup, {
|
|
528
|
+
props: { options: tooltipOptions, modelValue: 'grid' },
|
|
529
|
+
})
|
|
530
|
+
const withSlot = mount(ToggleGroup, {
|
|
531
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
532
|
+
slots: { option: '<template #option><b /></template>' },
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
expect(pressed(withTooltip)).toEqual(['false', 'true'])
|
|
536
|
+
expect(pressed(withSlot)).toEqual(['true', 'false', 'false'])
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
it('is a toolbar, not a radiogroup: the arrows move focus, they do not select', () => {
|
|
540
|
+
const wrapper = mount(ToggleGroup, { props: { options: labelOptions, modelValue: 'week' } })
|
|
541
|
+
|
|
542
|
+
expect(wrapper.attributes('role')).toBe('toolbar')
|
|
543
|
+
expect(wrapper.find('[role="radiogroup"], [role="radio"]').exists()).toBe(false)
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
it('names the toolbar with its visible label', () => {
|
|
547
|
+
const wrapper = mount(ToggleGroup, {
|
|
548
|
+
props: { options: labelOptions, modelValue: 'week', label: 'Periode' },
|
|
549
|
+
})
|
|
550
|
+
const id = wrapper.attributes('aria-labelledby')!
|
|
551
|
+
|
|
552
|
+
expect(wrapper.get(`[id="${id}"]`).text()).toBe('Periode')
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
it('takes a fallthrough aria-label as the toolbar name when there is no label', () => {
|
|
556
|
+
const wrapper = mount(ToggleGroup, {
|
|
557
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
558
|
+
attrs: { 'aria-label': 'Periode' },
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
expect(wrapper.attributes('aria-label')).toBe('Periode')
|
|
562
|
+
expect(wrapper.attributes('aria-labelledby')).toBeUndefined()
|
|
563
|
+
})
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
it('lets the pill and its overlay jump instead of slide under reduced motion', async () => {
|
|
567
|
+
const wrapper = mount(ToggleGroup, {
|
|
568
|
+
props: { options: labelOptions, modelValue: 'week' },
|
|
569
|
+
})
|
|
570
|
+
await new Promise((resolve) => setTimeout(resolve))
|
|
571
|
+
await wrapper.vm.$nextTick()
|
|
572
|
+
const animated = wrapper
|
|
573
|
+
.findAll('[aria-hidden="true"]')
|
|
574
|
+
.filter((el) => el.classes().some((name) => name.startsWith('transition-')))
|
|
575
|
+
expect(animated).toHaveLength(2)
|
|
576
|
+
animated.forEach((el) => expect(el.classes()).toContain('motion-reduce:transition-none'))
|
|
577
|
+
})
|
|
578
|
+
})
|