@datametria/vue-components 1.2.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +554 -657
  2. package/dist/index.es.js +2570 -1433
  3. package/dist/index.umd.js +10 -10
  4. package/dist/vue-components.css +1 -1
  5. package/package.json +102 -98
  6. package/src/components/DatametriaAlert.vue +137 -137
  7. package/src/components/DatametriaAutocomplete.vue +184 -138
  8. package/src/components/DatametriaAvatar.vue +177 -33
  9. package/src/components/DatametriaBadge.vue +98 -98
  10. package/src/components/DatametriaBreadcrumb.vue +21 -21
  11. package/src/components/DatametriaButton.vue +177 -165
  12. package/src/components/DatametriaCard.vue +12 -12
  13. package/src/components/DatametriaCheckbox.vue +8 -8
  14. package/src/components/DatametriaChip.vue +145 -149
  15. package/src/components/DatametriaContainer.vue +4 -4
  16. package/src/components/DatametriaDatePicker.vue +686 -68
  17. package/src/components/DatametriaDivider.vue +13 -13
  18. package/src/components/DatametriaFileUpload.vue +272 -140
  19. package/src/components/DatametriaFloatingBar.vue +126 -0
  20. package/src/components/DatametriaGrid.vue +3 -3
  21. package/src/components/DatametriaInput.vue +15 -15
  22. package/src/components/DatametriaMenu.vue +604 -619
  23. package/src/components/DatametriaModal.vue +16 -16
  24. package/src/components/DatametriaNavbar.vue +230 -252
  25. package/src/components/DatametriaPasswordInput.vue +430 -0
  26. package/src/components/DatametriaProgress.vue +18 -18
  27. package/src/components/DatametriaRadio.vue +20 -20
  28. package/src/components/DatametriaSelect.vue +15 -15
  29. package/src/components/DatametriaSidebar.vue +230 -0
  30. package/src/components/DatametriaSkeleton.vue +243 -239
  31. package/src/components/DatametriaSlider.vue +395 -407
  32. package/src/components/DatametriaSortableTable.vue +585 -0
  33. package/src/components/DatametriaSpinner.vue +7 -7
  34. package/src/components/DatametriaSwitch.vue +16 -16
  35. package/src/components/DatametriaTable.vue +14 -14
  36. package/src/components/DatametriaTabs.vue +150 -29
  37. package/src/components/DatametriaTextarea.vue +28 -28
  38. package/src/components/DatametriaTimePicker.vue +285 -285
  39. package/src/components/DatametriaToast.vue +176 -176
  40. package/src/components/DatametriaTooltip.vue +408 -408
  41. package/src/components/__tests__/DatametriaAlert.test.js +35 -35
  42. package/src/components/__tests__/DatametriaAlert.test.ts +190 -0
  43. package/src/components/__tests__/DatametriaAutocomplete.test.ts +180 -0
  44. package/src/components/__tests__/DatametriaAvatar.test.ts +152 -0
  45. package/src/components/__tests__/DatametriaBadge.test.js +29 -29
  46. package/src/components/__tests__/DatametriaBadge.test.ts +167 -0
  47. package/src/components/__tests__/DatametriaBreadcrumb.test.ts +75 -0
  48. package/src/components/__tests__/DatametriaButton.test.js +30 -30
  49. package/src/components/__tests__/DatametriaButton.test.ts +283 -0
  50. package/src/components/__tests__/DatametriaCard.test.ts +201 -0
  51. package/src/components/__tests__/DatametriaCheckbox.test.ts +47 -0
  52. package/src/components/__tests__/DatametriaChip.test.js +38 -38
  53. package/src/components/__tests__/DatametriaContainer.test.ts +52 -0
  54. package/src/components/__tests__/DatametriaDatePicker.test.ts +234 -0
  55. package/src/components/__tests__/DatametriaDivider.test.ts +54 -0
  56. package/src/components/__tests__/DatametriaFileUpload.test.ts +291 -0
  57. package/src/components/__tests__/DatametriaFloatingBar.test.ts +137 -0
  58. package/src/components/__tests__/DatametriaGrid.test.ts +31 -0
  59. package/src/components/__tests__/DatametriaInput.test.ts +72 -0
  60. package/src/components/__tests__/DatametriaMenu.test.ts +366 -0
  61. package/src/components/__tests__/DatametriaModal.test.ts +86 -0
  62. package/src/components/__tests__/DatametriaNavbar.test.js +48 -48
  63. package/src/components/__tests__/DatametriaNavbar.test.ts +203 -0
  64. package/src/components/__tests__/DatametriaPasswordInput.test.js +305 -0
  65. package/src/components/__tests__/DatametriaProgress.test.ts +90 -0
  66. package/src/components/__tests__/DatametriaRadio.test.ts +77 -0
  67. package/src/components/__tests__/DatametriaSelect.test.ts +77 -0
  68. package/src/components/__tests__/DatametriaSidebar.test.ts +169 -0
  69. package/src/components/__tests__/DatametriaSlider.test.ts +261 -0
  70. package/src/components/__tests__/DatametriaSortableTable.test.js +168 -0
  71. package/src/components/__tests__/DatametriaSpinner.test.ts +156 -0
  72. package/src/components/__tests__/DatametriaSwitch.test.ts +64 -0
  73. package/src/components/__tests__/DatametriaTable.test.ts +97 -0
  74. package/src/components/__tests__/DatametriaTabs.test.ts +232 -0
  75. package/src/components/__tests__/DatametriaTextarea.test.ts +66 -0
  76. package/src/components/__tests__/DatametriaToast.test.js +48 -48
  77. package/src/components/__tests__/DatametriaToast.test.ts +99 -0
  78. package/src/composables/useAccessibilityScale.ts +94 -94
  79. package/src/composables/useBreakpoints.ts +82 -82
  80. package/src/composables/useHapticFeedback.ts +439 -439
  81. package/src/composables/useRipple.ts +218 -218
  82. package/src/index.ts +70 -61
  83. package/src/stories/Variants.stories.js +95 -95
  84. package/src/styles/design-tokens.css +623 -623
  85. package/src/theme/ThemeProvider.vue +96 -0
  86. package/src/theme/__tests__/ThemeProvider.test.ts +208 -0
  87. package/src/theme/__tests__/constants.test.ts +31 -0
  88. package/src/theme/__tests__/presets.test.ts +166 -0
  89. package/src/theme/__tests__/tokens.test.ts +155 -0
  90. package/src/theme/__tests__/types.test.ts +153 -0
  91. package/src/theme/__tests__/useTheme.test.ts +146 -0
  92. package/src/theme/constants.ts +14 -0
  93. package/src/theme/index.ts +12 -0
  94. package/src/theme/presets/datametria.ts +94 -0
  95. package/src/theme/presets/default.ts +94 -0
  96. package/src/theme/presets/index.ts +8 -0
  97. package/src/theme/tokens/colors.ts +28 -0
  98. package/src/theme/tokens/index.ts +47 -0
  99. package/src/theme/tokens/spacing.ts +21 -0
  100. package/src/theme/tokens/typography.ts +35 -0
  101. package/src/theme/types.ts +111 -0
  102. package/src/theme/useTheme.ts +28 -0
  103. package/src/types/index.ts +19 -0
@@ -0,0 +1,291 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import DatametriaFileUpload from '../DatametriaFileUpload.vue'
4
+ import { datametriaTheme } from '../../theme/presets'
5
+ import { THEME_INJECTION_KEY } from '../../theme/constants'
6
+
7
+ const createWrapper = (props = {}, themeProps = {}) => {
8
+ return mount(DatametriaFileUpload, {
9
+ props,
10
+ global: {
11
+ plugins: [{
12
+ install(app) {
13
+ app.provide(THEME_INJECTION_KEY, datametriaTheme)
14
+ }
15
+ }]
16
+ }
17
+ })
18
+ }
19
+
20
+ // Mock File API
21
+ const createMockFile = (name: string, size: number, type: string) => {
22
+ const file = new File([''], name, { type })
23
+ Object.defineProperty(file, 'size', { value: size })
24
+ return file
25
+ }
26
+
27
+ describe('DatametriaFileUpload', () => {
28
+ beforeEach(() => {
29
+ vi.clearAllMocks()
30
+ })
31
+
32
+ it('renders correctly', () => {
33
+ const wrapper = createWrapper()
34
+ expect(wrapper.find('.dm-file-upload').exists()).toBe(true)
35
+ })
36
+
37
+ it('applies theme colors correctly', () => {
38
+ const wrapper = createWrapper()
39
+ expect(wrapper.find('.dm-file-upload').exists()).toBe(true)
40
+ })
41
+
42
+ it('displays upload area', () => {
43
+ const wrapper = createWrapper()
44
+ expect(wrapper.find('.dm-file-upload__area').exists()).toBe(true)
45
+ })
46
+
47
+ it('shows upload text and icon', () => {
48
+ const wrapper = createWrapper()
49
+ expect(wrapper.find('.dm-file-upload__icon').exists()).toBe(true)
50
+ expect(wrapper.find('.dm-file-upload__text').exists()).toBe(true)
51
+ })
52
+
53
+ it('handles file selection via input', async () => {
54
+ const wrapper = createWrapper()
55
+ const input = wrapper.find('.dm-file-upload__input')
56
+ const file = createMockFile('test.txt', 1024, 'text/plain')
57
+
58
+ Object.defineProperty(input.element, 'files', {
59
+ value: [file],
60
+ writable: false
61
+ })
62
+
63
+ await input.trigger('change')
64
+
65
+ const fileUpload = wrapper.findComponent(DatametriaFileUpload)
66
+ expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
67
+ })
68
+
69
+ it('handles drag and drop', async () => {
70
+ const wrapper = createWrapper()
71
+ const dropArea = wrapper.find('.dm-file-upload__area')
72
+ const file = createMockFile('test.txt', 1024, 'text/plain')
73
+
74
+ const mockDataTransfer = {
75
+ files: [file]
76
+ }
77
+
78
+ await dropArea.trigger('drop', {
79
+ dataTransfer: mockDataTransfer
80
+ })
81
+
82
+ const fileUpload = wrapper.findComponent(DatametriaFileUpload)
83
+ expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
84
+ })
85
+
86
+ it('shows drag over state', async () => {
87
+ const wrapper = createWrapper()
88
+ const dropArea = wrapper.find('.dm-file-upload__area')
89
+
90
+ await dropArea.trigger('dragenter')
91
+ await wrapper.vm.$nextTick()
92
+ expect(wrapper.find('.dm-file-upload__area--dragover').exists()).toBe(true)
93
+
94
+ await dropArea.trigger('dragleave', {
95
+ relatedTarget: document.body
96
+ })
97
+ await wrapper.vm.$nextTick()
98
+ expect(wrapper.find('.dm-file-upload__area--dragover').exists()).toBe(false)
99
+ })
100
+
101
+ it('supports multiple file selection', async () => {
102
+ const wrapper = createWrapper({ multiple: true })
103
+ const input = wrapper.find('.dm-file-upload__input')
104
+
105
+ expect(input.attributes('multiple')).toBeDefined()
106
+
107
+ const files = [
108
+ createMockFile('test1.txt', 1024, 'text/plain'),
109
+ createMockFile('test2.txt', 2048, 'text/plain')
110
+ ]
111
+
112
+ Object.defineProperty(input.element, 'files', {
113
+ value: files,
114
+ writable: false
115
+ })
116
+
117
+ await input.trigger('change')
118
+
119
+ const fileUpload = wrapper.findComponent(DatametriaFileUpload)
120
+ expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
121
+ })
122
+
123
+ it('validates file types', async () => {
124
+ const wrapper = createWrapper({ accept: '.txt,.pdf' })
125
+ const input = wrapper.find('.dm-file-upload__input')
126
+
127
+ expect(input.attributes('accept')).toBe('.txt,.pdf')
128
+
129
+ const invalidFile = createMockFile('test.jpg', 1024, 'image/jpeg')
130
+ Object.defineProperty(input.element, 'files', {
131
+ value: [invalidFile],
132
+ writable: false
133
+ })
134
+
135
+ await input.trigger('change')
136
+ await wrapper.vm.$nextTick()
137
+
138
+ expect(wrapper.text()).toContain('Invalid file type')
139
+ })
140
+
141
+ it('validates file size', async () => {
142
+ const wrapper = createWrapper({ maxSize: 1024 }) // 1KB
143
+ const input = wrapper.find('.dm-file-upload__input')
144
+
145
+ const largeFile = createMockFile('large.txt', 2048, 'text/plain') // 2KB
146
+ Object.defineProperty(input.element, 'files', {
147
+ value: [largeFile],
148
+ writable: false
149
+ })
150
+
151
+ await input.trigger('change')
152
+ await wrapper.vm.$nextTick()
153
+
154
+ expect(wrapper.text()).toContain('too large')
155
+ })
156
+
157
+ it('validates maximum number of files', async () => {
158
+ const wrapper = createWrapper({ multiple: true, maxFiles: 2 })
159
+ const input = wrapper.find('.dm-file-upload__input')
160
+
161
+ const files = [
162
+ createMockFile('test1.txt', 1024, 'text/plain'),
163
+ createMockFile('test2.txt', 1024, 'text/plain'),
164
+ createMockFile('test3.txt', 1024, 'text/plain')
165
+ ]
166
+
167
+ Object.defineProperty(input.element, 'files', {
168
+ value: files,
169
+ writable: false
170
+ })
171
+
172
+ await input.trigger('change')
173
+ await wrapper.vm.$nextTick()
174
+
175
+ expect(wrapper.text()).toContain('Maximum 2 files')
176
+ })
177
+
178
+ it('shows file list when files are selected', async () => {
179
+ const wrapper = createWrapper({ multiple: true })
180
+ const input = wrapper.find('.dm-file-upload__input')
181
+
182
+ const files = [
183
+ createMockFile('test1.txt', 1024, 'text/plain'),
184
+ createMockFile('test2.txt', 2048, 'text/plain')
185
+ ]
186
+
187
+ Object.defineProperty(input.element, 'files', {
188
+ value: files,
189
+ writable: false
190
+ })
191
+
192
+ await input.trigger('change')
193
+
194
+ expect(wrapper.find('.dm-file-upload__files').exists()).toBe(true)
195
+ expect(wrapper.findAll('.dm-file-upload__file')).toHaveLength(2)
196
+ })
197
+
198
+ it('allows file removal', async () => {
199
+ const wrapper = createWrapper({ multiple: true })
200
+ const input = wrapper.find('.dm-file-upload__input')
201
+
202
+ const files = [
203
+ createMockFile('test1.txt', 1024, 'text/plain'),
204
+ createMockFile('test2.txt', 2048, 'text/plain')
205
+ ]
206
+
207
+ Object.defineProperty(input.element, 'files', {
208
+ value: files,
209
+ writable: false
210
+ })
211
+
212
+ await input.trigger('change')
213
+
214
+ const removeButton = wrapper.find('.dm-file-upload__remove')
215
+ await removeButton.trigger('click')
216
+
217
+ const fileUpload = wrapper.findComponent(DatametriaFileUpload)
218
+ expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
219
+ })
220
+
221
+ it('supports disabled state', () => {
222
+ const wrapper = createWrapper({ disabled: true })
223
+ const input = wrapper.find('.dm-file-upload__input')
224
+
225
+ expect(input.attributes('disabled')).toBeDefined()
226
+ expect(wrapper.find('.dm-file-upload--disabled').exists()).toBe(true)
227
+ })
228
+
229
+ it('shows loading state during upload', () => {
230
+ const wrapper = createWrapper({ loading: true })
231
+ expect(wrapper.find('.dm-file-upload--loading').exists()).toBe(true)
232
+ expect(wrapper.find('.dm-file-upload__spinner').exists()).toBe(true)
233
+ })
234
+
235
+ it('shows upload progress', () => {
236
+ const wrapper = createWrapper({ progress: 50 })
237
+ const progressBar = wrapper.find('.dm-file-upload__progress-bar')
238
+
239
+ expect(progressBar.exists()).toBe(true)
240
+ expect(progressBar.attributes('style')).toContain('width: 50%')
241
+ })
242
+
243
+ it('supports custom upload text', () => {
244
+ const customText = 'Drop your files here'
245
+ const wrapper = createWrapper({ uploadText: customText })
246
+
247
+ expect(wrapper.find('.dm-file-upload__text').text()).toContain(customText)
248
+ })
249
+
250
+ it('supports custom error messages', () => {
251
+ const errorMessage = 'Upload failed'
252
+ const wrapper = createWrapper({ error: errorMessage })
253
+
254
+ expect(wrapper.find('.dm-file-upload__error').text()).toBe(errorMessage)
255
+ })
256
+
257
+ it('emits file-added event', async () => {
258
+ const wrapper = createWrapper()
259
+ const input = wrapper.find('.dm-file-upload__input')
260
+ const file = createMockFile('test.txt', 1024, 'text/plain')
261
+
262
+ Object.defineProperty(input.element, 'files', {
263
+ value: [file],
264
+ writable: false
265
+ })
266
+
267
+ await input.trigger('change')
268
+
269
+ const fileUpload = wrapper.findComponent(DatametriaFileUpload)
270
+ expect(fileUpload.emitted('file-added')).toBeTruthy()
271
+ })
272
+
273
+ it('emits file-removed event', async () => {
274
+ const wrapper = createWrapper({ multiple: true })
275
+ const input = wrapper.find('.dm-file-upload__input')
276
+
277
+ const files = [createMockFile('test.txt', 1024, 'text/plain')]
278
+ Object.defineProperty(input.element, 'files', {
279
+ value: files,
280
+ writable: false
281
+ })
282
+
283
+ await input.trigger('change')
284
+
285
+ const removeButton = wrapper.find('.dm-file-upload__remove')
286
+ await removeButton.trigger('click')
287
+
288
+ const fileUpload = wrapper.findComponent(DatametriaFileUpload)
289
+ expect(fileUpload.emitted('file-removed')).toBeTruthy()
290
+ })
291
+ })
@@ -0,0 +1,137 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import DatametriaFloatingBar from '../DatametriaFloatingBar.vue'
4
+
5
+ describe('DatametriaFloatingBar', () => {
6
+ it('renders correctly', () => {
7
+ const wrapper = mount(DatametriaFloatingBar)
8
+ expect(wrapper.find('.dm-floating-bar').exists()).toBe(true)
9
+ })
10
+
11
+ it('applies position classes', () => {
12
+ const positions = ['top', 'bottom', 'left', 'right'] as const
13
+ positions.forEach(position => {
14
+ const wrapper = mount(DatametriaFloatingBar, { props: { position } })
15
+ expect(wrapper.find(`.dm-floating-bar--${position}`).exists()).toBe(true)
16
+ })
17
+ })
18
+
19
+ it('applies variant classes', () => {
20
+ const variants = ['light', 'dark', 'primary'] as const
21
+ variants.forEach(variant => {
22
+ const wrapper = mount(DatametriaFloatingBar, { props: { variant } })
23
+ expect(wrapper.find(`.dm-floating-bar--${variant}`).exists()).toBe(true)
24
+ })
25
+ })
26
+
27
+ it('applies shadow class when shadow is true', () => {
28
+ const wrapper = mount(DatametriaFloatingBar, { props: { shadow: true } })
29
+ expect(wrapper.find('.dm-floating-bar--shadow').exists()).toBe(true)
30
+ })
31
+
32
+ it('does not apply shadow class when shadow is false', () => {
33
+ const wrapper = mount(DatametriaFloatingBar, { props: { shadow: false } })
34
+ expect(wrapper.find('.dm-floating-bar--shadow').exists()).toBe(false)
35
+ })
36
+
37
+ it('applies rounded class when rounded is true', () => {
38
+ const wrapper = mount(DatametriaFloatingBar, { props: { rounded: true } })
39
+ expect(wrapper.find('.dm-floating-bar--rounded').exists()).toBe(true)
40
+ })
41
+
42
+ it('does not apply rounded class when rounded is false', () => {
43
+ const wrapper = mount(DatametriaFloatingBar, { props: { rounded: false } })
44
+ expect(wrapper.find('.dm-floating-bar--rounded').exists()).toBe(false)
45
+ })
46
+
47
+ it('renders slot content', () => {
48
+ const wrapper = mount(DatametriaFloatingBar, {
49
+ slots: { default: '<button class="test-button">Action</button>' }
50
+ })
51
+ expect(wrapper.find('.test-button').exists()).toBe(true)
52
+ expect(wrapper.text()).toContain('Action')
53
+ })
54
+
55
+ it('applies correct position style for top', () => {
56
+ const wrapper = mount(DatametriaFloatingBar, {
57
+ props: { position: 'top', offset: '20px' }
58
+ })
59
+ const style = wrapper.find('.dm-floating-bar').attributes('style')
60
+ expect(style).toContain('top: 20px')
61
+ })
62
+
63
+ it('applies correct position style for bottom', () => {
64
+ const wrapper = mount(DatametriaFloatingBar, {
65
+ props: { position: 'bottom', offset: '24px' }
66
+ })
67
+ const style = wrapper.find('.dm-floating-bar').attributes('style')
68
+ expect(style).toContain('bottom: 24px')
69
+ })
70
+
71
+ it('applies correct position style for left', () => {
72
+ const wrapper = mount(DatametriaFloatingBar, {
73
+ props: { position: 'left', offset: '32px' }
74
+ })
75
+ const style = wrapper.find('.dm-floating-bar').attributes('style')
76
+ expect(style).toContain('left: 32px')
77
+ })
78
+
79
+ it('applies correct position style for right', () => {
80
+ const wrapper = mount(DatametriaFloatingBar, {
81
+ props: { position: 'right', offset: '40px' }
82
+ })
83
+ const style = wrapper.find('.dm-floating-bar').attributes('style')
84
+ expect(style).toContain('right: 40px')
85
+ })
86
+
87
+ it('uses default offset when not provided', () => {
88
+ const wrapper = mount(DatametriaFloatingBar, { props: { position: 'bottom' } })
89
+ const style = wrapper.find('.dm-floating-bar').attributes('style')
90
+ expect(style).toContain('bottom: 16px')
91
+ })
92
+
93
+ it('has correct aria attributes', () => {
94
+ const wrapper = mount(DatametriaFloatingBar, {
95
+ props: { ariaLabel: 'Floating toolbar' }
96
+ })
97
+ const bar = wrapper.find('.dm-floating-bar')
98
+ expect(bar.attributes('role')).toBe('toolbar')
99
+ expect(bar.attributes('aria-label')).toBe('Floating toolbar')
100
+ })
101
+
102
+ it('renders content wrapper', () => {
103
+ const wrapper = mount(DatametriaFloatingBar)
104
+ expect(wrapper.find('.dm-floating-bar__content').exists()).toBe(true)
105
+ })
106
+
107
+ it('applies all classes correctly', () => {
108
+ const wrapper = mount(DatametriaFloatingBar, {
109
+ props: {
110
+ position: 'top',
111
+ variant: 'primary',
112
+ shadow: true,
113
+ rounded: true
114
+ }
115
+ })
116
+ const bar = wrapper.find('.dm-floating-bar')
117
+ expect(bar.classes()).toContain('dm-floating-bar--top')
118
+ expect(bar.classes()).toContain('dm-floating-bar--primary')
119
+ expect(bar.classes()).toContain('dm-floating-bar--shadow')
120
+ expect(bar.classes()).toContain('dm-floating-bar--rounded')
121
+ })
122
+
123
+ it('renders multiple action buttons', () => {
124
+ const wrapper = mount(DatametriaFloatingBar, {
125
+ slots: {
126
+ default: `
127
+ <button class="btn-1">Action 1</button>
128
+ <button class="btn-2">Action 2</button>
129
+ <button class="btn-3">Action 3</button>
130
+ `
131
+ }
132
+ })
133
+ expect(wrapper.find('.btn-1').exists()).toBe(true)
134
+ expect(wrapper.find('.btn-2').exists()).toBe(true)
135
+ expect(wrapper.find('.btn-3').exists()).toBe(true)
136
+ })
137
+ })
@@ -0,0 +1,31 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import DatametriaGrid from '../DatametriaGrid.vue'
4
+
5
+ describe('DatametriaGrid', () => {
6
+ it('renders correctly', () => {
7
+ const wrapper = mount(DatametriaGrid)
8
+ expect(wrapper.find('.dm-grid').exists()).toBe(true)
9
+ })
10
+
11
+ it('applies custom cols', () => {
12
+ const wrapper = mount(DatametriaGrid, {
13
+ props: { cols: 6 }
14
+ })
15
+ expect(wrapper.find('.dm-grid').attributes('style')).toContain('--dm-grid-cols: 6')
16
+ })
17
+
18
+ it('applies custom gap', () => {
19
+ const wrapper = mount(DatametriaGrid, {
20
+ props: { gap: '2rem' }
21
+ })
22
+ expect(wrapper.find('.dm-grid').attributes('style')).toContain('--dm-grid-gap: 2rem')
23
+ })
24
+
25
+ it('renders slot content', () => {
26
+ const wrapper = mount(DatametriaGrid, {
27
+ slots: { default: '<div>Grid Item</div>' }
28
+ })
29
+ expect(wrapper.html()).toContain('Grid Item')
30
+ })
31
+ })
@@ -0,0 +1,72 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import DatametriaInput from '../DatametriaInput.vue'
4
+
5
+ describe('DatametriaInput', () => {
6
+ it('renders correctly', () => {
7
+ const wrapper = mount(DatametriaInput)
8
+ expect(wrapper.find('.datametria-input').exists()).toBe(true)
9
+ })
10
+
11
+ it('renders label when provided', () => {
12
+ const wrapper = mount(DatametriaInput, {
13
+ props: { label: 'Test Label' }
14
+ })
15
+ expect(wrapper.find('.datametria-input__label').text()).toContain('Test Label')
16
+ })
17
+
18
+ it('shows required asterisk when required', () => {
19
+ const wrapper = mount(DatametriaInput, {
20
+ props: { label: 'Test', required: true }
21
+ })
22
+ expect(wrapper.find('.datametria-input__required').exists()).toBe(true)
23
+ })
24
+
25
+ it('binds modelValue correctly', () => {
26
+ const wrapper = mount(DatametriaInput, {
27
+ props: { modelValue: 'test value' }
28
+ })
29
+ expect((wrapper.find('input').element as HTMLInputElement).value).toBe('test value')
30
+ })
31
+
32
+ it('emits update:modelValue on input', async () => {
33
+ const wrapper = mount(DatametriaInput)
34
+ const input = wrapper.find('input')
35
+ await input.setValue('new value')
36
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['new value'])
37
+ })
38
+
39
+ it('applies disabled state', () => {
40
+ const wrapper = mount(DatametriaInput, {
41
+ props: { disabled: true }
42
+ })
43
+ expect(wrapper.find('input').attributes('disabled')).toBeDefined()
44
+ })
45
+
46
+ it('shows error message when provided', () => {
47
+ const wrapper = mount(DatametriaInput, {
48
+ props: { errorMessage: 'Error text' }
49
+ })
50
+ expect(wrapper.find('.datametria-input__error').text()).toBe('Error text')
51
+ })
52
+
53
+ it('applies error class when error exists', () => {
54
+ const wrapper = mount(DatametriaInput, {
55
+ props: { errorMessage: 'Error' }
56
+ })
57
+ expect(wrapper.find('.datametria-input__field--error').exists()).toBe(true)
58
+ })
59
+
60
+ it('applies placeholder', () => {
61
+ const wrapper = mount(DatametriaInput, {
62
+ props: { placeholder: 'Enter text' }
63
+ })
64
+ expect(wrapper.find('input').attributes('placeholder')).toBe('Enter text')
65
+ })
66
+
67
+ it('uses CSS variables with fallbacks', () => {
68
+ const wrapper = mount(DatametriaInput)
69
+ const styles = wrapper.find('.datametria-input').attributes('style')
70
+ expect(wrapper.html()).toContain('datametria-input')
71
+ })
72
+ })