@datametria/vue-components 2.0.1 → 2.1.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 (72) hide show
  1. package/README.md +43 -23
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.es.js +1687 -1539
  4. package/dist/index.umd.js +9 -9
  5. package/dist/src/components/DatametriaAlert.vue.d.ts +33 -0
  6. package/dist/src/components/DatametriaAutocomplete.vue.d.ts +28 -0
  7. package/dist/src/components/DatametriaAvatar.vue.d.ts +25 -0
  8. package/dist/src/components/DatametriaBadge.vue.d.ts +26 -0
  9. package/dist/src/components/DatametriaBreadcrumb.vue.d.ts +16 -0
  10. package/dist/src/components/DatametriaButton.vue.d.ts +37 -0
  11. package/dist/src/components/DatametriaCard.vue.d.ts +25 -0
  12. package/dist/src/components/DatametriaCheckbox.vue.d.ts +14 -0
  13. package/dist/src/components/DatametriaChip.vue.d.ts +34 -0
  14. package/dist/src/components/DatametriaContainer.vue.d.ts +24 -0
  15. package/dist/src/components/DatametriaDatePicker.vue.d.ts +55 -0
  16. package/dist/src/components/DatametriaDivider.vue.d.ts +25 -0
  17. package/dist/src/components/DatametriaFileUpload.vue.d.ts +28 -0
  18. package/dist/src/components/DatametriaFloatingBar.vue.d.ts +32 -0
  19. package/dist/src/components/DatametriaGrid.vue.d.ts +24 -0
  20. package/dist/src/components/DatametriaInput.vue.d.ts +18 -0
  21. package/dist/src/components/DatametriaMenu.vue.d.ts +71 -0
  22. package/dist/src/components/DatametriaModal.vue.d.ts +34 -0
  23. package/dist/src/components/DatametriaNavbar.vue.d.ts +34 -0
  24. package/dist/src/components/DatametriaPasswordInput.vue.d.ts +29 -0
  25. package/dist/src/components/DatametriaProgress.vue.d.ts +12 -0
  26. package/dist/src/components/DatametriaRadio.vue.d.ts +17 -0
  27. package/dist/src/components/DatametriaSelect.vue.d.ts +23 -0
  28. package/dist/src/components/DatametriaSidebar.vue.d.ts +45 -0
  29. package/dist/src/components/DatametriaSkeleton.vue.d.ts +18 -0
  30. package/dist/src/components/DatametriaSlider.vue.d.ts +41 -0
  31. package/dist/src/components/DatametriaSortableTable.vue.d.ts +32 -0
  32. package/dist/src/components/DatametriaSpinner.vue.d.ts +12 -0
  33. package/dist/src/components/DatametriaSwitch.vue.d.ts +16 -0
  34. package/dist/src/components/DatametriaTable.vue.d.ts +29 -0
  35. package/dist/src/components/DatametriaTabs.vue.d.ts +41 -0
  36. package/dist/src/components/DatametriaTextarea.vue.d.ts +22 -0
  37. package/dist/src/components/DatametriaTimePicker.vue.d.ts +36 -0
  38. package/dist/src/components/DatametriaToast.vue.d.ts +20 -0
  39. package/dist/src/components/DatametriaTooltip.vue.d.ts +58 -0
  40. package/dist/src/composables/useAPI.d.ts +14 -0
  41. package/dist/src/composables/useAccessibilityScale.d.ts +14 -0
  42. package/dist/src/composables/useBreakpoints.d.ts +33 -0
  43. package/dist/src/composables/useClipboard.d.ts +6 -0
  44. package/dist/src/composables/useDebounce.d.ts +2 -0
  45. package/dist/src/composables/useHapticFeedback.d.ts +34 -0
  46. package/dist/src/composables/useLocalStorage.d.ts +2 -0
  47. package/dist/src/composables/useRipple.d.ts +49 -0
  48. package/dist/src/composables/useTheme.d.ts +10 -0
  49. package/dist/src/composables/useValidation.d.ts +14 -0
  50. package/dist/src/index.d.ts +53 -0
  51. package/dist/src/theme/ThemeProvider.vue.d.ts +24 -0
  52. package/dist/src/theme/constants.d.ts +5 -0
  53. package/dist/src/theme/index.d.ts +11 -0
  54. package/dist/src/theme/presets/datametria.d.ts +2 -0
  55. package/dist/src/theme/presets/default.d.ts +2 -0
  56. package/dist/src/theme/presets/index.d.ts +7 -0
  57. package/dist/src/theme/tokens/colors.d.ts +2 -0
  58. package/dist/src/theme/tokens/index.d.ts +8 -0
  59. package/dist/src/theme/tokens/spacing.d.ts +2 -0
  60. package/dist/src/theme/tokens/typography.d.ts +2 -0
  61. package/dist/src/theme/types.d.ts +102 -0
  62. package/dist/src/theme/useTheme.d.ts +8 -0
  63. package/dist/src/types/index.d.ts +47 -0
  64. package/dist/vue-components.css +1 -1
  65. package/package.json +5 -3
  66. package/src/components/DatametriaFloatingBar.vue +126 -0
  67. package/src/components/DatametriaSidebar.vue +230 -0
  68. package/src/components/DatametriaTabs.vue +150 -29
  69. package/src/components/__tests__/DatametriaFloatingBar.test.ts +137 -0
  70. package/src/components/__tests__/DatametriaSidebar.test.ts +169 -0
  71. package/src/components/__tests__/DatametriaTabs.test.ts +232 -0
  72. package/src/index.ts +2 -0
@@ -0,0 +1,126 @@
1
+ <template>
2
+ <div
3
+ :class="floatingBarClasses"
4
+ role="toolbar"
5
+ :aria-label="ariaLabel"
6
+ :style="positionStyle"
7
+ >
8
+ <div class="dm-floating-bar__content">
9
+ <slot></slot>
10
+ </div>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { computed } from 'vue'
16
+
17
+ interface Props {
18
+ position?: 'top' | 'bottom' | 'left' | 'right'
19
+ variant?: 'light' | 'dark' | 'primary'
20
+ offset?: string
21
+ shadow?: boolean
22
+ rounded?: boolean
23
+ ariaLabel?: string
24
+ }
25
+
26
+ const props = withDefaults(defineProps<Props>(), {
27
+ position: 'bottom',
28
+ variant: 'light',
29
+ offset: '16px',
30
+ shadow: true,
31
+ rounded: true,
32
+ ariaLabel: 'Floating toolbar'
33
+ })
34
+
35
+ const floatingBarClasses = computed(() => [
36
+ 'dm-floating-bar',
37
+ `dm-floating-bar--${props.position}`,
38
+ `dm-floating-bar--${props.variant}`,
39
+ { 'dm-floating-bar--shadow': props.shadow },
40
+ { 'dm-floating-bar--rounded': props.rounded }
41
+ ])
42
+
43
+ const positionStyle = computed(() => {
44
+ const styles: Record<string, string> = {}
45
+
46
+ switch (props.position) {
47
+ case 'top':
48
+ styles.top = props.offset
49
+ break
50
+ case 'bottom':
51
+ styles.bottom = props.offset
52
+ break
53
+ case 'left':
54
+ styles.left = props.offset
55
+ break
56
+ case 'right':
57
+ styles.right = props.offset
58
+ break
59
+ }
60
+
61
+ return styles
62
+ })
63
+ </script>
64
+
65
+ <style scoped>
66
+ .dm-floating-bar {
67
+ position: fixed;
68
+ z-index: 1000;
69
+ background: var(--dm-neutral-50, #ffffff);
70
+ border: 1px solid var(--dm-neutral-200, #e5e7eb);
71
+ transition: all 0.3s ease;
72
+ }
73
+
74
+ .dm-floating-bar--top,
75
+ .dm-floating-bar--bottom {
76
+ left: 50%;
77
+ transform: translateX(-50%);
78
+ max-width: calc(100% - 32px);
79
+ }
80
+
81
+ .dm-floating-bar--left,
82
+ .dm-floating-bar--right {
83
+ top: 50%;
84
+ transform: translateY(-50%);
85
+ max-height: calc(100vh - 32px);
86
+ }
87
+
88
+ .dm-floating-bar--dark {
89
+ background: var(--dm-neutral-900, #111827);
90
+ border-color: var(--dm-neutral-800, #1f2937);
91
+ color: var(--dm-neutral-50, #ffffff);
92
+ }
93
+
94
+ .dm-floating-bar--primary {
95
+ background: var(--dm-primary, #0072CE);
96
+ border-color: color-mix(in srgb, var(--dm-primary, #0072CE) 90%, black);
97
+ color: var(--dm-neutral-50, #ffffff);
98
+ }
99
+
100
+ .dm-floating-bar--shadow {
101
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
102
+ }
103
+
104
+ .dm-floating-bar--rounded {
105
+ border-radius: var(--dm-radius-lg, 0.5rem);
106
+ }
107
+
108
+ .dm-floating-bar__content {
109
+ padding: var(--dm-spacing-3, 0.75rem) var(--dm-spacing-4, 1rem);
110
+ display: flex;
111
+ align-items: center;
112
+ gap: var(--dm-spacing-2, 0.5rem);
113
+ }
114
+
115
+ @media (max-width: 768px) {
116
+ .dm-floating-bar--top,
117
+ .dm-floating-bar--bottom {
118
+ max-width: calc(100% - 16px);
119
+ }
120
+
121
+ .dm-floating-bar__content {
122
+ padding: var(--dm-spacing-2, 0.5rem) var(--dm-spacing-3, 0.75rem);
123
+ gap: var(--dm-spacing-1, 0.25rem);
124
+ }
125
+ }
126
+ </style>
@@ -0,0 +1,230 @@
1
+ <template>
2
+ <aside
3
+ :class="sidebarClasses"
4
+ role="complementary"
5
+ :aria-label="ariaLabel"
6
+ :aria-expanded="isOpen"
7
+ >
8
+ <div class="dm-sidebar__header" v-if="$slots.header">
9
+ <slot name="header"></slot>
10
+ <button
11
+ v-if="collapsible"
12
+ class="dm-sidebar__toggle"
13
+ @click="toggle"
14
+ :aria-label="isOpen ? 'Fechar sidebar' : 'Abrir sidebar'"
15
+ >
16
+ <span class="dm-sidebar__toggle-icon" :class="{ 'dm-sidebar__toggle-icon--open': isOpen }"></span>
17
+ </button>
18
+ </div>
19
+
20
+ <nav class="dm-sidebar__content">
21
+ <slot></slot>
22
+ </nav>
23
+
24
+ <div class="dm-sidebar__footer" v-if="$slots.footer">
25
+ <slot name="footer"></slot>
26
+ </div>
27
+ </aside>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { ref, computed, watch } from 'vue'
32
+
33
+ interface Props {
34
+ position?: 'left' | 'right'
35
+ variant?: 'light' | 'dark' | 'primary'
36
+ width?: string
37
+ collapsible?: boolean
38
+ defaultOpen?: boolean
39
+ ariaLabel?: string
40
+ }
41
+
42
+ const props = withDefaults(defineProps<Props>(), {
43
+ position: 'left',
44
+ variant: 'light',
45
+ width: '280px',
46
+ collapsible: false,
47
+ defaultOpen: true,
48
+ ariaLabel: 'Sidebar navigation'
49
+ })
50
+
51
+ const emit = defineEmits<{
52
+ toggle: [isOpen: boolean]
53
+ open: []
54
+ close: []
55
+ }>()
56
+
57
+ const isOpen = ref(props.defaultOpen)
58
+
59
+ const sidebarClasses = computed(() => [
60
+ 'dm-sidebar',
61
+ `dm-sidebar--${props.position}`,
62
+ `dm-sidebar--${props.variant}`,
63
+ { 'dm-sidebar--collapsed': !isOpen.value && props.collapsible }
64
+ ])
65
+
66
+ const toggle = () => {
67
+ isOpen.value = !isOpen.value
68
+ emit('toggle', isOpen.value)
69
+ if (isOpen.value) {
70
+ emit('open')
71
+ } else {
72
+ emit('close')
73
+ }
74
+ }
75
+
76
+ watch(() => props.defaultOpen, (newVal) => {
77
+ isOpen.value = newVal
78
+ })
79
+
80
+ defineExpose({ isOpen, toggle })
81
+ </script>
82
+
83
+ <style scoped>
84
+ .dm-sidebar {
85
+ height: 100vh;
86
+ background: var(--dm-neutral-50, #ffffff);
87
+ border-right: 1px solid var(--dm-neutral-200, #e5e7eb);
88
+ display: flex;
89
+ flex-direction: column;
90
+ transition: width 0.3s ease;
91
+ width: v-bind(width);
92
+ position: fixed;
93
+ top: 0;
94
+ z-index: 90;
95
+ }
96
+
97
+ .dm-sidebar--left {
98
+ left: 0;
99
+ }
100
+
101
+ .dm-sidebar--right {
102
+ right: 0;
103
+ border-right: none;
104
+ border-left: 1px solid var(--dm-neutral-200, #e5e7eb);
105
+ }
106
+
107
+ .dm-sidebar--dark {
108
+ background: var(--dm-neutral-900, #111827);
109
+ border-color: var(--dm-neutral-800, #1f2937);
110
+ color: var(--dm-neutral-50, #ffffff);
111
+ }
112
+
113
+ .dm-sidebar--primary {
114
+ background: var(--dm-primary, #0072CE);
115
+ border-color: color-mix(in srgb, var(--dm-primary, #0072CE) 90%, black);
116
+ color: var(--dm-neutral-50, #ffffff);
117
+ }
118
+
119
+ .dm-sidebar--collapsed {
120
+ width: 64px;
121
+ }
122
+
123
+ .dm-sidebar__header {
124
+ padding: var(--dm-spacing-4, 1rem);
125
+ border-bottom: 1px solid var(--dm-neutral-200, #e5e7eb);
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: space-between;
129
+ min-height: 64px;
130
+ }
131
+
132
+ .dm-sidebar--dark .dm-sidebar__header {
133
+ border-color: var(--dm-neutral-800, #1f2937);
134
+ }
135
+
136
+ .dm-sidebar--primary .dm-sidebar__header {
137
+ border-color: color-mix(in srgb, var(--dm-primary, #0072CE) 90%, black);
138
+ }
139
+
140
+ .dm-sidebar__toggle {
141
+ width: 32px;
142
+ height: 32px;
143
+ padding: 0;
144
+ border: none;
145
+ background: transparent;
146
+ cursor: pointer;
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ border-radius: var(--dm-radius-md, 0.375rem);
151
+ transition: background 0.2s ease;
152
+ }
153
+
154
+ .dm-sidebar__toggle:hover {
155
+ background: var(--dm-neutral-100, #f3f4f6);
156
+ }
157
+
158
+ .dm-sidebar--dark .dm-sidebar__toggle:hover {
159
+ background: var(--dm-neutral-800, #1f2937);
160
+ }
161
+
162
+ .dm-sidebar__toggle-icon {
163
+ width: 16px;
164
+ height: 2px;
165
+ background: var(--dm-neutral-900, #111827);
166
+ position: relative;
167
+ transition: transform 0.3s ease;
168
+ }
169
+
170
+ .dm-sidebar--dark .dm-sidebar__toggle-icon,
171
+ .dm-sidebar--primary .dm-sidebar__toggle-icon {
172
+ background: var(--dm-neutral-50, #ffffff);
173
+ }
174
+
175
+ .dm-sidebar__toggle-icon::before,
176
+ .dm-sidebar__toggle-icon::after {
177
+ content: '';
178
+ position: absolute;
179
+ width: 16px;
180
+ height: 2px;
181
+ background: inherit;
182
+ transition: transform 0.3s ease;
183
+ }
184
+
185
+ .dm-sidebar__toggle-icon::before {
186
+ top: -5px;
187
+ }
188
+
189
+ .dm-sidebar__toggle-icon::after {
190
+ bottom: -5px;
191
+ }
192
+
193
+ .dm-sidebar__toggle-icon--open {
194
+ transform: rotate(180deg);
195
+ }
196
+
197
+ .dm-sidebar__content {
198
+ flex: 1;
199
+ overflow-y: auto;
200
+ padding: var(--dm-spacing-4, 1rem);
201
+ }
202
+
203
+ .dm-sidebar__footer {
204
+ padding: var(--dm-spacing-4, 1rem);
205
+ border-top: 1px solid var(--dm-neutral-200, #e5e7eb);
206
+ }
207
+
208
+ .dm-sidebar--dark .dm-sidebar__footer {
209
+ border-color: var(--dm-neutral-800, #1f2937);
210
+ }
211
+
212
+ .dm-sidebar--primary .dm-sidebar__footer {
213
+ border-color: color-mix(in srgb, var(--dm-primary, #0072CE) 90%, black);
214
+ }
215
+
216
+ @media (max-width: 768px) {
217
+ .dm-sidebar {
218
+ transform: translateX(0);
219
+ transition: transform 0.3s ease;
220
+ }
221
+
222
+ .dm-sidebar--left.dm-sidebar--collapsed {
223
+ transform: translateX(-100%);
224
+ }
225
+
226
+ .dm-sidebar--right.dm-sidebar--collapsed {
227
+ transform: translateX(100%);
228
+ }
229
+ }
230
+ </style>
@@ -1,24 +1,29 @@
1
1
  <template>
2
- <div class="dm-tabs">
3
- <div class="dm-tabs__header" role="tablist" :aria-label="ariaLabel">
2
+ <div :class="tabsClasses">
3
+ <div class="dm-tabs__header" role="tablist" :aria-label="ariaLabel" :aria-orientation="orientation">
4
4
  <button
5
5
  v-for="(tab, index) in tabs"
6
6
  :key="index"
7
7
  :id="`tab-${index}`"
8
8
  class="dm-tabs__tab"
9
- :class="{ 'dm-tabs__tab--active': activeTab === index }"
9
+ :class="{ 'dm-tabs__tab--active': activeTab === index, 'dm-tabs__tab--disabled': typeof tab === 'object' && 'disabled' in tab && tab.disabled }"
10
10
  role="tab"
11
11
  :aria-selected="activeTab === index"
12
12
  :aria-controls="`panel-${index}`"
13
+ :aria-disabled="typeof tab === 'object' && 'disabled' in tab ? tab.disabled : false"
13
14
  :tabindex="activeTab === index ? 0 : -1"
15
+ :disabled="typeof tab === 'object' && 'disabled' in tab ? tab.disabled : false"
14
16
  @click="selectTab(index)"
15
17
  @keydown="handleKeydown($event, index)"
16
18
  >
17
- {{ tab }}
19
+ <span v-if="typeof tab === 'object' && 'icon' in tab && tab.icon" class="dm-tabs__icon">{{ tab.icon }}</span>
20
+ <span class="dm-tabs__label">{{ typeof tab === 'string' ? tab : tab.label }}</span>
21
+ <span v-if="typeof tab === 'object' && 'badge' in tab && tab.badge" class="dm-tabs__badge">{{ tab.badge }}</span>
18
22
  </button>
19
23
  <div
24
+ v-if="showIndicator"
20
25
  class="dm-tabs__indicator"
21
- :style="{ transform: `translateX(${activeTab * 100}%)` }"
26
+ :style="indicatorStyle"
22
27
  ></div>
23
28
  </div>
24
29
  <div class="dm-tabs__panels">
@@ -39,21 +44,35 @@
39
44
  </template>
40
45
 
41
46
  <script setup lang="ts">
42
- import { ref, watch } from 'vue'
47
+ import { ref, watch, computed } from 'vue'
48
+
49
+ interface Tab {
50
+ label: string
51
+ icon?: string
52
+ badge?: string | number
53
+ disabled?: boolean
54
+ }
43
55
 
44
56
  interface Props {
45
- tabs: string[]
57
+ tabs: (string | Tab)[]
46
58
  modelValue?: number
59
+ variant?: 'default' | 'pills' | 'underline'
60
+ orientation?: 'horizontal' | 'vertical'
61
+ showIndicator?: boolean
47
62
  ariaLabel?: string
48
63
  }
49
64
 
50
65
  const props = withDefaults(defineProps<Props>(), {
51
66
  modelValue: 0,
67
+ variant: 'default',
68
+ orientation: 'horizontal',
69
+ showIndicator: true,
52
70
  ariaLabel: 'Tabs'
53
71
  })
54
72
 
55
73
  const emit = defineEmits<{
56
74
  'update:modelValue': [index: number]
75
+ change: [index: number]
57
76
  }>()
58
77
 
59
78
  const activeTab = ref(props.modelValue)
@@ -62,20 +81,59 @@ watch(() => props.modelValue, (newValue) => {
62
81
  activeTab.value = newValue
63
82
  })
64
83
 
84
+ const tabsClasses = computed(() => [
85
+ 'dm-tabs',
86
+ `dm-tabs--${props.variant}`,
87
+ `dm-tabs--${props.orientation}`
88
+ ])
89
+
90
+ const indicatorStyle = computed(() => {
91
+ const count = props.tabs.length
92
+ const position = props.orientation === 'horizontal'
93
+ ? `translateX(${activeTab.value * 100}%)`
94
+ : `translateY(${activeTab.value * 100}%)`
95
+
96
+ return {
97
+ transform: position,
98
+ width: props.orientation === 'horizontal' ? `${100 / count}%` : '100%',
99
+ height: props.orientation === 'vertical' ? `${100 / count}%` : '2px'
100
+ }
101
+ })
102
+
65
103
  const selectTab = (index: number) => {
104
+ const tab = props.tabs[index]
105
+ const isDisabled = typeof tab === 'object' && 'disabled' in tab && tab.disabled
106
+
107
+ if (isDisabled) return
108
+
66
109
  activeTab.value = index
67
110
  emit('update:modelValue', index)
111
+ emit('change', index)
68
112
  }
69
113
 
70
114
  const handleKeydown = (event: KeyboardEvent, index: number) => {
71
115
  let newIndex = index
72
116
 
117
+ const isHorizontal = props.orientation === 'horizontal'
118
+
73
119
  switch (event.key) {
74
120
  case 'ArrowLeft':
121
+ if (!isHorizontal) return
75
122
  event.preventDefault()
76
123
  newIndex = index > 0 ? index - 1 : props.tabs.length - 1
77
124
  break
78
125
  case 'ArrowRight':
126
+ if (!isHorizontal) return
127
+ event.preventDefault()
128
+ newIndex = index < props.tabs.length - 1 ? index + 1 : 0
129
+ break
130
+ case 'ArrowUp':
131
+ if (isHorizontal) return
132
+ event.preventDefault()
133
+ newIndex = index > 0 ? index - 1 : props.tabs.length - 1
134
+ break
135
+ case 'ArrowDown':
136
+ if (isHorizontal) return
79
137
  event.preventDefault()
80
138
  newIndex = index < props.tabs.length - 1 ? index + 1 : 0
81
139
  break
@@ -102,10 +160,24 @@ const handleKeydown = (event: KeyboardEvent, index: number) => {
102
160
  flex-direction: column;
103
161
  }
104
162
 
163
+ .dm-tabs--vertical {
164
+ flex-direction: row;
165
+ }
166
+
167
+ .dm-tabs--vertical .dm-tabs__header {
168
+ flex-direction: column;
169
+ border-bottom: none;
170
+ border-right: 2px solid var(--dm-neutral-200, #e5e7eb);
171
+ }
172
+
173
+ .dm-tabs--vertical .dm-tabs__tab {
174
+ text-align: left;
175
+ }
176
+
105
177
  .dm-tabs__header {
106
178
  display: flex;
107
179
  position: relative;
108
- border-bottom: 2px solid var(--dm-gray-200);
180
+ border-bottom: 2px solid var(--dm-neutral-200, #e5e7eb);
109
181
  overflow-x: auto;
110
182
  scrollbar-width: none;
111
183
  }
@@ -117,43 +189,95 @@ const handleKeydown = (event: KeyboardEvent, index: number) => {
117
189
  .dm-tabs__tab {
118
190
  flex: 1;
119
191
  min-width: max-content;
120
- padding: var(--dm-space-3) var(--dm-space-4);
192
+ padding: var(--dm-spacing-3, 0.75rem) var(--dm-spacing-4, 1rem);
121
193
  border: none;
122
194
  background: transparent;
123
- color: var(--dm-text-secondary);
124
- font-size: var(--dm-text-base);
195
+ color: var(--dm-neutral-600, #6b7280);
196
+ font-size: 1rem;
125
197
  font-weight: 500;
126
198
  cursor: pointer;
127
- transition: var(--dm-transition);
199
+ transition: all 0.2s ease;
128
200
  position: relative;
129
201
  white-space: nowrap;
202
+ display: flex;
203
+ align-items: center;
204
+ gap: var(--dm-spacing-2, 0.5rem);
130
205
  }
131
206
 
132
- .dm-tabs__tab:hover {
133
- color: var(--dm-text-primary);
207
+ .dm-tabs__tab--disabled {
208
+ opacity: 0.5;
209
+ cursor: not-allowed;
210
+ }
211
+
212
+ .dm-tabs__icon {
213
+ font-size: 1.25rem;
214
+ }
215
+
216
+ .dm-tabs__badge {
217
+ display: inline-flex;
218
+ align-items: center;
219
+ justify-content: center;
220
+ min-width: 20px;
221
+ height: 20px;
222
+ padding: 0 6px;
223
+ background: var(--dm-primary, #0072CE);
224
+ color: white;
225
+ font-size: 0.75rem;
226
+ font-weight: 600;
227
+ border-radius: 10px;
228
+ }
229
+
230
+ .dm-tabs__tab:hover:not(:disabled) {
231
+ color: var(--dm-neutral-900, #111827);
134
232
  }
135
233
 
136
234
  .dm-tabs__tab:focus-visible {
137
- outline: var(--dm-focus-ring);
235
+ outline: 2px solid var(--dm-primary, #0072CE);
138
236
  outline-offset: -2px;
237
+ border-radius: 4px;
139
238
  }
140
239
 
141
240
  .dm-tabs__tab--active {
142
- color: var(--dm-primary);
241
+ color: var(--dm-primary, #0072CE);
143
242
  }
144
243
 
145
244
  .dm-tabs__indicator {
146
245
  position: absolute;
147
246
  bottom: -2px;
148
247
  left: 0;
149
- width: calc(100% / var(--tab-count, 1));
150
- height: 2px;
151
- background: var(--dm-primary);
248
+ background: var(--dm-primary, #0072CE);
152
249
  transition: transform 0.3s ease;
153
250
  }
154
251
 
252
+ .dm-tabs--vertical .dm-tabs__indicator {
253
+ bottom: auto;
254
+ left: auto;
255
+ right: -2px;
256
+ top: 0;
257
+ width: 2px;
258
+ }
259
+
260
+ .dm-tabs--pills .dm-tabs__header {
261
+ border-bottom: none;
262
+ gap: var(--dm-spacing-2, 0.5rem);
263
+ }
264
+
265
+ .dm-tabs--pills .dm-tabs__tab {
266
+ border-radius: var(--dm-radius-md, 0.375rem);
267
+ }
268
+
269
+ .dm-tabs--pills .dm-tabs__tab--active {
270
+ background: var(--dm-primary, #0072CE);
271
+ color: white;
272
+ }
273
+
274
+ .dm-tabs--pills .dm-tabs__indicator {
275
+ display: none;
276
+ }
277
+
155
278
  .dm-tabs__panels {
156
- padding: var(--dm-space-4);
279
+ padding: var(--dm-spacing-4, 1rem);
280
+ flex: 1;
157
281
  }
158
282
 
159
283
  .dm-tabs__panel {
@@ -164,17 +288,14 @@ const handleKeydown = (event: KeyboardEvent, index: number) => {
164
288
  display: block;
165
289
  }
166
290
 
167
- @media (prefers-color-scheme: dark) {
168
- .dm-tabs__header {
169
- border-bottom-color: var(--dm-gray-700);
170
- }
171
-
291
+ @media (max-width: 768px) {
172
292
  .dm-tabs__tab {
173
- color: var(--dm-gray-400);
293
+ padding: var(--dm-spacing-2, 0.5rem) var(--dm-spacing-3, 0.75rem);
294
+ font-size: 0.875rem;
174
295
  }
175
-
176
- .dm-tabs__tab:hover {
177
- color: var(--dm-white);
296
+
297
+ .dm-tabs__icon {
298
+ font-size: 1rem;
178
299
  }
179
300
  }
180
301
  </style>