@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,104 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import CalendarDayView from './_CalendarDayView.vue'
|
|
4
|
+
import { nl } from 'date-fns/locale'
|
|
5
|
+
import { startOfMonth, endOfMonth, startOfWeek, endOfWeek, eachDayOfInterval } from 'date-fns'
|
|
6
|
+
|
|
7
|
+
const VIEW_DATE = new Date(2026, 2, 20) // March 20, 2026
|
|
8
|
+
const start = startOfWeek(startOfMonth(VIEW_DATE), { weekStartsOn: 1 })
|
|
9
|
+
const end = endOfWeek(endOfMonth(VIEW_DATE), { weekStartsOn: 1 })
|
|
10
|
+
const DAYS = eachDayOfInterval({ start, end })
|
|
11
|
+
|
|
12
|
+
const defaults = {
|
|
13
|
+
viewDate: VIEW_DATE,
|
|
14
|
+
calendarDays: DAYS,
|
|
15
|
+
modelValue: null,
|
|
16
|
+
markedDates: [],
|
|
17
|
+
locale: nl,
|
|
18
|
+
isDisabled: () => false,
|
|
19
|
+
timezone: 'UTC',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const mountDayView = (props: Record<string, unknown> = {}) =>
|
|
23
|
+
mount(CalendarDayView, {
|
|
24
|
+
props: { ...defaults, ...props },
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('CalendarDayView', () => {
|
|
28
|
+
it('renders the correct number of days', () => {
|
|
29
|
+
const wrapper = mountDayView()
|
|
30
|
+
const dayButtons = wrapper.findAll('button')
|
|
31
|
+
expect(dayButtons.length).toBe(DAYS.length)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('highlights the selected day', () => {
|
|
35
|
+
const selectedDate = new Date(2026, 2, 15)
|
|
36
|
+
const wrapper = mountDayView({
|
|
37
|
+
modelValue: selectedDate,
|
|
38
|
+
})
|
|
39
|
+
const selectedCell = wrapper.find('[role="gridcell"][aria-selected="true"]')
|
|
40
|
+
expect(selectedCell.exists()).toBe(true)
|
|
41
|
+
expect(selectedCell.text()).toBe('15')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('marks dates correctly', () => {
|
|
45
|
+
const markedDates = [new Date(2026, 2, 10)]
|
|
46
|
+
const wrapper = mountDayView({
|
|
47
|
+
markedDates,
|
|
48
|
+
})
|
|
49
|
+
// In our component, isMarked(day) is used to show a small dot.
|
|
50
|
+
// The dot is a span with bg-cornflower-blue-500 class.
|
|
51
|
+
expect(wrapper.find('.bg-cornflower-blue-500').exists()).toBe(true)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('disables dates based on isDisabled prop', () => {
|
|
55
|
+
const wrapper = mountDayView({
|
|
56
|
+
isDisabled: (day: Date) => day.getDate() === 15,
|
|
57
|
+
})
|
|
58
|
+
const disabledButton = wrapper.find('button[disabled]')
|
|
59
|
+
expect(disabledButton.exists()).toBe(true)
|
|
60
|
+
expect(disabledButton.text()).toBe('15')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('emits select event when a day is clicked', async () => {
|
|
64
|
+
const wrapper = mountDayView()
|
|
65
|
+
const button = wrapper.findAll('button')[10]
|
|
66
|
+
if (button) {
|
|
67
|
+
await button.trigger('click')
|
|
68
|
+
expect(wrapper.emitted('select')).toBeTruthy()
|
|
69
|
+
expect(wrapper.emitted('select')?.[0]?.[0]).toBeInstanceOf(Date)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('handles keyboard navigation (ArrowRight)', async () => {
|
|
74
|
+
const wrapper = mountDayView({
|
|
75
|
+
attachTo: document.body,
|
|
76
|
+
})
|
|
77
|
+
const button = wrapper.findAll('button')[0]
|
|
78
|
+
if (button) {
|
|
79
|
+
await button.trigger('keydown', { key: 'ArrowRight' })
|
|
80
|
+
}
|
|
81
|
+
// In vitest/jsdom, focus might not move as easily, so we check if the method logic runs
|
|
82
|
+
// For unit tests, we can also check if emit('select') is called on Enter/Space
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('emits select when Enter or Space is pressed', async () => {
|
|
86
|
+
const wrapper = mountDayView()
|
|
87
|
+
const button = wrapper.findAll('button')[0]
|
|
88
|
+
if (button) {
|
|
89
|
+
await button.trigger('keydown', { key: 'Enter' })
|
|
90
|
+
expect(wrapper.emitted('select')).toBeTruthy()
|
|
91
|
+
await button.trigger('keydown', { key: ' ' })
|
|
92
|
+
expect(wrapper.emitted('select')?.[1]).toBeTruthy()
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('does not emit select for other keys', async () => {
|
|
97
|
+
const wrapper = mountDayView()
|
|
98
|
+
const button = wrapper.findAll('button')[0]
|
|
99
|
+
if (button) {
|
|
100
|
+
await button.trigger('keydown', { key: 'Tab' })
|
|
101
|
+
expect(wrapper.emitted('select')).toBeFalsy()
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
})
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import CalendarHeader from './_CalendarHeader.vue'
|
|
4
|
+
import { nl } from 'date-fns/locale'
|
|
5
|
+
|
|
6
|
+
const VIEW_DATE = new Date(2026, 2, 20) // March 20, 2026
|
|
7
|
+
|
|
8
|
+
describe('CalendarHeader', () => {
|
|
9
|
+
it('renders the correct month and year label', () => {
|
|
10
|
+
const wrapper = mount(CalendarHeader, {
|
|
11
|
+
props: {
|
|
12
|
+
viewDate: VIEW_DATE,
|
|
13
|
+
pickerView: 'days',
|
|
14
|
+
monthYearPicker: false,
|
|
15
|
+
locale: nl,
|
|
16
|
+
canGoPrev: true,
|
|
17
|
+
canGoNext: true,
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
expect(wrapper.text()).toContain('Mrt.')
|
|
21
|
+
expect(wrapper.text()).toContain('2026')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('renders month and year as buttons if monthYearPicker is true', () => {
|
|
25
|
+
const wrapper = mount(CalendarHeader, {
|
|
26
|
+
props: {
|
|
27
|
+
viewDate: VIEW_DATE,
|
|
28
|
+
pickerView: 'days',
|
|
29
|
+
monthYearPicker: true,
|
|
30
|
+
locale: nl,
|
|
31
|
+
canGoPrev: true,
|
|
32
|
+
canGoNext: true,
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
const buttons = wrapper.findAll('.flex.items-center.gap-1 button')
|
|
36
|
+
expect(buttons.length).toBe(2)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('emits openMonthPicker when month label button is clicked', async () => {
|
|
40
|
+
const wrapper = mount(CalendarHeader, {
|
|
41
|
+
props: {
|
|
42
|
+
viewDate: VIEW_DATE,
|
|
43
|
+
pickerView: 'days',
|
|
44
|
+
monthYearPicker: true,
|
|
45
|
+
locale: nl,
|
|
46
|
+
canGoPrev: true,
|
|
47
|
+
canGoNext: true,
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
await wrapper.findAll('.flex.items-center.gap-1 button')[0].trigger('click')
|
|
51
|
+
expect(wrapper.emitted('openMonthPicker')).toBeTruthy()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('emits prev and next events', async () => {
|
|
55
|
+
const wrapper = mount(CalendarHeader, {
|
|
56
|
+
props: {
|
|
57
|
+
viewDate: VIEW_DATE,
|
|
58
|
+
pickerView: 'days',
|
|
59
|
+
monthYearPicker: false,
|
|
60
|
+
locale: nl,
|
|
61
|
+
canGoPrev: true,
|
|
62
|
+
canGoNext: true,
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
const navButtons = wrapper.findAll('button[aria-label]')
|
|
66
|
+
await navButtons[0].trigger('click')
|
|
67
|
+
expect(wrapper.emitted('prev')).toBeTruthy()
|
|
68
|
+
await navButtons[1].trigger('click')
|
|
69
|
+
expect(wrapper.emitted('next')).toBeTruthy()
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('shows back arrow instead of chevron when in years view', () => {
|
|
73
|
+
const wrapper = mount(CalendarHeader, {
|
|
74
|
+
props: {
|
|
75
|
+
viewDate: VIEW_DATE,
|
|
76
|
+
pickerView: 'years',
|
|
77
|
+
monthYearPicker: true,
|
|
78
|
+
locale: nl,
|
|
79
|
+
canGoPrev: false,
|
|
80
|
+
canGoNext: false,
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
const backButton = wrapper.find('button[aria-label="Terug naar maanden"]')
|
|
84
|
+
expect(backButton.exists()).toBe(true)
|
|
85
|
+
})
|
|
86
|
+
})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import CalendarMonthView from './_CalendarMonthView.vue'
|
|
4
|
+
import { nl } from 'date-fns/locale'
|
|
5
|
+
|
|
6
|
+
const VIEW_YEAR = 2026
|
|
7
|
+
const CURRENT_MONTH = 2 // March
|
|
8
|
+
|
|
9
|
+
const mountMonthView = (props: Record<string, unknown>) =>
|
|
10
|
+
mount(CalendarMonthView, {
|
|
11
|
+
props: {
|
|
12
|
+
viewYear: VIEW_YEAR,
|
|
13
|
+
modelValue: null,
|
|
14
|
+
currentMonth: CURRENT_MONTH,
|
|
15
|
+
locale: nl,
|
|
16
|
+
timezone: 'UTC',
|
|
17
|
+
...(props as Record<string, unknown>),
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
describe('CalendarMonthView', () => {
|
|
22
|
+
it('renders all 12 months', () => {
|
|
23
|
+
const wrapper = mountMonthView({})
|
|
24
|
+
const buttons = wrapper.findAll('button')
|
|
25
|
+
expect(buttons.length).toBe(12)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('highlights the selected month', () => {
|
|
29
|
+
const selectedDate = new Date(Date.UTC(VIEW_YEAR, 5, 15)) // June
|
|
30
|
+
const wrapper = mountMonthView({ modelValue: selectedDate })
|
|
31
|
+
const selectedButton = wrapper.find('button[aria-selected="true"]')
|
|
32
|
+
expect(selectedButton.text()).toBe('Jun')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('disables months based on minDate and maxDate', () => {
|
|
36
|
+
const minDate = new Date(Date.UTC(VIEW_YEAR, 2, 1)) // March 1st
|
|
37
|
+
const wrapper = mountMonthView({ minDate })
|
|
38
|
+
// January (0) and February (1) should be disabled
|
|
39
|
+
const disabledButtons = wrapper.findAll('button[disabled]')
|
|
40
|
+
expect(disabledButtons.length).toBe(2)
|
|
41
|
+
expect(disabledButtons[0]?.text()).toBe('Jan')
|
|
42
|
+
expect(disabledButtons[1]?.text()).toBe('Feb')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('emits select event when a month is clicked', async () => {
|
|
46
|
+
const wrapper = mountMonthView({})
|
|
47
|
+
await wrapper.findAll('button')[5]?.trigger('click')
|
|
48
|
+
const emitted = wrapper.emitted('select')
|
|
49
|
+
expect(emitted).toBeTruthy()
|
|
50
|
+
expect(emitted?.[0]?.[0]).toBe(5)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import { getHours, getMinutes } from 'date-fns'
|
|
4
|
+
import TimePicker from './_CalendarTimePicker.vue'
|
|
5
|
+
|
|
6
|
+
describe('CalendarTimePicker', () => {
|
|
7
|
+
it('renders correctly with modelValue', () => {
|
|
8
|
+
const date = new Date(2024, 0, 1, 10, 30)
|
|
9
|
+
const wrapper = mount(TimePicker, {
|
|
10
|
+
props: {
|
|
11
|
+
modelValue: date,
|
|
12
|
+
},
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const displays = wrapper.findAll('.tabular-nums')
|
|
16
|
+
expect(displays[0].text()).toBe('10')
|
|
17
|
+
expect(displays[1].text()).toBe('30')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('updates hours when buttons are clicked', async () => {
|
|
21
|
+
const date = new Date(2024, 0, 1, 10, 30)
|
|
22
|
+
const wrapper = mount(TimePicker, {
|
|
23
|
+
props: {
|
|
24
|
+
modelValue: date,
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const hourButtons = wrapper.findAll('button')
|
|
29
|
+
// First button is increment hours
|
|
30
|
+
await hourButtons[0].trigger('click')
|
|
31
|
+
|
|
32
|
+
const emitted = wrapper.emitted('update:modelValue')
|
|
33
|
+
expect(emitted).toBeTruthy()
|
|
34
|
+
const updatedDate = emitted![0][0] as Date
|
|
35
|
+
expect(getHours(updatedDate)).toBe(11)
|
|
36
|
+
expect(getMinutes(updatedDate)).toBe(30)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('updates minutes when buttons are clicked', async () => {
|
|
40
|
+
const date = new Date(2024, 0, 1, 10, 30)
|
|
41
|
+
const wrapper = mount(TimePicker, {
|
|
42
|
+
props: {
|
|
43
|
+
modelValue: date,
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const minuteButtons = wrapper.findAll('button')
|
|
48
|
+
// Third button is increment minutes (0: inc hours, 1: dec hours, 2: inc minutes, 3: dec minutes)
|
|
49
|
+
await minuteButtons[2].trigger('click')
|
|
50
|
+
|
|
51
|
+
const emitted = wrapper.emitted('update:modelValue')
|
|
52
|
+
expect(emitted).toBeTruthy()
|
|
53
|
+
const updatedDate = emitted![0][0] as Date
|
|
54
|
+
expect(getHours(updatedDate)).toBe(10)
|
|
55
|
+
expect(getMinutes(updatedDate)).toBe(31)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('handles null modelValue by using current time as default', () => {
|
|
59
|
+
const now = new Date()
|
|
60
|
+
const wrapper = mount(TimePicker, {
|
|
61
|
+
props: {
|
|
62
|
+
modelValue: null,
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const displays = wrapper.findAll('.tabular-nums')
|
|
67
|
+
expect(displays[0].text()).toBe(now.getHours().toString().padStart(2, '0'))
|
|
68
|
+
expect(displays[1].text()).toBe(now.getMinutes().toString().padStart(2, '0'))
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('emits current date and time when buttons clicked with null modelValue', async () => {
|
|
72
|
+
const wrapper = mount(TimePicker, {
|
|
73
|
+
props: {
|
|
74
|
+
modelValue: null,
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const hourButtons = wrapper.findAll('button')
|
|
79
|
+
await hourButtons[0].trigger('click') // increment hours
|
|
80
|
+
|
|
81
|
+
const emitted = wrapper.emitted('update:modelValue')
|
|
82
|
+
expect(emitted).toBeTruthy()
|
|
83
|
+
const updatedDate = emitted![0][0] as Date
|
|
84
|
+
expect(updatedDate).toBeInstanceOf(Date)
|
|
85
|
+
// Check that it roughly matches current time + 1 hour
|
|
86
|
+
const expectedHour = (new Date().getHours() + 1) % 24
|
|
87
|
+
expect(getHours(updatedDate)).toBe(expectedHour)
|
|
88
|
+
})
|
|
89
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import CalendarYearView from './_CalendarYearView.vue'
|
|
4
|
+
|
|
5
|
+
describe('CalendarYearView', () => {
|
|
6
|
+
it('renders a range of years', () => {
|
|
7
|
+
const wrapper = mount(CalendarYearView, {
|
|
8
|
+
props: {
|
|
9
|
+
viewYear: 2024,
|
|
10
|
+
timezone: 'UTC',
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
const items = wrapper.findAll('button')
|
|
14
|
+
expect(items.length).toBeGreaterThan(100) // Default range is viewYear - 100 to + 20
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('respects minDate and maxDate', () => {
|
|
18
|
+
const wrapper = mount(CalendarYearView, {
|
|
19
|
+
props: {
|
|
20
|
+
viewYear: 2024,
|
|
21
|
+
minDate: new Date(Date.UTC(2020, 0, 1)),
|
|
22
|
+
maxDate: new Date(Date.UTC(2025, 0, 1)),
|
|
23
|
+
timezone: 'UTC',
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
const items = wrapper.findAll('button')
|
|
27
|
+
// 2020 to 2025 inclusive is 6 years
|
|
28
|
+
expect(items.length).toBe(6)
|
|
29
|
+
expect(items[0]?.text()).toBe('2020')
|
|
30
|
+
expect(items[5]?.text()).toBe('2025')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('emits select when a year is clicked', async () => {
|
|
34
|
+
const wrapper = mount(CalendarYearView, {
|
|
35
|
+
props: {
|
|
36
|
+
viewYear: 2024,
|
|
37
|
+
timezone: 'UTC',
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
const year2024 = wrapper.findAll('button').find((i) => i.text() === '2024')
|
|
41
|
+
await year2024?.trigger('click')
|
|
42
|
+
expect(wrapper.emitted('select')).toBeTruthy()
|
|
43
|
+
expect(wrapper.emitted('select')?.[0]?.[0]).toBe(2024)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('highlights the current year', async () => {
|
|
47
|
+
const wrapper = mount(CalendarYearView, {
|
|
48
|
+
props: {
|
|
49
|
+
viewYear: 2024,
|
|
50
|
+
timezone: 'UTC',
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
const activeYear = wrapper.find('button.text-cornflower-blue-500')
|
|
54
|
+
expect(activeYear.text()).toBe('2024')
|
|
55
|
+
})
|
|
56
|
+
})
|
|
@@ -0,0 +1,229 @@
|
|
|
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 type { ColorPickerGradient, ColorPickerFillMode } from './ColorPicker.vue'
|
|
5
|
+
import NexxtColorPicker from './ColorPicker.vue'
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: 'Components/Organisms/Color picker',
|
|
9
|
+
component: NexxtColorPicker,
|
|
10
|
+
} satisfies Meta<typeof NexxtColorPicker>
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof NexxtColorPicker>
|
|
13
|
+
|
|
14
|
+
const render = (args: Story['args']) => ({
|
|
15
|
+
components: { NexxtColorPicker },
|
|
16
|
+
setup() {
|
|
17
|
+
return { args }
|
|
18
|
+
},
|
|
19
|
+
template: `
|
|
20
|
+
<NexxtColorPicker
|
|
21
|
+
v-bind="args"
|
|
22
|
+
:modelValue="args.modelValue"
|
|
23
|
+
@update:modelValue="args.modelValue = $event"
|
|
24
|
+
/>
|
|
25
|
+
`,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
export const Default: Story = {
|
|
29
|
+
render,
|
|
30
|
+
args: {
|
|
31
|
+
label: '',
|
|
32
|
+
placeholder: 'Kies kleur...',
|
|
33
|
+
modelValue: '',
|
|
34
|
+
error: false,
|
|
35
|
+
errorMessage: '',
|
|
36
|
+
required: false,
|
|
37
|
+
showAlpha: false,
|
|
38
|
+
formats: ['hex'],
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const WithLabel: Story = {
|
|
43
|
+
render,
|
|
44
|
+
args: {
|
|
45
|
+
...Default.args,
|
|
46
|
+
label: 'Merkkleur',
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const WithValue: Story = {
|
|
51
|
+
render,
|
|
52
|
+
args: {
|
|
53
|
+
...Default.args,
|
|
54
|
+
label: 'Achtergrondkleur',
|
|
55
|
+
modelValue: '#6366f1',
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
/** A value with a name of its own shows that name in the trigger instead of the colour. */
|
|
59
|
+
export const WithValueLabel: Story = {
|
|
60
|
+
render,
|
|
61
|
+
args: {
|
|
62
|
+
...Default.args,
|
|
63
|
+
label: 'Achtergrondkleur',
|
|
64
|
+
modelValue: '#1777ea',
|
|
65
|
+
valueLabel: 'Hoofdkleur',
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
export const WithSuggestions: Story = {
|
|
69
|
+
render,
|
|
70
|
+
args: {
|
|
71
|
+
...Default.args,
|
|
72
|
+
label: 'Achtergrondkleur',
|
|
73
|
+
suggestions: { hex: ['#1777ea', '#f0f4f8', '#1f2937'] },
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const Error: Story = {
|
|
78
|
+
render,
|
|
79
|
+
args: {
|
|
80
|
+
...Default.args,
|
|
81
|
+
label: 'Kleur',
|
|
82
|
+
error: true,
|
|
83
|
+
errorMessage: 'Kies een kleur om door te gaan',
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const Required: Story = {
|
|
88
|
+
render,
|
|
89
|
+
args: {
|
|
90
|
+
...Default.args,
|
|
91
|
+
label: 'Primaire kleur',
|
|
92
|
+
required: true,
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The opacity slider is named by its visible label. The play runs in Chromium,
|
|
98
|
+
* where the name is computed from the rendered label rather than read off an
|
|
99
|
+
* attribute.
|
|
100
|
+
*/
|
|
101
|
+
export const WithAlpha: Story = {
|
|
102
|
+
render,
|
|
103
|
+
args: {
|
|
104
|
+
...Default.args,
|
|
105
|
+
label: 'Overlay kleur',
|
|
106
|
+
modelValue: '#3b82f680',
|
|
107
|
+
showAlpha: true,
|
|
108
|
+
},
|
|
109
|
+
play: async ({ canvasElement, args }) => {
|
|
110
|
+
const canvas = within(canvasElement)
|
|
111
|
+
|
|
112
|
+
await userEvent.click(canvas.getByRole('button', { name: 'Overlay kleur' }))
|
|
113
|
+
|
|
114
|
+
// The name is matched exactly: the label alone, once, and not reka's "Alpha".
|
|
115
|
+
const slider = await canvas.findByRole('slider', { name: 'Dekking' })
|
|
116
|
+
expect(slider).not.toHaveAttribute('aria-label')
|
|
117
|
+
|
|
118
|
+
// `#…80` is 50.196% to reka; the slider announces it whole, the colour stays.
|
|
119
|
+
expect(slider).toHaveAttribute('aria-valuenow', '50')
|
|
120
|
+
expect(slider).toHaveAttribute('aria-valuetext', '50%')
|
|
121
|
+
expect(args.modelValue).toBe('#3b82f680')
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const HslFormat: Story = {
|
|
126
|
+
render,
|
|
127
|
+
args: {
|
|
128
|
+
...Default.args,
|
|
129
|
+
label: 'HSL kleur',
|
|
130
|
+
modelValue: '#6366f1',
|
|
131
|
+
formats: ['hsl'],
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const RgbFormat: Story = {
|
|
136
|
+
render,
|
|
137
|
+
args: {
|
|
138
|
+
...Default.args,
|
|
139
|
+
label: 'RGB kleur',
|
|
140
|
+
modelValue: '#6366f1',
|
|
141
|
+
formats: ['rgb'],
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export const AllFormats: Story = {
|
|
146
|
+
render,
|
|
147
|
+
args: {
|
|
148
|
+
...Default.args,
|
|
149
|
+
label: 'Alle formaten',
|
|
150
|
+
formats: ['hex', 'hsl', 'rgb'],
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const FullWidth: Story = {
|
|
155
|
+
render,
|
|
156
|
+
args: {
|
|
157
|
+
...Default.args,
|
|
158
|
+
label: 'Volledige breedte',
|
|
159
|
+
modelValue: '#6366f1',
|
|
160
|
+
fullWidth: true,
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const MatchWidth: Story = {
|
|
165
|
+
render,
|
|
166
|
+
args: {
|
|
167
|
+
...Default.args,
|
|
168
|
+
label: 'Panel op triggerbreedte',
|
|
169
|
+
modelValue: '#6366f1',
|
|
170
|
+
fullWidth: true,
|
|
171
|
+
matchWidth: true,
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The gradient mode on its own: the picker edits plain data (type, angle,
|
|
177
|
+
* centre, stops) and knows no class names; NexxtEditorColor turns it into
|
|
178
|
+
* Tailwind classes. Rendered at the editor column's width.
|
|
179
|
+
*/
|
|
180
|
+
export const Gradient: Story = {
|
|
181
|
+
args: { modes: ['solid', 'gradient'], suggestions: { hex: ['#7f56d9', '#432e73'] } },
|
|
182
|
+
render: (args) => ({
|
|
183
|
+
components: { NexxtColorPicker },
|
|
184
|
+
setup() {
|
|
185
|
+
const mode = ref<ColorPickerFillMode>('gradient')
|
|
186
|
+
const gradient = ref<ColorPickerGradient>({
|
|
187
|
+
type: 'linear',
|
|
188
|
+
angle: 135,
|
|
189
|
+
centerX: 50,
|
|
190
|
+
centerY: 50,
|
|
191
|
+
stops: [
|
|
192
|
+
{ color: '#7f56d9', position: 0 },
|
|
193
|
+
{ color: '#432e73cc', position: 100 },
|
|
194
|
+
],
|
|
195
|
+
})
|
|
196
|
+
return { args, mode, gradient }
|
|
197
|
+
},
|
|
198
|
+
template: `
|
|
199
|
+
<div class="w-64">
|
|
200
|
+
<NexxtColorPicker
|
|
201
|
+
v-bind="args"
|
|
202
|
+
v-model:mode="mode"
|
|
203
|
+
v-model:gradient-value="gradient"
|
|
204
|
+
full-width
|
|
205
|
+
match-width
|
|
206
|
+
/>
|
|
207
|
+
</div>
|
|
208
|
+
`,
|
|
209
|
+
}),
|
|
210
|
+
play: async ({ canvasElement }) => {
|
|
211
|
+
const canvas = within(canvasElement)
|
|
212
|
+
const trigger = canvas.getByRole('button', { name: /Kies kleur/ })
|
|
213
|
+
expect(trigger).toHaveTextContent('Lineair verloop')
|
|
214
|
+
await userEvent.click(trigger)
|
|
215
|
+
await waitFor(() => expect(canvasElement.querySelector('[data-gradient-bar]')).not.toBeNull())
|
|
216
|
+
|
|
217
|
+
const panel = canvasElement
|
|
218
|
+
.querySelector('[data-gradient-bar]')!
|
|
219
|
+
.closest<HTMLElement>('div[style*="position: fixed"]')!
|
|
220
|
+
expect(within(panel).getByRole('slider', { name: 'Hoek' })).toHaveAttribute(
|
|
221
|
+
'aria-valuetext',
|
|
222
|
+
'135 graden',
|
|
223
|
+
)
|
|
224
|
+
expect(within(panel).getAllByRole('slider', { name: /^Kleurstop \d van 2$/ })).toHaveLength(2)
|
|
225
|
+
const surface = panel.querySelector<HTMLElement>('.rounded-xl')!
|
|
226
|
+
expect(surface.offsetWidth).toBe(trigger.offsetWidth)
|
|
227
|
+
expect(surface.scrollHeight).toBeLessThanOrEqual(surface.clientHeight)
|
|
228
|
+
},
|
|
229
|
+
}
|