@nexxtmove/ui 0.1.21 → 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 +2415 -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,131 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils'
|
|
2
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
3
|
+
import SocialMediaCustomTemplate from './SocialMediaCustomTemplate.vue'
|
|
4
|
+
|
|
5
|
+
describe('SocialMediaCustomTemplate', () => {
|
|
6
|
+
it('renders correctly with video and poster', () => {
|
|
7
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
8
|
+
const video = wrapper.find('video')
|
|
9
|
+
|
|
10
|
+
expect(wrapper.element.tagName).toBe('BUTTON')
|
|
11
|
+
expect(video.exists()).toBe(true)
|
|
12
|
+
// Check video properties directly
|
|
13
|
+
const videoElement = video.element as HTMLVideoElement
|
|
14
|
+
expect(videoElement.muted).toBe(true)
|
|
15
|
+
expect(video.attributes('poster')).toContain('Template_aanvragen.jpg')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('handles video ended event correctly', async () => {
|
|
19
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
20
|
+
const videoElement = wrapper.find('video').element as HTMLVideoElement
|
|
21
|
+
const loadSpy = vi.spyOn(videoElement, 'load').mockImplementation(() => {})
|
|
22
|
+
|
|
23
|
+
// Simulate video ending
|
|
24
|
+
await wrapper.find('video').trigger('ended')
|
|
25
|
+
|
|
26
|
+
expect(videoElement.currentTime).toBe(0)
|
|
27
|
+
expect(loadSpy).toHaveBeenCalled()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('plays video on mouseenter after first play', async () => {
|
|
31
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
32
|
+
const videoElement = wrapper.find('video').element as HTMLVideoElement
|
|
33
|
+
const playSpy = vi.spyOn(videoElement, 'play').mockImplementation(() => Promise.resolve())
|
|
34
|
+
|
|
35
|
+
// Set state to hasPlayedOnce
|
|
36
|
+
await wrapper.find('video').trigger('ended')
|
|
37
|
+
|
|
38
|
+
// Trigger mouseenter
|
|
39
|
+
await wrapper.trigger('mouseenter')
|
|
40
|
+
|
|
41
|
+
expect(playSpy).toHaveBeenCalled()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('pauses video on mouseleave after first play', async () => {
|
|
45
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
46
|
+
const videoElement = wrapper.find('video').element as HTMLVideoElement
|
|
47
|
+
const pauseSpy = vi.spyOn(videoElement, 'pause')
|
|
48
|
+
|
|
49
|
+
// Set state to hasPlayedOnce
|
|
50
|
+
await wrapper.find('video').trigger('ended')
|
|
51
|
+
|
|
52
|
+
// Trigger mouseleave
|
|
53
|
+
await wrapper.trigger('mouseleave')
|
|
54
|
+
|
|
55
|
+
expect(pauseSpy).toHaveBeenCalled()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('sets loop to true after first play', async () => {
|
|
59
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
60
|
+
const video = wrapper.find('video')
|
|
61
|
+
const videoElement = video.element as HTMLVideoElement
|
|
62
|
+
|
|
63
|
+
expect(videoElement.loop).toBe(false)
|
|
64
|
+
|
|
65
|
+
// Simulate video ending
|
|
66
|
+
await video.trigger('ended')
|
|
67
|
+
|
|
68
|
+
expect(videoElement.loop).toBe(true)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('does not play on mouseenter before first play has ended', async () => {
|
|
72
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
73
|
+
const videoElement = wrapper.find('video').element as HTMLVideoElement
|
|
74
|
+
const playSpy = vi.spyOn(videoElement, 'play')
|
|
75
|
+
|
|
76
|
+
await wrapper.trigger('mouseenter')
|
|
77
|
+
|
|
78
|
+
expect(playSpy).not.toHaveBeenCalled()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('does not pause on mouseleave before first play has ended', async () => {
|
|
82
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
83
|
+
const videoElement = wrapper.find('video').element as HTMLVideoElement
|
|
84
|
+
const pauseSpy = vi.spyOn(videoElement, 'pause')
|
|
85
|
+
|
|
86
|
+
await wrapper.trigger('mouseleave')
|
|
87
|
+
|
|
88
|
+
expect(pauseSpy).not.toHaveBeenCalled()
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('does not call handleEnded if videoRef is null', async () => {
|
|
92
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
93
|
+
// @ts-expect-error - manually setting ref to null for test
|
|
94
|
+
wrapper.vm.videoRef = null
|
|
95
|
+
|
|
96
|
+
// Trigger handleEnded directly (internally)
|
|
97
|
+
// @ts-expect-error - calling internal method
|
|
98
|
+
wrapper.vm.handleEnded()
|
|
99
|
+
|
|
100
|
+
// @ts-expect-error - checking internal state
|
|
101
|
+
expect(wrapper.vm.hasPlayedOnce).toBe(false)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('internal methods do nothing if videoRef is null', async () => {
|
|
105
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
106
|
+
// @ts-expect-error - manually setting ref to null for test
|
|
107
|
+
wrapper.vm.videoRef = null
|
|
108
|
+
// @ts-expect-error - manually setting hasPlayedOnce for branch test
|
|
109
|
+
wrapper.vm.hasPlayedOnce = true
|
|
110
|
+
|
|
111
|
+
// Trigger handleMouseEnter directly (internally)
|
|
112
|
+
// @ts-expect-error - calling internal method
|
|
113
|
+
wrapper.vm.handleMouseEnter()
|
|
114
|
+
// Trigger handleMouseLeave directly (internally)
|
|
115
|
+
// @ts-expect-error - calling internal method
|
|
116
|
+
wrapper.vm.handleMouseLeave()
|
|
117
|
+
|
|
118
|
+
// No errors should occur
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('plays onMounted if videoRef is valid', async () => {
|
|
122
|
+
const wrapper = mount(SocialMediaCustomTemplate)
|
|
123
|
+
const videoElement = wrapper.find('video').element as HTMLVideoElement
|
|
124
|
+
const playSpy = vi.spyOn(videoElement, 'play').mockImplementation(() => Promise.resolve())
|
|
125
|
+
|
|
126
|
+
// Simulate onMounted behavior by calling it again (it already ran once on mount)
|
|
127
|
+
// @ts-expect-error - manually calling onMounted setup code
|
|
128
|
+
wrapper.vm.handleMouseEnter() // hasPlayedOnce is false, should not play
|
|
129
|
+
expect(playSpy).not.toHaveBeenCalled()
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import missingVideo from '../../assets/video/Template_aanvragen.mp4'
|
|
3
|
+
import { ref, onMounted } from 'vue'
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'NexxtSocialMediaCustomTemplate',
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const videoRef = ref<HTMLVideoElement>()
|
|
10
|
+
const hasPlayedOnce = ref(false)
|
|
11
|
+
|
|
12
|
+
const handleEnded = () => {
|
|
13
|
+
if (videoRef.value) {
|
|
14
|
+
videoRef.value.load()
|
|
15
|
+
hasPlayedOnce.value = true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const handleMouseEnter = () => {
|
|
20
|
+
if (hasPlayedOnce.value && videoRef.value) {
|
|
21
|
+
videoRef.value.play()
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const handleMouseLeave = () => {
|
|
26
|
+
if (hasPlayedOnce.value && videoRef.value) {
|
|
27
|
+
videoRef.value.pause()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
onMounted(() => {
|
|
32
|
+
if (videoRef.value) {
|
|
33
|
+
videoRef.value.play()
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<button
|
|
40
|
+
class="flex aspect-9/16 w-64 cursor-pointer items-center justify-center overflow-hidden rounded-3xl bg-gray-50 outline-1 -outline-offset-1 outline-gray-200 transition-all focus-visible:outline-2 focus-visible:outline-cornflower-blue-600"
|
|
41
|
+
@mouseenter="handleMouseEnter"
|
|
42
|
+
@mouseleave="handleMouseLeave"
|
|
43
|
+
>
|
|
44
|
+
<video
|
|
45
|
+
ref="videoRef"
|
|
46
|
+
:src="missingVideo"
|
|
47
|
+
muted
|
|
48
|
+
playsinline
|
|
49
|
+
:loop="hasPlayedOnce"
|
|
50
|
+
class="h-full w-full object-cover"
|
|
51
|
+
poster="../../assets/images/Template_aanvragen.jpg"
|
|
52
|
+
@ended.once="handleEnded"
|
|
53
|
+
/>
|
|
54
|
+
</button>
|
|
55
|
+
</template>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import SocialMediaTemplate from './SocialMediaTemplate.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Organisms/Social Media Template',
|
|
6
|
+
component: SocialMediaTemplate,
|
|
7
|
+
argTypes: {
|
|
8
|
+
variant: {
|
|
9
|
+
control: 'select',
|
|
10
|
+
options: ['post', 'video', 'slideshow'],
|
|
11
|
+
},
|
|
12
|
+
selected: {
|
|
13
|
+
control: 'boolean',
|
|
14
|
+
},
|
|
15
|
+
muted: {
|
|
16
|
+
control: 'boolean',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
parameters: {
|
|
20
|
+
design: {
|
|
21
|
+
type: 'figma',
|
|
22
|
+
url: 'https://www.figma.com/design/CdbFJ7qUga6mtjagcPDvYK/Design-System?node-id=578-340&t=CbHvOQfEMIr7M5mO-11',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
} satisfies Meta<typeof SocialMediaTemplate>
|
|
26
|
+
|
|
27
|
+
type Story = StoryObj<typeof SocialMediaTemplate>
|
|
28
|
+
|
|
29
|
+
export const Post: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
variant: 'post',
|
|
32
|
+
media: 'https://loremflickr.com/400/600/house',
|
|
33
|
+
mediaType: 'image',
|
|
34
|
+
name: 'Amsterdam',
|
|
35
|
+
type: 'Woning',
|
|
36
|
+
selected: false,
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const Video: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
variant: 'video',
|
|
43
|
+
media: '/barcelona.mp4',
|
|
44
|
+
mediaType: 'video',
|
|
45
|
+
muted: true,
|
|
46
|
+
name: 'Barcelona',
|
|
47
|
+
type: 'Woning',
|
|
48
|
+
selected: false,
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const Slideshow: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
variant: 'slideshow',
|
|
55
|
+
media: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
|
56
|
+
mediaType: 'image',
|
|
57
|
+
name: 'Stockholm',
|
|
58
|
+
type: 'Bedrijfsunit',
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const Selected: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
variant: 'post',
|
|
65
|
+
media: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
|
66
|
+
mediaType: 'image',
|
|
67
|
+
name: 'Amsterdam',
|
|
68
|
+
type: 'Woning',
|
|
69
|
+
selected: true,
|
|
70
|
+
},
|
|
71
|
+
}
|