@nexxtmove/ui 2.5.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/components/editor/molecules/EditorBorder/EditorBorder.vue.d.ts +12 -0
- package/dist/components/editor/molecules/EditorColor/_ThemeRoleSwatches.vue.d.ts +16 -0
- package/dist/index.js +1094 -1135
- 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/EditorBorder/EditorBorder.vue +58 -2
- 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/_ColorField.vue +7 -29
- package/src/components/editor/molecules/EditorColor/_ThemeRoleSwatches.vue +57 -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,28 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import Skeleton from './Skeleton.vue'
|
|
4
|
+
|
|
5
|
+
describe('Skeleton', () => {
|
|
6
|
+
it('renders with default classes', () => {
|
|
7
|
+
const wrapper = mount(Skeleton)
|
|
8
|
+
|
|
9
|
+
expect(wrapper.find('.animate-pulse').exists()).toBe(true)
|
|
10
|
+
expect(wrapper.find('.bg-gray-200').exists()).toBe(true)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
// The pulse is decoration, so it stops entirely under reduced motion instead of slowing down
|
|
14
|
+
it('stops pulsing under reduced motion', () => {
|
|
15
|
+
const wrapper = mount(Skeleton)
|
|
16
|
+
|
|
17
|
+
expect(wrapper.classes()).toContain('motion-reduce:animate-none')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('applies custom class via attrs', () => {
|
|
21
|
+
const wrapper = mount(Skeleton, {
|
|
22
|
+
attrs: { class: 'h-10 w-40' },
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
expect(wrapper.find('.h-10').exists()).toBe(true)
|
|
26
|
+
expect(wrapper.find('.w-40').exists()).toBe(true)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import Slider from './Slider.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Atoms/Slider',
|
|
6
|
+
component: Slider,
|
|
7
|
+
argTypes: {
|
|
8
|
+
modelValue: {
|
|
9
|
+
control: 'object',
|
|
10
|
+
},
|
|
11
|
+
color: {
|
|
12
|
+
control: 'select',
|
|
13
|
+
options: ['blue', 'green'],
|
|
14
|
+
},
|
|
15
|
+
size: {
|
|
16
|
+
control: 'select',
|
|
17
|
+
options: ['sm', 'md', 'lg'],
|
|
18
|
+
},
|
|
19
|
+
variant: {
|
|
20
|
+
control: 'select',
|
|
21
|
+
options: ['filled', 'plain'],
|
|
22
|
+
},
|
|
23
|
+
label: {
|
|
24
|
+
control: 'text',
|
|
25
|
+
},
|
|
26
|
+
valueSuffix: {
|
|
27
|
+
control: 'text',
|
|
28
|
+
},
|
|
29
|
+
showValue: {
|
|
30
|
+
control: 'boolean',
|
|
31
|
+
},
|
|
32
|
+
disabled: {
|
|
33
|
+
control: 'boolean',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
args: {
|
|
37
|
+
modelValue: [25],
|
|
38
|
+
min: 0,
|
|
39
|
+
max: 100,
|
|
40
|
+
step: 1,
|
|
41
|
+
color: 'blue',
|
|
42
|
+
size: 'md',
|
|
43
|
+
variant: 'filled',
|
|
44
|
+
showValue: false,
|
|
45
|
+
disabled: false,
|
|
46
|
+
},
|
|
47
|
+
} satisfies Meta<typeof Slider>
|
|
48
|
+
|
|
49
|
+
type Story = StoryObj<typeof Slider>
|
|
50
|
+
|
|
51
|
+
export const Default: Story = {}
|
|
52
|
+
|
|
53
|
+
export const WithLabel: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
label: 'Ronding',
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const WithValue: Story = {
|
|
60
|
+
args: {
|
|
61
|
+
label: 'Ronding',
|
|
62
|
+
showValue: true,
|
|
63
|
+
valueSuffix: 'px',
|
|
64
|
+
max: 50,
|
|
65
|
+
modelValue: [12],
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const Percentage: Story = {
|
|
70
|
+
args: {
|
|
71
|
+
label: 'Marge',
|
|
72
|
+
showValue: true,
|
|
73
|
+
valueSuffix: '%',
|
|
74
|
+
modelValue: [40],
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Two values means two thumbs — no extra prop needed */
|
|
79
|
+
export const Range: Story = {
|
|
80
|
+
args: {
|
|
81
|
+
label: 'Prijsklasse',
|
|
82
|
+
showValue: true,
|
|
83
|
+
min: 0,
|
|
84
|
+
max: 1000,
|
|
85
|
+
step: 10,
|
|
86
|
+
minStepsBetweenThumbs: 1,
|
|
87
|
+
modelValue: [200, 800],
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Neutral track, coloured thumb — quieter, and pairs well with a value readout */
|
|
92
|
+
export const Plain: Story = {
|
|
93
|
+
args: {
|
|
94
|
+
label: 'Ronding',
|
|
95
|
+
variant: 'plain',
|
|
96
|
+
showValue: true,
|
|
97
|
+
valueSuffix: 'px',
|
|
98
|
+
max: 50,
|
|
99
|
+
modelValue: [8],
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The accent is per-instance, so a slider can match the context it sits in */
|
|
104
|
+
export const Green: Story = {
|
|
105
|
+
args: {
|
|
106
|
+
label: 'Voortgang',
|
|
107
|
+
color: 'green',
|
|
108
|
+
showValue: true,
|
|
109
|
+
valueSuffix: '%',
|
|
110
|
+
modelValue: [60],
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const Small: Story = {
|
|
115
|
+
args: {
|
|
116
|
+
label: 'Lijndikte',
|
|
117
|
+
size: 'sm',
|
|
118
|
+
showValue: true,
|
|
119
|
+
max: 50,
|
|
120
|
+
modelValue: [8],
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const Medium: Story = {
|
|
125
|
+
args: {
|
|
126
|
+
label: 'Lijndikte',
|
|
127
|
+
size: 'md',
|
|
128
|
+
showValue: true,
|
|
129
|
+
max: 50,
|
|
130
|
+
modelValue: [8],
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const Large: Story = {
|
|
135
|
+
args: {
|
|
136
|
+
label: 'Lijndikte',
|
|
137
|
+
size: 'lg',
|
|
138
|
+
showValue: true,
|
|
139
|
+
max: 50,
|
|
140
|
+
modelValue: [8],
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const Disabled: Story = {
|
|
145
|
+
args: {
|
|
146
|
+
label: 'Ronding',
|
|
147
|
+
showValue: true,
|
|
148
|
+
valueSuffix: 'px',
|
|
149
|
+
disabled: true,
|
|
150
|
+
},
|
|
151
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import Slider from './Slider.vue'
|
|
4
|
+
|
|
5
|
+
// jsdom ships no ResizeObserver, and reka-ui's slider observes its track to place the thumbs
|
|
6
|
+
vi.stubGlobal(
|
|
7
|
+
'ResizeObserver',
|
|
8
|
+
class {
|
|
9
|
+
observe() {}
|
|
10
|
+
unobserve() {}
|
|
11
|
+
disconnect() {}
|
|
12
|
+
},
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// jsdom implements no pointer capture either, and reka-ui captures the pointer on thumb pointerdown
|
|
16
|
+
Element.prototype.setPointerCapture ??= () => {}
|
|
17
|
+
Element.prototype.releasePointerCapture ??= () => {}
|
|
18
|
+
Element.prototype.hasPointerCapture ??= () => false
|
|
19
|
+
|
|
20
|
+
describe('Slider', () => {
|
|
21
|
+
it('renders a slider role', () => {
|
|
22
|
+
const wrapper = mount(Slider)
|
|
23
|
+
|
|
24
|
+
expect(wrapper.find('[role="slider"]').exists()).toBe(true)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('renders one thumb per value', () => {
|
|
28
|
+
const wrapper = mount(Slider, { props: { modelValue: [20, 80] } })
|
|
29
|
+
|
|
30
|
+
expect(wrapper.findAll('[role="slider"]')).toHaveLength(2)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('renders a single thumb by default', () => {
|
|
34
|
+
const wrapper = mount(Slider)
|
|
35
|
+
|
|
36
|
+
expect(wrapper.findAll('[role="slider"]')).toHaveLength(1)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// aria-valuenow is left out on purpose: reka-ui fills it once the thumb registers with its
|
|
40
|
+
// collection, which needs a layout pass jsdom never performs
|
|
41
|
+
it('exposes min and max on the thumb', () => {
|
|
42
|
+
const wrapper = mount(Slider, { props: { modelValue: [30], min: 5, max: 40 } })
|
|
43
|
+
const thumb = wrapper.find('[role="slider"]')
|
|
44
|
+
|
|
45
|
+
expect(thumb.attributes('aria-valuemin')).toBe('5')
|
|
46
|
+
expect(thumb.attributes('aria-valuemax')).toBe('40')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('fills the range with the blue accent by default', () => {
|
|
50
|
+
const wrapper = mount(Slider)
|
|
51
|
+
|
|
52
|
+
expect(wrapper.html()).toContain('bg-cornflower-blue-500')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('fills the range with the chosen accent', () => {
|
|
56
|
+
const wrapper = mount(Slider, { props: { color: 'green' } })
|
|
57
|
+
|
|
58
|
+
expect(wrapper.html()).toContain('bg-green-400')
|
|
59
|
+
expect(wrapper.html()).not.toContain('bg-cornflower-blue-500')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('colours the thumb instead of the track in the plain variant', () => {
|
|
63
|
+
const wrapper = mount(Slider, { props: { variant: 'plain' } })
|
|
64
|
+
const thumb = wrapper.find('[role="slider"]')
|
|
65
|
+
|
|
66
|
+
expect(thumb.classes()).toContain('bg-cornflower-blue-500')
|
|
67
|
+
expect(thumb.classes()).not.toContain('bg-white')
|
|
68
|
+
expect(wrapper.html()).toContain('bg-transparent')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('follows the accent in the plain variant', () => {
|
|
72
|
+
const wrapper = mount(Slider, { props: { variant: 'plain', color: 'green' } })
|
|
73
|
+
|
|
74
|
+
expect(wrapper.find('[role="slider"]').classes()).toContain('bg-green-400')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('leaves the thumb white in the filled variant', () => {
|
|
78
|
+
const wrapper = mount(Slider)
|
|
79
|
+
|
|
80
|
+
expect(wrapper.find('[role="slider"]').classes()).toContain('bg-white')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('scales the track with size', () => {
|
|
84
|
+
const wrapper = mount(Slider, { props: { size: 'lg' } })
|
|
85
|
+
|
|
86
|
+
expect(wrapper.html()).toContain('h-1.5')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// reka-ui preventDefaults the pointerdown and refocuses the thumb from script, so :focus-visible
|
|
90
|
+
// alone cannot tell a click from a keypress — the component tracks the modality itself
|
|
91
|
+
it('suppresses the focus ring after a pointer interaction', async () => {
|
|
92
|
+
const wrapper = mount(Slider)
|
|
93
|
+
await wrapper.find('[role="slider"]').trigger('pointerdown')
|
|
94
|
+
|
|
95
|
+
expect(wrapper.find('[role="slider"]').classes()).toContain('focus-visible:outline-none')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('restores the focus ring once a key is used', async () => {
|
|
99
|
+
const wrapper = mount(Slider)
|
|
100
|
+
const thumb = wrapper.find('[role="slider"]')
|
|
101
|
+
await thumb.trigger('pointerdown')
|
|
102
|
+
await thumb.trigger('keydown', { key: 'ArrowRight' })
|
|
103
|
+
|
|
104
|
+
expect(wrapper.find('[role="slider"]').classes()).toContain('focus-visible:outline-2')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('restores the focus ring once focus leaves the slider', async () => {
|
|
108
|
+
const wrapper = mount(Slider)
|
|
109
|
+
await wrapper.find('[role="slider"]').trigger('pointerdown')
|
|
110
|
+
await wrapper.find('[role="slider"]').trigger('focusout', { relatedTarget: null })
|
|
111
|
+
|
|
112
|
+
expect(wrapper.find('[role="slider"]').classes()).toContain('focus-visible:outline-2')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('renders no label by default', () => {
|
|
116
|
+
const wrapper = mount(Slider)
|
|
117
|
+
|
|
118
|
+
expect(wrapper.find('label').exists()).toBe(false)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('renders the label when given', () => {
|
|
122
|
+
const wrapper = mount(Slider, { props: { label: 'Ronding' } })
|
|
123
|
+
|
|
124
|
+
expect(wrapper.find('label').text()).toBe('Ronding')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('labels the thumb with the label', () => {
|
|
128
|
+
const wrapper = mount(Slider, { props: { label: 'Ronding' } })
|
|
129
|
+
|
|
130
|
+
expect(wrapper.find('[role="slider"]').attributes('aria-label')).toBe('Ronding')
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('names the thumb with ariaLabel when there is no visible label', () => {
|
|
134
|
+
const wrapper = mount(Slider, { props: { ariaLabel: 'Tussenruimte' } })
|
|
135
|
+
|
|
136
|
+
expect(wrapper.find('[role="slider"]').attributes('aria-label')).toBe('Tussenruimte')
|
|
137
|
+
expect(wrapper.find('label').exists()).toBe(false)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
// The model can be an index into a scale, in which case aria-valuenow announces a number the user
|
|
141
|
+
// never sees. This is the only way to correct that from outside the component.
|
|
142
|
+
it('announces ariaValuetext on the thumb', () => {
|
|
143
|
+
const wrapper = mount(Slider, { props: { modelValue: [4], ariaValuetext: '16 px' } })
|
|
144
|
+
|
|
145
|
+
expect(wrapper.find('[role="slider"]').attributes('aria-valuetext')).toBe('16 px')
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('leaves both aria attributes off the thumb when neither prop is given', () => {
|
|
149
|
+
const thumb = mount(Slider).find('[role="slider"]')
|
|
150
|
+
|
|
151
|
+
expect(thumb.attributes('aria-label')).toBeUndefined()
|
|
152
|
+
expect(thumb.attributes('aria-valuetext')).toBeUndefined()
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// One string cannot describe two thumbs, so it is dropped rather than repeated on both.
|
|
156
|
+
it('omits ariaValuetext on a range', () => {
|
|
157
|
+
const wrapper = mount(Slider, { props: { modelValue: [20, 80], ariaValuetext: '16 px' } })
|
|
158
|
+
|
|
159
|
+
for (const thumb of wrapper.findAll('[role="slider"]')) {
|
|
160
|
+
expect(thumb.attributes('aria-valuetext')).toBeUndefined()
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('hides the value by default', () => {
|
|
165
|
+
const wrapper = mount(Slider, { props: { modelValue: [12] } })
|
|
166
|
+
|
|
167
|
+
expect(wrapper.text()).not.toContain('12')
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('shows the value with its suffix when showValue is set', () => {
|
|
171
|
+
const wrapper = mount(Slider, {
|
|
172
|
+
props: { modelValue: [12], showValue: true, valueSuffix: 'px' },
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
expect(wrapper.text()).toContain('12px')
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('shows both ends of a range', () => {
|
|
179
|
+
const wrapper = mount(Slider, {
|
|
180
|
+
props: { modelValue: [200, 800], showValue: true, max: 1000 },
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
expect(wrapper.text()).toContain('200 – 800')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('disables the slider when disabled', () => {
|
|
187
|
+
const wrapper = mount(Slider, { props: { disabled: true } })
|
|
188
|
+
|
|
189
|
+
expect(wrapper.find('[role="slider"]').attributes('data-disabled')).toBeDefined()
|
|
190
|
+
})
|
|
191
|
+
})
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import Squircle from './Squircle.vue'
|
|
3
|
+
import propertyPlaceholder from '../../../assets/images/property_placeholder.jpg'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Atoms/Squircle',
|
|
7
|
+
component: Squircle,
|
|
8
|
+
argTypes: {
|
|
9
|
+
size: {
|
|
10
|
+
control: { type: 'select' },
|
|
11
|
+
options: ['xs', 'sm', 'md', 'lg', 'xl'],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
} satisfies Meta<typeof Squircle>
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof Squircle>
|
|
17
|
+
|
|
18
|
+
const imageSlot = `<img src="${propertyPlaceholder}" style="width:100%;height:100%;object-fit:cover;" />`
|
|
19
|
+
|
|
20
|
+
export const ExtraSmall: Story = {
|
|
21
|
+
args: { size: 'xs' },
|
|
22
|
+
render: (args) => ({
|
|
23
|
+
components: { Squircle },
|
|
24
|
+
setup: () => ({ args }),
|
|
25
|
+
template: `<Squircle v-bind="args">${imageSlot}</Squircle>`,
|
|
26
|
+
}),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const Small: Story = {
|
|
30
|
+
args: { size: 'sm' },
|
|
31
|
+
render: (args) => ({
|
|
32
|
+
components: { Squircle },
|
|
33
|
+
setup: () => ({ args }),
|
|
34
|
+
template: `<Squircle v-bind="args">${imageSlot}</Squircle>`,
|
|
35
|
+
}),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const Medium: Story = {
|
|
39
|
+
args: { size: 'md' },
|
|
40
|
+
render: (args) => ({
|
|
41
|
+
components: { Squircle },
|
|
42
|
+
setup: () => ({ args }),
|
|
43
|
+
template: `<Squircle v-bind="args">${imageSlot}</Squircle>`,
|
|
44
|
+
}),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const Large: Story = {
|
|
48
|
+
args: { size: 'lg' },
|
|
49
|
+
render: (args) => ({
|
|
50
|
+
components: { Squircle },
|
|
51
|
+
setup: () => ({ args }),
|
|
52
|
+
template: `<Squircle v-bind="args">${imageSlot}</Squircle>`,
|
|
53
|
+
}),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const ExtraLarge: Story = {
|
|
57
|
+
args: { size: 'xl' },
|
|
58
|
+
render: (args) => ({
|
|
59
|
+
components: { Squircle },
|
|
60
|
+
setup: () => ({ args }),
|
|
61
|
+
template: `<Squircle v-bind="args">${imageSlot}</Squircle>`,
|
|
62
|
+
}),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const CustomSize: Story = {
|
|
66
|
+
args: { size: 120 },
|
|
67
|
+
argTypes: {
|
|
68
|
+
size: {
|
|
69
|
+
control: { type: 'number' },
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
render: (args) => ({
|
|
73
|
+
components: { Squircle },
|
|
74
|
+
setup: () => ({ args }),
|
|
75
|
+
template: `<Squircle v-bind="args">${imageSlot}</Squircle>`,
|
|
76
|
+
}),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const WithImage: Story = {
|
|
80
|
+
args: { size: 'md' },
|
|
81
|
+
render: (args) => ({
|
|
82
|
+
components: { Squircle },
|
|
83
|
+
setup: () => ({ args }),
|
|
84
|
+
template: `<Squircle v-bind="args">${imageSlot}</Squircle>`,
|
|
85
|
+
}),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const WithColor: Story = {
|
|
89
|
+
args: { size: 'md' },
|
|
90
|
+
render: (args) => ({
|
|
91
|
+
components: { Squircle },
|
|
92
|
+
setup: () => ({ args }),
|
|
93
|
+
template: `
|
|
94
|
+
<Squircle v-bind="args">
|
|
95
|
+
<div style="width:100%;height:100%;background:#6366f1;display:flex;align-items:center;justify-content:center;">
|
|
96
|
+
<span style="color:white;font-size:1.5em;">✦</span>
|
|
97
|
+
</div>
|
|
98
|
+
</Squircle>
|
|
99
|
+
`,
|
|
100
|
+
}),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const WithGradient: Story = {
|
|
104
|
+
args: { size: 'md' },
|
|
105
|
+
render: (args) => ({
|
|
106
|
+
components: { Squircle },
|
|
107
|
+
setup: () => ({ args }),
|
|
108
|
+
template: `
|
|
109
|
+
<Squircle v-bind="args">
|
|
110
|
+
<div style="width:100%;height:100%;background:linear-gradient(135deg,#f97316,#ec4899);" />
|
|
111
|
+
</Squircle>
|
|
112
|
+
`,
|
|
113
|
+
}),
|
|
114
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import Squircle from './Squircle.vue'
|
|
4
|
+
|
|
5
|
+
describe('Squircle', () => {
|
|
6
|
+
it('renders slot content', () => {
|
|
7
|
+
const wrapper = mount(Squircle, {
|
|
8
|
+
slots: {
|
|
9
|
+
default: '<div class="test-content">Content</div>',
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
expect(wrapper.find('.test-content').exists()).toBe(true)
|
|
14
|
+
expect(wrapper.find('.test-content').text()).toBe('Content')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('applies default size (md)', () => {
|
|
18
|
+
const wrapper = mount(Squircle)
|
|
19
|
+
|
|
20
|
+
// md = 40px
|
|
21
|
+
expect(wrapper.attributes('style')).toContain('width: 40px')
|
|
22
|
+
expect(wrapper.attributes('style')).toContain('height: 40px')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('applies named sizes correctly', () => {
|
|
26
|
+
const sizes = {
|
|
27
|
+
xs: '24',
|
|
28
|
+
sm: '32',
|
|
29
|
+
md: '40',
|
|
30
|
+
lg: '48',
|
|
31
|
+
xl: '64',
|
|
32
|
+
} as const
|
|
33
|
+
|
|
34
|
+
for (const [name, value] of Object.entries(sizes)) {
|
|
35
|
+
const wrapper = mount(Squircle, {
|
|
36
|
+
props: { size: name as keyof typeof sizes },
|
|
37
|
+
})
|
|
38
|
+
expect(wrapper.attributes('style')).toContain(`width: ${value}px`)
|
|
39
|
+
expect(wrapper.attributes('style')).toContain(`height: ${value}px`)
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('applies custom numeric size', () => {
|
|
44
|
+
const wrapper = mount(Squircle, {
|
|
45
|
+
props: { size: 120 },
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
expect(wrapper.attributes('style')).toContain('width: 120px')
|
|
49
|
+
expect(wrapper.attributes('style')).toContain('height: 120px')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('clips the container with a unique clip-path', () => {
|
|
53
|
+
const wrapper = mount(Squircle)
|
|
54
|
+
const clipPath = wrapper.find('clipPath')
|
|
55
|
+
const id = clipPath.attributes('id')
|
|
56
|
+
|
|
57
|
+
expect(id).toMatch(/^squircle-clip-/)
|
|
58
|
+
expect(wrapper.attributes('style')).toMatch(new RegExp(`clip-path: url\\("?#${id}"?\\)`))
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('defines the squircle clipPath in objectBoundingBox units', () => {
|
|
62
|
+
const wrapper = mount(Squircle, { props: { size: 100 } })
|
|
63
|
+
const clipPath = wrapper.find('clipPath')
|
|
64
|
+
const path = clipPath.find('path')
|
|
65
|
+
|
|
66
|
+
expect(clipPath.attributes('clipPathUnits')).toBe('objectBoundingBox')
|
|
67
|
+
expect(path.exists()).toBe(true)
|
|
68
|
+
expect(path.attributes('d')).toContain('M0.5,1')
|
|
69
|
+
})
|
|
70
|
+
})
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test'
|
|
3
|
+
import Switch from './Switch.vue'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Atoms/Switch',
|
|
7
|
+
component: Switch,
|
|
8
|
+
argTypes: {
|
|
9
|
+
modelValue: {
|
|
10
|
+
control: 'boolean',
|
|
11
|
+
},
|
|
12
|
+
size: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['sm', 'md', 'lg'],
|
|
15
|
+
},
|
|
16
|
+
color: {
|
|
17
|
+
control: 'select',
|
|
18
|
+
options: ['blue', 'green'],
|
|
19
|
+
},
|
|
20
|
+
labelPosition: {
|
|
21
|
+
control: 'select',
|
|
22
|
+
options: ['before', 'after'],
|
|
23
|
+
},
|
|
24
|
+
iconOn: {
|
|
25
|
+
control: 'text',
|
|
26
|
+
},
|
|
27
|
+
iconOff: {
|
|
28
|
+
control: 'text',
|
|
29
|
+
},
|
|
30
|
+
default: {
|
|
31
|
+
control: 'text',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
args: {
|
|
35
|
+
modelValue: false,
|
|
36
|
+
size: 'lg',
|
|
37
|
+
color: 'blue',
|
|
38
|
+
labelPosition: 'after',
|
|
39
|
+
},
|
|
40
|
+
} satisfies Meta<typeof Switch>
|
|
41
|
+
|
|
42
|
+
type Story = StoryObj<typeof Switch>
|
|
43
|
+
|
|
44
|
+
export const Default: Story = {}
|
|
45
|
+
|
|
46
|
+
export const Green: Story = {
|
|
47
|
+
args: { color: 'green' },
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const WithIcons: Story = {
|
|
51
|
+
args: { iconOn: 'check', iconOff: 'xmark' },
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const GreenWithIcons: Story = {
|
|
55
|
+
args: { color: 'green', iconOn: 'check', iconOff: 'xmark' },
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const Small: Story = {
|
|
59
|
+
args: { size: 'sm' },
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const Medium: Story = {
|
|
63
|
+
args: { size: 'md' },
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const Large: Story = {
|
|
67
|
+
args: { size: 'lg' },
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const LabelAfter: Story = {
|
|
71
|
+
args: { default: 'Enable notifications', labelPosition: 'after' },
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const LabelBefore: Story = {
|
|
75
|
+
args: { default: 'Enable notifications', labelPosition: 'before' },
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const KeyboardFocus: Story = {
|
|
79
|
+
play: async ({ canvasElement }) => {
|
|
80
|
+
const canvas = within(canvasElement)
|
|
81
|
+
const input = canvas.getByRole('switch')
|
|
82
|
+
const track = input.nextElementSibling as HTMLElement
|
|
83
|
+
|
|
84
|
+
await userEvent.tab()
|
|
85
|
+
|
|
86
|
+
await waitFor(() => {
|
|
87
|
+
expect(input).toHaveFocus()
|
|
88
|
+
expect(getComputedStyle(track).outlineWidth).toBe('2px')
|
|
89
|
+
})
|
|
90
|
+
},
|
|
91
|
+
}
|