@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,361 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import Progress from './Progress.vue'
|
|
4
|
+
|
|
5
|
+
describe('Progress', () => {
|
|
6
|
+
describe('Linear variant', () => {
|
|
7
|
+
it('renders linear progress by default', () => {
|
|
8
|
+
const wrapper = mount(Progress)
|
|
9
|
+
expect(wrapper.find('.ui-progress-linear').exists()).toBe(true)
|
|
10
|
+
expect(wrapper.find('.ui-progress-circular').exists()).toBe(false)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('renders track and indicator', () => {
|
|
14
|
+
const wrapper = mount(Progress)
|
|
15
|
+
expect(wrapper.find('.ui-progress-linear__track').exists()).toBe(true)
|
|
16
|
+
expect(wrapper.find('.ui-progress-linear__indicator').exists()).toBe(true)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('sets indicator width based on value', () => {
|
|
20
|
+
const wrapper = mount(Progress, {
|
|
21
|
+
props: { value: 50 }
|
|
22
|
+
})
|
|
23
|
+
const indicator = wrapper.find('.ui-progress-linear__indicator')
|
|
24
|
+
expect(indicator.attributes('style')).toContain('width: 50%')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('clamps value to 0-100 range', async () => {
|
|
28
|
+
const wrapper = mount(Progress, {
|
|
29
|
+
props: { value: 150 }
|
|
30
|
+
})
|
|
31
|
+
const indicator = wrapper.find('.ui-progress-linear__indicator')
|
|
32
|
+
expect(indicator.attributes('style')).toContain('width: 100%')
|
|
33
|
+
|
|
34
|
+
await wrapper.setProps({ value: -50 })
|
|
35
|
+
expect(indicator.attributes('style')).toContain('width: 0%')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('applies size classes', async () => {
|
|
39
|
+
const wrapper = mount(Progress, {
|
|
40
|
+
props: { size: 'sm' }
|
|
41
|
+
})
|
|
42
|
+
expect(wrapper.find('.ui-progress-linear--sm').exists()).toBe(true)
|
|
43
|
+
|
|
44
|
+
await wrapper.setProps({ size: 'md' })
|
|
45
|
+
expect(wrapper.find('.ui-progress-linear--md').exists()).toBe(true)
|
|
46
|
+
|
|
47
|
+
await wrapper.setProps({ size: 'lg' })
|
|
48
|
+
expect(wrapper.find('.ui-progress-linear--lg').exists()).toBe(true)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('applies color classes', async () => {
|
|
52
|
+
const wrapper = mount(Progress, {
|
|
53
|
+
props: { color: 'primary' }
|
|
54
|
+
})
|
|
55
|
+
expect(wrapper.find('.ui-progress-linear--primary').exists()).toBe(true)
|
|
56
|
+
|
|
57
|
+
await wrapper.setProps({ color: 'success' })
|
|
58
|
+
expect(wrapper.find('.ui-progress-linear--success').exists()).toBe(true)
|
|
59
|
+
|
|
60
|
+
await wrapper.setProps({ color: 'warning' })
|
|
61
|
+
expect(wrapper.find('.ui-progress-linear--warning').exists()).toBe(true)
|
|
62
|
+
|
|
63
|
+
await wrapper.setProps({ color: 'error' })
|
|
64
|
+
expect(wrapper.find('.ui-progress-linear--error').exists()).toBe(true)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
describe('Circular variant', () => {
|
|
69
|
+
it('renders circular progress when variant is circular', () => {
|
|
70
|
+
const wrapper = mount(Progress, {
|
|
71
|
+
props: { variant: 'circular' }
|
|
72
|
+
})
|
|
73
|
+
expect(wrapper.find('.ui-progress-circular').exists()).toBe(true)
|
|
74
|
+
expect(wrapper.find('.ui-progress-linear').exists()).toBe(false)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('renders SVG with track and indicator circles', () => {
|
|
78
|
+
const wrapper = mount(Progress, {
|
|
79
|
+
props: { variant: 'circular' }
|
|
80
|
+
})
|
|
81
|
+
expect(wrapper.find('.ui-progress-circular__svg').exists()).toBe(true)
|
|
82
|
+
expect(wrapper.find('.ui-progress-circular__track').exists()).toBe(true)
|
|
83
|
+
expect(wrapper.find('.ui-progress-circular__indicator').exists()).toBe(true)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('sets stroke-dashoffset based on value', () => {
|
|
87
|
+
const wrapper = mount(Progress, {
|
|
88
|
+
props: { variant: 'circular', value: 50, size: 'md' }
|
|
89
|
+
})
|
|
90
|
+
const indicator = wrapper.find('.ui-progress-circular__indicator')
|
|
91
|
+
expect(indicator.attributes('stroke-dasharray')).toBeDefined()
|
|
92
|
+
expect(indicator.attributes('stroke-dashoffset')).toBeDefined()
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('applies size to SVG dimensions', async () => {
|
|
96
|
+
const wrapper = mount(Progress, {
|
|
97
|
+
props: { variant: 'circular', size: 'sm' }
|
|
98
|
+
})
|
|
99
|
+
let svg = wrapper.find('.ui-progress-circular__svg')
|
|
100
|
+
expect(svg.attributes('width')).toBe('32')
|
|
101
|
+
expect(svg.attributes('height')).toBe('32')
|
|
102
|
+
|
|
103
|
+
await wrapper.setProps({ size: 'md' })
|
|
104
|
+
svg = wrapper.find('.ui-progress-circular__svg')
|
|
105
|
+
expect(svg.attributes('width')).toBe('48')
|
|
106
|
+
expect(svg.attributes('height')).toBe('48')
|
|
107
|
+
|
|
108
|
+
await wrapper.setProps({ size: 'lg' })
|
|
109
|
+
svg = wrapper.find('.ui-progress-circular__svg')
|
|
110
|
+
expect(svg.attributes('width')).toBe('64')
|
|
111
|
+
expect(svg.attributes('height')).toBe('64')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('applies color classes', async () => {
|
|
115
|
+
const wrapper = mount(Progress, {
|
|
116
|
+
props: { variant: 'circular', color: 'success' }
|
|
117
|
+
})
|
|
118
|
+
expect(wrapper.find('.ui-progress-circular--success').exists()).toBe(true)
|
|
119
|
+
|
|
120
|
+
await wrapper.setProps({ color: 'error' })
|
|
121
|
+
expect(wrapper.find('.ui-progress-circular--error').exists()).toBe(true)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('allows custom stroke width', () => {
|
|
125
|
+
const wrapper = mount(Progress, {
|
|
126
|
+
props: { variant: 'circular', strokeWidth: 8 }
|
|
127
|
+
})
|
|
128
|
+
const track = wrapper.find('.ui-progress-circular__track')
|
|
129
|
+
expect(track.attributes('stroke-width')).toBe('8')
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
describe('Indeterminate state', () => {
|
|
134
|
+
it('applies indeterminate class to linear progress', () => {
|
|
135
|
+
const wrapper = mount(Progress, {
|
|
136
|
+
props: { indeterminate: true }
|
|
137
|
+
})
|
|
138
|
+
expect(wrapper.find('.ui-progress-linear--indeterminate').exists()).toBe(true)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('applies indeterminate class to circular progress', () => {
|
|
142
|
+
const wrapper = mount(Progress, {
|
|
143
|
+
props: { variant: 'circular', indeterminate: true }
|
|
144
|
+
})
|
|
145
|
+
expect(wrapper.find('.ui-progress-circular--indeterminate').exists()).toBe(true)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('does not set inline width style when indeterminate', () => {
|
|
149
|
+
const wrapper = mount(Progress, {
|
|
150
|
+
props: { value: 50, indeterminate: true }
|
|
151
|
+
})
|
|
152
|
+
const indicator = wrapper.find('.ui-progress-linear__indicator')
|
|
153
|
+
expect(indicator.attributes('style')).toBeUndefined()
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('does not show value label when indeterminate', () => {
|
|
157
|
+
const wrapper = mount(Progress, {
|
|
158
|
+
props: { value: 50, showValue: true, indeterminate: true }
|
|
159
|
+
})
|
|
160
|
+
expect(wrapper.find('.ui-progress-linear__value').exists()).toBe(false)
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
describe('Striped pattern', () => {
|
|
165
|
+
it('applies striped class when striped prop is true', () => {
|
|
166
|
+
const wrapper = mount(Progress, {
|
|
167
|
+
props: { striped: true }
|
|
168
|
+
})
|
|
169
|
+
expect(wrapper.find('.ui-progress-linear--striped').exists()).toBe(true)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('does not apply striped class when indeterminate', () => {
|
|
173
|
+
const wrapper = mount(Progress, {
|
|
174
|
+
props: { striped: true, indeterminate: true }
|
|
175
|
+
})
|
|
176
|
+
expect(wrapper.find('.ui-progress-linear--striped').exists()).toBe(false)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('applies animated class when both striped and animated', () => {
|
|
180
|
+
const wrapper = mount(Progress, {
|
|
181
|
+
props: { striped: true, animated: true }
|
|
182
|
+
})
|
|
183
|
+
expect(wrapper.find('.ui-progress-linear--animated').exists()).toBe(true)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('does not apply animated class without striped', () => {
|
|
187
|
+
const wrapper = mount(Progress, {
|
|
188
|
+
props: { animated: true }
|
|
189
|
+
})
|
|
190
|
+
expect(wrapper.find('.ui-progress-linear--animated').exists()).toBe(false)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('does not apply animated class when indeterminate', () => {
|
|
194
|
+
const wrapper = mount(Progress, {
|
|
195
|
+
props: { striped: true, animated: true, indeterminate: true }
|
|
196
|
+
})
|
|
197
|
+
expect(wrapper.find('.ui-progress-linear--animated').exists()).toBe(false)
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
describe('Value label', () => {
|
|
202
|
+
it('does not show value by default', () => {
|
|
203
|
+
const wrapper = mount(Progress, {
|
|
204
|
+
props: { value: 50 }
|
|
205
|
+
})
|
|
206
|
+
expect(wrapper.find('.ui-progress-linear__value').exists()).toBe(false)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('shows value when showValue is true (linear)', () => {
|
|
210
|
+
const wrapper = mount(Progress, {
|
|
211
|
+
props: { value: 50, showValue: true }
|
|
212
|
+
})
|
|
213
|
+
const valueEl = wrapper.find('.ui-progress-linear__value')
|
|
214
|
+
expect(valueEl.exists()).toBe(true)
|
|
215
|
+
expect(valueEl.text()).toBe('50%')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('shows value when showValue is true (circular)', () => {
|
|
219
|
+
const wrapper = mount(Progress, {
|
|
220
|
+
props: { variant: 'circular', value: 75, showValue: true }
|
|
221
|
+
})
|
|
222
|
+
const valueEl = wrapper.find('.ui-progress-circular__value')
|
|
223
|
+
expect(valueEl.exists()).toBe(true)
|
|
224
|
+
expect(valueEl.text()).toBe('75%')
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it('displays clamped value', () => {
|
|
228
|
+
const wrapper = mount(Progress, {
|
|
229
|
+
props: { value: 150, showValue: true }
|
|
230
|
+
})
|
|
231
|
+
expect(wrapper.find('.ui-progress-linear__value').text()).toBe('100%')
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
describe('Accessibility', () => {
|
|
236
|
+
it('has progressbar role', () => {
|
|
237
|
+
const wrapper = mount(Progress)
|
|
238
|
+
expect(wrapper.find('.ui-progress-linear').attributes('role')).toBe('progressbar')
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('has progressbar role for circular variant', () => {
|
|
242
|
+
const wrapper = mount(Progress, {
|
|
243
|
+
props: { variant: 'circular' }
|
|
244
|
+
})
|
|
245
|
+
expect(wrapper.find('.ui-progress-circular').attributes('role')).toBe('progressbar')
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it('sets aria-valuemin and aria-valuemax', () => {
|
|
249
|
+
const wrapper = mount(Progress)
|
|
250
|
+
const progress = wrapper.find('.ui-progress-linear')
|
|
251
|
+
expect(progress.attributes('aria-valuemin')).toBe('0')
|
|
252
|
+
expect(progress.attributes('aria-valuemax')).toBe('100')
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
it('sets aria-valuenow to current value', () => {
|
|
256
|
+
const wrapper = mount(Progress, {
|
|
257
|
+
props: { value: 42 }
|
|
258
|
+
})
|
|
259
|
+
expect(wrapper.find('.ui-progress-linear').attributes('aria-valuenow')).toBe('42')
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('removes aria-valuenow when indeterminate', () => {
|
|
263
|
+
const wrapper = mount(Progress, {
|
|
264
|
+
props: { value: 50, indeterminate: true }
|
|
265
|
+
})
|
|
266
|
+
expect(wrapper.find('.ui-progress-linear').attributes('aria-valuenow')).toBeUndefined()
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('applies aria-label from label prop', () => {
|
|
270
|
+
const wrapper = mount(Progress, {
|
|
271
|
+
props: { label: 'Upload progress' }
|
|
272
|
+
})
|
|
273
|
+
expect(wrapper.find('.ui-progress-linear').attributes('aria-label')).toBe('Upload progress')
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
it('applies aria-label to circular variant', () => {
|
|
277
|
+
const wrapper = mount(Progress, {
|
|
278
|
+
props: { variant: 'circular', label: 'Loading data' }
|
|
279
|
+
})
|
|
280
|
+
expect(wrapper.find('.ui-progress-circular').attributes('aria-label')).toBe('Loading data')
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
describe('SVG geometry', () => {
|
|
285
|
+
it('has correct viewBox matching size', () => {
|
|
286
|
+
const wrapper = mount(Progress, {
|
|
287
|
+
props: { variant: 'circular', size: 'lg' }
|
|
288
|
+
})
|
|
289
|
+
expect(wrapper.find('svg').attributes('viewBox')).toBe('0 0 64 64')
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it('calculates correct radius accounting for stroke width', () => {
|
|
293
|
+
const wrapper = mount(Progress, {
|
|
294
|
+
props: { variant: 'circular', size: 'md' }
|
|
295
|
+
})
|
|
296
|
+
const track = wrapper.find('.ui-progress-circular__track')
|
|
297
|
+
const radius = track.attributes('r')
|
|
298
|
+
expect(Number(radius)).toBe(22)
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
it('has stroke-linecap round on indicator', () => {
|
|
302
|
+
const wrapper = mount(Progress, {
|
|
303
|
+
props: { variant: 'circular' }
|
|
304
|
+
})
|
|
305
|
+
const indicator = wrapper.find('.ui-progress-circular__indicator')
|
|
306
|
+
expect(indicator.attributes('stroke-linecap')).toBe('round')
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
it('has fill="none" on circles', () => {
|
|
310
|
+
const wrapper = mount(Progress, {
|
|
311
|
+
props: { variant: 'circular' }
|
|
312
|
+
})
|
|
313
|
+
expect(wrapper.find('.ui-progress-circular__track').attributes('fill')).toBe('none')
|
|
314
|
+
expect(wrapper.find('.ui-progress-circular__indicator').attributes('fill')).toBe('none')
|
|
315
|
+
})
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
describe('Progress updates', () => {
|
|
319
|
+
it('updates indicator width when value changes', async () => {
|
|
320
|
+
const wrapper = mount(Progress, {
|
|
321
|
+
props: { value: 25 }
|
|
322
|
+
})
|
|
323
|
+
expect(wrapper.find('.ui-progress-linear__indicator').attributes('style')).toContain('width: 25%')
|
|
324
|
+
|
|
325
|
+
await wrapper.setProps({ value: 75 })
|
|
326
|
+
expect(wrapper.find('.ui-progress-linear__indicator').attributes('style')).toContain('width: 75%')
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
it('updates value label when value changes', async () => {
|
|
330
|
+
const wrapper = mount(Progress, {
|
|
331
|
+
props: { value: 30, showValue: true }
|
|
332
|
+
})
|
|
333
|
+
expect(wrapper.find('.ui-progress-linear__value').text()).toBe('30%')
|
|
334
|
+
|
|
335
|
+
await wrapper.setProps({ value: 80 })
|
|
336
|
+
expect(wrapper.find('.ui-progress-linear__value').text()).toBe('80%')
|
|
337
|
+
})
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
describe('Default props', () => {
|
|
341
|
+
it('has default value of 0', () => {
|
|
342
|
+
const wrapper = mount(Progress)
|
|
343
|
+
expect(wrapper.find('.ui-progress-linear__indicator').attributes('style')).toContain('width: 0%')
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it('has default variant of linear', () => {
|
|
347
|
+
const wrapper = mount(Progress)
|
|
348
|
+
expect(wrapper.find('.ui-progress-linear').exists()).toBe(true)
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it('has default size of md', () => {
|
|
352
|
+
const wrapper = mount(Progress)
|
|
353
|
+
expect(wrapper.find('.ui-progress-linear--md').exists()).toBe(true)
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
it('has default color of primary', () => {
|
|
357
|
+
const wrapper = mount(Progress)
|
|
358
|
+
expect(wrapper.find('.ui-progress-linear--primary').exists()).toBe(true)
|
|
359
|
+
})
|
|
360
|
+
})
|
|
361
|
+
})
|