@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.
Files changed (228) hide show
  1. package/dist/components/editor/molecules/EditorBorder/EditorBorder.vue.d.ts +12 -0
  2. package/dist/components/editor/molecules/EditorColor/_ThemeRoleSwatches.vue.d.ts +16 -0
  3. package/dist/index.js +1094 -1135
  4. package/dist/nuxt.js +0 -1
  5. package/package.json +38 -36
  6. package/src/attribute-contract.test.ts +151 -0
  7. package/src/components/atoms/AnimatedNumber/AnimatedNumber.stories.ts +36 -0
  8. package/src/components/atoms/AnimatedNumber/AnimatedNumber.test.ts +21 -0
  9. package/src/components/atoms/Avatar/Avatar.stories.ts +122 -0
  10. package/src/components/atoms/Avatar/Avatar.test.ts +134 -0
  11. package/src/components/atoms/Button/Button.stories.ts +290 -0
  12. package/src/components/atoms/Button/Button.test.ts +406 -0
  13. package/src/components/atoms/Card/Card.stories.ts +45 -0
  14. package/src/components/atoms/Card/Card.test.ts +46 -0
  15. package/src/components/atoms/Checkbox/Checkbox.stories.ts +35 -0
  16. package/src/components/atoms/Checkbox/Checkbox.test.ts +55 -0
  17. package/src/components/atoms/Chip/Chip.stories.ts +274 -0
  18. package/src/components/atoms/Chip/Chip.test.ts +230 -0
  19. package/src/components/atoms/EnergyLabel/EnergyLabel.stories.ts +189 -0
  20. package/src/components/atoms/EnergyLabel/EnergyLabel.test.ts +100 -0
  21. package/src/components/atoms/FloatingPanel/FloatingPanel.stories.ts +677 -0
  22. package/src/components/atoms/FloatingPanel/FloatingPanel.test.ts +864 -0
  23. package/src/components/atoms/Icon/Icon.stories.ts +63 -0
  24. package/src/components/atoms/Icon/Icon.test.ts +89 -0
  25. package/src/components/atoms/Loader/Loader.stories.ts +36 -0
  26. package/src/components/atoms/Loader/Loader.test.ts +40 -0
  27. package/src/components/atoms/PickerItem/PickerItem.stories.ts +172 -0
  28. package/src/components/atoms/PickerItem/PickerItem.test.ts +142 -0
  29. package/src/components/atoms/PickerPreview/PickerPreview.stories.ts +183 -0
  30. package/src/components/atoms/PickerPreview/PickerPreview.test.ts +137 -0
  31. package/src/components/atoms/PresenceIndicator/PresenceIndicator.stories.ts +21 -0
  32. package/src/components/atoms/PropertyListing/PropertyListing.stories.ts +38 -0
  33. package/src/components/atoms/PropertyListing/PropertyListing.test.ts +46 -0
  34. package/src/components/atoms/SelectableOption/SelectableOption.stories.ts +131 -0
  35. package/src/components/atoms/SelectableOption/SelectableOption.test.ts +96 -0
  36. package/src/components/atoms/Skeleton/Skeleton.stories.ts +27 -0
  37. package/src/components/atoms/Skeleton/Skeleton.test.ts +28 -0
  38. package/src/components/atoms/Slider/Slider.stories.ts +151 -0
  39. package/src/components/atoms/Slider/Slider.test.ts +191 -0
  40. package/src/components/atoms/Squircle/Squircle.stories.ts +114 -0
  41. package/src/components/atoms/Squircle/Squircle.test.ts +70 -0
  42. package/src/components/atoms/Switch/Switch.stories.ts +91 -0
  43. package/src/components/atoms/Switch/Switch.test.ts +183 -0
  44. package/src/components/atoms/Tooltip/Tooltip.stories.ts +158 -0
  45. package/src/components/atoms/Tooltip/Tooltip.test.ts +134 -0
  46. package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.stories.ts +124 -0
  47. package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.test.ts +464 -0
  48. package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.stories.ts +266 -0
  49. package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.test.ts +421 -0
  50. package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.stories.ts +365 -0
  51. package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.test.ts +484 -0
  52. package/src/components/editor/composables/useRadioGrid.test.ts +261 -0
  53. package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.stories.ts +73 -0
  54. package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.test.ts +189 -0
  55. package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.stories.ts +309 -0
  56. package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.test.ts +359 -0
  57. package/src/components/editor/molecules/EditorAnchor/EditorAnchor.stories.ts +138 -0
  58. package/src/components/editor/molecules/EditorAnchor/EditorAnchor.test.ts +344 -0
  59. package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.stories.ts +87 -0
  60. package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.test.ts +262 -0
  61. package/src/components/editor/molecules/EditorBlur/EditorBlur.stories.ts +115 -0
  62. package/src/components/editor/molecules/EditorBlur/EditorBlur.test.ts +243 -0
  63. package/src/components/editor/molecules/EditorBorder/EditorBorder.stories.ts +187 -0
  64. package/src/components/editor/molecules/EditorBorder/EditorBorder.test.ts +456 -0
  65. package/src/components/editor/molecules/EditorBorder/EditorBorder.vue +58 -2
  66. package/src/components/editor/molecules/EditorColor/EditorColor.stories.ts +563 -0
  67. package/src/components/editor/molecules/EditorColor/EditorColor.test.ts +689 -0
  68. package/src/components/editor/molecules/EditorColor/EditorColorGradient.test.ts +793 -0
  69. package/src/components/editor/molecules/EditorColor/_ColorField.vue +7 -29
  70. package/src/components/editor/molecules/EditorColor/_ThemeRoleSwatches.vue +57 -0
  71. package/src/components/editor/molecules/EditorColor/gradientClass.test.ts +303 -0
  72. package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.stories.ts +72 -0
  73. package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.test.ts +124 -0
  74. package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.stories.ts +46 -0
  75. package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.test.ts +97 -0
  76. package/src/components/editor/molecules/EditorFontSize/EditorFontSize.stories.ts +248 -0
  77. package/src/components/editor/molecules/EditorFontSize/EditorFontSize.test.ts +288 -0
  78. package/src/components/editor/molecules/EditorGap/EditorGap.stories.ts +129 -0
  79. package/src/components/editor/molecules/EditorGap/EditorGap.test.ts +253 -0
  80. package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.stories.ts +68 -0
  81. package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.test.ts +150 -0
  82. package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.stories.ts +71 -0
  83. package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.test.ts +161 -0
  84. package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.stories.ts +204 -0
  85. package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.test.ts +238 -0
  86. package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.stories.ts +257 -0
  87. package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.test.ts +286 -0
  88. package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.stories.ts +135 -0
  89. package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.test.ts +230 -0
  90. package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.stories.ts +154 -0
  91. package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.test.ts +112 -0
  92. package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.stories.ts +206 -0
  93. package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.test.ts +332 -0
  94. package/src/components/editor/molecules/EditorPadding/EditorPadding.stories.ts +374 -0
  95. package/src/components/editor/molecules/EditorPadding/EditorPadding.test.ts +712 -0
  96. package/src/components/editor/molecules/EditorRadius/EditorRadius.stories.ts +64 -0
  97. package/src/components/editor/molecules/EditorRadius/EditorRadius.test.ts +137 -0
  98. package/src/components/editor/molecules/EditorShadow/EditorShadow.stories.ts +103 -0
  99. package/src/components/editor/molecules/EditorShadow/EditorShadow.test.ts +168 -0
  100. package/src/components/editor/molecules/EditorSize/EditorSize.stories.ts +84 -0
  101. package/src/components/editor/molecules/EditorSize/EditorSize.test.ts +253 -0
  102. package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.stories.ts +49 -0
  103. package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.test.ts +43 -0
  104. package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.stories.ts +69 -0
  105. package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.test.ts +155 -0
  106. package/src/components/molecules/Announcement/Announcement.stories.ts +224 -0
  107. package/src/components/molecules/Announcement/Announcement.test.ts +161 -0
  108. package/src/components/molecules/ContactInfoCard/ContactInfoCard.stories.ts +99 -0
  109. package/src/components/molecules/ContactInfoCard/ContactInfoCard.test.ts +70 -0
  110. package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.stories.ts +148 -0
  111. package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.test.ts +271 -0
  112. package/src/components/molecules/DoughnutChart/DoughnutChart.stories.ts +45 -0
  113. package/src/components/molecules/DoughnutChart/DoughnutChart.test.ts +205 -0
  114. package/src/components/molecules/InfoBlock/InfoBlock.stories.ts +84 -0
  115. package/src/components/molecules/InfoBlock/InfoBlock.test.ts +101 -0
  116. package/src/components/molecules/InputField/InputField.stories.ts +117 -0
  117. package/src/components/molecules/InputField/InputField.test.ts +138 -0
  118. package/src/components/molecules/InputSelect/InputSelect.stories.ts +116 -0
  119. package/src/components/molecules/InputSelect/InputSelect.test.ts +127 -0
  120. package/src/components/molecules/ModalFooter/ModalFooter.stories.ts +204 -0
  121. package/src/components/molecules/ModalFooter/ModalFooter.test.ts +276 -0
  122. package/src/components/molecules/PageCard/PageCard.stories.ts +100 -0
  123. package/src/components/molecules/PageCard/PageCard.test.ts +91 -0
  124. package/src/components/molecules/PageContainer/PageContainer.stories.ts +90 -0
  125. package/src/components/molecules/PageContainer/PageContainer.test.ts +50 -0
  126. package/src/components/molecules/PageMockup/PageMockup.stories.ts +38 -0
  127. package/src/components/molecules/PageMockup/PageMockup.test.ts +20 -0
  128. package/src/components/molecules/PageTypeTile/PageTypeTile.stories.ts +63 -0
  129. package/src/components/molecules/PageTypeTile/PageTypeTile.test.ts +41 -0
  130. package/src/components/molecules/Pagination/Pagination.stories.ts +72 -0
  131. package/src/components/molecules/Pagination/Pagination.test.ts +130 -0
  132. package/src/components/molecules/PickerGroup/PickerGroup.stories.ts +90 -0
  133. package/src/components/molecules/PickerGroup/PickerGroup.test.ts +145 -0
  134. package/src/components/molecules/PickerList/PickerList.stories.ts +436 -0
  135. package/src/components/molecules/PickerList/PickerList.test.ts +870 -0
  136. package/src/components/molecules/PlaceholderInput/PlaceholderInput.stories.ts +48 -0
  137. package/src/components/molecules/PlaceholderInput/PlaceholderInput.test.ts +107 -0
  138. package/src/components/molecules/PropertyCard/PropertyCard.stories.ts +46 -0
  139. package/src/components/molecules/PropertyCard/PropertyCard.test.ts +59 -0
  140. package/src/components/molecules/Select/Select.stories.ts +264 -0
  141. package/src/components/molecules/Select/Select.test.ts +315 -0
  142. package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.stories.ts +84 -0
  143. package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.test.ts +103 -0
  144. package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.stories.ts +11 -0
  145. package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.test.ts +38 -0
  146. package/src/components/molecules/SocialIcons/SocialIcons.stories.ts +28 -0
  147. package/src/components/molecules/SocialIcons/SocialIcons.test.ts +58 -0
  148. package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.stories.ts +11 -0
  149. package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.test.ts +116 -0
  150. package/src/components/molecules/SocialMediaType/SocialMediaType.stories.ts +37 -0
  151. package/src/components/molecules/SocialMediaType/SocialMediaType.test.ts +126 -0
  152. package/src/components/molecules/Source/Source.stories.ts +35 -0
  153. package/src/components/molecules/Source/Source.test.ts +45 -0
  154. package/src/components/molecules/TabbedContent/TabbedContent.stories.ts +96 -0
  155. package/src/components/molecules/TabbedContent/TabbedContent.test.ts +109 -0
  156. package/src/components/molecules/Tabs/Tabs.stories.ts +230 -0
  157. package/src/components/molecules/Tabs/Tabs.test.ts +280 -0
  158. package/src/components/molecules/TemplateCard/TemplateCard.stories.ts +327 -0
  159. package/src/components/molecules/TemplateCard/TemplateCard.test.ts +339 -0
  160. package/src/components/molecules/Textarea/Textarea.stories.ts +216 -0
  161. package/src/components/molecules/Textarea/Textarea.test.ts +191 -0
  162. package/src/components/molecules/TimelineEvent/TimelineEvent.stories.ts +319 -0
  163. package/src/components/molecules/TimelineEvent/TimelineEvent.test.ts +224 -0
  164. package/src/components/molecules/TimelineLanes/TimelineLanes.stories.ts +29 -0
  165. package/src/components/molecules/TimelineLanes/TimelineLanes.test.ts +30 -0
  166. package/src/components/molecules/Toast/Toast.stories.ts +110 -0
  167. package/src/components/molecules/Toast/Toast.test.ts +103 -0
  168. package/src/components/molecules/ToggleGroup/ToggleGroup.stories.ts +297 -0
  169. package/src/components/molecules/ToggleGroup/ToggleGroup.test.ts +578 -0
  170. package/src/components/molecules/Tree/Tree.stories.ts +884 -0
  171. package/src/components/molecules/Tree/Tree.test.ts +1247 -0
  172. package/src/components/molecules/Tree/tree-drop.test.ts +223 -0
  173. package/src/components/organisms/Calendar/Calendar.stories.ts +108 -0
  174. package/src/components/organisms/Calendar/Calendar.test.ts +279 -0
  175. package/src/components/organisms/Calendar/_CalendarDayView.test.ts +104 -0
  176. package/src/components/organisms/Calendar/_CalendarHeader.test.ts +86 -0
  177. package/src/components/organisms/Calendar/_CalendarMonthView.test.ts +52 -0
  178. package/src/components/organisms/Calendar/_CalendarTimePicker.test.ts +89 -0
  179. package/src/components/organisms/Calendar/_CalendarYearView.test.ts +56 -0
  180. package/src/components/organisms/ColorPicker/ColorPicker.stories.ts +229 -0
  181. package/src/components/organisms/ColorPicker/ColorPicker.test.ts +638 -0
  182. package/src/components/organisms/ColorPicker/gradient.test.ts +67 -0
  183. package/src/components/organisms/ColorPicker/gradientGeometry.test.ts +206 -0
  184. package/src/components/organisms/Combobox/Combobox.stories.ts +234 -0
  185. package/src/components/organisms/Combobox/Combobox.test.ts +512 -0
  186. package/src/components/organisms/Combobox/Combobox.vue +1 -1
  187. package/src/components/organisms/ComboboxPanel/ComboboxPanel.stories.ts +158 -0
  188. package/src/components/organisms/ComboboxPanel/ComboboxPanel.test.ts +524 -0
  189. package/src/components/organisms/ComboboxPanel/ComboboxPanel.vue +1 -1
  190. package/src/components/organisms/CountrySelect/CountrySelect.stories.ts +139 -0
  191. package/src/components/organisms/CountrySelect/CountrySelect.test.ts +149 -0
  192. package/src/components/organisms/DatePicker/DatePicker.stories.ts +163 -0
  193. package/src/components/organisms/DatePicker/DatePicker.test.ts +214 -0
  194. package/src/components/organisms/DropdownButton/DropdownButton.stories.ts +123 -0
  195. package/src/components/organisms/DropdownButton/DropdownButton.test.ts +379 -0
  196. package/src/components/organisms/FontPicker/FontPicker.stories.ts +476 -0
  197. package/src/components/organisms/FontPicker/FontPicker.test.ts +873 -0
  198. package/src/components/organisms/Header/Header.stories.ts +75 -0
  199. package/src/components/organisms/Header/Header.test.ts +233 -0
  200. package/src/components/organisms/IconPicker/IconPicker.stories.ts +734 -0
  201. package/src/components/organisms/IconPicker/IconPicker.test.ts +669 -0
  202. package/src/components/organisms/IconPicker/_IconPickerGrid.test.ts +184 -0
  203. package/src/components/organisms/IconPicker/_IconPickerRail.test.ts +102 -0
  204. package/src/components/organisms/IconPicker/useIconPickerNavigation.test.ts +215 -0
  205. package/src/components/organisms/Modal/Modal.stories.ts +350 -0
  206. package/src/components/organisms/Modal/Modal.test.ts +275 -0
  207. package/src/components/organisms/PickerPanel/PickerPanel.stories.ts +452 -0
  208. package/src/components/organisms/PickerPanel/PickerPanel.test.ts +358 -0
  209. package/src/components/organisms/ProgressBar/ProgressBar.stories.ts +100 -0
  210. package/src/components/organisms/ProgressBar/ProgressBar.test.ts +417 -0
  211. package/src/components/organisms/ReferenceCard/ReferenceCard.stories.ts +191 -0
  212. package/src/components/organisms/ReferenceCard/ReferenceCard.test.ts +165 -0
  213. package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.stories.ts +65 -0
  214. package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.test.ts +466 -0
  215. package/src/components/organisms/StepperHeader/StepperHeader.stories.ts +91 -0
  216. package/src/components/organisms/StepperHeader/StepperHeader.test.ts +279 -0
  217. package/src/components/organisms/Table/Table.stories.ts +332 -0
  218. package/src/components/organisms/Table/Table.test.ts +320 -0
  219. package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.stories.ts +198 -0
  220. package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.test.ts +283 -0
  221. package/src/components/organisms/TimelineTrack/TimelineTrack.stories.ts +120 -0
  222. package/src/components/organisms/TimelineTrack/TimelineTrack.test.ts +91 -0
  223. package/src/components/organisms/Toaster/Toaster.stories.ts +51 -0
  224. package/src/components/organisms/Toaster/Toaster.test.ts +75 -0
  225. package/src/components/organisms/VideoControls/VideoControls.stories.ts +792 -0
  226. package/src/components/organisms/VideoControls/VideoControls.test.ts +1056 -0
  227. package/src/components/organisms/VideoPlayer/VideoPlayer.stories.ts +327 -0
  228. package/src/components/organisms/VideoPlayer/VideoPlayer.test.ts +439 -0
@@ -0,0 +1,91 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite'
2
+ import StepperHeader from './StepperHeader.vue'
3
+ import Button from '../../atoms/Button/Button.vue'
4
+
5
+ export default {
6
+ title: 'Components/Organisms/Stepper Header',
7
+ component: StepperHeader,
8
+ } satisfies Meta<typeof StepperHeader>
9
+
10
+ type Story = StoryObj<typeof StepperHeader>
11
+
12
+ export const Default: Story = {
13
+ args: {
14
+ title: 'Stepper Header Title',
15
+ steps: ['Soort', 'Type', 'Inhoud', 'Template', 'Bewerk', 'Inplannen'],
16
+ currentStep: 0,
17
+ backButtonText: 'Back',
18
+ backButtonAction: () => alert('Back button clicked'),
19
+ },
20
+ }
21
+
22
+ export const ManySteps: Story = {
23
+ args: {
24
+ title: 'Stepper Header Title',
25
+ steps: [
26
+ 'Soort',
27
+ 'Type',
28
+ 'Inhoud',
29
+ 'Template',
30
+ 'Bewerk',
31
+ 'Inplannen',
32
+ 'Doelgroep',
33
+ 'Kanalen',
34
+ 'Budget',
35
+ 'Planning',
36
+ 'Controle',
37
+ 'Verzenden',
38
+ ],
39
+ currentStep: 4,
40
+ backButtonText: 'Back',
41
+ backButtonAction: () => alert('Back button clicked'),
42
+ },
43
+ }
44
+
45
+ export const WithSlots: Story = {
46
+ args: {
47
+ title: 'Stepper Header Title',
48
+ steps: ['Soort', 'Type', 'Inhoud', 'Template', 'Bewerk', 'Inplannen'],
49
+ currentStep: 0,
50
+ backButtonText: 'Back',
51
+ backButtonAction: () => alert('Back button clicked'),
52
+ },
53
+ render: (args) => ({
54
+ components: { StepperHeader, Button },
55
+ setup() {
56
+ return { args }
57
+ },
58
+ template: `
59
+ <StepperHeader v-bind="args">
60
+ <Button>Next</Button>
61
+ </StepperHeader>
62
+ `,
63
+ }),
64
+ }
65
+
66
+ // The title slot replaces the static title, e.g. with an inline editable field.
67
+ export const EditableTitle: Story = {
68
+ args: {
69
+ steps: ['Soort', 'Type', 'Inhoud', 'Template', 'Bewerk', 'Inplannen'],
70
+ currentStep: 2,
71
+ backButtonText: 'Back',
72
+ backButtonAction: () => alert('Back button clicked'),
73
+ },
74
+ render: (args) => ({
75
+ components: { StepperHeader, Button },
76
+ setup() {
77
+ return { args }
78
+ },
79
+ template: `
80
+ <StepperHeader v-bind="args">
81
+ <template #title>
82
+ <input
83
+ class="min-w-0 flex-1 truncate rounded-lg border border-gray-200 px-4 py-2 heading-4 text-sapphire-500"
84
+ value="Voorstel voor Jan de Vries"
85
+ />
86
+ </template>
87
+ <Button>Next</Button>
88
+ </StepperHeader>
89
+ `,
90
+ }),
91
+ }
@@ -0,0 +1,279 @@
1
+ import { describe, it, expect, vi } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import StepperHeader from './StepperHeader.vue'
4
+ import Header from '../Header/Header.vue'
5
+ import ProgressBar from '../ProgressBar/ProgressBar.vue'
6
+
7
+ describe('StepperHeader', () => {
8
+ const defaultProps = {
9
+ title: 'Test Title',
10
+ currentStep: 0,
11
+ steps: ['Step 1', 'Step 2', 'Step 3'],
12
+ backButtonAction: vi.fn(),
13
+ }
14
+
15
+ it('renders the header component', () => {
16
+ const wrapper = mount(StepperHeader, {
17
+ props: defaultProps,
18
+ })
19
+
20
+ const header = wrapper.findComponent(Header)
21
+ expect(header.exists()).toBe(true)
22
+ })
23
+
24
+ it('passes title prop to Header component', () => {
25
+ const wrapper = mount(StepperHeader, {
26
+ props: defaultProps,
27
+ })
28
+
29
+ const header = wrapper.findComponent(Header)
30
+ expect(header.props('title')).toBe('Test Title')
31
+ })
32
+
33
+ it('passes backButtonAction to Header component', () => {
34
+ const backButtonAction = vi.fn()
35
+ const wrapper = mount(StepperHeader, {
36
+ props: {
37
+ ...defaultProps,
38
+ backButtonAction,
39
+ },
40
+ })
41
+
42
+ const header = wrapper.findComponent(Header)
43
+ expect(header.props('backButtonAction')).toBe(backButtonAction)
44
+ })
45
+
46
+ it('passes backButtonText to Header component when provided', () => {
47
+ const wrapper = mount(StepperHeader, {
48
+ props: {
49
+ ...defaultProps,
50
+ backButtonText: 'Go Back',
51
+ },
52
+ })
53
+
54
+ const header = wrapper.findComponent(Header)
55
+ expect(header.props('backButtonText')).toBe('Go Back')
56
+ })
57
+
58
+ it('renders ProgressBar component when steps are provided', () => {
59
+ const wrapper = mount(StepperHeader, {
60
+ props: defaultProps,
61
+ })
62
+
63
+ const progressBar = wrapper.findComponent(ProgressBar)
64
+ expect(progressBar.exists()).toBe(true)
65
+ })
66
+
67
+ it('passes correct props to ProgressBar component', () => {
68
+ const wrapper = mount(StepperHeader, {
69
+ props: {
70
+ ...defaultProps,
71
+ currentStep: 2,
72
+ steps: ['Step 1', 'Step 2', 'Step 3', 'Step 4'],
73
+ },
74
+ })
75
+
76
+ const progressBar = wrapper.findComponent(ProgressBar)
77
+ expect(progressBar.props('steps')).toBe(4)
78
+ expect(progressBar.props('stepTitles')).toEqual(['Step 1', 'Step 2', 'Step 3', 'Step 4'])
79
+ expect(progressBar.props('currentStep')).toBe(2)
80
+ })
81
+
82
+ it('does not render ProgressBar when steps is null or undefined', () => {
83
+ const wrapper = mount(StepperHeader, {
84
+ props: {
85
+ title: 'Test',
86
+ currentStep: 0,
87
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
88
+ steps: null as any,
89
+ backButtonAction: vi.fn(),
90
+ },
91
+ })
92
+
93
+ const progressBar = wrapper.findComponent(ProgressBar)
94
+ expect(progressBar.exists()).toBe(false)
95
+ })
96
+
97
+ it('renders default slot content in Header right slot', () => {
98
+ const wrapper = mount(StepperHeader, {
99
+ props: defaultProps,
100
+ slots: {
101
+ default: '<button class="test-button">Next</button>',
102
+ },
103
+ })
104
+
105
+ expect(wrapper.find('.test-button').exists()).toBe(true)
106
+ expect(wrapper.find('.test-button').text()).toBe('Next')
107
+ })
108
+
109
+ it('does not render right slot when default slot is empty', () => {
110
+ const wrapper = mount(StepperHeader, {
111
+ props: defaultProps,
112
+ })
113
+
114
+ // When no default slot is provided, the right slot in Header should not exist
115
+ expect(wrapper.find('.ml-auto').exists()).toBe(false)
116
+ })
117
+
118
+ it('applies w-full class to ProgressBar', () => {
119
+ const wrapper = mount(StepperHeader, {
120
+ props: defaultProps,
121
+ })
122
+
123
+ const progressBar = wrapper.findComponent(ProgressBar)
124
+ expect(progressBar.classes()).toContain('w-full')
125
+ })
126
+
127
+ it('renders with all props and slots correctly', () => {
128
+ const backButtonAction = vi.fn()
129
+ const wrapper = mount(StepperHeader, {
130
+ props: {
131
+ title: 'Complete Header',
132
+ currentStep: 1,
133
+ steps: ['One', 'Two', 'Three'],
134
+ backButtonText: 'Previous',
135
+ backButtonAction,
136
+ },
137
+ slots: {
138
+ default: '<button>Continue</button>',
139
+ },
140
+ })
141
+
142
+ const header = wrapper.findComponent(Header)
143
+ expect(header.props('title')).toBe('Complete Header')
144
+ expect(header.props('backButtonText')).toBe('Previous')
145
+ expect(header.props('backButtonAction')).toBe(backButtonAction)
146
+
147
+ const progressBar = wrapper.findComponent(ProgressBar)
148
+ expect(progressBar.props('currentStep')).toBe(1)
149
+ expect(progressBar.props('steps')).toBe(3)
150
+ expect(progressBar.props('stepTitles')).toEqual(['One', 'Two', 'Three'])
151
+
152
+ expect(wrapper.text()).toContain('Continue')
153
+ })
154
+
155
+ it('renders without steps and without default slot', () => {
156
+ const wrapper = mount(StepperHeader, {
157
+ props: {
158
+ title: 'Test',
159
+ currentStep: 0,
160
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
161
+ steps: null as any,
162
+ backButtonAction: vi.fn(),
163
+ },
164
+ })
165
+
166
+ const progressBar = wrapper.findComponent(ProgressBar)
167
+ expect(progressBar.exists()).toBe(false)
168
+ expect(wrapper.find('.ml-auto').exists()).toBe(false)
169
+ })
170
+
171
+ it('renders with steps but without default slot', () => {
172
+ const wrapper = mount(StepperHeader, {
173
+ props: defaultProps,
174
+ })
175
+
176
+ const progressBar = wrapper.findComponent(ProgressBar)
177
+ expect(progressBar.exists()).toBe(true)
178
+ expect(wrapper.find('.ml-auto').exists()).toBe(false)
179
+ })
180
+
181
+ it('renders without steps but with default slot', () => {
182
+ const wrapper = mount(StepperHeader, {
183
+ props: {
184
+ title: 'Test',
185
+ currentStep: 0,
186
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
187
+ steps: null as any,
188
+ backButtonAction: vi.fn(),
189
+ },
190
+ slots: {
191
+ default: '<button class="action-button">Action</button>',
192
+ },
193
+ })
194
+
195
+ const progressBar = wrapper.findComponent(ProgressBar)
196
+ expect(progressBar.exists()).toBe(false)
197
+ expect(wrapper.find('.action-button').exists()).toBe(true)
198
+ expect(wrapper.find('.ml-auto').exists()).toBe(true)
199
+ })
200
+
201
+ it('renders with empty steps array', () => {
202
+ const wrapper = mount(StepperHeader, {
203
+ props: {
204
+ title: 'Test',
205
+ currentStep: 0,
206
+ steps: [],
207
+ backButtonAction: vi.fn(),
208
+ },
209
+ })
210
+
211
+ // Empty array is truthy, so ProgressBar should still render
212
+ const progressBar = wrapper.findComponent(ProgressBar)
213
+ expect(progressBar.exists()).toBe(true)
214
+ expect(progressBar.props('steps')).toBe(0)
215
+ expect(progressBar.props('stepTitles')).toEqual([])
216
+ })
217
+
218
+ it('renders with undefined steps', () => {
219
+ const wrapper = mount(StepperHeader, {
220
+ props: {
221
+ title: 'Test',
222
+ currentStep: 0,
223
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
224
+ steps: undefined as any,
225
+ backButtonAction: vi.fn(),
226
+ },
227
+ })
228
+
229
+ const progressBar = wrapper.findComponent(ProgressBar)
230
+ expect(progressBar.exists()).toBe(false)
231
+ })
232
+
233
+ it('emits update:currentStep when ProgressBar emits it', async () => {
234
+ const wrapper = mount(StepperHeader, {
235
+ props: defaultProps,
236
+ })
237
+
238
+ const progressBar = wrapper.findComponent(ProgressBar)
239
+ await progressBar.vm.$emit('update:currentStep', 1)
240
+
241
+ expect(wrapper.emitted('update:currentStep')).toBeTruthy()
242
+ expect(wrapper.emitted('update:currentStep')![0]).toEqual([1])
243
+ })
244
+
245
+ it('forwards the title slot to Header', () => {
246
+ const wrapper = mount(StepperHeader, {
247
+ props: defaultProps,
248
+ slots: { title: '<input class="title-field" value="Eigen titel" />' },
249
+ })
250
+
251
+ expect(wrapper.find('.title-field').exists()).toBe(true)
252
+ expect(wrapper.text()).not.toContain('Test Title')
253
+ })
254
+
255
+ it('renders the static title when no title slot is given', () => {
256
+ const wrapper = mount(StepperHeader, { props: defaultProps })
257
+
258
+ expect(wrapper.text()).toContain('Test Title')
259
+ })
260
+
261
+ it('forwards the back-button slot to Header', () => {
262
+ const wrapper = mount(StepperHeader, {
263
+ props: defaultProps,
264
+ slots: { 'back-button': '<a class="own-back">Terug</a>' },
265
+ })
266
+
267
+ expect(wrapper.find('.own-back').text()).toBe('Terug')
268
+ })
269
+
270
+ it('keeps the ProgressBar centered when the title slot is used', () => {
271
+ const wrapper = mount(StepperHeader, {
272
+ props: defaultProps,
273
+ slots: { title: '<input class="title-field" />' },
274
+ })
275
+
276
+ expect(wrapper.findComponent(ProgressBar).exists()).toBe(true)
277
+ expect(wrapper.find('.header').classes()).toContain('grid-cols-3')
278
+ })
279
+ })
@@ -0,0 +1,332 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite'
2
+ import { computed, ref, type ConcreteComponent } from 'vue'
3
+ import Table, { type TableColumn } from './Table.vue'
4
+
5
+ type RowKey = 'name' | 'email' | 'role' | 'status' | 'department' | 'lastLogin'
6
+
7
+ interface TableStoryProps {
8
+ columns: TableColumn<RowKey>[]
9
+ rows: Record<RowKey, string>[]
10
+ selectable?: boolean
11
+ selectionMode?: 'single' | 'multiple'
12
+ selectOnRowClick?: boolean
13
+ loading?: boolean
14
+ }
15
+
16
+ const meta: Meta<TableStoryProps> = {
17
+ title: 'Components/Organisms/Table',
18
+ component: Table as ConcreteComponent<TableStoryProps>,
19
+ }
20
+
21
+ export default meta
22
+ type Story = StoryObj<TableStoryProps>
23
+
24
+ const columns: TableColumn<RowKey>[] = [
25
+ { key: 'name', label: 'Name', sortable: true },
26
+ { key: 'email', label: 'Email', sortable: true },
27
+ { key: 'department', label: 'Department' },
28
+ { key: 'role', label: 'Role', sortable: true, width: '0.5fr' },
29
+ { key: 'lastLogin', label: 'lastLogin' },
30
+ { key: 'status', label: 'Status', width: '0.5fr' },
31
+ ]
32
+
33
+ const allRows = [
34
+ {
35
+ name: 'Alice Johnson',
36
+ email: 'alice@example.com',
37
+ role: 'Admin',
38
+ status: 'Active',
39
+ department: 'HR',
40
+ lastLogin: '2026-03-25',
41
+ },
42
+ {
43
+ name: 'Bob Smith',
44
+ email: 'bob@example.com',
45
+ role: 'Editor',
46
+ status: 'Active',
47
+ department: 'Marketing',
48
+ lastLogin: '2026-03-27',
49
+ },
50
+ {
51
+ name: 'Carol White',
52
+ email: 'carol@example.com',
53
+ role: 'Viewer',
54
+ status: 'Inactive',
55
+ department: 'Finance',
56
+ lastLogin: '2026-02-12',
57
+ },
58
+ {
59
+ name: 'David Brown',
60
+ email: 'david@example.com',
61
+ role: 'Editor',
62
+ status: 'Active',
63
+ department: 'IT',
64
+ lastLogin: '2026-03-30',
65
+ },
66
+ {
67
+ name: 'Eve Turner',
68
+ email: 'eve@example.com',
69
+ role: 'Admin',
70
+ status: 'Active',
71
+ department: 'HR',
72
+ lastLogin: '2026-03-28',
73
+ },
74
+ {
75
+ name: 'Frank Miller',
76
+ email: 'frank@example.com',
77
+ role: 'Viewer',
78
+ status: 'Active',
79
+ department: 'Support',
80
+ lastLogin: '2026-03-26',
81
+ },
82
+ {
83
+ name: 'Grace Lee',
84
+ email: 'grace@example.com',
85
+ role: 'Editor',
86
+ status: 'Active',
87
+ department: 'Product',
88
+ lastLogin: '2026-03-29',
89
+ },
90
+ {
91
+ name: 'Henry Wilson',
92
+ email: 'henry@example.com',
93
+ role: 'Viewer',
94
+ status: 'Inactive',
95
+ department: 'Finance',
96
+ lastLogin: '2026-01-10',
97
+ },
98
+ {
99
+ name: 'Ivy Clark',
100
+ email: 'ivy@example.com',
101
+ role: 'Admin',
102
+ status: 'Active',
103
+ department: 'IT',
104
+ lastLogin: '2026-03-20',
105
+ },
106
+ {
107
+ name: 'Jack Davis',
108
+ email: 'jack@example.com',
109
+ role: 'Editor',
110
+ status: 'Active',
111
+ department: 'Marketing',
112
+ lastLogin: '2026-03-23',
113
+ },
114
+ {
115
+ name: 'Karen Harris',
116
+ email: 'karen@example.com',
117
+ role: 'Viewer',
118
+ status: 'Active',
119
+ department: 'Support',
120
+ lastLogin: '2026-03-19',
121
+ },
122
+ {
123
+ name: 'Leo King',
124
+ email: 'leo@example.com',
125
+ role: 'Editor',
126
+ status: 'Active',
127
+ department: 'Product',
128
+ lastLogin: '2026-03-28',
129
+ },
130
+ {
131
+ name: 'Mia Scott',
132
+ email: 'mia@example.com',
133
+ role: 'Admin',
134
+ status: 'Active',
135
+ department: 'HR',
136
+ lastLogin: '2026-03-30',
137
+ },
138
+ {
139
+ name: 'Nick Evans',
140
+ email: 'nick@example.com',
141
+ role: 'Viewer',
142
+ status: 'Inactive',
143
+ department: 'Finance',
144
+ lastLogin: '2026-02-05',
145
+ },
146
+ {
147
+ name: 'Olivia Foster',
148
+ email: 'olivia@example.com',
149
+ role: 'Editor',
150
+ status: 'Active',
151
+ department: 'Product',
152
+ lastLogin: '2026-03-27',
153
+ },
154
+ {
155
+ name: 'Paul Green',
156
+ email: 'paul@example.com',
157
+ role: 'Viewer',
158
+ status: 'Active',
159
+ department: 'Support',
160
+ lastLogin: '2026-03-18',
161
+ },
162
+ {
163
+ name: 'Quincy Adams',
164
+ email: 'quincy@example.com',
165
+ role: 'Editor',
166
+ status: 'Active',
167
+ department: 'Marketing',
168
+ lastLogin: '2026-03-25',
169
+ },
170
+ {
171
+ name: 'Rachel Lewis',
172
+ email: 'rachel@example.com',
173
+ role: 'Admin',
174
+ status: 'Active',
175
+ department: 'HR',
176
+ lastLogin: '2026-03-29',
177
+ },
178
+ {
179
+ name: 'Sam Nelson',
180
+ email: 'sam@example.com',
181
+ role: 'Viewer',
182
+ status: 'Inactive',
183
+ department: 'Finance',
184
+ lastLogin: '2026-01-15',
185
+ },
186
+ {
187
+ name: 'Tina Brooks',
188
+ email: 'tina@example.com',
189
+ role: 'Editor',
190
+ status: 'Active',
191
+ department: 'IT',
192
+ lastLogin: '2026-03-30',
193
+ },
194
+ ]
195
+
196
+ const sortRows = (rows: typeof allRows, key: string | undefined, direction: 'asc' | 'desc') => {
197
+ if (!key) return rows
198
+ return [...rows].sort((a, b) => {
199
+ const aVal = String(a[key as keyof typeof a] ?? '')
200
+ const bVal = String(b[key as keyof typeof b] ?? '')
201
+ const result = aVal.localeCompare(bVal, undefined, { numeric: true, sensitivity: 'base' })
202
+ return direction === 'asc' ? result : -result
203
+ })
204
+ }
205
+
206
+ export const Default: Story = {
207
+ args: { columns, rows: allRows },
208
+ render: (args) => ({
209
+ components: { Table },
210
+ setup() {
211
+ const sortKey = ref<string | undefined>(undefined)
212
+ const sortDirection = ref<'asc' | 'desc'>('asc')
213
+ const rows = computed(() =>
214
+ sortRows(args.rows as typeof allRows, sortKey.value, sortDirection.value),
215
+ )
216
+ return { args, rows, sortKey, sortDirection }
217
+ },
218
+ template: `<Table :columns="args.columns" :rows="rows" v-model:sort-key="sortKey" v-model:sort-direction="sortDirection" />`,
219
+ }),
220
+ }
221
+
222
+ export const WithSelection: Story = {
223
+ args: { columns, rows: allRows, selectable: true },
224
+ render: (args) => ({
225
+ components: { Table },
226
+ setup() {
227
+ const sortKey = ref<string | undefined>(undefined)
228
+ const sortDirection = ref<'asc' | 'desc'>('asc')
229
+ const selected = ref<Record<RowKey, string>[]>([])
230
+ const rows = computed(() =>
231
+ sortRows(args.rows as typeof allRows, sortKey.value, sortDirection.value),
232
+ )
233
+ return { args, rows, sortKey, sortDirection, selected }
234
+ },
235
+ template: `<Table :columns="args.columns" :rows="rows" v-model:sort-key="sortKey" v-model:sort-direction="sortDirection" :selectable="args.selectable" v-model="selected" />`,
236
+ }),
237
+ }
238
+
239
+ export const SingleSelection: Story = {
240
+ args: { columns, rows: allRows, selectable: true, selectionMode: 'single' },
241
+ render: (args) => ({
242
+ components: { Table },
243
+ setup() {
244
+ const sortKey = ref<string | undefined>(undefined)
245
+ const sortDirection = ref<'asc' | 'desc'>('asc')
246
+ const selected = ref<Record<RowKey, string>[]>([])
247
+ const rows = computed(() =>
248
+ sortRows(args.rows as typeof allRows, sortKey.value, sortDirection.value),
249
+ )
250
+ return { args, rows, sortKey, sortDirection, selected }
251
+ },
252
+ template: `<Table :columns="args.columns" :rows="rows" v-model:sort-key="sortKey" v-model:sort-direction="sortDirection" :selectable="args.selectable" :selection-mode="args.selectionMode" v-model="selected" />`,
253
+ }),
254
+ }
255
+
256
+ export const SelectionOnRowClick: Story = {
257
+ args: {
258
+ columns,
259
+ rows: allRows,
260
+ selectable: true,
261
+ selectionMode: 'single',
262
+ selectOnRowClick: true,
263
+ },
264
+ render: (args) => ({
265
+ components: { Table },
266
+ setup() {
267
+ const sortKey = ref<string | undefined>(undefined)
268
+ const sortDirection = ref<'asc' | 'desc'>('asc')
269
+ const selected = ref<Record<RowKey, string>[]>([])
270
+ const rows = computed(() =>
271
+ sortRows(args.rows as typeof allRows, sortKey.value, sortDirection.value),
272
+ )
273
+ return { args, rows, sortKey, sortDirection, selected }
274
+ },
275
+ template: `<Table :columns="args.columns" :rows="rows" v-model:sort-key="sortKey" v-model:sort-direction="sortDirection" :selectable="args.selectable" :selection-mode="args.selectionMode" :select-on-row-click="args.selectOnRowClick" v-model="selected" />`,
276
+ }),
277
+ }
278
+
279
+ export const Loading: Story = {
280
+ args: { columns, rows: allRows, loading: true },
281
+ render: (args) => ({
282
+ components: { Table },
283
+ setup() {
284
+ const sortKey = ref<string | undefined>(undefined)
285
+ const sortDirection = ref<'asc' | 'desc'>('asc')
286
+ const rows = computed(() =>
287
+ sortRows(args.rows as typeof allRows, sortKey.value, sortDirection.value),
288
+ )
289
+ args.loading = true
290
+
291
+ return { args, rows, sortKey, sortDirection }
292
+ },
293
+ template: `<Table :columns="args.columns" :rows="rows" v-model:sort-key="sortKey" v-model:sort-direction="sortDirection" :loading="args.loading" />`,
294
+ }),
295
+ }
296
+
297
+ export const WithSlots: Story = {
298
+ args: { columns, rows: allRows },
299
+ render: (args) => ({
300
+ components: { Table },
301
+ setup() {
302
+ const sortKey = ref<string | undefined>(undefined)
303
+ const sortDirection = ref<'asc' | 'desc'>('asc')
304
+ const rows = computed(() =>
305
+ sortRows(args.rows as typeof allRows, sortKey.value, sortDirection.value),
306
+ )
307
+ return { args, rows, sortKey, sortDirection }
308
+ },
309
+ template: `
310
+ <Table :columns="args.columns" :rows="rows" v-model:sort-key="sortKey" v-model:sort-direction="sortDirection" :selectable="true">
311
+ <template #cell-name="{ value, row }">
312
+ <div class="flex flex-col">
313
+ <span class="font-medium">{{ value }}</span>
314
+ <span class="text-xs text-slate-400">{{ row.email }}</span>
315
+ </div>
316
+ </template>
317
+ <template #cell-status="{ value }">
318
+ <span
319
+ class="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium"
320
+ :class="value === 'Active' ? 'bg-green-100 text-green-700' : 'bg-slate-100 text-slate-500'"
321
+ >
322
+ {{ value }}
323
+ </span>
324
+ </template>
325
+ </Table>
326
+ `,
327
+ }),
328
+ }
329
+
330
+ export const Empty: Story = {
331
+ args: { columns, rows: [] },
332
+ }