@datametria/vue-components 1.1.3 → 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 -590
  2. package/dist/index.es.js +2460 -1440
  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 +38 -24
  7. package/src/components/DatametriaAutocomplete.vue +184 -138
  8. package/src/components/DatametriaAvatar.vue +177 -33
  9. package/src/components/DatametriaBadge.vue +31 -23
  10. package/src/components/DatametriaBreadcrumb.vue +21 -21
  11. package/src/components/DatametriaButton.vue +38 -18
  12. package/src/components/DatametriaCard.vue +12 -12
  13. package/src/components/DatametriaCheckbox.vue +8 -8
  14. package/src/components/DatametriaChip.vue +29 -33
  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 +57 -54
  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 +32 -19
  37. package/src/components/DatametriaTooltip.vue +408 -408
  38. package/src/components/__tests__/DatametriaAlert.test.js +36 -0
  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 +30 -0
  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 +31 -0
  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 +39 -0
  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 +49 -0
  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 +49 -0
  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 +96 -0
  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
@@ -1,286 +1,286 @@
1
- <template>
2
- <div class="dm-time-picker" :class="{ 'dm-time-picker--disabled': disabled }">
3
- <label v-if="label" :for="inputId" class="dm-time-picker__label">
4
- {{ label }}
5
- <span v-if="required" class="dm-time-picker__required" aria-label="obrigatório">*</span>
6
- </label>
7
-
8
- <div class="dm-time-picker__wrapper">
9
- <input
10
- :id="inputId"
11
- ref="inputRef"
12
- v-model="displayValue"
13
- type="time"
14
- class="dm-time-picker__input"
15
- :class="{
16
- 'dm-time-picker__input--error': hasError,
17
- 'dm-time-picker__input--success': hasSuccess
18
- }"
19
- :disabled="disabled"
20
- :required="required"
21
- :min="min"
22
- :max="max"
23
- :step="step"
24
- :aria-describedby="ariaDescribedBy"
25
- :aria-invalid="hasError"
26
- @input="handleInput"
27
- @blur="handleBlur"
28
- @focus="handleFocus"
29
- />
30
-
31
- <div v-if="hasError || hasSuccess" class="dm-time-picker__icon">
32
- <svg v-if="hasError" class="dm-time-picker__icon--error" viewBox="0 0 20 20" fill="currentColor">
33
- <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
34
- </svg>
35
- <svg v-else-if="hasSuccess" class="dm-time-picker__icon--success" viewBox="0 0 20 20" fill="currentColor">
36
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
37
- </svg>
38
- </div>
39
- </div>
40
-
41
- <div v-if="errorMessage || successMessage || helperText" class="dm-time-picker__messages">
42
- <p v-if="errorMessage" :id="`${inputId}-error`" class="dm-time-picker__error" role="alert">
43
- {{ errorMessage }}
44
- </p>
45
- <p v-else-if="successMessage" :id="`${inputId}-success`" class="dm-time-picker__success">
46
- {{ successMessage }}
47
- </p>
48
- <p v-else-if="helperText" :id="`${inputId}-helper`" class="dm-time-picker__helper">
49
- {{ helperText }}
50
- </p>
51
- </div>
52
- </div>
53
- </template>
54
-
55
- <script setup lang="ts">
56
- import { ref, computed, watch, nextTick } from 'vue'
57
-
58
- interface Props {
59
- modelValue?: string
60
- label?: string
61
- placeholder?: string
62
- disabled?: boolean
63
- required?: boolean
64
- errorMessage?: string
65
- successMessage?: string
66
- helperText?: string
67
- min?: string
68
- max?: string
69
- step?: number
70
- format24h?: boolean
71
- }
72
-
73
- interface Emits {
74
- (e: 'update:modelValue', value: string): void
75
- (e: 'blur', event: FocusEvent): void
76
- (e: 'focus', event: FocusEvent): void
77
- (e: 'change', value: string): void
78
- }
79
-
80
- const props = withDefaults(defineProps<Props>(), {
81
- modelValue: '',
82
- step: 60,
83
- format24h: true
84
- })
85
-
86
- const emit = defineEmits<Emits>()
87
-
88
- // Refs
89
- const inputRef = ref<HTMLInputElement>()
90
-
91
- // Computed
92
- const inputId = computed(() => `dm-time-picker-${Math.random().toString(36).substr(2, 9)}`)
93
-
94
- const hasError = computed(() => !!props.errorMessage)
95
- const hasSuccess = computed(() => !!props.successMessage && !hasError.value)
96
-
97
- const ariaDescribedBy = computed(() => {
98
- const ids = []
99
- if (props.errorMessage) ids.push(`${inputId.value}-error`)
100
- else if (props.successMessage) ids.push(`${inputId.value}-success`)
101
- else if (props.helperText) ids.push(`${inputId.value}-helper`)
102
- return ids.length > 0 ? ids.join(' ') : undefined
103
- })
104
-
105
- const displayValue = computed({
106
- get: () => props.modelValue,
107
- set: (value: string) => {
108
- emit('update:modelValue', value)
109
- emit('change', value)
110
- }
111
- })
112
-
113
- // Methods
114
- const handleInput = (event: Event) => {
115
- const target = event.target as HTMLInputElement
116
- displayValue.value = target.value
117
- }
118
-
119
- const handleBlur = (event: FocusEvent) => {
120
- emit('blur', event)
121
- }
122
-
123
- const handleFocus = (event: FocusEvent) => {
124
- emit('focus', event)
125
- }
126
-
127
- const focus = () => {
128
- nextTick(() => {
129
- inputRef.value?.focus()
130
- })
131
- }
132
-
133
- const blur = () => {
134
- inputRef.value?.blur()
135
- }
136
-
137
- // Watch for external changes
138
- watch(() => props.modelValue, (newValue) => {
139
- if (inputRef.value && inputRef.value.value !== newValue) {
140
- inputRef.value.value = newValue
141
- }
142
- })
143
-
144
- // Expose methods
145
- defineExpose({
146
- focus,
147
- blur,
148
- inputRef
149
- })
150
- </script>
151
-
152
- <style scoped>
153
- .dm-time-picker {
154
- @apply w-full;
155
- }
156
-
157
- .dm-time-picker--disabled {
158
- @apply opacity-60 cursor-not-allowed;
159
- }
160
-
161
- .dm-time-picker__label {
162
- @apply block text-sm font-medium text-gray-700 mb-1;
163
- color: var(--dm-gray-700);
164
- }
165
-
166
- [data-theme="dark"] .dm-time-picker__label {
167
- color: var(--dm-text-secondary);
168
- }
169
-
170
- .dm-time-picker__required {
171
- @apply text-red-500 ml-1;
172
- color: var(--dm-error);
173
- }
174
-
175
- .dm-time-picker__wrapper {
176
- @apply relative;
177
- }
178
-
179
- .dm-time-picker__input {
180
- @apply w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm;
181
- @apply focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500;
182
- @apply disabled:bg-gray-50 disabled:cursor-not-allowed;
183
- @apply transition-colors duration-200;
184
-
185
- border-color: var(--dm-gray-300, #d1d5db);
186
- background-color: var(--dm-bg-primary, #ffffff);
187
- color: var(--dm-text-primary);
188
- border-radius: var(--dm-radius);
189
- transition: var(--dm-transition);
190
- }
191
-
192
- .dm-time-picker__input:focus {
193
- box-shadow: var(--dm-focus-ring);
194
- border-color: var(--dm-primary);
195
- }
196
-
197
- .dm-time-picker__input--error {
198
- @apply border-red-500 focus:ring-red-500 focus:border-red-500;
199
- border-color: var(--dm-error);
200
- }
201
-
202
- .dm-time-picker__input--error:focus {
203
- box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
204
- }
205
-
206
- .dm-time-picker__input--success {
207
- @apply border-green-500 focus:ring-green-500 focus:border-green-500;
208
- border-color: var(--dm-success);
209
- }
210
-
211
- .dm-time-picker__input--success:focus {
212
- box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
213
- }
214
-
215
- [data-theme="dark"] .dm-time-picker__input {
216
- background-color: var(--dm-bg-secondary);
217
- border-color: var(--dm-gray-600, #4b5563);
218
- color: var(--dm-text-primary);
219
- }
220
-
221
- [data-theme="dark"] .dm-time-picker__input:disabled {
222
- background-color: var(--dm-gray-700, #374151);
223
- }
224
-
225
- .dm-time-picker__icon {
226
- @apply absolute right-3 top-1/2 transform -translate-y-1/2 pointer-events-none;
227
- }
228
-
229
- .dm-time-picker__icon--error {
230
- @apply w-5 h-5 text-red-500;
231
- color: var(--dm-error);
232
- }
233
-
234
- .dm-time-picker__icon--success {
235
- @apply w-5 h-5 text-green-500;
236
- color: var(--dm-success);
237
- }
238
-
239
- .dm-time-picker__messages {
240
- @apply mt-1;
241
- }
242
-
243
- .dm-time-picker__error {
244
- @apply text-sm text-red-600;
245
- color: var(--dm-error);
246
- }
247
-
248
- .dm-time-picker__success {
249
- @apply text-sm text-green-600;
250
- color: var(--dm-success);
251
- }
252
-
253
- .dm-time-picker__helper {
254
- @apply text-sm text-gray-500;
255
- color: var(--dm-gray-500, #6b7280);
256
- }
257
-
258
- [data-theme="dark"] .dm-time-picker__helper {
259
- color: var(--dm-text-secondary);
260
- }
261
-
262
- /* Responsive adjustments */
263
- @media (max-width: 640px) {
264
- .dm-time-picker__input {
265
- @apply text-base; /* Prevent zoom on iOS */
266
- }
267
- }
268
-
269
- /* High contrast mode support */
270
- @media (prefers-contrast: high) {
271
- .dm-time-picker__input {
272
- @apply border-2;
273
- }
274
-
275
- .dm-time-picker__input:focus {
276
- @apply border-4;
277
- }
278
- }
279
-
280
- /* Reduced motion support */
281
- @media (prefers-reduced-motion: reduce) {
282
- .dm-time-picker__input {
283
- @apply transition-none;
284
- }
285
- }
1
+ <template>
2
+ <div class="dm-time-picker" :class="{ 'dm-time-picker--disabled': disabled }">
3
+ <label v-if="label" :for="inputId" class="dm-time-picker__label">
4
+ {{ label }}
5
+ <span v-if="required" class="dm-time-picker__required" aria-label="obrigatório">*</span>
6
+ </label>
7
+
8
+ <div class="dm-time-picker__wrapper">
9
+ <input
10
+ :id="inputId"
11
+ ref="inputRef"
12
+ v-model="displayValue"
13
+ type="time"
14
+ class="dm-time-picker__input"
15
+ :class="{
16
+ 'dm-time-picker__input--error': hasError,
17
+ 'dm-time-picker__input--success': hasSuccess
18
+ }"
19
+ :disabled="disabled"
20
+ :required="required"
21
+ :min="min"
22
+ :max="max"
23
+ :step="step"
24
+ :aria-describedby="ariaDescribedBy"
25
+ :aria-invalid="hasError"
26
+ @input="handleInput"
27
+ @blur="handleBlur"
28
+ @focus="handleFocus"
29
+ />
30
+
31
+ <div v-if="hasError || hasSuccess" class="dm-time-picker__icon">
32
+ <svg v-if="hasError" class="dm-time-picker__icon--error" viewBox="0 0 20 20" fill="currentColor">
33
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
34
+ </svg>
35
+ <svg v-else-if="hasSuccess" class="dm-time-picker__icon--success" viewBox="0 0 20 20" fill="currentColor">
36
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
37
+ </svg>
38
+ </div>
39
+ </div>
40
+
41
+ <div v-if="errorMessage || successMessage || helperText" class="dm-time-picker__messages">
42
+ <p v-if="errorMessage" :id="`${inputId}-error`" class="dm-time-picker__error" role="alert">
43
+ {{ errorMessage }}
44
+ </p>
45
+ <p v-else-if="successMessage" :id="`${inputId}-success`" class="dm-time-picker__success">
46
+ {{ successMessage }}
47
+ </p>
48
+ <p v-else-if="helperText" :id="`${inputId}-helper`" class="dm-time-picker__helper">
49
+ {{ helperText }}
50
+ </p>
51
+ </div>
52
+ </div>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ import { ref, computed, watch, nextTick } from 'vue'
57
+
58
+ interface Props {
59
+ modelValue?: string
60
+ label?: string
61
+ placeholder?: string
62
+ disabled?: boolean
63
+ required?: boolean
64
+ errorMessage?: string
65
+ successMessage?: string
66
+ helperText?: string
67
+ min?: string
68
+ max?: string
69
+ step?: number
70
+ format24h?: boolean
71
+ }
72
+
73
+ interface Emits {
74
+ (e: 'update:modelValue', value: string): void
75
+ (e: 'blur', event: FocusEvent): void
76
+ (e: 'focus', event: FocusEvent): void
77
+ (e: 'change', value: string): void
78
+ }
79
+
80
+ const props = withDefaults(defineProps<Props>(), {
81
+ modelValue: '',
82
+ step: 60,
83
+ format24h: true
84
+ })
85
+
86
+ const emit = defineEmits<Emits>()
87
+
88
+ // Refs
89
+ const inputRef = ref<HTMLInputElement>()
90
+
91
+ // Computed
92
+ const inputId = computed(() => `dm-time-picker-${Math.random().toString(36).substr(2, 9)}`)
93
+
94
+ const hasError = computed(() => !!props.errorMessage)
95
+ const hasSuccess = computed(() => !!props.successMessage && !hasError.value)
96
+
97
+ const ariaDescribedBy = computed(() => {
98
+ const ids = []
99
+ if (props.errorMessage) ids.push(`${inputId.value}-error`)
100
+ else if (props.successMessage) ids.push(`${inputId.value}-success`)
101
+ else if (props.helperText) ids.push(`${inputId.value}-helper`)
102
+ return ids.length > 0 ? ids.join(' ') : undefined
103
+ })
104
+
105
+ const displayValue = computed({
106
+ get: () => props.modelValue,
107
+ set: (value: string) => {
108
+ emit('update:modelValue', value)
109
+ emit('change', value)
110
+ }
111
+ })
112
+
113
+ // Methods
114
+ const handleInput = (event: Event) => {
115
+ const target = event.target as HTMLInputElement
116
+ displayValue.value = target.value
117
+ }
118
+
119
+ const handleBlur = (event: FocusEvent) => {
120
+ emit('blur', event)
121
+ }
122
+
123
+ const handleFocus = (event: FocusEvent) => {
124
+ emit('focus', event)
125
+ }
126
+
127
+ const focus = () => {
128
+ nextTick(() => {
129
+ inputRef.value?.focus()
130
+ })
131
+ }
132
+
133
+ const blur = () => {
134
+ inputRef.value?.blur()
135
+ }
136
+
137
+ // Watch for external changes
138
+ watch(() => props.modelValue, (newValue) => {
139
+ if (inputRef.value && inputRef.value.value !== newValue) {
140
+ inputRef.value.value = newValue
141
+ }
142
+ })
143
+
144
+ // Expose methods
145
+ defineExpose({
146
+ focus,
147
+ blur,
148
+ inputRef
149
+ })
150
+ </script>
151
+
152
+ <style scoped>
153
+ .dm-time-picker {
154
+ @apply w-full;
155
+ }
156
+
157
+ .dm-time-picker--disabled {
158
+ @apply opacity-60 cursor-not-allowed;
159
+ }
160
+
161
+ .dm-time-picker__label {
162
+ @apply block text-sm font-medium text-gray-700 mb-1;
163
+ color: var(--dm-gray-700);
164
+ }
165
+
166
+ [data-theme="dark"] .dm-time-picker__label {
167
+ color: var(--dm-text-secondary);
168
+ }
169
+
170
+ .dm-time-picker__required {
171
+ @apply text-red-500 ml-1;
172
+ color: var(--dm-error);
173
+ }
174
+
175
+ .dm-time-picker__wrapper {
176
+ @apply relative;
177
+ }
178
+
179
+ .dm-time-picker__input {
180
+ @apply w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm;
181
+ @apply focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500;
182
+ @apply disabled:bg-gray-50 disabled:cursor-not-allowed;
183
+ @apply transition-colors duration-200;
184
+
185
+ border-color: var(--dm-gray-300, #d1d5db);
186
+ background-color: var(--dm-bg-primary, #ffffff);
187
+ color: var(--dm-text-primary);
188
+ border-radius: var(--dm-radius);
189
+ transition: var(--dm-transition);
190
+ }
191
+
192
+ .dm-time-picker__input:focus {
193
+ box-shadow: var(--dm-focus-ring);
194
+ border-color: var(--dm-primary);
195
+ }
196
+
197
+ .dm-time-picker__input--error {
198
+ @apply border-red-500 focus:ring-red-500 focus:border-red-500;
199
+ border-color: var(--dm-error);
200
+ }
201
+
202
+ .dm-time-picker__input--error:focus {
203
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
204
+ }
205
+
206
+ .dm-time-picker__input--success {
207
+ @apply border-green-500 focus:ring-green-500 focus:border-green-500;
208
+ border-color: var(--dm-success);
209
+ }
210
+
211
+ .dm-time-picker__input--success:focus {
212
+ box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
213
+ }
214
+
215
+ [data-theme="dark"] .dm-time-picker__input {
216
+ background-color: var(--dm-bg-secondary);
217
+ border-color: var(--dm-gray-600, #4b5563);
218
+ color: var(--dm-text-primary);
219
+ }
220
+
221
+ [data-theme="dark"] .dm-time-picker__input:disabled {
222
+ background-color: var(--dm-gray-700, #374151);
223
+ }
224
+
225
+ .dm-time-picker__icon {
226
+ @apply absolute right-3 top-1/2 transform -translate-y-1/2 pointer-events-none;
227
+ }
228
+
229
+ .dm-time-picker__icon--error {
230
+ @apply w-5 h-5 text-red-500;
231
+ color: var(--dm-error);
232
+ }
233
+
234
+ .dm-time-picker__icon--success {
235
+ @apply w-5 h-5 text-green-500;
236
+ color: var(--dm-success);
237
+ }
238
+
239
+ .dm-time-picker__messages {
240
+ @apply mt-1;
241
+ }
242
+
243
+ .dm-time-picker__error {
244
+ @apply text-sm text-red-600;
245
+ color: var(--dm-error);
246
+ }
247
+
248
+ .dm-time-picker__success {
249
+ @apply text-sm text-green-600;
250
+ color: var(--dm-success);
251
+ }
252
+
253
+ .dm-time-picker__helper {
254
+ @apply text-sm text-gray-500;
255
+ color: var(--dm-gray-500, #6b7280);
256
+ }
257
+
258
+ [data-theme="dark"] .dm-time-picker__helper {
259
+ color: var(--dm-text-secondary);
260
+ }
261
+
262
+ /* Responsive adjustments */
263
+ @media (max-width: 640px) {
264
+ .dm-time-picker__input {
265
+ @apply text-base; /* Prevent zoom on iOS */
266
+ }
267
+ }
268
+
269
+ /* High contrast mode support */
270
+ @media (prefers-contrast: high) {
271
+ .dm-time-picker__input {
272
+ @apply border-2;
273
+ }
274
+
275
+ .dm-time-picker__input:focus {
276
+ @apply border-4;
277
+ }
278
+ }
279
+
280
+ /* Reduced motion support */
281
+ @media (prefers-reduced-motion: reduce) {
282
+ .dm-time-picker__input {
283
+ @apply transition-none;
284
+ }
285
+ }
286
286
  </style>
@@ -27,7 +27,7 @@ import { ref, watch, onMounted } from 'vue'
27
27
 
28
28
  interface Props {
29
29
  message: string
30
- variant?: 'success' | 'error' | 'warning' | 'info'
30
+ variant?: 'success' | 'error' | 'warning' | 'info' | 'primary'
31
31
  duration?: number
32
32
  closable?: boolean
33
33
  modelValue?: boolean
@@ -40,6 +40,14 @@ const props = withDefaults(defineProps<Props>(), {
40
40
  modelValue: false
41
41
  })
42
42
 
43
+ // Validação em desenvolvimento
44
+ if (process.env.NODE_ENV === 'development') {
45
+ const validVariants = ['success', 'error', 'warning', 'info', 'primary']
46
+ if (!validVariants.includes(props.variant)) {
47
+ console.warn(`[DatametriaToast] Invalid variant "${props.variant}". Valid options: ${validVariants.join(', ')}`)
48
+ }
49
+ }
50
+
43
51
  const emit = defineEmits<{
44
52
  'update:modelValue': [value: boolean]
45
53
  close: []
@@ -79,45 +87,50 @@ onMounted(() => {
79
87
  <style scoped>
80
88
  .dm-toast {
81
89
  position: fixed;
82
- top: var(--dm-space-4);
83
- right: var(--dm-space-4);
90
+ top: var(--dm-spacing-4, 1rem);
91
+ right: var(--dm-spacing-4, 1rem);
84
92
  min-width: 300px;
85
93
  max-width: 500px;
86
- padding: var(--dm-space-4);
87
- border-radius: var(--dm-radius);
88
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
94
+ padding: var(--dm-spacing-4, 1rem);
95
+ border-radius: var(--dm-radius-md, 0.375rem);
96
+ box-shadow: var(--dm-shadow-lg, 0 4px 12px rgba(0, 0, 0, 0.15));
89
97
  z-index: 9999;
90
98
  }
91
99
 
92
100
  .dm-toast--success {
93
- background: var(--dm-success);
94
- color: var(--dm-white);
101
+ background: var(--dm-success, #10b981);
102
+ color: white;
95
103
  }
96
104
 
97
105
  .dm-toast--error {
98
- background: var(--dm-error);
99
- color: var(--dm-white);
106
+ background: var(--dm-error, #ef4444);
107
+ color: white;
100
108
  }
101
109
 
102
110
  .dm-toast--warning {
103
- background: var(--dm-warning);
104
- color: var(--dm-gray-900);
111
+ background: var(--dm-warning, #f59e0b);
112
+ color: var(--dm-neutral-900, #111827);
113
+ }
114
+
115
+ .dm-toast--primary {
116
+ background: var(--dm-primary, #0072CE);
117
+ color: white;
105
118
  }
106
119
 
107
120
  .dm-toast--info {
108
- background: var(--dm-primary);
109
- color: var(--dm-white);
121
+ background: var(--dm-neutral-600, #4b5563);
122
+ color: white;
110
123
  }
111
124
 
112
125
  .dm-toast__content {
113
126
  display: flex;
114
127
  align-items: center;
115
- gap: var(--dm-space-3);
128
+ gap: var(--dm-spacing-3, 0.75rem);
116
129
  }
117
130
 
118
131
  .dm-toast__message {
119
132
  flex: 1;
120
- font-size: var(--dm-text-sm);
133
+ font-size: var(--dm-font-size-sm, 0.875rem);
121
134
  line-height: 1.5;
122
135
  }
123
136
 
@@ -131,7 +144,7 @@ onMounted(() => {
131
144
  line-height: 1;
132
145
  cursor: pointer;
133
146
  opacity: 0.8;
134
- transition: var(--dm-transition);
147
+ transition: all 0.2s;
135
148
  }
136
149
 
137
150
  .dm-toast__close:hover {
@@ -155,8 +168,8 @@ onMounted(() => {
155
168
 
156
169
  @media (max-width: 640px) {
157
170
  .dm-toast {
158
- left: var(--dm-space-4);
159
- right: var(--dm-space-4);
171
+ left: var(--dm-spacing-4, 1rem);
172
+ right: var(--dm-spacing-4, 1rem);
160
173
  min-width: auto;
161
174
  }
162
175
  }