@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.
- package/README.md +548 -657
- package/dist/index.es.js +2353 -1364
- package/dist/index.umd.js +10 -10
- package/dist/vue-components.css +1 -1
- package/package.json +102 -98
- package/src/components/DatametriaAlert.vue +137 -137
- package/src/components/DatametriaAutocomplete.vue +184 -138
- package/src/components/DatametriaAvatar.vue +177 -33
- package/src/components/DatametriaBadge.vue +98 -98
- package/src/components/DatametriaBreadcrumb.vue +21 -21
- package/src/components/DatametriaButton.vue +177 -165
- package/src/components/DatametriaCard.vue +12 -12
- package/src/components/DatametriaCheckbox.vue +8 -8
- package/src/components/DatametriaChip.vue +145 -149
- package/src/components/DatametriaContainer.vue +4 -4
- package/src/components/DatametriaDatePicker.vue +686 -68
- package/src/components/DatametriaDivider.vue +13 -13
- package/src/components/DatametriaFileUpload.vue +272 -140
- package/src/components/DatametriaGrid.vue +3 -3
- package/src/components/DatametriaInput.vue +15 -15
- package/src/components/DatametriaMenu.vue +604 -619
- package/src/components/DatametriaModal.vue +16 -16
- package/src/components/DatametriaNavbar.vue +230 -252
- package/src/components/DatametriaPasswordInput.vue +430 -0
- package/src/components/DatametriaProgress.vue +18 -18
- package/src/components/DatametriaRadio.vue +20 -20
- package/src/components/DatametriaSelect.vue +15 -15
- package/src/components/DatametriaSkeleton.vue +243 -239
- package/src/components/DatametriaSlider.vue +395 -407
- package/src/components/DatametriaSortableTable.vue +585 -0
- package/src/components/DatametriaSpinner.vue +7 -7
- package/src/components/DatametriaSwitch.vue +16 -16
- package/src/components/DatametriaTable.vue +14 -14
- package/src/components/DatametriaTextarea.vue +28 -28
- package/src/components/DatametriaTimePicker.vue +285 -285
- package/src/components/DatametriaToast.vue +176 -176
- package/src/components/DatametriaTooltip.vue +408 -408
- package/src/components/__tests__/DatametriaAlert.test.js +35 -35
- package/src/components/__tests__/DatametriaAlert.test.ts +190 -0
- package/src/components/__tests__/DatametriaAutocomplete.test.ts +180 -0
- package/src/components/__tests__/DatametriaAvatar.test.ts +152 -0
- package/src/components/__tests__/DatametriaBadge.test.js +29 -29
- package/src/components/__tests__/DatametriaBadge.test.ts +167 -0
- package/src/components/__tests__/DatametriaBreadcrumb.test.ts +75 -0
- package/src/components/__tests__/DatametriaButton.test.js +30 -30
- package/src/components/__tests__/DatametriaButton.test.ts +283 -0
- package/src/components/__tests__/DatametriaCard.test.ts +201 -0
- package/src/components/__tests__/DatametriaCheckbox.test.ts +47 -0
- package/src/components/__tests__/DatametriaChip.test.js +38 -38
- package/src/components/__tests__/DatametriaContainer.test.ts +52 -0
- package/src/components/__tests__/DatametriaDatePicker.test.ts +234 -0
- package/src/components/__tests__/DatametriaDivider.test.ts +54 -0
- package/src/components/__tests__/DatametriaFileUpload.test.ts +291 -0
- package/src/components/__tests__/DatametriaGrid.test.ts +31 -0
- package/src/components/__tests__/DatametriaInput.test.ts +72 -0
- package/src/components/__tests__/DatametriaMenu.test.ts +366 -0
- package/src/components/__tests__/DatametriaModal.test.ts +86 -0
- package/src/components/__tests__/DatametriaNavbar.test.js +48 -48
- package/src/components/__tests__/DatametriaNavbar.test.ts +203 -0
- package/src/components/__tests__/DatametriaPasswordInput.test.js +305 -0
- package/src/components/__tests__/DatametriaProgress.test.ts +90 -0
- package/src/components/__tests__/DatametriaRadio.test.ts +77 -0
- package/src/components/__tests__/DatametriaSelect.test.ts +77 -0
- package/src/components/__tests__/DatametriaSlider.test.ts +261 -0
- package/src/components/__tests__/DatametriaSortableTable.test.js +168 -0
- package/src/components/__tests__/DatametriaSpinner.test.ts +156 -0
- package/src/components/__tests__/DatametriaSwitch.test.ts +64 -0
- package/src/components/__tests__/DatametriaTable.test.ts +97 -0
- package/src/components/__tests__/DatametriaTextarea.test.ts +66 -0
- package/src/components/__tests__/DatametriaToast.test.js +48 -48
- package/src/components/__tests__/DatametriaToast.test.ts +99 -0
- package/src/composables/useAccessibilityScale.ts +94 -94
- package/src/composables/useBreakpoints.ts +82 -82
- package/src/composables/useHapticFeedback.ts +439 -439
- package/src/composables/useRipple.ts +218 -218
- package/src/index.ts +68 -61
- package/src/stories/Variants.stories.js +95 -95
- package/src/styles/design-tokens.css +623 -623
- package/src/theme/ThemeProvider.vue +96 -0
- package/src/theme/__tests__/ThemeProvider.test.ts +208 -0
- package/src/theme/__tests__/constants.test.ts +31 -0
- package/src/theme/__tests__/presets.test.ts +166 -0
- package/src/theme/__tests__/tokens.test.ts +155 -0
- package/src/theme/__tests__/types.test.ts +153 -0
- package/src/theme/__tests__/useTheme.test.ts +146 -0
- package/src/theme/constants.ts +14 -0
- package/src/theme/index.ts +12 -0
- package/src/theme/presets/datametria.ts +94 -0
- package/src/theme/presets/default.ts +94 -0
- package/src/theme/presets/index.ts +8 -0
- package/src/theme/tokens/colors.ts +28 -0
- package/src/theme/tokens/index.ts +47 -0
- package/src/theme/tokens/spacing.ts +21 -0
- package/src/theme/tokens/typography.ts +35 -0
- package/src/theme/types.ts +111 -0
- package/src/theme/useTheme.ts +28 -0
- package/src/types/index.ts +19 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaSwitch from '../DatametriaSwitch.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaSwitch', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
const wrapper = mount(DatametriaSwitch)
|
|
8
|
+
expect(wrapper.find('.dm-switch').exists()).toBe(true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('renders label when provided', () => {
|
|
12
|
+
const wrapper = mount(DatametriaSwitch, {
|
|
13
|
+
props: { label: 'Enable feature' }
|
|
14
|
+
})
|
|
15
|
+
expect(wrapper.find('.dm-switch__text').text()).toBe('Enable feature')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('binds checked state correctly', () => {
|
|
19
|
+
const wrapper = mount(DatametriaSwitch, {
|
|
20
|
+
props: { modelValue: true }
|
|
21
|
+
})
|
|
22
|
+
expect((wrapper.find('input').element as HTMLInputElement).checked).toBe(true)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('emits update:modelValue on change', async () => {
|
|
26
|
+
const wrapper = mount(DatametriaSwitch)
|
|
27
|
+
await wrapper.find('input').setValue(true)
|
|
28
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('applies disabled state', () => {
|
|
32
|
+
const wrapper = mount(DatametriaSwitch, {
|
|
33
|
+
props: { disabled: true }
|
|
34
|
+
})
|
|
35
|
+
expect(wrapper.find('input').attributes('disabled')).toBeDefined()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('does not emit when disabled', async () => {
|
|
39
|
+
const wrapper = mount(DatametriaSwitch, {
|
|
40
|
+
props: { disabled: true }
|
|
41
|
+
})
|
|
42
|
+
await wrapper.find('input').trigger('change')
|
|
43
|
+
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('shows error message', () => {
|
|
47
|
+
const wrapper = mount(DatametriaSwitch, {
|
|
48
|
+
props: { error: 'Error text' }
|
|
49
|
+
})
|
|
50
|
+
expect(wrapper.find('.dm-switch__error').text()).toBe('Error text')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('applies aria-label', () => {
|
|
54
|
+
const wrapper = mount(DatametriaSwitch, {
|
|
55
|
+
props: { ariaLabel: 'Toggle feature' }
|
|
56
|
+
})
|
|
57
|
+
expect(wrapper.find('input').attributes('aria-label')).toBe('Toggle feature')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('has role switch', () => {
|
|
61
|
+
const wrapper = mount(DatametriaSwitch)
|
|
62
|
+
expect(wrapper.find('input').attributes('role')).toBe('switch')
|
|
63
|
+
})
|
|
64
|
+
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaTable from '../DatametriaTable.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaTable', () => {
|
|
6
|
+
const columns = [
|
|
7
|
+
{ key: 'name', label: 'Name' },
|
|
8
|
+
{ key: 'email', label: 'Email' },
|
|
9
|
+
{ key: 'age', label: 'Age' }
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
const data = [
|
|
13
|
+
{ name: 'John Doe', email: 'john@example.com', age: 30 },
|
|
14
|
+
{ name: 'Jane Smith', email: 'jane@example.com', age: 25 }
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
it('renders correctly', () => {
|
|
18
|
+
const wrapper = mount(DatametriaTable, {
|
|
19
|
+
props: { columns, data }
|
|
20
|
+
})
|
|
21
|
+
expect(wrapper.find('.datametria-table').exists()).toBe(true)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('renders table headers correctly', () => {
|
|
25
|
+
const wrapper = mount(DatametriaTable, {
|
|
26
|
+
props: { columns, data }
|
|
27
|
+
})
|
|
28
|
+
const headers = wrapper.findAll('.datametria-table__th')
|
|
29
|
+
expect(headers).toHaveLength(3)
|
|
30
|
+
expect(headers[0].text()).toBe('Name')
|
|
31
|
+
expect(headers[1].text()).toBe('Email')
|
|
32
|
+
expect(headers[2].text()).toBe('Age')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('renders table rows correctly', () => {
|
|
36
|
+
const wrapper = mount(DatametriaTable, {
|
|
37
|
+
props: { columns, data }
|
|
38
|
+
})
|
|
39
|
+
const rows = wrapper.findAll('.datametria-table__tr')
|
|
40
|
+
expect(rows).toHaveLength(2)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('renders table cells correctly', () => {
|
|
44
|
+
const wrapper = mount(DatametriaTable, {
|
|
45
|
+
props: { columns, data }
|
|
46
|
+
})
|
|
47
|
+
const cells = wrapper.findAll('.datametria-table__td')
|
|
48
|
+
expect(cells[0].text()).toBe('John Doe')
|
|
49
|
+
expect(cells[1].text()).toBe('john@example.com')
|
|
50
|
+
expect(cells[2].text()).toBe('30')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('shows empty state when no data', () => {
|
|
54
|
+
const wrapper = mount(DatametriaTable, {
|
|
55
|
+
props: { columns, data: [] }
|
|
56
|
+
})
|
|
57
|
+
expect(wrapper.find('.datametria-table__empty').exists()).toBe(true)
|
|
58
|
+
expect(wrapper.find('.datametria-table__empty').text()).toBe('Nenhum dado disponível')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('renders custom empty slot', () => {
|
|
62
|
+
const wrapper = mount(DatametriaTable, {
|
|
63
|
+
props: { columns, data: [] },
|
|
64
|
+
slots: { empty: 'Custom empty message' }
|
|
65
|
+
})
|
|
66
|
+
expect(wrapper.find('.datametria-table__empty').text()).toBe('Custom empty message')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('applies column width when specified', () => {
|
|
70
|
+
const columnsWithWidth = [
|
|
71
|
+
{ key: 'name', label: 'Name', width: '200px' },
|
|
72
|
+
{ key: 'email', label: 'Email' }
|
|
73
|
+
]
|
|
74
|
+
const wrapper = mount(DatametriaTable, {
|
|
75
|
+
props: { columns: columnsWithWidth, data }
|
|
76
|
+
})
|
|
77
|
+
const firstHeader = wrapper.find('.datametria-table__th')
|
|
78
|
+
expect(firstHeader.attributes('style')).toContain('width: 200px')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('renders custom cell slot', () => {
|
|
82
|
+
const wrapper = mount(DatametriaTable, {
|
|
83
|
+
props: { columns, data },
|
|
84
|
+
slots: {
|
|
85
|
+
'cell-name': '<strong>Custom Name</strong>'
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
expect(wrapper.html()).toContain('<strong>Custom Name</strong>')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('uses CSS variables with fallbacks', () => {
|
|
92
|
+
const wrapper = mount(DatametriaTable, {
|
|
93
|
+
props: { columns, data }
|
|
94
|
+
})
|
|
95
|
+
expect(wrapper.html()).toContain('datametria-table')
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaTextarea from '../DatametriaTextarea.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaTextarea', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
const wrapper = mount(DatametriaTextarea)
|
|
8
|
+
expect(wrapper.find('.dm-textarea').exists()).toBe(true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('renders label when provided', () => {
|
|
12
|
+
const wrapper = mount(DatametriaTextarea, {
|
|
13
|
+
props: { label: 'Textarea Label' }
|
|
14
|
+
})
|
|
15
|
+
expect(wrapper.find('.dm-textarea__label').text()).toContain('Textarea Label')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('shows required indicator', () => {
|
|
19
|
+
const wrapper = mount(DatametriaTextarea, {
|
|
20
|
+
props: { label: 'Test', required: true }
|
|
21
|
+
})
|
|
22
|
+
expect(wrapper.find('.dm-textarea__required').exists()).toBe(true)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('binds modelValue correctly', () => {
|
|
26
|
+
const wrapper = mount(DatametriaTextarea, {
|
|
27
|
+
props: { modelValue: 'test value' }
|
|
28
|
+
})
|
|
29
|
+
expect((wrapper.find('textarea').element as HTMLTextAreaElement).value).toBe('test value')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('emits update:modelValue on input', async () => {
|
|
33
|
+
const wrapper = mount(DatametriaTextarea)
|
|
34
|
+
await wrapper.find('textarea').setValue('new value')
|
|
35
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['new value'])
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('applies disabled state', () => {
|
|
39
|
+
const wrapper = mount(DatametriaTextarea, {
|
|
40
|
+
props: { disabled: true }
|
|
41
|
+
})
|
|
42
|
+
expect(wrapper.find('textarea').attributes('disabled')).toBeDefined()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('shows error message', () => {
|
|
46
|
+
const wrapper = mount(DatametriaTextarea, {
|
|
47
|
+
props: { error: 'Error text' }
|
|
48
|
+
})
|
|
49
|
+
expect(wrapper.find('.dm-textarea__error').text()).toBe('Error text')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('shows character counter when maxLength provided', () => {
|
|
53
|
+
const wrapper = mount(DatametriaTextarea, {
|
|
54
|
+
props: { maxLength: 100, modelValue: 'test' }
|
|
55
|
+
})
|
|
56
|
+
expect(wrapper.find('.dm-textarea__counter').exists()).toBe(true)
|
|
57
|
+
expect(wrapper.find('.dm-textarea__counter').text()).toContain('4/100')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('applies custom rows', () => {
|
|
61
|
+
const wrapper = mount(DatametriaTextarea, {
|
|
62
|
+
props: { rows: 10 }
|
|
63
|
+
})
|
|
64
|
+
expect(wrapper.find('textarea').attributes('rows')).toBe('10')
|
|
65
|
+
})
|
|
66
|
+
})
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
-
import { mount } from '@vue/test-utils'
|
|
3
|
-
import DatametriaToast from '../DatametriaToast.vue'
|
|
4
|
-
|
|
5
|
-
describe('DatametriaToast', () => {
|
|
6
|
-
it('renders with primary variant', () => {
|
|
7
|
-
// Create body element for Teleport
|
|
8
|
-
const body = document.createElement('div')
|
|
9
|
-
document.body.appendChild(body)
|
|
10
|
-
|
|
11
|
-
const wrapper = mount(DatametriaToast, {
|
|
12
|
-
props: {
|
|
13
|
-
message: 'Test message',
|
|
14
|
-
variant: 'primary',
|
|
15
|
-
modelValue: true
|
|
16
|
-
},
|
|
17
|
-
attachTo: body
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
// Check if toast exists in document body
|
|
21
|
-
const toast = document.querySelector('.dm-toast')
|
|
22
|
-
expect(toast).toBeTruthy()
|
|
23
|
-
expect(toast.classList.contains('dm-toast--primary')).toBe(true)
|
|
24
|
-
|
|
25
|
-
wrapper.unmount()
|
|
26
|
-
document.body.removeChild(body)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('validates invalid variant in development', () => {
|
|
30
|
-
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
31
|
-
const originalEnv = process.env.NODE_ENV
|
|
32
|
-
process.env.NODE_ENV = 'development'
|
|
33
|
-
|
|
34
|
-
mount(DatametriaToast, {
|
|
35
|
-
props: {
|
|
36
|
-
message: 'Test',
|
|
37
|
-
variant: 'invalid',
|
|
38
|
-
modelValue: true
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
43
|
-
expect.stringContaining('[DatametriaToast] Invalid variant "invalid"')
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
process.env.NODE_ENV = originalEnv
|
|
47
|
-
consoleSpy.mockRestore()
|
|
48
|
-
})
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaToast from '../DatametriaToast.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaToast', () => {
|
|
6
|
+
it('renders with primary variant', () => {
|
|
7
|
+
// Create body element for Teleport
|
|
8
|
+
const body = document.createElement('div')
|
|
9
|
+
document.body.appendChild(body)
|
|
10
|
+
|
|
11
|
+
const wrapper = mount(DatametriaToast, {
|
|
12
|
+
props: {
|
|
13
|
+
message: 'Test message',
|
|
14
|
+
variant: 'primary',
|
|
15
|
+
modelValue: true
|
|
16
|
+
},
|
|
17
|
+
attachTo: body
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// Check if toast exists in document body
|
|
21
|
+
const toast = document.querySelector('.dm-toast')
|
|
22
|
+
expect(toast).toBeTruthy()
|
|
23
|
+
expect(toast.classList.contains('dm-toast--primary')).toBe(true)
|
|
24
|
+
|
|
25
|
+
wrapper.unmount()
|
|
26
|
+
document.body.removeChild(body)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('validates invalid variant in development', () => {
|
|
30
|
+
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
31
|
+
const originalEnv = process.env.NODE_ENV
|
|
32
|
+
process.env.NODE_ENV = 'development'
|
|
33
|
+
|
|
34
|
+
mount(DatametriaToast, {
|
|
35
|
+
props: {
|
|
36
|
+
message: 'Test',
|
|
37
|
+
variant: 'invalid',
|
|
38
|
+
modelValue: true
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
43
|
+
expect.stringContaining('[DatametriaToast] Invalid variant "invalid"')
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
process.env.NODE_ENV = originalEnv
|
|
47
|
+
consoleSpy.mockRestore()
|
|
48
|
+
})
|
|
49
49
|
})
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaToast from '../DatametriaToast.vue'
|
|
4
|
+
|
|
5
|
+
describe.skip('DatametriaToast', () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
vi.useFakeTimers()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.restoreAllMocks()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('renders correctly when visible', () => {
|
|
15
|
+
const wrapper = mount(DatametriaToast, {
|
|
16
|
+
props: { message: 'Test message', modelValue: true }
|
|
17
|
+
})
|
|
18
|
+
expect(wrapper.html()).toContain('dm-toast')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('displays message correctly', () => {
|
|
22
|
+
const wrapper = mount(DatametriaToast, {
|
|
23
|
+
props: { message: 'Test message', modelValue: true }
|
|
24
|
+
})
|
|
25
|
+
expect(wrapper.html()).toContain('Test message')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('applies success variant class', () => {
|
|
29
|
+
const wrapper = mount(DatametriaToast, {
|
|
30
|
+
props: { message: 'Success', variant: 'success', modelValue: true }
|
|
31
|
+
})
|
|
32
|
+
expect(wrapper.html()).toContain('dm-toast--success')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('applies error variant class', () => {
|
|
36
|
+
const wrapper = mount(DatametriaToast, {
|
|
37
|
+
props: { message: 'Error', variant: 'error', modelValue: true }
|
|
38
|
+
})
|
|
39
|
+
expect(wrapper.html()).toContain('dm-toast--error')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('applies warning variant class', () => {
|
|
43
|
+
const wrapper = mount(DatametriaToast, {
|
|
44
|
+
props: { message: 'Warning', variant: 'warning', modelValue: true }
|
|
45
|
+
})
|
|
46
|
+
expect(wrapper.html()).toContain('dm-toast--warning')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('applies primary variant class', () => {
|
|
50
|
+
const wrapper = mount(DatametriaToast, {
|
|
51
|
+
props: { message: 'Primary', variant: 'primary', modelValue: true }
|
|
52
|
+
})
|
|
53
|
+
expect(wrapper.html()).toContain('dm-toast--primary')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('applies info variant class', () => {
|
|
57
|
+
const wrapper = mount(DatametriaToast, {
|
|
58
|
+
props: { message: 'Info', variant: 'info', modelValue: true }
|
|
59
|
+
})
|
|
60
|
+
expect(wrapper.html()).toContain('dm-toast--info')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('renders close button when closable', () => {
|
|
64
|
+
const wrapper = mount(DatametriaToast, {
|
|
65
|
+
props: { message: 'Test', closable: true, modelValue: true }
|
|
66
|
+
})
|
|
67
|
+
expect(wrapper.html()).toContain('dm-toast__close')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('does not render close button when not closable', () => {
|
|
71
|
+
const wrapper = mount(DatametriaToast, {
|
|
72
|
+
props: { message: 'Test', closable: false, modelValue: true }
|
|
73
|
+
})
|
|
74
|
+
expect(wrapper.html()).not.toContain('dm-toast__close')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('emits update:modelValue when close called', async () => {
|
|
78
|
+
const wrapper = mount(DatametriaToast, {
|
|
79
|
+
props: { message: 'Test', closable: true, modelValue: true }
|
|
80
|
+
})
|
|
81
|
+
await (wrapper.vm as any).close()
|
|
82
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([false])
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('emits close event when close called', async () => {
|
|
86
|
+
const wrapper = mount(DatametriaToast, {
|
|
87
|
+
props: { message: 'Test', closable: true, modelValue: true }
|
|
88
|
+
})
|
|
89
|
+
await (wrapper.vm as any).close()
|
|
90
|
+
expect(wrapper.emitted('close')).toBeTruthy()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('uses CSS variables with fallbacks', () => {
|
|
94
|
+
const wrapper = mount(DatametriaToast, {
|
|
95
|
+
props: { message: 'Test', modelValue: true }
|
|
96
|
+
})
|
|
97
|
+
expect(wrapper.html()).toContain('--dm-')
|
|
98
|
+
})
|
|
99
|
+
})
|
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
import { ref, computed, watch, onMounted } from 'vue'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Composable para controle de escalabilidade de acessibilidade
|
|
5
|
-
* Implementa escala controlada entre 0.8x e 2.0x conforme WCAG 2.1
|
|
6
|
-
*/
|
|
7
|
-
export function useAccessibilityScale() {
|
|
8
|
-
const scale = ref(1.0)
|
|
9
|
-
const STORAGE_KEY = 'datametria-accessibility-scale'
|
|
10
|
-
const MIN_SCALE = 0.8
|
|
11
|
-
const MAX_SCALE = 2.0
|
|
12
|
-
|
|
13
|
-
// Computed para escala clampada
|
|
14
|
-
const clampedScale = computed(() =>
|
|
15
|
-
Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale.value))
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
// Computed para classe CSS
|
|
19
|
-
const scaleClass = computed(() => {
|
|
20
|
-
const s = clampedScale.value
|
|
21
|
-
if (s <= 0.9) return 'scale-small'
|
|
22
|
-
if (s >= 1.1) return 'scale-large'
|
|
23
|
-
return 'scale-normal'
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
// Aplicar escala ao documento
|
|
27
|
-
const applyScale = (newScale: number) => {
|
|
28
|
-
const finalScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, newScale))
|
|
29
|
-
document.documentElement.style.setProperty('--user-scale', finalScale.toString())
|
|
30
|
-
scale.value = finalScale
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Salvar no localStorage
|
|
34
|
-
const saveScale = (scaleValue: number) => {
|
|
35
|
-
try {
|
|
36
|
-
localStorage.setItem(STORAGE_KEY, scaleValue.toString())
|
|
37
|
-
} catch (error) {
|
|
38
|
-
console.warn('Failed to save accessibility scale:', error)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Carregar do localStorage
|
|
43
|
-
const loadScale = (): number => {
|
|
44
|
-
try {
|
|
45
|
-
const saved = localStorage.getItem(STORAGE_KEY)
|
|
46
|
-
return saved ? parseFloat(saved) : 1.0
|
|
47
|
-
} catch (error) {
|
|
48
|
-
console.warn('Failed to load accessibility scale:', error)
|
|
49
|
-
return 1.0
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Definir escala
|
|
54
|
-
const setScale = (newScale: number) => {
|
|
55
|
-
applyScale(newScale)
|
|
56
|
-
saveScale(clampedScale.value)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Incrementar escala
|
|
60
|
-
const increaseScale = () => {
|
|
61
|
-
setScale(scale.value + 0.1)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Decrementar escala
|
|
65
|
-
const decreaseScale = () => {
|
|
66
|
-
setScale(scale.value - 0.1)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Reset para padrão
|
|
70
|
-
const resetScale = () => {
|
|
71
|
-
setScale(1.0)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Watch para mudanças na escala
|
|
75
|
-
watch(scale, (newScale) => {
|
|
76
|
-
applyScale(newScale)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
// Inicializar na montagem
|
|
80
|
-
onMounted(() => {
|
|
81
|
-
const savedScale = loadScale()
|
|
82
|
-
applyScale(savedScale)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
scale: clampedScale,
|
|
87
|
-
scaleClass,
|
|
88
|
-
setScale,
|
|
89
|
-
increaseScale,
|
|
90
|
-
decreaseScale,
|
|
91
|
-
resetScale,
|
|
92
|
-
minScale: MIN_SCALE,
|
|
93
|
-
maxScale: MAX_SCALE
|
|
94
|
-
}
|
|
1
|
+
import { ref, computed, watch, onMounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composable para controle de escalabilidade de acessibilidade
|
|
5
|
+
* Implementa escala controlada entre 0.8x e 2.0x conforme WCAG 2.1
|
|
6
|
+
*/
|
|
7
|
+
export function useAccessibilityScale() {
|
|
8
|
+
const scale = ref(1.0)
|
|
9
|
+
const STORAGE_KEY = 'datametria-accessibility-scale'
|
|
10
|
+
const MIN_SCALE = 0.8
|
|
11
|
+
const MAX_SCALE = 2.0
|
|
12
|
+
|
|
13
|
+
// Computed para escala clampada
|
|
14
|
+
const clampedScale = computed(() =>
|
|
15
|
+
Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale.value))
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
// Computed para classe CSS
|
|
19
|
+
const scaleClass = computed(() => {
|
|
20
|
+
const s = clampedScale.value
|
|
21
|
+
if (s <= 0.9) return 'scale-small'
|
|
22
|
+
if (s >= 1.1) return 'scale-large'
|
|
23
|
+
return 'scale-normal'
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// Aplicar escala ao documento
|
|
27
|
+
const applyScale = (newScale: number) => {
|
|
28
|
+
const finalScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, newScale))
|
|
29
|
+
document.documentElement.style.setProperty('--user-scale', finalScale.toString())
|
|
30
|
+
scale.value = finalScale
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Salvar no localStorage
|
|
34
|
+
const saveScale = (scaleValue: number) => {
|
|
35
|
+
try {
|
|
36
|
+
localStorage.setItem(STORAGE_KEY, scaleValue.toString())
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.warn('Failed to save accessibility scale:', error)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Carregar do localStorage
|
|
43
|
+
const loadScale = (): number => {
|
|
44
|
+
try {
|
|
45
|
+
const saved = localStorage.getItem(STORAGE_KEY)
|
|
46
|
+
return saved ? parseFloat(saved) : 1.0
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.warn('Failed to load accessibility scale:', error)
|
|
49
|
+
return 1.0
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Definir escala
|
|
54
|
+
const setScale = (newScale: number) => {
|
|
55
|
+
applyScale(newScale)
|
|
56
|
+
saveScale(clampedScale.value)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Incrementar escala
|
|
60
|
+
const increaseScale = () => {
|
|
61
|
+
setScale(scale.value + 0.1)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Decrementar escala
|
|
65
|
+
const decreaseScale = () => {
|
|
66
|
+
setScale(scale.value - 0.1)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Reset para padrão
|
|
70
|
+
const resetScale = () => {
|
|
71
|
+
setScale(1.0)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Watch para mudanças na escala
|
|
75
|
+
watch(scale, (newScale) => {
|
|
76
|
+
applyScale(newScale)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// Inicializar na montagem
|
|
80
|
+
onMounted(() => {
|
|
81
|
+
const savedScale = loadScale()
|
|
82
|
+
applyScale(savedScale)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
scale: clampedScale,
|
|
87
|
+
scaleClass,
|
|
88
|
+
setScale,
|
|
89
|
+
increaseScale,
|
|
90
|
+
decreaseScale,
|
|
91
|
+
resetScale,
|
|
92
|
+
minScale: MIN_SCALE,
|
|
93
|
+
maxScale: MAX_SCALE
|
|
94
|
+
}
|
|
95
95
|
}
|