@datametria/vue-components 2.3.0 → 2.4.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.
- package/README.md +625 -594
- package/dist/index.es.js +1962 -1887
- package/dist/index.umd.js +6 -6
- package/dist/src/components/DatametriaForm.vue.d.ts +1 -1
- package/dist/src/components/DatametriaInput.vue.d.ts +9 -1
- package/dist/src/components/DatametriaSelect.vue.d.ts +10 -1
- package/dist/vue-components.css +1 -1
- package/package.json +103 -105
- package/src/components/DatametriaAlert.vue +151 -133
- package/src/components/DatametriaAutocomplete.vue +250 -229
- package/src/components/DatametriaAvatar.vue +256 -238
- package/src/components/DatametriaBadge.vue +101 -96
- package/src/components/DatametriaBreadcrumb.vue +132 -128
- package/src/components/DatametriaButton.vue +191 -173
- package/src/components/DatametriaCard.vue +84 -66
- package/src/components/DatametriaCheckbox.vue +197 -193
- package/src/components/DatametriaCheckboxGroup.vue +56 -38
- package/src/components/DatametriaChip.vue +159 -141
- package/src/components/DatametriaContainer.vue +70 -52
- package/src/components/DatametriaDataTable.vue +318 -300
- package/src/components/DatametriaDatePicker.vue +396 -378
- package/src/components/DatametriaDialog.vue +297 -293
- package/src/components/DatametriaDivider.vue +105 -98
- package/src/components/DatametriaDropdown.vue +356 -350
- package/src/components/DatametriaEmpty.vue +155 -151
- package/src/components/DatametriaFileUpload.vue +413 -395
- package/src/components/DatametriaFloatingBar.vue +144 -126
- package/src/components/DatametriaForm.vue +174 -156
- package/src/components/DatametriaFormItem.vue +183 -179
- package/src/components/DatametriaGrid.vue +55 -37
- package/src/components/DatametriaInput.vue +314 -263
- package/src/components/DatametriaMenu.vue +618 -600
- package/src/components/DatametriaModal.vue +147 -129
- package/src/components/DatametriaNavbar.vue +277 -223
- package/src/components/DatametriaPagination.vue +375 -371
- package/src/components/DatametriaPasswordInput.vue +444 -426
- package/src/components/DatametriaPopconfirm.vue +240 -234
- package/src/components/DatametriaProgress.vue +228 -224
- package/src/components/DatametriaRadio.vue +151 -147
- package/src/components/DatametriaRadioGroup.vue +55 -37
- package/src/components/DatametriaResult.vue +135 -131
- package/src/components/DatametriaSelect.vue +311 -211
- package/src/components/DatametriaSidebar.vue +294 -222
- package/src/components/DatametriaSkeleton.vue +257 -234
- package/src/components/DatametriaSlider.vue +409 -391
- package/src/components/DatametriaSortableTable.vue +820 -802
- package/src/components/DatametriaSpinner.vue +114 -110
- package/src/components/DatametriaSteps.vue +318 -312
- package/src/components/DatametriaSwitch.vue +146 -142
- package/src/components/DatametriaTabPane.vue +94 -76
- package/src/components/DatametriaTable.vue +118 -100
- package/src/components/DatametriaTabs.vue +315 -297
- package/src/components/DatametriaTextarea.vue +213 -195
- package/src/components/DatametriaTimePicker.vue +317 -299
- package/src/components/DatametriaToast.vue +176 -176
- package/src/components/DatametriaTooltip.vue +421 -400
- package/src/components/DatametriaTree.vue +126 -122
- package/src/components/DatametriaTreeNode.vue +176 -172
- package/src/components/DatametriaUpload.vue +379 -361
- package/src/components/__tests__/DatametriaAlert.test.js +35 -35
- package/src/components/__tests__/DatametriaAlert.test.ts +190 -190
- package/src/components/__tests__/DatametriaAvatar.test.ts +151 -151
- package/src/components/__tests__/DatametriaBadge.test.js +29 -29
- package/src/components/__tests__/DatametriaBadge.test.ts +167 -167
- package/src/components/__tests__/DatametriaBreadcrumb.test.ts +187 -0
- package/src/components/__tests__/DatametriaButton.test.js +30 -30
- package/src/components/__tests__/DatametriaButton.test.ts +283 -283
- package/src/components/__tests__/DatametriaCard.test.ts +201 -201
- package/src/components/__tests__/DatametriaCheckbox.test.ts +204 -0
- package/src/components/__tests__/DatametriaChip.test.js +38 -38
- package/src/components/__tests__/DatametriaContainer.test.ts +52 -52
- package/src/components/__tests__/DatametriaDialog.test.ts +338 -0
- package/src/components/__tests__/DatametriaDivider.test.ts +54 -54
- package/src/components/__tests__/DatametriaDropdown.test.ts +357 -0
- package/src/components/__tests__/DatametriaEmpty.test.ts +261 -0
- package/src/components/__tests__/DatametriaFileUpload.test.ts +290 -290
- package/src/components/__tests__/DatametriaFloatingBar.test.ts +137 -137
- package/src/components/__tests__/DatametriaForm.test.ts +96 -0
- package/src/components/__tests__/DatametriaFormItem.test.ts +58 -0
- package/src/components/__tests__/DatametriaGrid.test.ts +31 -31
- package/src/components/__tests__/DatametriaInput.test.ts +72 -72
- package/src/components/__tests__/DatametriaMenu.test.ts +366 -366
- package/src/components/__tests__/DatametriaModal.test.ts +86 -86
- package/src/components/__tests__/DatametriaNavbar.test.js +48 -48
- package/src/components/__tests__/DatametriaNavbar.test.ts +203 -203
- package/src/components/__tests__/DatametriaPasswordInput.test.js +305 -305
- package/src/components/__tests__/DatametriaRadio.test.ts +195 -0
- package/src/components/__tests__/DatametriaSelect.test.ts +77 -77
- package/src/components/__tests__/DatametriaSidebar.test.ts +169 -169
- package/src/components/__tests__/DatametriaSlider.test.ts +261 -261
- package/src/components/__tests__/DatametriaSortableTable.test.js +168 -168
- package/src/components/__tests__/DatametriaSpinner.test.ts +156 -156
- package/src/components/__tests__/DatametriaSteps.test.ts +211 -0
- package/src/components/__tests__/DatametriaSwitch.test.ts +129 -0
- package/src/components/__tests__/DatametriaTabPane.test.ts +205 -0
- package/src/components/__tests__/DatametriaTable.test.ts +97 -97
- package/src/components/__tests__/DatametriaTabs.test.ts +232 -232
- package/src/components/__tests__/DatametriaToast.test.js +48 -48
- package/src/components/__tests__/DatametriaToast.test.ts +99 -99
- package/src/components/__tests__/DatametriaTree.test.ts +376 -0
- package/src/components/__tests__/index.test.ts +48 -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/composables/useTheme.ts +5 -1
- package/src/index.ts +84 -84
- package/src/stories/Variants.stories.js +95 -95
- package/src/styles/design-tokens.css +623 -623
- package/src/theme/ThemeProvider.vue +96 -96
- package/src/theme/__tests__/ThemeProvider.test.ts +208 -208
- package/src/theme/__tests__/constants.test.ts +31 -31
- package/src/theme/__tests__/presets.test.ts +166 -166
- package/src/theme/__tests__/tokens.test.ts +155 -155
- package/src/theme/__tests__/types.test.ts +153 -153
- package/src/theme/__tests__/useTheme.test.ts +146 -146
- package/src/theme/constants.ts +14 -14
- package/src/theme/index.ts +12 -12
- package/src/theme/presets/datametria.ts +94 -94
- package/src/theme/presets/default.ts +94 -94
- package/src/theme/presets/index.ts +8 -8
- package/src/theme/tokens/colors.ts +28 -28
- package/src/theme/tokens/index.ts +47 -47
- package/src/theme/tokens/spacing.ts +21 -21
- package/src/theme/tokens/typography.ts +35 -35
- package/src/theme/types.ts +111 -111
- package/src/theme/useTheme.ts +28 -28
- package/src/types/index.ts +55 -55
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import * as exports from '@/index'
|
|
3
|
+
|
|
4
|
+
describe('Package Exports', () => {
|
|
5
|
+
it('exports all components', () => {
|
|
6
|
+
expect(exports.DatametriaButton).toBeDefined()
|
|
7
|
+
expect(exports.DatametriaInput).toBeDefined()
|
|
8
|
+
expect(exports.DatametriaSelect).toBeDefined()
|
|
9
|
+
expect(exports.DatametriaCheckbox).toBeDefined()
|
|
10
|
+
expect(exports.DatametriaRadio).toBeDefined()
|
|
11
|
+
expect(exports.DatametriaSwitch).toBeDefined()
|
|
12
|
+
expect(exports.DatametriaTextarea).toBeDefined()
|
|
13
|
+
expect(exports.DatametriaDatePicker).toBeDefined()
|
|
14
|
+
expect(exports.DatametriaFileUpload).toBeDefined()
|
|
15
|
+
expect(exports.DatametriaAutocomplete).toBeDefined()
|
|
16
|
+
expect(exports.DatametriaCard).toBeDefined()
|
|
17
|
+
expect(exports.DatametriaModal).toBeDefined()
|
|
18
|
+
expect(exports.DatametriaContainer).toBeDefined()
|
|
19
|
+
expect(exports.DatametriaGrid).toBeDefined()
|
|
20
|
+
expect(exports.DatametriaDivider).toBeDefined()
|
|
21
|
+
expect(exports.DatametriaAlert).toBeDefined()
|
|
22
|
+
expect(exports.DatametriaToast).toBeDefined()
|
|
23
|
+
expect(exports.DatametriaProgress).toBeDefined()
|
|
24
|
+
expect(exports.DatametriaSpinner).toBeDefined()
|
|
25
|
+
expect(exports.DatametriaTable).toBeDefined()
|
|
26
|
+
expect(exports.DatametriaAvatar).toBeDefined()
|
|
27
|
+
expect(exports.DatametriaBadge).toBeDefined()
|
|
28
|
+
expect(exports.DatametriaChip).toBeDefined()
|
|
29
|
+
expect(exports.DatametriaNavbar).toBeDefined()
|
|
30
|
+
expect(exports.DatametriaBreadcrumb).toBeDefined()
|
|
31
|
+
expect(exports.DatametriaTabs).toBeDefined()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('exports all composables', () => {
|
|
35
|
+
expect(exports.useTheme).toBeDefined()
|
|
36
|
+
expect(exports.useValidation).toBeDefined()
|
|
37
|
+
expect(exports.useAPI).toBeDefined()
|
|
38
|
+
expect(exports.useLocalStorage).toBeDefined()
|
|
39
|
+
expect(exports.useDebounce).toBeDefined()
|
|
40
|
+
expect(exports.useClipboard).toBeDefined()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Types são apenas TypeScript, não valores JavaScript exportáveis
|
|
44
|
+
it('exports types (TypeScript only)', () => {
|
|
45
|
+
// Types não podem ser testados em runtime
|
|
46
|
+
expect(true).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -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
|
}
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
import { ref, onMounted, onUnmounted } from 'vue'
|
|
2
|
-
|
|
3
|
-
export const breakpoints = {
|
|
4
|
-
xs: 475,
|
|
5
|
-
sm: 640,
|
|
6
|
-
md: 768,
|
|
7
|
-
lg: 1024,
|
|
8
|
-
xl: 1280,
|
|
9
|
-
'2xl': 1536
|
|
10
|
-
} as const
|
|
11
|
-
|
|
12
|
-
export type Breakpoint = keyof typeof breakpoints
|
|
13
|
-
|
|
14
|
-
export function useBreakpoints() {
|
|
15
|
-
const windowWidth = ref(0)
|
|
16
|
-
|
|
17
|
-
const updateWidth = () => {
|
|
18
|
-
windowWidth.value = window.innerWidth
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const isGreaterOrEqual = (breakpoint: Breakpoint) => {
|
|
22
|
-
return windowWidth.value >= breakpoints[breakpoint]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const isLessOrEqual = (breakpoint: Breakpoint) => {
|
|
26
|
-
return windowWidth.value <= breakpoints[breakpoint]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const isBetween = (min: Breakpoint, max: Breakpoint) => {
|
|
30
|
-
return windowWidth.value >= breakpoints[min] && windowWidth.value <= breakpoints[max]
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const getCurrentBreakpoint = (): Breakpoint => {
|
|
34
|
-
const width = windowWidth.value
|
|
35
|
-
|
|
36
|
-
if (width >= breakpoints['2xl']) return '2xl'
|
|
37
|
-
if (width >= breakpoints.xl) return 'xl'
|
|
38
|
-
if (width >= breakpoints.lg) return 'lg'
|
|
39
|
-
if (width >= breakpoints.md) return 'md'
|
|
40
|
-
if (width >= breakpoints.sm) return 'sm'
|
|
41
|
-
return 'xs'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Reactive breakpoint checks
|
|
45
|
-
const isXs = () => windowWidth.value < breakpoints.sm
|
|
46
|
-
const isSm = () => isGreaterOrEqual('sm') && windowWidth.value < breakpoints.md
|
|
47
|
-
const isMd = () => isGreaterOrEqual('md') && windowWidth.value < breakpoints.lg
|
|
48
|
-
const isLg = () => isGreaterOrEqual('lg') && windowWidth.value < breakpoints.xl
|
|
49
|
-
const isXl = () => isGreaterOrEqual('xl') && windowWidth.value < breakpoints['2xl']
|
|
50
|
-
const is2xl = () => isGreaterOrEqual('2xl')
|
|
51
|
-
|
|
52
|
-
// Mobile/tablet/desktop helpers
|
|
53
|
-
const isMobile = () => windowWidth.value < breakpoints.md
|
|
54
|
-
const isTablet = () => isBetween('md', 'lg')
|
|
55
|
-
const isDesktop = () => isGreaterOrEqual('lg')
|
|
56
|
-
|
|
57
|
-
onMounted(() => {
|
|
58
|
-
updateWidth()
|
|
59
|
-
window.addEventListener('resize', updateWidth)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
onUnmounted(() => {
|
|
63
|
-
window.removeEventListener('resize', updateWidth)
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
windowWidth,
|
|
68
|
-
breakpoints,
|
|
69
|
-
isGreaterOrEqual,
|
|
70
|
-
isLessOrEqual,
|
|
71
|
-
isBetween,
|
|
72
|
-
getCurrentBreakpoint,
|
|
73
|
-
isXs,
|
|
74
|
-
isSm,
|
|
75
|
-
isMd,
|
|
76
|
-
isLg,
|
|
77
|
-
isXl,
|
|
78
|
-
is2xl,
|
|
79
|
-
isMobile,
|
|
80
|
-
isTablet,
|
|
81
|
-
isDesktop
|
|
82
|
-
}
|
|
1
|
+
import { ref, onMounted, onUnmounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
export const breakpoints = {
|
|
4
|
+
xs: 475,
|
|
5
|
+
sm: 640,
|
|
6
|
+
md: 768,
|
|
7
|
+
lg: 1024,
|
|
8
|
+
xl: 1280,
|
|
9
|
+
'2xl': 1536
|
|
10
|
+
} as const
|
|
11
|
+
|
|
12
|
+
export type Breakpoint = keyof typeof breakpoints
|
|
13
|
+
|
|
14
|
+
export function useBreakpoints() {
|
|
15
|
+
const windowWidth = ref(0)
|
|
16
|
+
|
|
17
|
+
const updateWidth = () => {
|
|
18
|
+
windowWidth.value = window.innerWidth
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const isGreaterOrEqual = (breakpoint: Breakpoint) => {
|
|
22
|
+
return windowWidth.value >= breakpoints[breakpoint]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const isLessOrEqual = (breakpoint: Breakpoint) => {
|
|
26
|
+
return windowWidth.value <= breakpoints[breakpoint]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isBetween = (min: Breakpoint, max: Breakpoint) => {
|
|
30
|
+
return windowWidth.value >= breakpoints[min] && windowWidth.value <= breakpoints[max]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const getCurrentBreakpoint = (): Breakpoint => {
|
|
34
|
+
const width = windowWidth.value
|
|
35
|
+
|
|
36
|
+
if (width >= breakpoints['2xl']) return '2xl'
|
|
37
|
+
if (width >= breakpoints.xl) return 'xl'
|
|
38
|
+
if (width >= breakpoints.lg) return 'lg'
|
|
39
|
+
if (width >= breakpoints.md) return 'md'
|
|
40
|
+
if (width >= breakpoints.sm) return 'sm'
|
|
41
|
+
return 'xs'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Reactive breakpoint checks
|
|
45
|
+
const isXs = () => windowWidth.value < breakpoints.sm
|
|
46
|
+
const isSm = () => isGreaterOrEqual('sm') && windowWidth.value < breakpoints.md
|
|
47
|
+
const isMd = () => isGreaterOrEqual('md') && windowWidth.value < breakpoints.lg
|
|
48
|
+
const isLg = () => isGreaterOrEqual('lg') && windowWidth.value < breakpoints.xl
|
|
49
|
+
const isXl = () => isGreaterOrEqual('xl') && windowWidth.value < breakpoints['2xl']
|
|
50
|
+
const is2xl = () => isGreaterOrEqual('2xl')
|
|
51
|
+
|
|
52
|
+
// Mobile/tablet/desktop helpers
|
|
53
|
+
const isMobile = () => windowWidth.value < breakpoints.md
|
|
54
|
+
const isTablet = () => isBetween('md', 'lg')
|
|
55
|
+
const isDesktop = () => isGreaterOrEqual('lg')
|
|
56
|
+
|
|
57
|
+
onMounted(() => {
|
|
58
|
+
updateWidth()
|
|
59
|
+
window.addEventListener('resize', updateWidth)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
onUnmounted(() => {
|
|
63
|
+
window.removeEventListener('resize', updateWidth)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
windowWidth,
|
|
68
|
+
breakpoints,
|
|
69
|
+
isGreaterOrEqual,
|
|
70
|
+
isLessOrEqual,
|
|
71
|
+
isBetween,
|
|
72
|
+
getCurrentBreakpoint,
|
|
73
|
+
isXs,
|
|
74
|
+
isSm,
|
|
75
|
+
isMd,
|
|
76
|
+
isLg,
|
|
77
|
+
isXl,
|
|
78
|
+
is2xl,
|
|
79
|
+
isMobile,
|
|
80
|
+
isTablet,
|
|
81
|
+
isDesktop
|
|
82
|
+
}
|
|
83
83
|
}
|