@datametria/vue-components 1.2.0 → 2.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.
Files changed (97) hide show
  1. package/README.md +548 -657
  2. package/dist/index.es.js +2353 -1364
  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/DatametriaGrid.vue +3 -3
  20. package/src/components/DatametriaInput.vue +15 -15
  21. package/src/components/DatametriaMenu.vue +604 -619
  22. package/src/components/DatametriaModal.vue +16 -16
  23. package/src/components/DatametriaNavbar.vue +230 -252
  24. package/src/components/DatametriaPasswordInput.vue +430 -0
  25. package/src/components/DatametriaProgress.vue +18 -18
  26. package/src/components/DatametriaRadio.vue +20 -20
  27. package/src/components/DatametriaSelect.vue +15 -15
  28. package/src/components/DatametriaSkeleton.vue +243 -239
  29. package/src/components/DatametriaSlider.vue +395 -407
  30. package/src/components/DatametriaSortableTable.vue +585 -0
  31. package/src/components/DatametriaSpinner.vue +7 -7
  32. package/src/components/DatametriaSwitch.vue +16 -16
  33. package/src/components/DatametriaTable.vue +14 -14
  34. package/src/components/DatametriaTextarea.vue +28 -28
  35. package/src/components/DatametriaTimePicker.vue +285 -285
  36. package/src/components/DatametriaToast.vue +176 -176
  37. package/src/components/DatametriaTooltip.vue +408 -408
  38. package/src/components/__tests__/DatametriaAlert.test.js +35 -35
  39. package/src/components/__tests__/DatametriaAlert.test.ts +190 -0
  40. package/src/components/__tests__/DatametriaAutocomplete.test.ts +180 -0
  41. package/src/components/__tests__/DatametriaAvatar.test.ts +152 -0
  42. package/src/components/__tests__/DatametriaBadge.test.js +29 -29
  43. package/src/components/__tests__/DatametriaBadge.test.ts +167 -0
  44. package/src/components/__tests__/DatametriaBreadcrumb.test.ts +75 -0
  45. package/src/components/__tests__/DatametriaButton.test.js +30 -30
  46. package/src/components/__tests__/DatametriaButton.test.ts +283 -0
  47. package/src/components/__tests__/DatametriaCard.test.ts +201 -0
  48. package/src/components/__tests__/DatametriaCheckbox.test.ts +47 -0
  49. package/src/components/__tests__/DatametriaChip.test.js +38 -38
  50. package/src/components/__tests__/DatametriaContainer.test.ts +52 -0
  51. package/src/components/__tests__/DatametriaDatePicker.test.ts +234 -0
  52. package/src/components/__tests__/DatametriaDivider.test.ts +54 -0
  53. package/src/components/__tests__/DatametriaFileUpload.test.ts +291 -0
  54. package/src/components/__tests__/DatametriaGrid.test.ts +31 -0
  55. package/src/components/__tests__/DatametriaInput.test.ts +72 -0
  56. package/src/components/__tests__/DatametriaMenu.test.ts +366 -0
  57. package/src/components/__tests__/DatametriaModal.test.ts +86 -0
  58. package/src/components/__tests__/DatametriaNavbar.test.js +48 -48
  59. package/src/components/__tests__/DatametriaNavbar.test.ts +203 -0
  60. package/src/components/__tests__/DatametriaPasswordInput.test.js +305 -0
  61. package/src/components/__tests__/DatametriaProgress.test.ts +90 -0
  62. package/src/components/__tests__/DatametriaRadio.test.ts +77 -0
  63. package/src/components/__tests__/DatametriaSelect.test.ts +77 -0
  64. package/src/components/__tests__/DatametriaSlider.test.ts +261 -0
  65. package/src/components/__tests__/DatametriaSortableTable.test.js +168 -0
  66. package/src/components/__tests__/DatametriaSpinner.test.ts +156 -0
  67. package/src/components/__tests__/DatametriaSwitch.test.ts +64 -0
  68. package/src/components/__tests__/DatametriaTable.test.ts +97 -0
  69. package/src/components/__tests__/DatametriaTextarea.test.ts +66 -0
  70. package/src/components/__tests__/DatametriaToast.test.js +48 -48
  71. package/src/components/__tests__/DatametriaToast.test.ts +99 -0
  72. package/src/composables/useAccessibilityScale.ts +94 -94
  73. package/src/composables/useBreakpoints.ts +82 -82
  74. package/src/composables/useHapticFeedback.ts +439 -439
  75. package/src/composables/useRipple.ts +218 -218
  76. package/src/index.ts +68 -61
  77. package/src/stories/Variants.stories.js +95 -95
  78. package/src/styles/design-tokens.css +623 -623
  79. package/src/theme/ThemeProvider.vue +96 -0
  80. package/src/theme/__tests__/ThemeProvider.test.ts +208 -0
  81. package/src/theme/__tests__/constants.test.ts +31 -0
  82. package/src/theme/__tests__/presets.test.ts +166 -0
  83. package/src/theme/__tests__/tokens.test.ts +155 -0
  84. package/src/theme/__tests__/types.test.ts +153 -0
  85. package/src/theme/__tests__/useTheme.test.ts +146 -0
  86. package/src/theme/constants.ts +14 -0
  87. package/src/theme/index.ts +12 -0
  88. package/src/theme/presets/datametria.ts +94 -0
  89. package/src/theme/presets/default.ts +94 -0
  90. package/src/theme/presets/index.ts +8 -0
  91. package/src/theme/tokens/colors.ts +28 -0
  92. package/src/theme/tokens/index.ts +47 -0
  93. package/src/theme/tokens/spacing.ts +21 -0
  94. package/src/theme/tokens/typography.ts +35 -0
  95. package/src/theme/types.ts +111 -0
  96. package/src/theme/useTheme.ts +28 -0
  97. 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,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
+ })