@nexxtmove/ui 0.1.22 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +75 -8
- package/dist/index.js +2408 -252
- package/dist/nuxt.d.ts +1 -0
- package/dist/nuxt.js +49 -0
- package/package.json +23 -13
- package/src/assets/images/Template_aanvragen.jpg +0 -0
- package/src/assets/svg/type_post.svg +1 -0
- package/src/assets/svg/type_reel.svg +54 -0
- package/src/assets/svg/type_story.svg +46 -0
- package/src/assets/svg/type_tiktok.svg +1 -0
- package/src/assets/video/Template_aanvragen.mp4 +0 -0
- package/src/components/AnimatedNumber/AnimatedNumber.stories.ts +15 -0
- package/src/components/AnimatedNumber/AnimatedNumber.test.ts +56 -0
- package/src/components/AnimatedNumber/AnimatedNumber.vue +61 -0
- package/src/components/Button/Button.stories.ts +212 -0
- package/src/components/Button/Button.test.ts +318 -0
- package/src/components/Button/Button.vue +67 -0
- package/src/components/Calendar/Calendar.stories.ts +91 -0
- package/src/components/Calendar/Calendar.test.ts +269 -0
- package/src/components/Calendar/Calendar.vue +221 -0
- package/src/components/Calendar/_CalendarDayView.test.ts +145 -0
- package/src/components/Calendar/_CalendarDayView.vue +156 -0
- package/src/components/Calendar/_CalendarHeader.test.ts +86 -0
- package/src/components/Calendar/_CalendarHeader.vue +123 -0
- package/src/components/Calendar/_CalendarMonthView.test.ts +68 -0
- package/src/components/Calendar/_CalendarMonthView.vue +70 -0
- package/src/components/Calendar/_CalendarYearView.vue +77 -0
- package/src/components/Calendar/calendar.types.ts +10 -0
- package/src/components/Chip/Chip.stories.ts +42 -0
- package/src/components/Chip/Chip.test.ts +51 -0
- package/src/components/Chip/Chip.vue +37 -0
- package/src/components/DatePicker/DatePicker.stories.ts +149 -0
- package/src/components/DatePicker/DatePicker.test.ts +191 -0
- package/src/components/DatePicker/DatePicker.vue +142 -0
- package/src/components/Header/Header.stories.ts +48 -0
- package/src/components/Header/Header.test.ts +169 -0
- package/src/components/Header/Header.vue +42 -0
- package/src/components/Icon/Icon.stories.ts +50 -0
- package/src/components/Icon/Icon.test.ts +73 -0
- package/src/components/Icon/Icon.vue +20 -0
- package/src/components/InfoBlock/InfoBlock.stories.ts +90 -0
- package/src/components/InfoBlock/InfoBlock.test.ts +101 -0
- package/src/components/InfoBlock/InfoBlock.vue +70 -0
- package/src/components/ProgressBar/ProgressBar.stories.ts +30 -0
- package/src/components/ProgressBar/ProgressBar.test.ts +314 -0
- package/src/components/ProgressBar/ProgressBar.vue +102 -0
- package/src/components/SocialIcons/SocialIcons.stories.ts +34 -0
- package/src/components/SocialIcons/SocialIcons.test.ts +58 -0
- package/src/components/SocialIcons/SocialIcons.vue +58 -0
- package/src/components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.stories.ts +11 -0
- package/src/components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.test.ts +131 -0
- package/src/components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.vue +55 -0
- package/src/components/SocialMediaTemplate/SocialMediaTemplate.stories.ts +71 -0
- package/src/components/SocialMediaTemplate/SocialMediaTemplate.test.ts +466 -0
- package/src/components/SocialMediaTemplate/SocialMediaTemplate.vue +130 -0
- package/src/components/SocialMediaType/SocialMediaType.stories.ts +43 -0
- package/src/components/SocialMediaType/SocialMediaType.test.ts +126 -0
- package/src/components/SocialMediaType/SocialMediaType.vue +117 -0
- package/src/components/StepperHeader/StepperHeader.stories.ts +47 -0
- package/src/components/StepperHeader/StepperHeader.test.ts +244 -0
- package/src/components/StepperHeader/StepperHeader.vue +37 -0
- package/src/components.json +16 -0
- package/src/env.d.ts +23 -0
- package/src/index.css +2 -0
- package/src/index.ts +15 -0
- package/src/nuxt.ts +50 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import Header from './Header.vue'
|
|
4
|
+
import Button from '../Button/Button.vue'
|
|
5
|
+
|
|
6
|
+
describe('Header', () => {
|
|
7
|
+
it('renders the title', () => {
|
|
8
|
+
const wrapper = mount(Header, {
|
|
9
|
+
props: {
|
|
10
|
+
title: 'My Page Title',
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
expect(wrapper.text()).toContain('My Page Title')
|
|
15
|
+
expect(wrapper.find('span.heading-4').text()).toBe('My Page Title')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('renders the back button with default text', () => {
|
|
19
|
+
const wrapper = mount(Header, {
|
|
20
|
+
props: {
|
|
21
|
+
title: 'Test',
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const button = wrapper.findComponent(Button)
|
|
26
|
+
expect(button.exists()).toBe(true)
|
|
27
|
+
expect(button.text()).toBe('Back')
|
|
28
|
+
expect(button.props('variant')).toBe('secondary')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('renders the back button with custom text', () => {
|
|
32
|
+
const wrapper = mount(Header, {
|
|
33
|
+
props: {
|
|
34
|
+
title: 'Test',
|
|
35
|
+
backButtonText: 'Go Back',
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const button = wrapper.findComponent(Button)
|
|
40
|
+
expect(button.text()).toBe('Go Back')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('calls backButtonAction when back button is clicked', async () => {
|
|
44
|
+
const backButtonAction = vi.fn()
|
|
45
|
+
const wrapper = mount(Header, {
|
|
46
|
+
props: {
|
|
47
|
+
title: 'Test',
|
|
48
|
+
backButtonAction,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const button = wrapper.findComponent(Button)
|
|
53
|
+
await button.trigger('click')
|
|
54
|
+
|
|
55
|
+
expect(backButtonAction).toHaveBeenCalledOnce()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('calls window.history.back() by default when back button is clicked', async () => {
|
|
59
|
+
const historyBackSpy = vi.spyOn(window.history, 'back').mockImplementation(() => {})
|
|
60
|
+
|
|
61
|
+
const wrapper = mount(Header, {
|
|
62
|
+
props: {
|
|
63
|
+
title: 'Test',
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const button = wrapper.findComponent(Button)
|
|
68
|
+
await button.trigger('click')
|
|
69
|
+
|
|
70
|
+
expect(historyBackSpy).toHaveBeenCalledOnce()
|
|
71
|
+
|
|
72
|
+
historyBackSpy.mockRestore()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('renders center slot content', () => {
|
|
76
|
+
const wrapper = mount(Header, {
|
|
77
|
+
props: {
|
|
78
|
+
title: 'Test',
|
|
79
|
+
},
|
|
80
|
+
slots: {
|
|
81
|
+
center: '<span class="logo">Logo</span>',
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
expect(wrapper.find('.logo').text()).toBe('Logo')
|
|
86
|
+
expect(wrapper.find('.col-start-2').exists()).toBe(true)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('does not render center slot wrapper when slot is empty', () => {
|
|
90
|
+
const wrapper = mount(Header, {
|
|
91
|
+
props: {
|
|
92
|
+
title: 'Test',
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
expect(wrapper.find('.col-start-2').exists()).toBe(false)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('renders right slot content', () => {
|
|
100
|
+
const wrapper = mount(Header, {
|
|
101
|
+
props: {
|
|
102
|
+
title: 'Test',
|
|
103
|
+
},
|
|
104
|
+
slots: {
|
|
105
|
+
right: '<button class="next">Next</button>',
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
expect(wrapper.find('.next').text()).toBe('Next')
|
|
110
|
+
expect(wrapper.find('.ml-auto').exists()).toBe(true)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('does not render right slot wrapper when slot is empty', () => {
|
|
114
|
+
const wrapper = mount(Header, {
|
|
115
|
+
props: {
|
|
116
|
+
title: 'Test',
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect(wrapper.find('.col-start-3').exists()).toBe(false)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('uses grid layout with 3 columns when center slot is provided', () => {
|
|
124
|
+
const wrapper = mount(Header, {
|
|
125
|
+
props: {
|
|
126
|
+
title: 'Test',
|
|
127
|
+
},
|
|
128
|
+
slots: {
|
|
129
|
+
center: '<span>Center</span>',
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const header = wrapper.find('.header')
|
|
134
|
+
expect(header.classes()).toContain('grid')
|
|
135
|
+
expect(header.classes()).toContain('grid-cols-3')
|
|
136
|
+
expect(header.classes()).toContain('items-center')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('uses flex layout when no center slot is provided', () => {
|
|
140
|
+
const wrapper = mount(Header, {
|
|
141
|
+
props: {
|
|
142
|
+
title: 'Test',
|
|
143
|
+
},
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const header = wrapper.find('.header')
|
|
147
|
+
expect(header.classes()).toContain('flex')
|
|
148
|
+
expect(header.classes()).toContain('items-center')
|
|
149
|
+
expect(header.classes()).not.toContain('grid')
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it('renders all slots correctly', () => {
|
|
153
|
+
const wrapper = mount(Header, {
|
|
154
|
+
props: {
|
|
155
|
+
title: 'Test Title',
|
|
156
|
+
backButtonText: 'Previous',
|
|
157
|
+
},
|
|
158
|
+
slots: {
|
|
159
|
+
center: '<div class="center-content">Center</div>',
|
|
160
|
+
right: '<div class="right-content">Right</div>',
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
expect(wrapper.text()).toContain('Previous')
|
|
165
|
+
expect(wrapper.text()).toContain('Test Title')
|
|
166
|
+
expect(wrapper.find('.center-content').text()).toBe('Center')
|
|
167
|
+
expect(wrapper.find('.right-content').text()).toBe('Right')
|
|
168
|
+
})
|
|
169
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import Button from '../Button/Button.vue'
|
|
3
|
+
|
|
4
|
+
interface NexxtHeaderProps {
|
|
5
|
+
title: string
|
|
6
|
+
backButtonText?: string
|
|
7
|
+
backButtonAction?: () => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
defineOptions({
|
|
11
|
+
name: 'NexxtHeader',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
backButtonText = 'Back',
|
|
16
|
+
backButtonAction = () => {
|
|
17
|
+
window.history.back()
|
|
18
|
+
},
|
|
19
|
+
} = defineProps<NexxtHeaderProps>()
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div class="header flex items-center" :class="$slots.center ? 'grid grid-cols-3' : ''">
|
|
24
|
+
<div class="flex max-w-full items-center justify-start gap-4">
|
|
25
|
+
<Button class="shrink-0" variant="secondary" @click="backButtonAction">{{
|
|
26
|
+
backButtonText
|
|
27
|
+
}}</Button>
|
|
28
|
+
<span class="block truncate heading-4 text-sapphire-500">
|
|
29
|
+
{{ title }}
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
<div v-if="$slots.center" class="col-span-1 col-start-2 flex justify-center">
|
|
33
|
+
<slot name="center" />
|
|
34
|
+
</div>
|
|
35
|
+
<div
|
|
36
|
+
v-if="$slots.right"
|
|
37
|
+
:class="$slots.center ? 'col-span-1 col-start-3 flex justify-end' : 'ml-auto'"
|
|
38
|
+
>
|
|
39
|
+
<slot name="right" />
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import Icon from './Icon.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Atoms/Icon',
|
|
6
|
+
component: Icon,
|
|
7
|
+
parameters: {
|
|
8
|
+
design: {
|
|
9
|
+
type: 'figma',
|
|
10
|
+
url: 'https://www.figma.com/design/CdbFJ7qUga6mtjagcPDvYK/Design-System?node-id=162-97&t=CbHvOQfEMIr7M5mO-11',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
} satisfies Meta<typeof Icon>
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof Icon>
|
|
16
|
+
|
|
17
|
+
export const Regular: Story = {
|
|
18
|
+
args: {
|
|
19
|
+
name: 'star',
|
|
20
|
+
type: 'regular',
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const Light: Story = {
|
|
25
|
+
args: {
|
|
26
|
+
name: 'star',
|
|
27
|
+
type: 'light',
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const Solid: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
name: 'star',
|
|
34
|
+
type: 'solid',
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const Duotone: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
name: 'star',
|
|
41
|
+
type: 'duotone',
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const Brands: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
name: 'github',
|
|
48
|
+
type: 'brands',
|
|
49
|
+
},
|
|
50
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import Icon from './Icon.vue'
|
|
4
|
+
|
|
5
|
+
describe('Icon', () => {
|
|
6
|
+
it('renders as an <i> tag', () => {
|
|
7
|
+
const wrapper = mount(Icon, {
|
|
8
|
+
props: {
|
|
9
|
+
name: 'star',
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
expect(wrapper.element.tagName).toBe('I')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('renders correctly with name', async () => {
|
|
17
|
+
const wrapper = mount(Icon, {
|
|
18
|
+
props: {
|
|
19
|
+
name: 'star',
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
expect(wrapper.classes()).toContain('fa-star')
|
|
24
|
+
|
|
25
|
+
await wrapper.setProps({ name: 'arrows-up-down' })
|
|
26
|
+
|
|
27
|
+
expect(wrapper.classes()).toContain('fa-arrows-up-down')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('applies default type "light"', () => {
|
|
31
|
+
const wrapper = mount(Icon, {
|
|
32
|
+
props: {
|
|
33
|
+
name: 'star',
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
expect(wrapper.classes()).toContain('fa-light')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('applies specified type', async () => {
|
|
41
|
+
const wrapper = mount(Icon, {
|
|
42
|
+
props: {
|
|
43
|
+
name: 'star',
|
|
44
|
+
type: 'regular',
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
expect(wrapper.classes()).toContain('fa-regular')
|
|
49
|
+
|
|
50
|
+
await wrapper.setProps({ type: 'light' })
|
|
51
|
+
expect(wrapper.classes()).toContain('fa-light')
|
|
52
|
+
|
|
53
|
+
await wrapper.setProps({ type: 'solid' })
|
|
54
|
+
expect(wrapper.classes()).toContain('fa-solid')
|
|
55
|
+
|
|
56
|
+
await wrapper.setProps({ type: 'duotone' })
|
|
57
|
+
expect(wrapper.classes()).toContain('fa-duotone')
|
|
58
|
+
|
|
59
|
+
await wrapper.setProps({ type: 'brands' })
|
|
60
|
+
expect(wrapper.classes()).toContain('fa-brands')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('applies basic layout classes', () => {
|
|
64
|
+
const wrapper = mount(Icon, {
|
|
65
|
+
props: {
|
|
66
|
+
name: 'star',
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
expect(wrapper.classes()).toContain('items-center')
|
|
71
|
+
expect(wrapper.classes()).toContain('justify-center')
|
|
72
|
+
})
|
|
73
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { IconName } from '@awesome.me/kit-37b149f3ef/icons'
|
|
3
|
+
|
|
4
|
+
export type IconType = 'regular' | 'solid' | 'light' | 'duotone' | 'brands'
|
|
5
|
+
|
|
6
|
+
interface NexxtIconProps {
|
|
7
|
+
name: IconName
|
|
8
|
+
type?: IconType
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
defineOptions({
|
|
12
|
+
name: 'NexxtIcon',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const { type = 'light' } = defineProps<NexxtIconProps>()
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<i :class="[`fa-${type}`, `fa-${name}`, 'items-center', 'justify-center']" />
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import InfoBlock from './InfoBlock.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Atoms/Info Block',
|
|
6
|
+
component: InfoBlock,
|
|
7
|
+
parameters: {
|
|
8
|
+
design: {
|
|
9
|
+
type: 'figma',
|
|
10
|
+
url: 'https://www.figma.com/design/CdbFJ7qUga6mtjagcPDvYK/Design-System?node-id=513-514&t=CbHvOQfEMIr7M5mO-11',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
} satisfies Meta<typeof InfoBlock>
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof InfoBlock>
|
|
16
|
+
|
|
17
|
+
const TEMPLATE =
|
|
18
|
+
'<span class="heading-4 text-yale-blue-500 inline">Tip!</span> <span class="body-medium text-gray-700">Koopwoningen doen het goed als post of reel</span>'
|
|
19
|
+
|
|
20
|
+
export const Green: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
icon: 'bell',
|
|
23
|
+
color: 'green',
|
|
24
|
+
},
|
|
25
|
+
render: (args) => ({
|
|
26
|
+
components: { InfoBlock },
|
|
27
|
+
setup() {
|
|
28
|
+
return { args }
|
|
29
|
+
},
|
|
30
|
+
template: `
|
|
31
|
+
<InfoBlock v-bind="args">
|
|
32
|
+
${TEMPLATE}
|
|
33
|
+
</InfoBlock>
|
|
34
|
+
`,
|
|
35
|
+
}),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const Purple: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
icon: 'circle-video',
|
|
41
|
+
color: 'purple',
|
|
42
|
+
},
|
|
43
|
+
render: (args) => ({
|
|
44
|
+
components: { InfoBlock },
|
|
45
|
+
setup() {
|
|
46
|
+
return { args }
|
|
47
|
+
},
|
|
48
|
+
template: `
|
|
49
|
+
<InfoBlock v-bind="args">
|
|
50
|
+
${TEMPLATE}
|
|
51
|
+
</InfoBlock>
|
|
52
|
+
`,
|
|
53
|
+
}),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const Blue: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
icon: 'info',
|
|
59
|
+
color: 'blue',
|
|
60
|
+
},
|
|
61
|
+
render: (args) => ({
|
|
62
|
+
components: { InfoBlock },
|
|
63
|
+
setup() {
|
|
64
|
+
return { args }
|
|
65
|
+
},
|
|
66
|
+
template: `
|
|
67
|
+
<InfoBlock v-bind="args">
|
|
68
|
+
${TEMPLATE}
|
|
69
|
+
</InfoBlock>
|
|
70
|
+
`,
|
|
71
|
+
}),
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const Rose: Story = {
|
|
75
|
+
args: {
|
|
76
|
+
icon: 'info',
|
|
77
|
+
color: 'rose',
|
|
78
|
+
},
|
|
79
|
+
render: (args) => ({
|
|
80
|
+
components: { InfoBlock },
|
|
81
|
+
setup() {
|
|
82
|
+
return { args }
|
|
83
|
+
},
|
|
84
|
+
template: `
|
|
85
|
+
<InfoBlock v-bind="args">
|
|
86
|
+
${TEMPLATE}
|
|
87
|
+
</InfoBlock>
|
|
88
|
+
`,
|
|
89
|
+
}),
|
|
90
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import InfoBlock from './InfoBlock.vue'
|
|
4
|
+
|
|
5
|
+
describe('InfoBlock', () => {
|
|
6
|
+
it('renders correctly with default slot content and green color', () => {
|
|
7
|
+
const customText = 'Koopwoningen doen het goed als post of reel'
|
|
8
|
+
const wrapper = mount(InfoBlock, {
|
|
9
|
+
props: {
|
|
10
|
+
icon: 'bell',
|
|
11
|
+
color: 'green',
|
|
12
|
+
},
|
|
13
|
+
slots: {
|
|
14
|
+
default: `<div class="heading-4">Tip!</div><div class="body-medium">${customText}</div>`,
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
expect(wrapper.text()).toContain('Tip!')
|
|
19
|
+
expect(wrapper.text()).toContain(customText)
|
|
20
|
+
expect(wrapper.find('.bg-green-50').exists()).toBe(true)
|
|
21
|
+
expect(wrapper.find('.bg-green-500').exists()).toBe(true)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('renders correctly with custom color purple', () => {
|
|
25
|
+
const wrapper = mount(InfoBlock, {
|
|
26
|
+
props: {
|
|
27
|
+
icon: 'star',
|
|
28
|
+
color: 'purple',
|
|
29
|
+
},
|
|
30
|
+
slots: {
|
|
31
|
+
default: 'Custom Purple Content',
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
expect(wrapper.text()).toContain('Custom Purple Content')
|
|
36
|
+
expect(wrapper.find('.bg-sapphire-50').exists()).toBe(true)
|
|
37
|
+
expect(wrapper.find('.bg-purple-500').exists()).toBe(true)
|
|
38
|
+
expect(wrapper.find('.border-purple-500').exists()).toBe(true)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('renders correctly with custom color blue', () => {
|
|
42
|
+
const wrapper = mount(InfoBlock, {
|
|
43
|
+
props: {
|
|
44
|
+
icon: 'info',
|
|
45
|
+
color: 'blue',
|
|
46
|
+
},
|
|
47
|
+
slots: {
|
|
48
|
+
default: 'Custom Blue Content',
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
expect(wrapper.text()).toContain('Custom Blue Content')
|
|
53
|
+
expect(wrapper.find('.bg-yale-blue-50').exists()).toBe(true)
|
|
54
|
+
expect(wrapper.find('.bg-cornflower-blue-500').exists()).toBe(true)
|
|
55
|
+
expect(wrapper.find('.border-cornflower-blue-500').exists()).toBe(true)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('renders correctly with custom color rose', () => {
|
|
59
|
+
const wrapper = mount(InfoBlock, {
|
|
60
|
+
props: {
|
|
61
|
+
icon: 'info',
|
|
62
|
+
color: 'rose',
|
|
63
|
+
},
|
|
64
|
+
slots: {
|
|
65
|
+
default: 'Custom Rose Content',
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
expect(wrapper.text()).toContain('Custom Rose Content')
|
|
70
|
+
expect(wrapper.find('.bg-rose-50').exists()).toBe(true)
|
|
71
|
+
expect(wrapper.find('.bg-rose-500').exists()).toBe(true)
|
|
72
|
+
expect(wrapper.find('.border-rose-500').exists()).toBe(true)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('has correct accessibility attributes', () => {
|
|
76
|
+
const wrapper = mount(InfoBlock, {
|
|
77
|
+
props: {
|
|
78
|
+
icon: 'bell',
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// Check for role="note"
|
|
83
|
+
expect(wrapper.attributes('role')).toBe('note')
|
|
84
|
+
|
|
85
|
+
// Check that the icon container is hidden from screen readers
|
|
86
|
+
const iconContainer = wrapper.find('[aria-hidden="true"]')
|
|
87
|
+
expect(iconContainer.exists()).toBe(true)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('renders the specific icon provided via props', () => {
|
|
91
|
+
const wrapper = mount(InfoBlock, {
|
|
92
|
+
props: {
|
|
93
|
+
icon: 'heart',
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const icon = wrapper.findComponent({ name: 'NexxtIcon' })
|
|
98
|
+
expect(icon.exists()).toBe(true)
|
|
99
|
+
expect(icon.props('name')).toBe('heart')
|
|
100
|
+
})
|
|
101
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import Icon from '../Icon/Icon.vue'
|
|
4
|
+
|
|
5
|
+
interface NexxtInfoBlockProps {
|
|
6
|
+
icon: InstanceType<typeof Icon>['name']
|
|
7
|
+
color?: 'green' | 'purple' | 'blue' | 'rose'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
defineOptions({
|
|
11
|
+
name: 'NexxtInfoBlock',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const { color = 'green' } = defineProps<NexxtInfoBlockProps>()
|
|
15
|
+
|
|
16
|
+
const colors = computed(() => {
|
|
17
|
+
switch (color) {
|
|
18
|
+
case 'green':
|
|
19
|
+
return {
|
|
20
|
+
border: 'border-green-500',
|
|
21
|
+
background: 'bg-green-50',
|
|
22
|
+
icon: 'bg-green-500',
|
|
23
|
+
}
|
|
24
|
+
case 'purple':
|
|
25
|
+
return {
|
|
26
|
+
border: 'border-purple-500',
|
|
27
|
+
background: 'bg-sapphire-50',
|
|
28
|
+
icon: 'bg-purple-500',
|
|
29
|
+
}
|
|
30
|
+
case 'blue':
|
|
31
|
+
return {
|
|
32
|
+
border: 'border-cornflower-blue-500',
|
|
33
|
+
background: 'bg-yale-blue-50',
|
|
34
|
+
icon: 'bg-cornflower-blue-500',
|
|
35
|
+
}
|
|
36
|
+
case 'rose':
|
|
37
|
+
return {
|
|
38
|
+
border: 'border-rose-500',
|
|
39
|
+
background: 'bg-rose-50',
|
|
40
|
+
icon: 'bg-rose-500',
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
return {
|
|
44
|
+
border: 'border-green-500',
|
|
45
|
+
background: 'bg-green-50',
|
|
46
|
+
icon: 'bg-green-500',
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<div class="info-block flex rounded-xl border" :class="colors.border" role="note">
|
|
54
|
+
<div
|
|
55
|
+
class="flex min-h-20 w-20 shrink-0 items-center justify-center rounded-l-lg"
|
|
56
|
+
:class="colors.background"
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
>
|
|
59
|
+
<div
|
|
60
|
+
class="flex aspect-square h-10 items-center justify-center rounded-3xl"
|
|
61
|
+
:class="colors.icon"
|
|
62
|
+
>
|
|
63
|
+
<Icon :name="icon" class="text-xl text-white" />
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="p-5">
|
|
67
|
+
<slot />
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import ProgressBar from './ProgressBar.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Atoms/Progress Bar',
|
|
6
|
+
component: ProgressBar,
|
|
7
|
+
parameters: {
|
|
8
|
+
design: {
|
|
9
|
+
type: 'figma',
|
|
10
|
+
url: 'https://www.figma.com/design/CdbFJ7qUga6mtjagcPDvYK/Design-System?node-id=369-218&t=CbHvOQfEMIr7M5mO-11',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
} satisfies Meta<typeof ProgressBar>
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof ProgressBar>
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args: {
|
|
19
|
+
steps: 5,
|
|
20
|
+
currentStep: 0,
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const WithTitles: Story = {
|
|
25
|
+
args: {
|
|
26
|
+
steps: 5,
|
|
27
|
+
currentStep: 0,
|
|
28
|
+
stepTitles: ['Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5'],
|
|
29
|
+
},
|
|
30
|
+
}
|