@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
@@ -1,137 +1,143 @@
1
1
  <template>
2
- <div class="dm-switch">
3
- <label class="dm-switch__label">
4
- <input
5
- type="checkbox"
6
- class="dm-switch__input"
7
- :checked="modelValue"
8
- :disabled="disabled"
9
- :aria-label="ariaLabel"
10
- :aria-checked="modelValue"
11
- role="switch"
12
- @change="handleChange"
13
- />
14
- <span class="dm-switch__track">
15
- <span class="dm-switch__thumb"></span>
2
+ <button
3
+ type="button"
4
+ role="switch"
5
+ class="datametria-switch"
6
+ :class="{
7
+ 'is-checked': modelValue,
8
+ 'is-disabled': disabled,
9
+ 'is-loading': loading
10
+ }"
11
+ :aria-checked="modelValue"
12
+ :disabled="disabled || loading"
13
+ @click="handleClick"
14
+ >
15
+ <span class="datametria-switch__core" :style="coreStyle">
16
+ <span v-if="loading" class="datametria-switch__loading">
17
+ <span class="spinner"></span>
16
18
  </span>
17
- <span v-if="label" class="dm-switch__text">{{ label }}</span>
18
- </label>
19
- <p v-if="error" class="dm-switch__error">{{ error }}</p>
20
- </div>
19
+ </span>
20
+ </button>
21
21
  </template>
22
22
 
23
23
  <script setup lang="ts">
24
+ import { computed } from 'vue'
25
+
24
26
  interface Props {
25
27
  modelValue?: boolean
26
- label?: string
27
28
  disabled?: boolean
28
- error?: string
29
- ariaLabel?: string
29
+ loading?: boolean
30
+ activeColor?: string
31
+ inactiveColor?: string
30
32
  }
31
33
 
32
34
  const props = withDefaults(defineProps<Props>(), {
33
35
  modelValue: false,
34
- disabled: false
36
+ disabled: false,
37
+ loading: false,
38
+ activeColor: '#0072ce',
39
+ inactiveColor: '#dcdfe6'
35
40
  })
36
41
 
37
42
  const emit = defineEmits<{
38
43
  'update:modelValue': [value: boolean]
44
+ change: [value: boolean]
39
45
  }>()
40
46
 
41
- const handleChange = (event: Event) => {
42
- if (!props.disabled) {
43
- emit('update:modelValue', (event.target as HTMLInputElement).checked)
44
- }
47
+ const coreStyle = computed(() => ({
48
+ backgroundColor: props.modelValue ? props.activeColor : props.inactiveColor
49
+ }))
50
+
51
+ const handleClick = () => {
52
+ if (props.disabled || props.loading) return
53
+ const newValue = !props.modelValue
54
+ emit('update:modelValue', newValue)
55
+ emit('change', newValue)
45
56
  }
46
57
  </script>
47
58
 
48
59
  <style scoped>
49
- .dm-switch {
50
- display: flex;
51
- flex-direction: column;
52
- gap: var(--dm-spacing-1, 0.25rem);
53
- }
54
-
55
- .dm-switch__label {
60
+ .datametria-switch {
56
61
  display: inline-flex;
57
62
  align-items: center;
58
- gap: var(--dm-spacing-3, 0.75rem);
63
+ position: relative;
64
+ font-size: 14px;
65
+ line-height: 20px;
66
+ height: 20px;
67
+ vertical-align: middle;
68
+ border: none;
69
+ background: transparent;
59
70
  cursor: pointer;
60
- min-height: 44px;
61
- padding: var(--dm-spacing-2, 0.5rem);
62
- user-select: none;
71
+ padding: 0;
63
72
  }
64
73
 
65
- .dm-switch__label:has(.dm-switch__input:disabled) {
74
+ .datametria-switch.is-disabled {
66
75
  cursor: not-allowed;
67
76
  opacity: 0.5;
68
77
  }
69
78
 
70
- .dm-switch__input {
71
- position: absolute;
72
- opacity: 0;
73
- width: 0;
74
- height: 0;
79
+ .datametria-switch.is-loading {
80
+ cursor: not-allowed;
75
81
  }
76
82
 
77
- .dm-switch__track {
83
+ .datametria-switch__core {
84
+ display: inline-block;
78
85
  position: relative;
79
- width: 44px;
80
- height: 24px;
81
- background: var(--dm-neutral-300, #d1d5db);
82
- border-radius: 12px;
83
- transition: all 0.2s;
84
- flex-shrink: 0;
86
+ width: 40px;
87
+ height: 20px;
88
+ border-radius: 10px;
89
+ transition: background-color 0.3s;
85
90
  }
86
91
 
87
- .dm-switch__thumb {
92
+ .datametria-switch__core::after {
93
+ content: '';
88
94
  position: absolute;
89
95
  top: 2px;
90
96
  left: 2px;
91
- width: 20px;
92
- height: 20px;
93
- background: white;
97
+ width: 16px;
98
+ height: 16px;
94
99
  border-radius: 50%;
95
- transition: all 0.2s;
96
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
97
- }
98
-
99
- .dm-switch__input:checked + .dm-switch__track {
100
- background: var(--dm-primary, #0072CE);
100
+ background-color: #fff;
101
+ transition: transform 0.3s;
101
102
  }
102
103
 
103
- .dm-switch__input:checked + .dm-switch__track .dm-switch__thumb {
104
+ .datametria-switch.is-checked .datametria-switch__core::after {
104
105
  transform: translateX(20px);
105
106
  }
106
107
 
107
- .dm-switch__input:focus-visible + .dm-switch__track {
108
- outline: 2px solid var(--dm-primary, #0072CE);
109
- outline-offset: 2px;
108
+ .datametria-switch__loading {
109
+ position: absolute;
110
+ top: 50%;
111
+ left: 50%;
112
+ transform: translate(-50%, -50%);
113
+ display: flex;
114
+ align-items: center;
115
+ justify-content: center;
110
116
  }
111
117
 
112
- .dm-switch__input:disabled + .dm-switch__track {
113
- background: var(--dm-neutral-200, #e5e7eb);
118
+ .spinner {
119
+ width: 12px;
120
+ height: 12px;
121
+ border: 2px solid #fff;
122
+ border-top-color: transparent;
123
+ border-radius: 50%;
124
+ animation: spin 0.6s linear infinite;
114
125
  }
115
126
 
116
- .dm-switch__text {
117
- color: var(--dm-neutral-900, #111827);
118
- font-size: var(--dm-font-size-base, 1rem);
119
- line-height: 1.5;
127
+ @keyframes spin {
128
+ to { transform: rotate(360deg); }
120
129
  }
121
130
 
122
- .dm-switch__error {
123
- color: var(--dm-error, #ef4444);
124
- font-size: var(--dm-font-size-sm, 0.875rem);
125
- margin: 0;
131
+ .datametria-switch:focus-visible {
132
+ outline: 2px solid var(--dm-color-primary, #0072ce);
133
+ outline-offset: 2px;
134
+ border-radius: 10px;
126
135
  }
127
136
 
137
+ /* Dark mode */
128
138
  @media (prefers-color-scheme: dark) {
129
- .dm-switch__track {
130
- background: var(--dm-neutral-700, #374151);
131
- }
132
-
133
- .dm-switch__input:disabled + .dm-switch__track {
134
- background: var(--dm-neutral-800, #1f2937);
139
+ .datametria-switch__core {
140
+ background-color: var(--dm-bg-color-dark, #1e1e1e);
135
141
  }
136
142
  }
137
143
  </style>
@@ -0,0 +1,82 @@
1
+ <template>
2
+ <div
3
+ :id="id"
4
+ class="datametria-tab-pane"
5
+ :class="{ 'is-active': active }"
6
+ role="tabpanel"
7
+ :aria-labelledby="ariaLabelledby"
8
+ :hidden="!active"
9
+ >
10
+ <slot v-if="lazy ? (active || wasActive) : true"></slot>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { ref, watch, inject, onMounted, onBeforeUnmount, computed } from 'vue'
16
+
17
+ interface Props {
18
+ label: string
19
+ name?: string
20
+ disabled?: boolean
21
+ lazy?: boolean
22
+ icon?: string
23
+ badge?: string | number
24
+ }
25
+
26
+ const props = withDefaults(defineProps<Props>(), {
27
+ disabled: false,
28
+ lazy: false
29
+ })
30
+
31
+ const tabsContext = inject<any>('datametriaTabs', null)
32
+ const wasActive = ref(false)
33
+
34
+ const active = computed(() => {
35
+ if (!tabsContext) return false
36
+ return tabsContext.activePane.value === (props.name || props.label)
37
+ })
38
+
39
+ const id = computed(() => {
40
+ const name = props.name || props.label
41
+ return `pane-${name.replace(/\s+/g, '-').toLowerCase()}`
42
+ })
43
+
44
+ const ariaLabelledby = computed(() => {
45
+ const name = props.name || props.label
46
+ return `tab-${name.replace(/\s+/g, '-').toLowerCase()}`
47
+ })
48
+
49
+ watch(active, (isActive) => {
50
+ if (isActive) {
51
+ wasActive.value = true
52
+ }
53
+ })
54
+
55
+ onMounted(() => {
56
+ if (tabsContext) {
57
+ tabsContext.registerPane({
58
+ label: props.label,
59
+ name: props.name || props.label,
60
+ disabled: props.disabled,
61
+ icon: props.icon,
62
+ badge: props.badge
63
+ })
64
+ }
65
+ })
66
+
67
+ onBeforeUnmount(() => {
68
+ if (tabsContext) {
69
+ tabsContext.unregisterPane(props.name || props.label)
70
+ }
71
+ })
72
+ </script>
73
+
74
+ <style scoped>
75
+ .datametria-tab-pane {
76
+ display: none;
77
+ }
78
+
79
+ .datametria-tab-pane.is-active {
80
+ display: block;
81
+ }
82
+ </style>
@@ -1,159 +1,199 @@
1
1
  <template>
2
- <div class="dm-textarea">
3
- <label v-if="label" :for="inputId" class="dm-textarea__label">
4
- {{ label }}
5
- <span v-if="required" class="dm-textarea__required">*</span>
6
- </label>
2
+ <div class="datametria-textarea" :class="textareaClasses">
7
3
  <textarea
8
- :id="inputId"
9
- v-model="internalValue"
10
- class="dm-textarea__input"
11
- :class="{ 'dm-textarea__input--error': error }"
4
+ ref="textareaRef"
5
+ v-model="currentValue"
6
+ class="datametria-textarea__inner"
12
7
  :placeholder="placeholder"
13
8
  :disabled="disabled"
14
- :required="required"
15
- :rows="rows"
16
- :maxlength="maxLength"
17
- :aria-label="ariaLabel"
18
- :aria-describedby="error ? `${inputId}-error` : undefined"
19
- :aria-invalid="!!error"
9
+ :readonly="readonly"
10
+ :rows="computedRows"
11
+ :maxlength="maxlength"
20
12
  @input="handleInput"
13
+ @focus="handleFocus"
14
+ @blur="handleBlur"
21
15
  />
22
- <div v-if="maxLength || error" class="dm-textarea__footer">
23
- <p v-if="error" :id="`${inputId}-error`" class="dm-textarea__error">{{ error }}</p>
24
- <span v-if="maxLength" class="dm-textarea__counter">
25
- {{ internalValue?.length || 0 }}/{{ maxLength }}
26
- </span>
16
+ <div v-if="showWordLimit && maxlength" class="datametria-textarea__count">
17
+ {{ currentValue.length }} / {{ maxlength }}
27
18
  </div>
28
19
  </div>
29
20
  </template>
30
21
 
31
22
  <script setup lang="ts">
32
- import { ref, watch } from 'vue'
23
+ import { ref, computed, watch, nextTick, onMounted } from 'vue'
33
24
 
34
25
  interface Props {
35
26
  modelValue?: string
36
- label?: string
37
27
  placeholder?: string
38
28
  disabled?: boolean
39
- required?: boolean
40
- error?: string
29
+ readonly?: boolean
41
30
  rows?: number
42
- maxLength?: number
43
- ariaLabel?: string
31
+ maxlength?: number
32
+ showWordLimit?: boolean
33
+ autosize?: boolean | { minRows?: number; maxRows?: number }
44
34
  }
45
35
 
46
36
  const props = withDefaults(defineProps<Props>(), {
47
37
  modelValue: '',
38
+ placeholder: '',
48
39
  disabled: false,
49
- required: false,
50
- rows: 4
40
+ readonly: false,
41
+ rows: 3,
42
+ showWordLimit: false,
43
+ autosize: false
51
44
  })
52
45
 
53
46
  const emit = defineEmits<{
54
47
  'update:modelValue': [value: string]
48
+ input: [value: string]
49
+ focus: [event: FocusEvent]
50
+ blur: [event: FocusEvent]
55
51
  }>()
56
52
 
57
- const inputId = `dm-textarea-${Math.random().toString(36).substr(2, 9)}`
58
- const internalValue = ref(props.modelValue)
53
+ const textareaRef = ref<HTMLTextAreaElement>()
54
+ const currentValue = ref(props.modelValue)
55
+ const isFocused = ref(false)
59
56
 
60
- watch(() => props.modelValue, (newValue) => {
61
- internalValue.value = newValue
57
+ const textareaClasses = computed(() => ({
58
+ 'datametria-textarea--disabled': props.disabled,
59
+ 'datametria-textarea--focused': isFocused.value
60
+ }))
61
+
62
+ const computedRows = computed(() => {
63
+ if (props.autosize) return undefined
64
+ return props.rows
62
65
  })
63
66
 
64
- const handleInput = () => {
65
- emit('update:modelValue', internalValue.value || '')
67
+ const handleInput = (event: Event) => {
68
+ const target = event.target as HTMLTextAreaElement
69
+ currentValue.value = target.value
70
+ emit('update:modelValue', target.value)
71
+ emit('input', target.value)
72
+
73
+ if (props.autosize) {
74
+ nextTick(() => resizeTextarea())
75
+ }
66
76
  }
67
- </script>
68
77
 
69
- <style scoped>
70
- .dm-textarea {
71
- display: flex;
72
- flex-direction: column;
73
- gap: var(--dm-spacing-2, 0.5rem);
78
+ const handleFocus = (event: FocusEvent) => {
79
+ isFocused.value = true
80
+ emit('focus', event)
74
81
  }
75
82
 
76
- .dm-textarea__label {
77
- color: var(--dm-neutral-900, #111827);
78
- font-size: var(--dm-font-size-sm, 0.875rem);
79
- font-weight: var(--dm-font-weight-medium, 500);
83
+ const handleBlur = (event: FocusEvent) => {
84
+ isFocused.value = false
85
+ emit('blur', event)
80
86
  }
81
87
 
82
- .dm-textarea__required {
83
- color: var(--dm-error, #ef4444);
84
- }
88
+ const resizeTextarea = () => {
89
+ if (!textareaRef.value || !props.autosize) return
85
90
 
86
- .dm-textarea__input {
87
- width: 100%;
88
- padding: var(--dm-spacing-3, 0.75rem);
89
- border: 1px solid var(--dm-neutral-300, #d1d5db);
90
- border-radius: var(--dm-radius-md, 0.375rem);
91
- font-size: var(--dm-font-size-base, 1rem);
92
- color: var(--dm-neutral-900, #111827);
93
- background: white;
94
- transition: all 0.2s;
95
- resize: vertical;
96
- font-family: inherit;
97
- line-height: 1.5;
98
- }
91
+ const textarea = textareaRef.value
92
+ textarea.style.height = 'auto'
93
+
94
+ let minHeight = 0
95
+ let maxHeight = Infinity
99
96
 
100
- .dm-textarea__input::placeholder {
101
- color: var(--dm-neutral-400, #9ca3af);
102
- }
97
+ if (typeof props.autosize === 'object') {
98
+ if (props.autosize.minRows) {
99
+ const lineHeight = parseInt(getComputedStyle(textarea).lineHeight)
100
+ minHeight = props.autosize.minRows * lineHeight
101
+ }
102
+ if (props.autosize.maxRows) {
103
+ const lineHeight = parseInt(getComputedStyle(textarea).lineHeight)
104
+ maxHeight = props.autosize.maxRows * lineHeight
105
+ }
106
+ }
103
107
 
104
- .dm-textarea__input:hover:not(:disabled) {
105
- border-color: var(--dm-neutral-400, #9ca3af);
108
+ const scrollHeight = textarea.scrollHeight
109
+ const height = Math.max(minHeight, Math.min(maxHeight, scrollHeight))
110
+ textarea.style.height = `${height}px`
106
111
  }
107
112
 
108
- .dm-textarea__input:focus {
109
- outline: 2px solid var(--dm-primary, #0072CE);
110
- outline-offset: 0;
111
- border-color: var(--dm-primary, #0072CE);
113
+ watch(() => props.modelValue, (newValue) => {
114
+ if (newValue !== currentValue.value) {
115
+ currentValue.value = newValue
116
+ if (props.autosize) {
117
+ nextTick(() => resizeTextarea())
118
+ }
119
+ }
120
+ })
121
+
122
+ onMounted(() => {
123
+ if (props.autosize) {
124
+ nextTick(() => resizeTextarea())
125
+ }
126
+ })
127
+
128
+ defineExpose({
129
+ focus: () => textareaRef.value?.focus(),
130
+ blur: () => textareaRef.value?.blur()
131
+ })
132
+ </script>
133
+
134
+ <style scoped>
135
+ .datametria-textarea {
136
+ position: relative;
137
+ display: inline-block;
138
+ width: 100%;
139
+ vertical-align: bottom;
140
+ font-size: 14px;
112
141
  }
113
142
 
114
- .dm-textarea__input:disabled {
115
- background: var(--dm-neutral-100, #f3f4f6);
116
- cursor: not-allowed;
117
- opacity: 0.6;
143
+ .datametria-textarea__inner {
144
+ display: block;
145
+ resize: vertical;
146
+ padding: 8px 12px;
147
+ line-height: 1.5;
148
+ box-sizing: border-box;
149
+ width: 100%;
150
+ font-size: inherit;
151
+ font-family: inherit;
152
+ color: var(--datametria-text-color, #303133);
153
+ background-color: var(--datametria-bg-color, #ffffff);
154
+ border: 1px solid var(--datametria-border-color, #dcdfe6);
155
+ border-radius: 4px;
156
+ transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
118
157
  }
119
158
 
120
- .dm-textarea__input--error {
121
- border-color: var(--dm-error, #ef4444);
159
+ .datametria-textarea__inner:hover {
160
+ border-color: var(--datametria-border-color-hover, #c0c4cc);
122
161
  }
123
162
 
124
- .dm-textarea__input--error:focus {
125
- outline-color: var(--dm-error, #ef4444);
163
+ .datametria-textarea__inner:focus {
164
+ outline: none;
165
+ border-color: var(--datametria-primary-color, #0072ce);
126
166
  }
127
167
 
128
- .dm-textarea__footer {
129
- display: flex;
130
- justify-content: space-between;
131
- align-items: center;
132
- gap: var(--dm-spacing-2, 0.5rem);
168
+ .datametria-textarea__inner::placeholder {
169
+ color: var(--datametria-placeholder-color, #a8abb2);
133
170
  }
134
171
 
135
- .dm-textarea__error {
136
- color: var(--dm-error, #ef4444);
137
- font-size: var(--dm-font-size-sm, 0.875rem);
138
- margin: 0;
139
- flex: 1;
172
+ .datametria-textarea__inner:disabled {
173
+ background-color: var(--datametria-disabled-bg-color, #f5f7fa);
174
+ border-color: var(--datametria-disabled-border-color, #e4e7ed);
175
+ color: var(--datametria-disabled-text-color, #c0c4cc);
176
+ cursor: not-allowed;
140
177
  }
141
178
 
142
- .dm-textarea__counter {
143
- color: var(--dm-neutral-500, #6b7280);
144
- font-size: var(--dm-font-size-sm, 0.875rem);
145
- white-space: nowrap;
179
+ .datametria-textarea--disabled .datametria-textarea__inner {
180
+ background-color: var(--datametria-disabled-bg-color, #f5f7fa);
181
+ border-color: var(--datametria-disabled-border-color, #e4e7ed);
182
+ color: var(--datametria-disabled-text-color, #c0c4cc);
183
+ cursor: not-allowed;
146
184
  }
147
185
 
148
- @media (prefers-color-scheme: dark) {
149
- .dm-textarea__input {
150
- background: var(--dm-neutral-800, #1f2937);
151
- border-color: var(--dm-neutral-600, #4b5563);
152
- color: white;
153
- }
186
+ .datametria-textarea__count {
187
+ position: absolute;
188
+ bottom: 8px;
189
+ right: 12px;
190
+ font-size: 12px;
191
+ color: var(--datametria-info-color, #909399);
192
+ background-color: var(--datametria-bg-color, #ffffff);
193
+ padding: 0 4px;
194
+ }
154
195
 
155
- .dm-textarea__input:disabled {
156
- background: var(--dm-neutral-900, #111827);
157
- }
196
+ .datametria-textarea--focused .datametria-textarea__inner {
197
+ border-color: var(--datametria-primary-color, #0072ce);
158
198
  }
159
199
  </style>