@datametria/vue-components 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +25 -7
  2. package/dist/index.es.js +3378 -2148
  3. package/dist/index.umd.js +9 -9
  4. package/dist/src/components/DatametriaAutocomplete.vue.d.ts +14 -17
  5. package/dist/src/components/DatametriaBreadcrumb.vue.d.ts +39 -7
  6. package/dist/src/components/DatametriaCheckbox.vue.d.ts +35 -6
  7. package/dist/src/components/DatametriaCheckboxGroup.vue.d.ts +30 -0
  8. package/dist/src/components/DatametriaDataTable.vue.d.ts +64 -0
  9. package/dist/src/components/DatametriaDatePicker.vue.d.ts +15 -37
  10. package/dist/src/components/DatametriaDialog.vue.d.ts +71 -0
  11. package/dist/src/components/DatametriaEmpty.vue.d.ts +30 -0
  12. package/dist/src/components/DatametriaFloatingBar.vue.d.ts +2 -2
  13. package/dist/src/components/DatametriaForm.vue.d.ts +40 -0
  14. package/dist/src/components/DatametriaFormItem.vue.d.ts +28 -0
  15. package/dist/src/components/DatametriaGrid.vue.d.ts +1 -1
  16. package/dist/src/components/DatametriaInput.vue.d.ts +69 -10
  17. package/dist/src/components/DatametriaMenu.vue.d.ts +3 -3
  18. package/dist/src/components/DatametriaNavbar.vue.d.ts +2 -2
  19. package/dist/src/components/DatametriaPagination.vue.d.ts +29 -0
  20. package/dist/src/components/DatametriaPopconfirm.vue.d.ts +43 -0
  21. package/dist/src/components/DatametriaProgress.vue.d.ts +33 -8
  22. package/dist/src/components/DatametriaRadio.vue.d.ts +25 -6
  23. package/dist/src/components/DatametriaRadioGroup.vue.d.ts +29 -0
  24. package/dist/src/components/DatametriaResult.vue.d.ts +30 -0
  25. package/dist/src/components/DatametriaSelect.vue.d.ts +16 -11
  26. package/dist/src/components/DatametriaSidebar.vue.d.ts +3 -3
  27. package/dist/src/components/DatametriaSlider.vue.d.ts +3 -3
  28. package/dist/src/components/DatametriaSortableTable.vue.d.ts +1 -1
  29. package/dist/src/components/DatametriaSteps.vue.d.ts +45 -0
  30. package/dist/src/components/DatametriaSwitch.vue.d.ts +9 -4
  31. package/dist/src/components/DatametriaTabPane.vue.d.ts +28 -0
  32. package/dist/src/components/DatametriaTextarea.vue.d.ts +27 -8
  33. package/dist/src/components/DatametriaTimePicker.vue.d.ts +17 -25
  34. package/dist/src/components/DatametriaToast.vue.d.ts +1 -1
  35. package/dist/src/components/DatametriaTooltip.vue.d.ts +1 -1
  36. package/dist/src/components/DatametriaTree.vue.d.ts +31 -0
  37. package/dist/src/components/DatametriaTreeNode.vue.d.ts +17 -0
  38. package/dist/src/components/DatametriaUpload.vue.d.ts +64 -0
  39. package/dist/src/index.d.ts +14 -0
  40. package/dist/vue-components.css +1 -1
  41. package/package.json +4 -3
  42. package/src/components/DatametriaAutocomplete.vue +155 -260
  43. package/src/components/DatametriaBreadcrumb.vue +66 -80
  44. package/src/components/DatametriaCheckbox.vue +150 -37
  45. package/src/components/DatametriaCheckboxGroup.vue +43 -0
  46. package/src/components/DatametriaDataTable.vue +304 -0
  47. package/src/components/DatametriaDatePicker.vue +238 -614
  48. package/src/components/DatametriaDialog.vue +295 -0
  49. package/src/components/DatametriaDropdown.vue +352 -0
  50. package/src/components/DatametriaEmpty.vue +153 -0
  51. package/src/components/DatametriaForm.vue +160 -0
  52. package/src/components/DatametriaFormItem.vue +181 -0
  53. package/src/components/DatametriaInput.vue +226 -63
  54. package/src/components/DatametriaPagination.vue +373 -0
  55. package/src/components/DatametriaPopconfirm.vue +236 -0
  56. package/src/components/DatametriaProgress.vue +176 -63
  57. package/src/components/DatametriaRadio.vue +83 -72
  58. package/src/components/DatametriaRadioGroup.vue +42 -0
  59. package/src/components/DatametriaResult.vue +133 -0
  60. package/src/components/DatametriaSelect.vue +172 -67
  61. package/src/components/DatametriaSortableTable.vue +35 -4
  62. package/src/components/DatametriaSteps.vue +314 -0
  63. package/src/components/DatametriaSwitch.vue +86 -80
  64. package/src/components/DatametriaTabPane.vue +82 -0
  65. package/src/components/DatametriaTextarea.vue +140 -100
  66. package/src/components/DatametriaTimePicker.vue +231 -214
  67. package/src/components/DatametriaTree.vue +124 -0
  68. package/src/components/DatametriaTreeNode.vue +174 -0
  69. package/src/components/DatametriaUpload.vue +365 -0
  70. package/src/index.ts +25 -11
  71. package/src/components/__tests__/DatametriaAutocomplete.test.ts +0 -180
  72. package/src/components/__tests__/DatametriaBreadcrumb.test.ts +0 -75
  73. package/src/components/__tests__/DatametriaCheckbox.test.ts +0 -47
  74. package/src/components/__tests__/DatametriaDatePicker.test.ts +0 -234
  75. package/src/components/__tests__/DatametriaProgress.test.ts +0 -90
  76. package/src/components/__tests__/DatametriaRadio.test.ts +0 -77
  77. package/src/components/__tests__/DatametriaSwitch.test.ts +0 -64
  78. package/src/components/__tests__/DatametriaTextarea.test.ts +0 -66
@@ -0,0 +1,295 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <Transition name="dialog-fade">
4
+ <div
5
+ v-if="modelValue"
6
+ class="datametria-dialog-overlay"
7
+ :class="{ 'datametria-dialog-overlay--modal': modal }"
8
+ @click="handleOverlayClick"
9
+ >
10
+ <div
11
+ class="datametria-dialog"
12
+ :class="dialogClasses"
13
+ :style="dialogStyles"
14
+ role="dialog"
15
+ aria-modal="true"
16
+ :aria-labelledby="titleId"
17
+ @click.stop
18
+ >
19
+ <!-- Header -->
20
+ <div v-if="$slots.header || title" class="datametria-dialog__header">
21
+ <slot name="header">
22
+ <h3 :id="titleId" class="datametria-dialog__title">{{ title }}</h3>
23
+ </slot>
24
+ <button
25
+ v-if="showClose"
26
+ class="datametria-dialog__close"
27
+ aria-label="Fechar"
28
+ @click="handleClose"
29
+ >
30
+ ×
31
+ </button>
32
+ </div>
33
+
34
+ <!-- Body -->
35
+ <div class="datametria-dialog__body">
36
+ <slot />
37
+ </div>
38
+
39
+ <!-- Footer -->
40
+ <div v-if="$slots.footer" class="datametria-dialog__footer">
41
+ <slot name="footer" />
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </Transition>
46
+ </Teleport>
47
+ </template>
48
+
49
+ <script setup lang="ts">
50
+ import { computed, watch, onMounted, onUnmounted } from 'vue'
51
+
52
+ /**
53
+ * DatametriaDialog - Modal/Dialog reutilizável com slots customizáveis
54
+ *
55
+ * @component
56
+ * @example
57
+ * <DatametriaDialog v-model="visible" title="Título">
58
+ * Conteúdo do dialog
59
+ * </DatametriaDialog>
60
+ */
61
+
62
+ interface Props {
63
+ /** Controla visibilidade do dialog */
64
+ modelValue: boolean
65
+ /** Título do dialog */
66
+ title?: string
67
+ /** Largura do dialog (px, %, vw) */
68
+ width?: string | number
69
+ /** Dialog em tela cheia */
70
+ fullscreen?: boolean
71
+ /** Exibir overlay modal */
72
+ modal?: boolean
73
+ /** Fechar ao clicar no overlay */
74
+ closeOnClickModal?: boolean
75
+ /** Fechar ao pressionar ESC */
76
+ closeOnPressEscape?: boolean
77
+ /** Exibir botão de fechar */
78
+ showClose?: boolean
79
+ /** Centralizar conteúdo */
80
+ center?: boolean
81
+ /** Callback antes de fechar */
82
+ beforeClose?: (done: () => void) => void
83
+ }
84
+
85
+ const props = withDefaults(defineProps<Props>(), {
86
+ title: '',
87
+ width: '50%',
88
+ fullscreen: false,
89
+ modal: true,
90
+ closeOnClickModal: true,
91
+ closeOnPressEscape: true,
92
+ showClose: true,
93
+ center: false
94
+ })
95
+
96
+ const emit = defineEmits<{
97
+ 'update:modelValue': [value: boolean]
98
+ 'open': []
99
+ 'opened': []
100
+ 'close': []
101
+ 'closed': []
102
+ }>()
103
+
104
+ const titleId = `dialog-title-${Math.random().toString(36).substr(2, 9)}`
105
+
106
+ const dialogClasses = computed(() => ({
107
+ 'datametria-dialog--fullscreen': props.fullscreen,
108
+ 'datametria-dialog--center': props.center
109
+ }))
110
+
111
+ const dialogStyles = computed(() => {
112
+ if (props.fullscreen) return {}
113
+ return {
114
+ width: typeof props.width === 'number' ? `${props.width}px` : props.width
115
+ }
116
+ })
117
+
118
+ const handleClose = () => {
119
+ if (props.beforeClose) {
120
+ props.beforeClose(() => {
121
+ emit('update:modelValue', false)
122
+ emit('close')
123
+ })
124
+ } else {
125
+ emit('update:modelValue', false)
126
+ emit('close')
127
+ }
128
+ }
129
+
130
+ const handleOverlayClick = () => {
131
+ if (props.closeOnClickModal) {
132
+ handleClose()
133
+ }
134
+ }
135
+
136
+ const handleEscape = (e: KeyboardEvent) => {
137
+ if (e.key === 'Escape' && props.closeOnPressEscape && props.modelValue) {
138
+ handleClose()
139
+ }
140
+ }
141
+
142
+ watch(() => props.modelValue, (newVal) => {
143
+ if (newVal) {
144
+ emit('open')
145
+ document.body.style.overflow = 'hidden'
146
+ setTimeout(() => emit('opened'), 300)
147
+ } else {
148
+ document.body.style.overflow = ''
149
+ setTimeout(() => emit('closed'), 300)
150
+ }
151
+ })
152
+
153
+ onMounted(() => {
154
+ document.addEventListener('keydown', handleEscape)
155
+ })
156
+
157
+ onUnmounted(() => {
158
+ document.removeEventListener('keydown', handleEscape)
159
+ document.body.style.overflow = ''
160
+ })
161
+ </script>
162
+
163
+ <style scoped>
164
+ .datametria-dialog-overlay {
165
+ position: fixed;
166
+ top: 0;
167
+ left: 0;
168
+ right: 0;
169
+ bottom: 0;
170
+ z-index: 2000;
171
+ display: flex;
172
+ align-items: center;
173
+ justify-content: center;
174
+ padding: 20px;
175
+ }
176
+
177
+ .datametria-dialog-overlay--modal {
178
+ background-color: rgba(0, 0, 0, 0.5);
179
+ }
180
+
181
+ .datametria-dialog {
182
+ position: relative;
183
+ background: var(--color-background, #ffffff);
184
+ border-radius: 8px;
185
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
186
+ max-width: 90vw;
187
+ max-height: 90vh;
188
+ display: flex;
189
+ flex-direction: column;
190
+ overflow: hidden;
191
+ }
192
+
193
+ .datametria-dialog--fullscreen {
194
+ width: 100vw !important;
195
+ height: 100vh !important;
196
+ max-width: 100vw;
197
+ max-height: 100vh;
198
+ border-radius: 0;
199
+ }
200
+
201
+ .datametria-dialog__header {
202
+ padding: 20px;
203
+ border-bottom: 1px solid var(--color-border, #e5e7eb);
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: space-between;
207
+ }
208
+
209
+ .datametria-dialog__title {
210
+ margin: 0;
211
+ font-size: 18px;
212
+ font-weight: 600;
213
+ color: var(--color-text-primary, #1f2937);
214
+ }
215
+
216
+ .datametria-dialog__close {
217
+ background: none;
218
+ border: none;
219
+ font-size: 28px;
220
+ line-height: 1;
221
+ color: var(--color-text-secondary, #6b7280);
222
+ cursor: pointer;
223
+ padding: 0;
224
+ width: 32px;
225
+ height: 32px;
226
+ display: flex;
227
+ align-items: center;
228
+ justify-content: center;
229
+ border-radius: 4px;
230
+ transition: all 0.2s;
231
+ }
232
+
233
+ .datametria-dialog__close:hover {
234
+ background-color: var(--color-background-hover, #f3f4f6);
235
+ color: var(--color-text-primary, #1f2937);
236
+ }
237
+
238
+ .datametria-dialog__body {
239
+ padding: 20px;
240
+ flex: 1;
241
+ overflow-y: auto;
242
+ }
243
+
244
+ .datametria-dialog--center .datametria-dialog__body {
245
+ text-align: center;
246
+ }
247
+
248
+ .datametria-dialog__footer {
249
+ padding: 20px;
250
+ border-top: 1px solid var(--color-border, #e5e7eb);
251
+ display: flex;
252
+ justify-content: flex-end;
253
+ gap: 12px;
254
+ }
255
+
256
+ /* Transitions */
257
+ .dialog-fade-enter-active,
258
+ .dialog-fade-leave-active {
259
+ transition: opacity 0.3s;
260
+ }
261
+
262
+ .dialog-fade-enter-from,
263
+ .dialog-fade-leave-to {
264
+ opacity: 0;
265
+ }
266
+
267
+ .dialog-fade-enter-active .datametria-dialog,
268
+ .dialog-fade-leave-active .datametria-dialog {
269
+ transition: transform 0.3s;
270
+ }
271
+
272
+ .dialog-fade-enter-from .datametria-dialog {
273
+ transform: scale(0.9);
274
+ }
275
+
276
+ .dialog-fade-leave-to .datametria-dialog {
277
+ transform: scale(0.9);
278
+ }
279
+
280
+ /* Dark mode support */
281
+ @media (prefers-color-scheme: dark) {
282
+ .datametria-dialog {
283
+ background: var(--color-background, #1f2937);
284
+ }
285
+
286
+ .datametria-dialog__title {
287
+ color: var(--color-text-primary, #f9fafb);
288
+ }
289
+
290
+ .datametria-dialog__header,
291
+ .datametria-dialog__footer {
292
+ border-color: var(--color-border, #374151);
293
+ }
294
+ }
295
+ </style>
@@ -0,0 +1,352 @@
1
+ <template>
2
+ <div class="datametria-dropdown" ref="dropdownRef">
3
+ <div
4
+ class="datametria-dropdown__trigger"
5
+ @click="handleTriggerClick"
6
+ @mouseenter="handleMouseEnter"
7
+ @mouseleave="handleMouseLeave"
8
+ @contextmenu.prevent="handleContextMenu"
9
+ >
10
+ <slot name="trigger">
11
+ <button class="datametria-dropdown__button">
12
+ {{ triggerText }}
13
+ <span class="datametria-dropdown__arrow" :class="{ 'is-open': visible }">▼</span>
14
+ </button>
15
+ </slot>
16
+ </div>
17
+
18
+ <Transition name="datametria-dropdown-fade">
19
+ <div
20
+ v-if="visible"
21
+ class="datametria-dropdown__menu"
22
+ :style="menuStyle"
23
+ @click="handleMenuClick"
24
+ >
25
+ <div
26
+ v-for="(item, index) in items"
27
+ :key="index"
28
+ class="datametria-dropdown__item"
29
+ :class="{
30
+ 'is-disabled': item.disabled,
31
+ 'is-divided': item.divided,
32
+ 'has-children': item.children
33
+ }"
34
+ @click="handleItemClick(item, $event)"
35
+ @mouseenter="handleItemMouseEnter(item, index)"
36
+ >
37
+ <span class="datametria-dropdown__item-content">
38
+ <span v-if="item.icon" class="datametria-dropdown__item-icon">{{ item.icon }}</span>
39
+ {{ item.label }}
40
+ </span>
41
+ <span v-if="item.children" class="datametria-dropdown__item-arrow">▶</span>
42
+
43
+ <div
44
+ v-if="item.children && activeSubmenu === index"
45
+ class="datametria-dropdown__submenu"
46
+ :style="submenuStyle"
47
+ >
48
+ <div
49
+ v-for="(child, childIndex) in item.children"
50
+ :key="childIndex"
51
+ class="datametria-dropdown__item"
52
+ :class="{ 'is-disabled': child.disabled }"
53
+ @click.stop="handleItemClick(child, $event)"
54
+ >
55
+ <span class="datametria-dropdown__item-content">
56
+ <span v-if="child.icon" class="datametria-dropdown__item-icon">{{ child.icon }}</span>
57
+ {{ child.label }}
58
+ </span>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </Transition>
64
+ </div>
65
+ </template>
66
+
67
+ <script setup lang="ts">
68
+ import { ref, computed, onMounted, onUnmounted } from 'vue'
69
+
70
+ export interface DropdownItem {
71
+ label: string
72
+ value?: string | number
73
+ icon?: string
74
+ disabled?: boolean
75
+ divided?: boolean
76
+ children?: DropdownItem[]
77
+ command?: () => void
78
+ }
79
+
80
+ interface Props {
81
+ items: DropdownItem[]
82
+ trigger?: 'hover' | 'click' | 'contextmenu'
83
+ placement?: 'bottom' | 'top' | 'left' | 'right'
84
+ triggerText?: string
85
+ }
86
+
87
+ const props = withDefaults(defineProps<Props>(), {
88
+ trigger: 'click',
89
+ placement: 'bottom',
90
+ triggerText: 'Dropdown'
91
+ })
92
+
93
+ const emit = defineEmits<{
94
+ command: [item: DropdownItem]
95
+ visibleChange: [visible: boolean]
96
+ }>()
97
+
98
+ const dropdownRef = ref<HTMLElement | null>(null)
99
+ const visible = ref(false)
100
+ const activeSubmenu = ref<number | null>(null)
101
+ const menuPosition = ref({ top: 0, left: 0 })
102
+
103
+ const menuStyle = computed(() => ({
104
+ top: `${menuPosition.value.top}px`,
105
+ left: `${menuPosition.value.left}px`
106
+ }))
107
+
108
+ const submenuStyle = computed(() => {
109
+ const offset = props.placement === 'right' ? '100%' : '-100%'
110
+ return {
111
+ left: offset,
112
+ top: '0'
113
+ }
114
+ })
115
+
116
+ const updateMenuPosition = () => {
117
+ if (!dropdownRef.value) return
118
+
119
+ const rect = dropdownRef.value.getBoundingClientRect()
120
+ const menuWidth = 200
121
+ const menuHeight = props.items.length * 40
122
+
123
+ let top = rect.bottom + window.scrollY
124
+ let left = rect.left + window.scrollX
125
+
126
+ if (props.placement === 'top') {
127
+ top = rect.top + window.scrollY - menuHeight
128
+ } else if (props.placement === 'left') {
129
+ top = rect.top + window.scrollY
130
+ left = rect.left + window.scrollX - menuWidth
131
+ } else if (props.placement === 'right') {
132
+ top = rect.top + window.scrollY
133
+ left = rect.right + window.scrollX
134
+ }
135
+
136
+ menuPosition.value = { top, left }
137
+ }
138
+
139
+ const show = () => {
140
+ visible.value = true
141
+ updateMenuPosition()
142
+ emit('visibleChange', true)
143
+ }
144
+
145
+ const hide = () => {
146
+ visible.value = false
147
+ activeSubmenu.value = null
148
+ emit('visibleChange', false)
149
+ }
150
+
151
+ const handleTriggerClick = () => {
152
+ if (props.trigger === 'click') {
153
+ visible.value ? hide() : show()
154
+ }
155
+ }
156
+
157
+ const handleMouseEnter = () => {
158
+ if (props.trigger === 'hover') {
159
+ show()
160
+ }
161
+ }
162
+
163
+ const handleMouseLeave = () => {
164
+ if (props.trigger === 'hover') {
165
+ setTimeout(() => {
166
+ if (!dropdownRef.value?.matches(':hover')) {
167
+ hide()
168
+ }
169
+ }, 200)
170
+ }
171
+ }
172
+
173
+ const handleContextMenu = () => {
174
+ if (props.trigger === 'contextmenu') {
175
+ show()
176
+ }
177
+ }
178
+
179
+ const handleItemClick = (item: DropdownItem, event: Event) => {
180
+ if (item.disabled) {
181
+ event.stopPropagation()
182
+ return
183
+ }
184
+
185
+ if (item.children) {
186
+ event.stopPropagation()
187
+ return
188
+ }
189
+
190
+ emit('command', item)
191
+ if (item.command) {
192
+ item.command()
193
+ }
194
+ hide()
195
+ }
196
+
197
+ const handleItemMouseEnter = (item: DropdownItem, index: number) => {
198
+ if (item.children) {
199
+ activeSubmenu.value = index
200
+ } else {
201
+ activeSubmenu.value = null
202
+ }
203
+ }
204
+
205
+ const handleMenuClick = (event: Event) => {
206
+ event.stopPropagation()
207
+ }
208
+
209
+ const handleClickOutside = (event: Event) => {
210
+ if (!dropdownRef.value?.contains(event.target as Node)) {
211
+ hide()
212
+ }
213
+ }
214
+
215
+ onMounted(() => {
216
+ document.addEventListener('click', handleClickOutside)
217
+ })
218
+
219
+ onUnmounted(() => {
220
+ document.removeEventListener('click', handleClickOutside)
221
+ })
222
+ </script>
223
+
224
+ <style scoped>
225
+ .datametria-dropdown {
226
+ display: inline-block;
227
+ position: relative;
228
+ }
229
+
230
+ .datametria-dropdown__trigger {
231
+ cursor: pointer;
232
+ }
233
+
234
+ .datametria-dropdown__button {
235
+ display: inline-flex;
236
+ align-items: center;
237
+ gap: 8px;
238
+ padding: 8px 16px;
239
+ background: var(--dm-color-primary, #0072ce);
240
+ color: white;
241
+ border: none;
242
+ border-radius: 4px;
243
+ cursor: pointer;
244
+ font-size: 14px;
245
+ transition: background-color 0.2s;
246
+ }
247
+
248
+ .datametria-dropdown__button:hover {
249
+ background: var(--dm-color-primary-dark, #005a9e);
250
+ }
251
+
252
+ .datametria-dropdown__arrow {
253
+ font-size: 10px;
254
+ transition: transform 0.2s;
255
+ }
256
+
257
+ .datametria-dropdown__arrow.is-open {
258
+ transform: rotate(180deg);
259
+ }
260
+
261
+ .datametria-dropdown__menu {
262
+ position: absolute;
263
+ z-index: 1000;
264
+ min-width: 160px;
265
+ background: white;
266
+ border: 1px solid var(--dm-color-border, #e0e0e0);
267
+ border-radius: 4px;
268
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
269
+ padding: 4px 0;
270
+ }
271
+
272
+ .datametria-dropdown__item {
273
+ position: relative;
274
+ display: flex;
275
+ align-items: center;
276
+ justify-content: space-between;
277
+ padding: 8px 16px;
278
+ cursor: pointer;
279
+ font-size: 14px;
280
+ color: var(--dm-color-text, #333);
281
+ transition: background-color 0.2s;
282
+ }
283
+
284
+ .datametria-dropdown__item:hover:not(.is-disabled) {
285
+ background: var(--dm-color-background-hover, #f5f5f5);
286
+ }
287
+
288
+ .datametria-dropdown__item.is-disabled {
289
+ color: var(--dm-color-text-disabled, #999);
290
+ cursor: not-allowed;
291
+ opacity: 0.5;
292
+ }
293
+
294
+ .datametria-dropdown__item.is-divided {
295
+ border-top: 1px solid var(--dm-color-border, #e0e0e0);
296
+ margin-top: 4px;
297
+ padding-top: 12px;
298
+ }
299
+
300
+ .datametria-dropdown__item-content {
301
+ display: flex;
302
+ align-items: center;
303
+ gap: 8px;
304
+ }
305
+
306
+ .datametria-dropdown__item-icon {
307
+ font-size: 16px;
308
+ }
309
+
310
+ .datametria-dropdown__item-arrow {
311
+ font-size: 10px;
312
+ color: var(--dm-color-text-secondary, #666);
313
+ }
314
+
315
+ .datametria-dropdown__submenu {
316
+ position: absolute;
317
+ top: 0;
318
+ min-width: 160px;
319
+ background: white;
320
+ border: 1px solid var(--dm-color-border, #e0e0e0);
321
+ border-radius: 4px;
322
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
323
+ padding: 4px 0;
324
+ }
325
+
326
+ .datametria-dropdown-fade-enter-active,
327
+ .datametria-dropdown-fade-leave-active {
328
+ transition: opacity 0.2s, transform 0.2s;
329
+ }
330
+
331
+ .datametria-dropdown-fade-enter-from,
332
+ .datametria-dropdown-fade-leave-to {
333
+ opacity: 0;
334
+ transform: translateY(-8px);
335
+ }
336
+
337
+ @media (prefers-color-scheme: dark) {
338
+ .datametria-dropdown__menu,
339
+ .datametria-dropdown__submenu {
340
+ background: var(--dm-color-background-dark, #1e1e1e);
341
+ border-color: var(--dm-color-border-dark, #333);
342
+ }
343
+
344
+ .datametria-dropdown__item {
345
+ color: var(--dm-color-text-dark, #e0e0e0);
346
+ }
347
+
348
+ .datametria-dropdown__item:hover:not(.is-disabled) {
349
+ background: var(--dm-color-background-hover-dark, #2a2a2a);
350
+ }
351
+ }
352
+ </style>