@datametria/vue-components 2.1.1 → 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 (80) hide show
  1. package/README.md +34 -8
  2. package/dist/index.es.js +3520 -2211
  3. package/dist/index.umd.js +10 -10
  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/src/types/index.d.ts +5 -0
  41. package/dist/vue-components.css +1 -1
  42. package/package.json +4 -3
  43. package/src/components/DatametriaAutocomplete.vue +155 -260
  44. package/src/components/DatametriaBreadcrumb.vue +66 -80
  45. package/src/components/DatametriaCheckbox.vue +150 -37
  46. package/src/components/DatametriaCheckboxGroup.vue +43 -0
  47. package/src/components/DatametriaDataTable.vue +304 -0
  48. package/src/components/DatametriaDatePicker.vue +238 -614
  49. package/src/components/DatametriaDialog.vue +295 -0
  50. package/src/components/DatametriaDropdown.vue +352 -0
  51. package/src/components/DatametriaEmpty.vue +153 -0
  52. package/src/components/DatametriaForm.vue +160 -0
  53. package/src/components/DatametriaFormItem.vue +181 -0
  54. package/src/components/DatametriaInput.vue +226 -63
  55. package/src/components/DatametriaPagination.vue +373 -0
  56. package/src/components/DatametriaPopconfirm.vue +236 -0
  57. package/src/components/DatametriaProgress.vue +176 -63
  58. package/src/components/DatametriaRadio.vue +83 -72
  59. package/src/components/DatametriaRadioGroup.vue +42 -0
  60. package/src/components/DatametriaResult.vue +133 -0
  61. package/src/components/DatametriaSelect.vue +172 -67
  62. package/src/components/DatametriaSortableTable.vue +241 -20
  63. package/src/components/DatametriaSteps.vue +314 -0
  64. package/src/components/DatametriaSwitch.vue +86 -80
  65. package/src/components/DatametriaTabPane.vue +82 -0
  66. package/src/components/DatametriaTextarea.vue +140 -100
  67. package/src/components/DatametriaTimePicker.vue +231 -214
  68. package/src/components/DatametriaTree.vue +124 -0
  69. package/src/components/DatametriaTreeNode.vue +174 -0
  70. package/src/components/DatametriaUpload.vue +365 -0
  71. package/src/index.ts +25 -11
  72. package/src/types/index.ts +2 -0
  73. package/src/components/__tests__/DatametriaAutocomplete.test.ts +0 -180
  74. package/src/components/__tests__/DatametriaBreadcrumb.test.ts +0 -75
  75. package/src/components/__tests__/DatametriaCheckbox.test.ts +0 -47
  76. package/src/components/__tests__/DatametriaDatePicker.test.ts +0 -234
  77. package/src/components/__tests__/DatametriaProgress.test.ts +0 -90
  78. package/src/components/__tests__/DatametriaRadio.test.ts +0 -77
  79. package/src/components/__tests__/DatametriaSwitch.test.ts +0 -64
  80. 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>