@sabrenski/spire-ui 0.0.1
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/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/index.d.ts +4981 -0
- package/dist/spire-ui.css +1 -0
- package/dist/spire-ui.es.js +18403 -0
- package/dist/spire-ui.umd.js +45 -0
- package/package.json +83 -0
- package/src/components/Accordion/Accordion.test.ts +218 -0
- package/src/components/Accordion/AccordionContent.vue +112 -0
- package/src/components/Accordion/AccordionItem.vue +87 -0
- package/src/components/Accordion/AccordionRoot.vue +111 -0
- package/src/components/Accordion/AccordionTrigger.vue +125 -0
- package/src/components/Accordion/index.ts +11 -0
- package/src/components/Accordion/keys.ts +23 -0
- package/src/components/Avatar/Avatar.test.ts +181 -0
- package/src/components/Avatar/Avatar.vue +150 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Badge/Badge.test.ts +141 -0
- package/src/components/Badge/Badge.vue +133 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/BadgeContainer/BadgeContainer.test.ts +150 -0
- package/src/components/BadgeContainer/BadgeContainer.vue +90 -0
- package/src/components/BadgeContainer/index.ts +2 -0
- package/src/components/Breadcrumb/Breadcrumb.test.ts +342 -0
- package/src/components/Breadcrumb/BreadcrumbEllipsis.vue +96 -0
- package/src/components/Breadcrumb/BreadcrumbItem.vue +16 -0
- package/src/components/Breadcrumb/BreadcrumbLink.vue +67 -0
- package/src/components/Breadcrumb/BreadcrumbList.vue +20 -0
- package/src/components/Breadcrumb/BreadcrumbPage.vue +25 -0
- package/src/components/Breadcrumb/BreadcrumbRoot.vue +41 -0
- package/src/components/Breadcrumb/BreadcrumbSeparator.vue +63 -0
- package/src/components/Breadcrumb/index.ts +13 -0
- package/src/components/Breadcrumb/keys.ts +7 -0
- package/src/components/Button/Button.test.ts +231 -0
- package/src/components/Button/Button.vue +349 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Callout/Callout.test.ts +260 -0
- package/src/components/Callout/Callout.vue +341 -0
- package/src/components/Callout/index.ts +2 -0
- package/src/components/Card/Card.test.ts +565 -0
- package/src/components/Card/Card.vue +209 -0
- package/src/components/Card/CardContent.vue +57 -0
- package/src/components/Card/CardFooter.vue +72 -0
- package/src/components/Card/CardHeader.vue +111 -0
- package/src/components/Card/CardImage.vue +124 -0
- package/src/components/Card/index.ts +14 -0
- package/src/components/Chart/BarChart.vue +208 -0
- package/src/components/Chart/BaseChart.vue +444 -0
- package/src/components/Chart/Chart.test.ts +359 -0
- package/src/components/Chart/DonutChart.vue +283 -0
- package/src/components/Chart/LineChart.vue +211 -0
- package/src/components/Chart/index.ts +20 -0
- package/src/components/Chart/useChartTheme.ts +192 -0
- package/src/components/Checkbox/Checkbox.test.ts +209 -0
- package/src/components/Checkbox/Checkbox.vue +285 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/ChoiceChip/ChoiceChip.test.ts +142 -0
- package/src/components/ChoiceChip/ChoiceChip.vue +218 -0
- package/src/components/ChoiceChip/index.ts +2 -0
- package/src/components/ChoiceChipGroup/ChoiceChipGroup.test.ts +151 -0
- package/src/components/ChoiceChipGroup/ChoiceChipGroup.vue +70 -0
- package/src/components/ChoiceChipGroup/index.ts +2 -0
- package/src/components/ColorPicker/ColorArea.vue +159 -0
- package/src/components/ColorPicker/ColorPicker.test.ts +250 -0
- package/src/components/ColorPicker/ColorPicker.vue +339 -0
- package/src/components/ColorPicker/ColorSlider.vue +191 -0
- package/src/components/ColorPicker/index.ts +7 -0
- package/src/components/Combobox/Combobox.test.ts +891 -0
- package/src/components/Combobox/Combobox.vue +934 -0
- package/src/components/Combobox/index.ts +2 -0
- package/src/components/DataTable/DataTable.test.ts +1221 -0
- package/src/components/DataTable/DataTable.vue +1415 -0
- package/src/components/DataTable/index.ts +10 -0
- package/src/components/DatePicker/DatePicker.test.ts +625 -0
- package/src/components/DatePicker/DatePicker.vue +1586 -0
- package/src/components/DatePicker/index.ts +2 -0
- package/src/components/Drawer/Drawer.test.ts +336 -0
- package/src/components/Drawer/Drawer.vue +466 -0
- package/src/components/Drawer/index.ts +2 -0
- package/src/components/Dropdown/Dropdown.test.ts +607 -0
- package/src/components/Dropdown/Dropdown.vue +807 -0
- package/src/components/Dropdown/DropdownItem.vue +227 -0
- package/src/components/Dropdown/DropdownSeparator.vue +14 -0
- package/src/components/Dropdown/DropdownSub.vue +104 -0
- package/src/components/Dropdown/DropdownSubContent.vue +187 -0
- package/src/components/Dropdown/DropdownSubTrigger.vue +151 -0
- package/src/components/Dropdown/index.ts +14 -0
- package/src/components/EmptyState/EmptyState.test.ts +180 -0
- package/src/components/EmptyState/EmptyState.vue +137 -0
- package/src/components/EmptyState/index.ts +2 -0
- package/src/components/FileUpload/FileUpload.test.ts +1151 -0
- package/src/components/FileUpload/FileUpload.vue +1042 -0
- package/src/components/FileUpload/index.ts +2 -0
- package/src/components/Heading/Heading.test.ts +107 -0
- package/src/components/Heading/Heading.vue +67 -0
- package/src/components/Heading/index.ts +2 -0
- package/src/components/Icon/Icon.test.ts +157 -0
- package/src/components/Icon/Icon.vue +86 -0
- package/src/components/Icon/index.ts +2 -0
- package/src/components/Input/Input.test.ts +273 -0
- package/src/components/Input/Input.vue +388 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Layout/Container.vue +67 -0
- package/src/components/Layout/Grid.vue +159 -0
- package/src/components/Layout/GridItem.vue +154 -0
- package/src/components/Layout/Layout.test.ts +202 -0
- package/src/components/Layout/Stack.vue +128 -0
- package/src/components/Layout/index.ts +9 -0
- package/src/components/Layout/keys.ts +7 -0
- package/src/components/Modal/Modal.test.ts +311 -0
- package/src/components/Modal/Modal.vue +336 -0
- package/src/components/Modal/index.ts +2 -0
- package/src/components/Pagination/Pagination.test.ts +303 -0
- package/src/components/Pagination/Pagination.vue +212 -0
- package/src/components/Pagination/index.ts +3 -0
- package/src/components/Pagination/utils.ts +86 -0
- package/src/components/Popover/Popover.test.ts +285 -0
- package/src/components/Popover/Popover.vue +441 -0
- package/src/components/Popover/index.ts +2 -0
- package/src/components/Progress/Progress.test.ts +361 -0
- package/src/components/Progress/Progress.vue +363 -0
- package/src/components/Progress/index.ts +7 -0
- package/src/components/Radio/Radio.test.ts +216 -0
- package/src/components/Radio/Radio.vue +214 -0
- package/src/components/Radio/index.ts +2 -0
- package/src/components/Rating/Rating.test.ts +319 -0
- package/src/components/Rating/Rating.vue +247 -0
- package/src/components/Rating/index.ts +2 -0
- package/src/components/SegmentedControl/SegmentedControl.test.ts +292 -0
- package/src/components/SegmentedControl/SegmentedControl.vue +288 -0
- package/src/components/SegmentedControl/index.ts +2 -0
- package/src/components/Select/Select.test.ts +589 -0
- package/src/components/Select/Select.vue +666 -0
- package/src/components/Select/index.ts +2 -0
- package/src/components/Sidebar/Sidebar.test.ts +301 -0
- package/src/components/Sidebar/SidebarGroup.vue +103 -0
- package/src/components/Sidebar/SidebarItem.vue +196 -0
- package/src/components/Sidebar/SidebarLayout.vue +42 -0
- package/src/components/Sidebar/SidebarRoot.vue +122 -0
- package/src/components/Sidebar/index.ts +11 -0
- package/src/components/Sidebar/keys.ts +14 -0
- package/src/components/Skeleton/Skeleton.test.ts +130 -0
- package/src/components/Skeleton/Skeleton.vue +104 -0
- package/src/components/Skeleton/index.ts +2 -0
- package/src/components/Slider/Slider.test.ts +416 -0
- package/src/components/Slider/Slider.vue +435 -0
- package/src/components/Slider/index.ts +2 -0
- package/src/components/Slider/utils.ts +91 -0
- package/src/components/Spinner/Spinner.test.ts +79 -0
- package/src/components/Spinner/Spinner.vue +159 -0
- package/src/components/Spinner/index.ts +2 -0
- package/src/components/SpireProvider/SpireProvider.vue +71 -0
- package/src/components/SpireProvider/index.ts +11 -0
- package/src/components/Stepper/Stepper.test.ts +221 -0
- package/src/components/Stepper/StepperContent.vue +51 -0
- package/src/components/Stepper/StepperItem.vue +89 -0
- package/src/components/Stepper/StepperRoot.vue +101 -0
- package/src/components/Stepper/StepperSeparator.vue +52 -0
- package/src/components/Stepper/StepperTrigger.vue +144 -0
- package/src/components/Stepper/index.ts +11 -0
- package/src/components/Stepper/keys.ts +27 -0
- package/src/components/Switch/Switch.test.ts +214 -0
- package/src/components/Switch/Switch.vue +235 -0
- package/src/components/Switch/index.ts +2 -0
- package/src/components/Tabs/Tabs.test.ts +363 -0
- package/src/components/Tabs/Tabs.vue +318 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Text/Text.test.ts +154 -0
- package/src/components/Text/Text.vue +100 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Textarea/Textarea.test.ts +432 -0
- package/src/components/Textarea/Textarea.vue +411 -0
- package/src/components/Textarea/index.ts +2 -0
- package/src/components/TimePicker/TimePicker.test.ts +352 -0
- package/src/components/TimePicker/TimePicker.vue +569 -0
- package/src/components/TimePicker/index.ts +2 -0
- package/src/components/Timeline/Timeline.test.ts +193 -0
- package/src/components/Timeline/Timeline.vue +111 -0
- package/src/components/Timeline/TimelineItem.vue +167 -0
- package/src/components/Timeline/index.ts +13 -0
- package/src/components/Timeline/keys.ts +21 -0
- package/src/components/Toast/ToastItem.test.ts +289 -0
- package/src/components/Toast/ToastItem.vue +370 -0
- package/src/components/Toast/ToastProvider.test.ts +158 -0
- package/src/components/Toast/ToastProvider.vue +181 -0
- package/src/components/Toast/index.ts +83 -0
- package/src/components/Toast/toastState.test.ts +165 -0
- package/src/components/Toast/toastState.ts +161 -0
- package/src/components/ToggleButton/ToggleButton.test.ts +166 -0
- package/src/components/ToggleButton/ToggleButton.vue +197 -0
- package/src/components/ToggleButton/index.ts +2 -0
- package/src/components/ToggleGroup/ToggleGroup.test.ts +181 -0
- package/src/components/ToggleGroup/ToggleGroup.vue +130 -0
- package/src/components/ToggleGroup/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.test.ts +238 -0
- package/src/components/Tooltip/Tooltip.vue +217 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/TreeView/TreeView.test.ts +357 -0
- package/src/components/TreeView/TreeView.vue +251 -0
- package/src/components/TreeView/TreeViewItem.vue +288 -0
- package/src/components/TreeView/index.ts +11 -0
- package/src/components/TreeView/keys.ts +35 -0
- package/src/composables/index.ts +12 -0
- package/src/composables/useClickOutside.ts +36 -0
- package/src/composables/useClipboard.ts +35 -0
- package/src/composables/useEventListener.ts +48 -0
- package/src/composables/useFocusTrap.ts +58 -0
- package/src/composables/useHoverReveal.ts +98 -0
- package/src/composables/useId.ts +10 -0
- package/src/composables/useMagnetic.ts +171 -0
- package/src/composables/useRelativePosition.ts +127 -0
- package/src/composables/useRipple.ts +146 -0
- package/src/composables/useScrollLock.ts +25 -0
- package/src/composables/useSpireConfig.ts +27 -0
- package/src/composables/useStagger.ts +224 -0
- package/src/config/icons.test.ts +115 -0
- package/src/config/icons.ts +170 -0
- package/src/index.ts +361 -0
- package/src/styles/depth.css +129 -0
- package/src/styles/effects.css +169 -0
- package/src/styles/fallback.css +152 -0
- package/src/styles/main.css +25 -0
- package/src/styles/mood.css +211 -0
- package/src/styles/motion.css +159 -0
- package/src/styles/reset.css +97 -0
- package/src/styles/theme.css +708 -0
- package/src/styles/tokens.css +183 -0
- package/src/utils/.gitkeep +0 -0
- package/src/utils/color.ts +277 -0
- package/src/utils/date.test.ts +522 -0
- package/src/utils/date.ts +380 -0
- package/src/utils/index.ts +23 -0
- package/src/utils/object.test.ts +80 -0
- package/src/utils/object.ts +25 -0
- package/src/utils/string.test.ts +64 -0
- package/src/utils/string.ts +32 -0
- package/src/utils/time.ts +156 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { mount, config } from '@vue/test-utils'
|
|
3
|
+
import TimePicker from './TimePicker.vue'
|
|
4
|
+
|
|
5
|
+
config.global.stubs = {
|
|
6
|
+
teleport: true
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe('TimePicker', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.useFakeTimers()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
vi.restoreAllMocks()
|
|
16
|
+
vi.useRealTimers()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('Rendering', () => {
|
|
20
|
+
it('renders input element', () => {
|
|
21
|
+
const wrapper = mount(TimePicker)
|
|
22
|
+
expect(wrapper.find('.ui-input-wrapper').exists()).toBe(true)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('renders with label', () => {
|
|
26
|
+
const wrapper = mount(TimePicker, {
|
|
27
|
+
props: { label: 'Start Time' }
|
|
28
|
+
})
|
|
29
|
+
expect(wrapper.find('.ui-input-field__label').text()).toBe('Start Time')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('renders with placeholder', () => {
|
|
33
|
+
const wrapper = mount(TimePicker, {
|
|
34
|
+
props: { placeholder: 'Select time' }
|
|
35
|
+
})
|
|
36
|
+
expect(wrapper.find('input').attributes('placeholder')).toBe('Select time')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('renders default placeholder for 12h format', () => {
|
|
40
|
+
const wrapper = mount(TimePicker, {
|
|
41
|
+
props: { format: '12h' }
|
|
42
|
+
})
|
|
43
|
+
expect(wrapper.find('input').attributes('placeholder')).toBe('hh:mm AM/PM')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('renders default placeholder for 24h format', () => {
|
|
47
|
+
const wrapper = mount(TimePicker, {
|
|
48
|
+
props: { format: '24h' }
|
|
49
|
+
})
|
|
50
|
+
expect(wrapper.find('input').attributes('placeholder')).toBe('HH:mm')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('renders with hint text', () => {
|
|
54
|
+
const wrapper = mount(TimePicker, {
|
|
55
|
+
props: { hint: 'Choose your preferred time' }
|
|
56
|
+
})
|
|
57
|
+
expect(wrapper.find('.ui-input-field__message--hint').text()).toBe('Choose your preferred time')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('renders with error message', () => {
|
|
61
|
+
const wrapper = mount(TimePicker, {
|
|
62
|
+
props: { error: 'Time is required' }
|
|
63
|
+
})
|
|
64
|
+
expect(wrapper.find('.ui-input-field__message--error').text()).toBe('Time is required')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('renders required indicator', () => {
|
|
68
|
+
const wrapper = mount(TimePicker, {
|
|
69
|
+
props: { label: 'Time', required: true }
|
|
70
|
+
})
|
|
71
|
+
expect(wrapper.find('.ui-input-field__required').exists()).toBe(true)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe('v-model', () => {
|
|
76
|
+
it('displays formatted time when value is set (12h)', () => {
|
|
77
|
+
const wrapper = mount(TimePicker, {
|
|
78
|
+
props: { modelValue: '14:30', format: '12h' }
|
|
79
|
+
})
|
|
80
|
+
expect(wrapper.find('input').element.value).toBe('02:30 PM')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('displays formatted time when value is set (24h)', () => {
|
|
84
|
+
const wrapper = mount(TimePicker, {
|
|
85
|
+
props: { modelValue: '14:30', format: '24h' }
|
|
86
|
+
})
|
|
87
|
+
expect(wrapper.find('input').element.value).toBe('14:30')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('emits update:modelValue when time is parsed from input', async () => {
|
|
91
|
+
const wrapper = mount(TimePicker, {
|
|
92
|
+
props: { format: '12h' }
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const input = wrapper.find('input')
|
|
96
|
+
await input.setValue('2:30pm')
|
|
97
|
+
await input.trigger('blur')
|
|
98
|
+
|
|
99
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
100
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['14:30'])
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('handles midnight correctly (12h)', () => {
|
|
104
|
+
const wrapper = mount(TimePicker, {
|
|
105
|
+
props: { modelValue: '00:00', format: '12h' }
|
|
106
|
+
})
|
|
107
|
+
expect(wrapper.find('input').element.value).toBe('12:00 AM')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('handles noon correctly (12h)', () => {
|
|
111
|
+
const wrapper = mount(TimePicker, {
|
|
112
|
+
props: { modelValue: '12:00', format: '12h' }
|
|
113
|
+
})
|
|
114
|
+
expect(wrapper.find('input').element.value).toBe('12:00 PM')
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
describe('Size variants', () => {
|
|
119
|
+
it('applies xs size class', () => {
|
|
120
|
+
const wrapper = mount(TimePicker, {
|
|
121
|
+
props: { size: 'xs' }
|
|
122
|
+
})
|
|
123
|
+
expect(wrapper.find('.ui-timepicker').classes()).toContain('ui-timepicker--xs')
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('applies sm size class', () => {
|
|
127
|
+
const wrapper = mount(TimePicker, {
|
|
128
|
+
props: { size: 'sm' }
|
|
129
|
+
})
|
|
130
|
+
expect(wrapper.find('.ui-timepicker').classes()).toContain('ui-timepicker--sm')
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('applies md size class', () => {
|
|
134
|
+
const wrapper = mount(TimePicker, {
|
|
135
|
+
props: { size: 'md' }
|
|
136
|
+
})
|
|
137
|
+
expect(wrapper.find('.ui-timepicker').classes()).toContain('ui-timepicker--md')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('applies lg size class', () => {
|
|
141
|
+
const wrapper = mount(TimePicker, {
|
|
142
|
+
props: { size: 'lg' }
|
|
143
|
+
})
|
|
144
|
+
expect(wrapper.find('.ui-timepicker').classes()).toContain('ui-timepicker--lg')
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('applies xl size class', () => {
|
|
148
|
+
const wrapper = mount(TimePicker, {
|
|
149
|
+
props: { size: 'xl' }
|
|
150
|
+
})
|
|
151
|
+
expect(wrapper.find('.ui-timepicker').classes()).toContain('ui-timepicker--xl')
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
describe('States', () => {
|
|
156
|
+
it('applies disabled state', () => {
|
|
157
|
+
const wrapper = mount(TimePicker, {
|
|
158
|
+
props: { disabled: true }
|
|
159
|
+
})
|
|
160
|
+
expect(wrapper.find('.ui-timepicker').classes()).toContain('ui-timepicker--disabled')
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('applies block state', () => {
|
|
164
|
+
const wrapper = mount(TimePicker, {
|
|
165
|
+
props: { block: true }
|
|
166
|
+
})
|
|
167
|
+
expect(wrapper.find('.ui-timepicker').classes()).toContain('ui-timepicker--block')
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
describe('Popover panel', () => {
|
|
172
|
+
it('renders hour column', async () => {
|
|
173
|
+
const wrapper = mount(TimePicker, {
|
|
174
|
+
attachTo: document.body
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
178
|
+
await wrapper.vm.$nextTick()
|
|
179
|
+
|
|
180
|
+
expect(wrapper.find('.ui-timepicker__column').exists()).toBe(true)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('renders separator between columns', async () => {
|
|
184
|
+
const wrapper = mount(TimePicker, {
|
|
185
|
+
attachTo: document.body
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
189
|
+
await wrapper.vm.$nextTick()
|
|
190
|
+
|
|
191
|
+
expect(wrapper.find('.ui-timepicker__separator').text()).toBe(':')
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('renders period column for 12h format', async () => {
|
|
195
|
+
const wrapper = mount(TimePicker, {
|
|
196
|
+
props: { format: '12h' },
|
|
197
|
+
attachTo: document.body
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
201
|
+
await wrapper.vm.$nextTick()
|
|
202
|
+
|
|
203
|
+
expect(wrapper.find('.ui-timepicker__column--period').exists()).toBe(true)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('does not render period column for 24h format', async () => {
|
|
207
|
+
const wrapper = mount(TimePicker, {
|
|
208
|
+
props: { format: '24h' },
|
|
209
|
+
attachTo: document.body
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
213
|
+
await wrapper.vm.$nextTick()
|
|
214
|
+
|
|
215
|
+
expect(wrapper.find('.ui-timepicker__column--period').exists()).toBe(false)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('renders highlight bar', async () => {
|
|
219
|
+
const wrapper = mount(TimePicker, {
|
|
220
|
+
attachTo: document.body
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
224
|
+
await wrapper.vm.$nextTick()
|
|
225
|
+
|
|
226
|
+
expect(wrapper.find('.ui-timepicker__highlight').exists()).toBe(true)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
it('renders 12 hours for 12h format', async () => {
|
|
230
|
+
const wrapper = mount(TimePicker, {
|
|
231
|
+
props: { format: '12h' },
|
|
232
|
+
attachTo: document.body
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
236
|
+
await wrapper.vm.$nextTick()
|
|
237
|
+
|
|
238
|
+
const columns = wrapper.findAll('.ui-timepicker__column')
|
|
239
|
+
const hourColumn = columns[0]
|
|
240
|
+
const hourItems = hourColumn.findAll('.ui-timepicker__item')
|
|
241
|
+
expect(hourItems.length).toBe(12)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('renders 24 hours for 24h format', async () => {
|
|
245
|
+
const wrapper = mount(TimePicker, {
|
|
246
|
+
props: { format: '24h' },
|
|
247
|
+
attachTo: document.body
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
251
|
+
await wrapper.vm.$nextTick()
|
|
252
|
+
|
|
253
|
+
const columns = wrapper.findAll('.ui-timepicker__column')
|
|
254
|
+
const hourColumn = columns[0]
|
|
255
|
+
const hourItems = hourColumn.findAll('.ui-timepicker__item')
|
|
256
|
+
expect(hourItems.length).toBe(24)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('renders 60 minutes by default', async () => {
|
|
260
|
+
const wrapper = mount(TimePicker, {
|
|
261
|
+
props: { minuteStep: 1 },
|
|
262
|
+
attachTo: document.body
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
266
|
+
await wrapper.vm.$nextTick()
|
|
267
|
+
|
|
268
|
+
const columns = wrapper.findAll('.ui-timepicker__column')
|
|
269
|
+
const minuteColumn = columns[1]
|
|
270
|
+
const minuteItems = minuteColumn.findAll('.ui-timepicker__item')
|
|
271
|
+
expect(minuteItems.length).toBe(60)
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('respects minuteStep prop', async () => {
|
|
275
|
+
const wrapper = mount(TimePicker, {
|
|
276
|
+
props: { minuteStep: 15 },
|
|
277
|
+
attachTo: document.body
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
await wrapper.find('.ui-popover__trigger').trigger('click')
|
|
281
|
+
await wrapper.vm.$nextTick()
|
|
282
|
+
|
|
283
|
+
const columns = wrapper.findAll('.ui-timepicker__column')
|
|
284
|
+
const minuteColumn = columns[1]
|
|
285
|
+
const minuteItems = minuteColumn.findAll('.ui-timepicker__item')
|
|
286
|
+
expect(minuteItems.length).toBe(4)
|
|
287
|
+
})
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
describe('Accessibility', () => {
|
|
291
|
+
it('auto-generates unique id', () => {
|
|
292
|
+
const wrapper = mount(TimePicker)
|
|
293
|
+
const input = wrapper.find('input')
|
|
294
|
+
expect(input.attributes('id')).toMatch(/^timepicker-/)
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('uses provided id', () => {
|
|
298
|
+
const wrapper = mount(TimePicker, {
|
|
299
|
+
props: { id: 'custom-time-id' }
|
|
300
|
+
})
|
|
301
|
+
const input = wrapper.find('input')
|
|
302
|
+
expect(input.attributes('id')).toBe('custom-time-id')
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('links label to input via for attribute', () => {
|
|
306
|
+
const wrapper = mount(TimePicker, {
|
|
307
|
+
props: { label: 'Time', id: 'time-input' }
|
|
308
|
+
})
|
|
309
|
+
expect(wrapper.find('label').attributes('for')).toBe('time-input')
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
describe('HTML attributes', () => {
|
|
314
|
+
it('passes name attribute to input', () => {
|
|
315
|
+
const wrapper = mount(TimePicker, {
|
|
316
|
+
props: { name: 'meeting-time' }
|
|
317
|
+
})
|
|
318
|
+
expect(wrapper.find('input').attributes('name')).toBe('meeting-time')
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
describe('Exposed methods', () => {
|
|
323
|
+
it('exposes open method', () => {
|
|
324
|
+
const wrapper = mount(TimePicker)
|
|
325
|
+
expect(typeof wrapper.vm.open).toBe('function')
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
it('exposes close method', () => {
|
|
329
|
+
const wrapper = mount(TimePicker)
|
|
330
|
+
expect(typeof wrapper.vm.close).toBe('function')
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
it('exposes toggle method', () => {
|
|
334
|
+
const wrapper = mount(TimePicker)
|
|
335
|
+
expect(typeof wrapper.vm.toggle).toBe('function')
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
describe('Focus and blur events', () => {
|
|
340
|
+
it('emits focus event', async () => {
|
|
341
|
+
const wrapper = mount(TimePicker)
|
|
342
|
+
await wrapper.find('input').trigger('focus')
|
|
343
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it('emits blur event', async () => {
|
|
347
|
+
const wrapper = mount(TimePicker)
|
|
348
|
+
await wrapper.find('input').trigger('blur')
|
|
349
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
350
|
+
})
|
|
351
|
+
})
|
|
352
|
+
})
|