dxd-style-code 0.1.11 → 0.1.13

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 (148) hide show
  1. package/dist/dxd-style-code.js +7470 -6336
  2. package/dist/dxd-style-code.umd.cjs +3 -3
  3. package/dist/style.css +1 -1
  4. package/package.json +2 -2
  5. package/src/components/atoms/DX/DX.stories.js +265 -0
  6. package/src/components/atoms/DX/DX.vue +80 -0
  7. package/src/components/atoms/DX/index.js +2 -0
  8. package/src/components/atoms/DXAvatar/DXAvatar.stories.js +1 -2
  9. package/src/components/atoms/DXBackdrop/DXBackdrop.stories.js +77 -1
  10. package/src/components/atoms/DXBadge/DXBadge.stories.js +83 -1
  11. package/src/components/atoms/DXBlockquote/DXBlockquote.stories.js +67 -1
  12. package/src/components/atoms/DXBox/DXBox.stories.js +1 -1
  13. package/src/components/atoms/DXBox/DXBox.vue +69 -2
  14. package/src/components/atoms/DXButton/DXButton.stories.js +94 -1
  15. package/src/components/atoms/DXButton/DXButton.vue +145 -11
  16. package/src/components/atoms/DXCard/DXCard.stories.js +72 -14
  17. package/src/components/atoms/DXCard/DXCard.vue +3 -4
  18. package/src/components/atoms/DXCheckbox/DXCheckbox.stories.js +85 -1
  19. package/src/components/atoms/DXCode/DXCode.stories.js +67 -1
  20. package/src/components/atoms/DXContainer/DXContainer.stories.js +1 -1
  21. package/src/components/atoms/DXContainer/DXContainer.vue +28 -1
  22. package/src/components/atoms/DXDivider/DXDivider.stories.js +84 -1
  23. package/src/components/atoms/DXFlex/DXFlex.stories.js +1 -1
  24. package/src/components/atoms/DXFlex/DXFlex.vue +57 -3
  25. package/src/components/atoms/DXFormLabel/DXFormLabel.stories.js +70 -1
  26. package/src/components/atoms/DXGrid/DXGrid.stories.js +1 -1
  27. package/src/components/atoms/DXHeading/DXHeading.stories.js +90 -1
  28. package/src/components/atoms/DXIcon/DXIcon.stories.js +74 -0
  29. package/src/components/atoms/DXIconWrapper/DXIconWrapper.stories.js +69 -0
  30. package/src/components/atoms/DXImage/DXImage.stories.js +483 -0
  31. package/src/components/atoms/DXImage/DXImage.vue +294 -0
  32. package/src/components/atoms/DXImage/index.js +2 -0
  33. package/src/components/atoms/DXInputAddon/DXInputAddon.stories.js +86 -1
  34. package/src/components/atoms/DXLabel/DXLabel.stories.js +62 -1
  35. package/src/components/atoms/DXLink/DXLink.stories.js +75 -10
  36. package/src/components/atoms/DXLink/DXLink.vue +59 -3
  37. package/src/components/atoms/DXList/DXList.stories.js +76 -1
  38. package/src/components/atoms/DXLoader/DXLoader.stories.js +75 -1
  39. package/src/components/atoms/DXNav/DXNav.stories.js +236 -0
  40. package/src/components/atoms/DXNav/DXNav.vue +114 -0
  41. package/src/components/atoms/DXNav/index.js +2 -0
  42. package/src/components/atoms/DXProgress/DXProgress.stories.js +76 -1
  43. package/src/components/atoms/DXRadio/DXRadio.stories.js +85 -1
  44. package/src/components/atoms/DXSkeleton/DXSkeleton.stories.js +59 -1
  45. package/src/components/atoms/DXSlider/DXSlider.stories.js +89 -0
  46. package/src/components/atoms/DXSpacer/DXSpacer.stories.js +1 -1
  47. package/src/components/atoms/DXStack/DXStack.stories.js +1 -1
  48. package/src/components/atoms/DXStack/DXStack.vue +5 -2
  49. package/src/components/atoms/DXTags/DXTags.stories.js +77 -0
  50. package/src/components/atoms/DXText/DXText.stories.js +83 -1
  51. package/src/components/atoms/DXToast/DXToast.stories.js +64 -1
  52. package/src/components/atoms/DXToggle/DXToggle.stories.js +84 -1
  53. package/src/components/atoms/DXToggleButton/DXToggleButton.stories.js +78 -1
  54. package/src/components/atoms/DXTooltip/DXTooltip.stories.js +98 -1
  55. package/src/components/atoms/index.js +3 -0
  56. package/src/components/molecules/DXActionButtons/DXActionButtons.stories.js +280 -77
  57. package/src/components/molecules/DXActionButtons/DXActionButtons.vue +31 -31
  58. package/src/components/molecules/DXAlert/DXAlert.stories.js +199 -1
  59. package/src/components/molecules/DXAlert/DXAlert.vue +35 -13
  60. package/src/components/molecules/DXBreadcrumb/DXBreadcrumb.stories.js +125 -1
  61. package/src/components/molecules/DXBreadcrumb/DXBreadcrumb.vue +22 -18
  62. package/src/components/molecules/DXButtonGroup/DXButtonGroup.stories.js +193 -6
  63. package/src/components/molecules/DXButtonGroup/DXButtonGroup.vue +39 -3
  64. package/src/components/molecules/DXCloseButton/DXCloseButton.stories.js +64 -1
  65. package/src/components/molecules/DXComboBox/DXComboBox.stories.js +66 -0
  66. package/src/components/molecules/DXCopyField/DXCopyField.stories.js +128 -1
  67. package/src/components/molecules/DXCopyField/DXCopyField.vue +60 -7
  68. package/src/components/molecules/DXDataFilter/DXDataFilter.vue +8 -6
  69. package/src/components/molecules/DXDatePicker/DXDatePicker.stories.js +58 -0
  70. package/src/components/molecules/DXFileUpload/DXFileUpload.stories.js +66 -0
  71. package/src/components/molecules/DXFilterGroup/DXFilterGroup.stories.js +61 -0
  72. package/src/components/molecules/DXFormControl/DXFormControl.stories.js +76 -0
  73. package/src/components/molecules/DXFormControl/DXFormControl.vue +9 -8
  74. package/src/components/molecules/DXInput/DXInput.stories.js +100 -1
  75. package/src/components/molecules/DXInputGroup/DXInputGroup.stories.js +89 -1
  76. package/src/components/molecules/DXInputMask/DXInputMask.stories.js +67 -0
  77. package/src/components/molecules/DXMenu/DXMenu.stories.js +111 -4
  78. package/src/components/molecules/DXMenu/DXMenu.vue +18 -5
  79. package/src/components/molecules/DXMenu/README.md +1 -1
  80. package/src/components/molecules/DXPagination/DXPagination.stories.js +105 -2
  81. package/src/components/molecules/DXPagination/DXPagination.vue +18 -33
  82. package/src/components/molecules/DXPasswordInput/DXPasswordInput.stories.js +67 -1
  83. package/src/components/molecules/DXRadioCard/DXRadioCard.stories.js +64 -0
  84. package/src/components/molecules/DXRadioGroup/DXRadioGroup.stories.js +84 -0
  85. package/src/components/molecules/DXRating/DXRating.stories.js +3 -2
  86. package/src/components/molecules/DXSearchBar/DXSearchBar.stories.js +1 -1
  87. package/src/components/molecules/DXSearchBar/DXSearchBar.vue +16 -12
  88. package/src/components/molecules/DXSearchSelect/DXSearchSelect.stories.js +71 -0
  89. package/src/components/molecules/DXSegmentedControl/DXSegmentedControl.stories.js +74 -0
  90. package/src/components/molecules/DXSelect/DXSelect.stories.js +92 -1
  91. package/src/components/molecules/DXStatCard/DXStatCard.stories.js +1 -1
  92. package/src/components/molecules/DXStatCard/DXStatCard.vue +30 -26
  93. package/src/components/molecules/DXTableFiltersPanel/index.js +3 -0
  94. package/src/components/molecules/DXTablePagination/DXTablePagination.stories.js +67 -0
  95. package/src/components/molecules/DXTableToolbar/DXTableToolbar.stories.js +71 -0
  96. package/src/components/molecules/DXTextarea/DXTextarea.stories.js +87 -1
  97. package/src/components/molecules/DXTimePicker/DXTimePicker.stories.js +1 -1
  98. package/src/components/molecules/DXValidationIcon/DXValidationIcon.stories.js +59 -1
  99. package/src/components/molecules/index.js +0 -1
  100. package/src/components/organisms/DXAccordion/DXAccordion.stories.js +75 -0
  101. package/src/components/organisms/DXAppLayout/DXAppLayout.stories.js +27 -25
  102. package/src/components/organisms/DXAuthenticationForm/DXAuthenticationForm.stories.js +0 -2
  103. package/src/components/organisms/DXAuthenticationForm/DXAuthenticationForm.vue +5 -8
  104. package/src/components/{molecules → organisms}/DXBaseTable/DXBaseTable.stories.js +78 -1
  105. package/src/components/{molecules → organisms}/DXBaseTable/DXBaseTable.vue +2 -2
  106. package/src/components/organisms/DXChartContainer/DXChartContainer.stories.js +1 -1
  107. package/src/components/organisms/DXChartContainer/DXChartContainer.vue +10 -6
  108. package/src/components/organisms/DXChatInterface/DXChatInterface.stories.js +1 -1
  109. package/src/components/organisms/DXChatInterface/DXChatInterface.vue +6 -4
  110. package/src/components/organisms/DXCommentSection/DXCommentSection.stories.js +1 -1
  111. package/src/components/organisms/DXCommentSection/DXCommentSection.vue +7 -6
  112. package/src/components/organisms/DXDashboardGrid/DXDashboardGrid.stories.js +1 -1
  113. package/src/components/organisms/DXDashboardGrid/DXDashboardGrid.vue +4 -2
  114. package/src/components/organisms/DXDashboardWidget/DXDashboardWidget.stories.js +1 -1
  115. package/src/components/organisms/DXDashboardWidget/DXDashboardWidget.vue +3 -2
  116. package/src/components/organisms/DXDataTable/DXDataTable.stories.js +1 -1
  117. package/src/components/organisms/DXDropdown/DXDropdown.stories.js +84 -1
  118. package/src/components/organisms/DXEmptyState/DXEmptyState.stories.js +64 -0
  119. package/src/components/organisms/DXEmptyState/DXEmptyState.vue +4 -2
  120. package/src/components/organisms/DXHeaderBar/DXHeaderBar.stories.js +409 -3
  121. package/src/components/organisms/DXHeaderBar/DXHeaderBar.vue +261 -52
  122. package/src/components/organisms/DXMediaGallery/DXMediaGallery.stories.js +1 -1
  123. package/src/components/organisms/DXMediaGallery/DXMediaGallery.vue +6 -4
  124. package/src/components/organisms/DXModal/DXModal.stories.js +93 -1
  125. package/src/components/organisms/DXModal/DXModal.vue +3 -2
  126. package/src/components/organisms/DXNotificationCenter/DXNotificationCenter.stories.js +1 -1
  127. package/src/components/organisms/DXNotificationCenter/DXNotificationCenter.vue +2 -1
  128. package/src/components/organisms/DXReportGenerator/DXReportGenerator.vue +4 -3
  129. package/src/components/organisms/DXSettingsPanel/DXSettingsPanel.vue +11 -8
  130. package/src/components/organisms/DXSidebar/DXSidebar.stories.js +1 -1
  131. package/src/components/organisms/DXSidebarMenu/DXSidebarMenu.stories.js +104 -1
  132. package/src/components/organisms/DXSidebarMenu/DXSidebarMenu.vue +14 -4
  133. package/src/components/organisms/DXSidebarMenu/README.md +3 -3
  134. package/src/components/organisms/DXTable/DXTable.stories.js +138 -11
  135. package/src/components/organisms/DXTable/DXTable.vue +1 -1
  136. package/src/components/organisms/DXTabs/DXTabs.stories.js +91 -1
  137. package/src/components/organisms/DXUserProfileCard/DXUserProfileCard.stories.js +1 -1
  138. package/src/components/organisms/DXUserProfileCard/DXUserProfileCard.vue +20 -18
  139. package/src/components/organisms/index.js +1 -0
  140. package/src/components/utilities/DXAnimatePresence/DXAnimatePresence.stories.js +1 -1
  141. package/src/components/utilities/DXBreakpointProvider/DXBreakpointProvider.stories.js +1 -1
  142. package/src/components/utilities/DXObserver/DXObserver.stories.js +1 -1
  143. package/src/components/utilities/DXPortal/DXPortal.stories.js +1 -1
  144. package/src/components/utilities/DXStaggeredAnimation/DXStaggeredAnimation.stories.js +2 -2
  145. package/src/components/utilities/DXThemeProvider/DXThemeProvider.stories.js +1 -1
  146. package/src/components/utilities/DXTransitionGroup/DXTransitionGroup.stories.js +1 -1
  147. package/src/composables/useSize.js +8 -1
  148. /package/src/components/{molecules → organisms}/DXBaseTable/index.js +0 -0
@@ -0,0 +1,294 @@
1
+ <template>
2
+ <div
3
+ :class="containerClasses"
4
+ data-component="DXImage"
5
+ :data-size="size"
6
+ :data-object-fit="objectFit"
7
+ :data-rounded="rounded"
8
+ :style="containerStyle"
9
+ >
10
+ <!-- Lazy loading wrapper -->
11
+ <DXObserver
12
+ v-if="lazy"
13
+ :threshold="0.1"
14
+ :once="true"
15
+ @intersect="handleIntersect"
16
+ >
17
+ <template v-if="isVisible">
18
+ <img
19
+ v-if="currentSrc && !imgError"
20
+ :src="currentSrc"
21
+ :alt="alt"
22
+ :srcset="srcset"
23
+ :sizes="sizes"
24
+ :class="imageClasses"
25
+ :style="imageStyle"
26
+ @load="handleLoad"
27
+ @error="handleError"
28
+ />
29
+ <slot v-else-if="$slots.fallback" name="fallback" />
30
+ <div v-else-if="fallback && !fallbackError" class="w-full h-full">
31
+ <img
32
+ :src="fallback"
33
+ :alt="alt"
34
+ :class="imageClasses"
35
+ :style="imageStyle"
36
+ @error="fallbackError = true"
37
+ />
38
+ </div>
39
+ <div v-else :class="defaultFallbackClasses">
40
+ <DXIcon :icon="PhotoIcon" :size="iconSize" class="text-slate-400" />
41
+ </div>
42
+ </template>
43
+ <div v-else-if="showSkeleton" :class="skeletonClasses">
44
+ <slot name="placeholder">
45
+ <div class="w-full h-full bg-slate-200 animate-pulse" />
46
+ </slot>
47
+ </div>
48
+ </DXObserver>
49
+
50
+ <!-- Non-lazy loading -->
51
+ <template v-else>
52
+ <img
53
+ v-if="currentSrc && !imgError"
54
+ :src="currentSrc"
55
+ :alt="alt"
56
+ :srcset="srcset"
57
+ :sizes="sizes"
58
+ :class="imageClasses"
59
+ :style="imageStyle"
60
+ @load="handleLoad"
61
+ @error="handleError"
62
+ />
63
+ <slot v-else-if="$slots.fallback" name="fallback" />
64
+ <div v-else-if="fallback && !fallbackError" class="w-full h-full">
65
+ <img
66
+ :src="fallback"
67
+ :alt="alt"
68
+ :class="imageClasses"
69
+ :style="imageStyle"
70
+ @error="fallbackError = true"
71
+ />
72
+ </div>
73
+ <div v-else :class="defaultFallbackClasses">
74
+ <DXIcon :icon="PhotoIcon" :size="iconSize" class="text-slate-400" />
75
+ </div>
76
+ </template>
77
+ </div>
78
+ </template>
79
+
80
+ <script setup>
81
+ import { ref, computed, watch } from "vue";
82
+ import { PhotoIcon } from "@heroicons/vue/24/outline";
83
+ import { useSize } from "../../../composables/useSize";
84
+ import { useClassComposition } from "../../../composables/useClassComposition";
85
+ import DXObserver from "../../utilities/DXObserver/DXObserver.vue";
86
+ import DXIcon from "../DXIcon/DXIcon.vue";
87
+
88
+ const props = defineProps({
89
+ /** URL изображения */
90
+ src: { type: String, required: true },
91
+ /** Alt текст для доступности */
92
+ alt: { type: String, default: "" },
93
+ /** Ширина изображения (кастомная) */
94
+ width: { type: [String, Number], default: null },
95
+ /** Высота изображения (кастомная) */
96
+ height: { type: [String, Number], default: null },
97
+ /** Предопределенный размер: xs | sm | md | lg | xl */
98
+ size: { type: String, default: null },
99
+ /** object-fit: cover | contain | fill | none | scale-down */
100
+ objectFit: { type: String, default: "cover", validator: (v) => ["cover", "contain", "fill", "none", "scale-down"].includes(v) },
101
+ /** Lazy loading через DXObserver */
102
+ lazy: { type: Boolean, default: false },
103
+ /** URL fallback изображения при ошибке */
104
+ fallback: { type: String, default: null },
105
+ /** URL placeholder изображения */
106
+ placeholder: { type: String, default: null },
107
+ /** Показывать skeleton при загрузке */
108
+ showSkeleton: { type: Boolean, default: true },
109
+ /** Скругление: none | sm | md | lg | xl | full */
110
+ rounded: { type: String, default: "none", validator: (v) => ["none", "sm", "md", "lg", "xl", "full"].includes(v) },
111
+ /** Responsive изображения (srcset атрибут) */
112
+ srcset: { type: String, default: null },
113
+ /** Sizes атрибут для responsive */
114
+ sizes: { type: String, default: null },
115
+ });
116
+
117
+ const emit = defineEmits(["load", "error"]);
118
+
119
+ /**
120
+ * Флаг ошибки загрузки основного изображения
121
+ */
122
+ const imgError = ref(false);
123
+
124
+ /**
125
+ * Флаг ошибки загрузки fallback изображения
126
+ */
127
+ const fallbackError = ref(false);
128
+
129
+ /**
130
+ * Флаг видимости для lazy loading
131
+ */
132
+ const isVisible = ref(false);
133
+
134
+ /**
135
+ * Текущий источник изображения
136
+ *
137
+ * @description
138
+ * Определяет какой источник использовать:
139
+ * - Если есть placeholder и изображение еще не загружено (lazy режим) → placeholder
140
+ * - Иначе → основной src
141
+ */
142
+ const currentSrc = computed(() => {
143
+ if (props.placeholder && props.lazy && !isVisible.value) {
144
+ return props.placeholder;
145
+ }
146
+ return props.src;
147
+ });
148
+
149
+ /**
150
+ * Стили для контейнера
151
+ *
152
+ * @description
153
+ * Вычисляет inline стили для контейнера на основе width и height props.
154
+ * Если указан size, размеры берутся из useSize.
155
+ */
156
+ const containerStyle = computed(() => {
157
+ const style = {};
158
+
159
+ if (props.width) {
160
+ style.width = typeof props.width === 'number' ? `${props.width}px` : props.width;
161
+ }
162
+
163
+ if (props.height) {
164
+ style.height = typeof props.height === 'number' ? `${props.height}px` : props.height;
165
+ }
166
+
167
+ return Object.keys(style).length > 0 ? style : null;
168
+ });
169
+
170
+ /**
171
+ * Стили для изображения
172
+ */
173
+ const imageStyle = computed(() => {
174
+ return null;
175
+ });
176
+
177
+ /**
178
+ * Классы для контейнера
179
+ */
180
+ const containerClasses = computed(() =>
181
+ useClassComposition(
182
+ "relative inline-block overflow-hidden",
183
+ props.size ? useSize(props.size, 'image') : null,
184
+ {
185
+ "rounded-sm": props.rounded === "sm",
186
+ "rounded-md": props.rounded === "md",
187
+ "rounded-lg": props.rounded === "lg",
188
+ "rounded-xl": props.rounded === "xl",
189
+ "rounded-full": props.rounded === "full",
190
+ }
191
+ )
192
+ );
193
+
194
+ /**
195
+ * Классы для изображения
196
+ */
197
+ const imageClasses = computed(() => {
198
+ const objectFitClasses = {
199
+ cover: "object-cover",
200
+ contain: "object-contain",
201
+ fill: "object-fill",
202
+ none: "object-none",
203
+ "scale-down": "object-scale-down",
204
+ };
205
+
206
+ return useClassComposition(
207
+ "w-full h-full",
208
+ objectFitClasses[props.objectFit] || objectFitClasses.cover
209
+ );
210
+ });
211
+
212
+ /**
213
+ * Классы для skeleton
214
+ */
215
+ const skeletonClasses = computed(() =>
216
+ useClassComposition("w-full h-full")
217
+ );
218
+
219
+ /**
220
+ * Классы для дефолтного fallback
221
+ */
222
+ const defaultFallbackClasses = computed(() =>
223
+ useClassComposition(
224
+ "w-full h-full bg-slate-100 flex items-center justify-center"
225
+ )
226
+ );
227
+
228
+ /**
229
+ * Размер иконки для fallback
230
+ */
231
+ const iconSize = computed(() => {
232
+ if (props.size) {
233
+ const sizeMap = {
234
+ xs: "sm",
235
+ sm: "md",
236
+ md: "lg",
237
+ lg: "xl",
238
+ xl: "xl",
239
+ };
240
+ return sizeMap[props.size] || "lg";
241
+ }
242
+ return "lg";
243
+ });
244
+
245
+ /**
246
+ * Обработчик успешной загрузки изображения
247
+ */
248
+ function handleLoad() {
249
+ emit("load");
250
+ }
251
+
252
+ /**
253
+ * Обработчик ошибки загрузки изображения
254
+ */
255
+ function handleError() {
256
+ imgError.value = true;
257
+ emit("error");
258
+ }
259
+
260
+ /**
261
+ * Обработчик пересечения для lazy loading
262
+ */
263
+ function handleIntersect(intersecting) {
264
+ if (intersecting) {
265
+ isVisible.value = true;
266
+ }
267
+ }
268
+
269
+ // Инициализация для non-lazy режима
270
+ if (!props.lazy) {
271
+ isVisible.value = true;
272
+ }
273
+
274
+ /**
275
+ * Сбрасывает ошибки при изменении src
276
+ */
277
+ watch(() => props.src, () => {
278
+ imgError.value = false;
279
+ fallbackError.value = false;
280
+ if (!props.lazy) {
281
+ isVisible.value = true;
282
+ }
283
+ });
284
+
285
+ /**
286
+ * Сбрасывает видимость при изменении lazy
287
+ */
288
+ watch(() => props.lazy, (newVal) => {
289
+ if (!newVal) {
290
+ isVisible.value = true;
291
+ }
292
+ });
293
+ </script>
294
+
@@ -0,0 +1,2 @@
1
+ export { default } from './DXImage.vue';
2
+
@@ -12,7 +12,92 @@ import {
12
12
  export default {
13
13
  title: 'Atoms/DXInputAddon',
14
14
  component: DXInputAddon,
15
- tags: ['autodocs'],
15
+ tags: ['autodocs', 'category:form'],
16
+ parameters: {
17
+ docs: {
18
+ description: {
19
+ component: `
20
+ # DXInputAddon
21
+
22
+ Компонент аддона для групп полей ввода, используемый для добавления префиксов и суффиксов к полям.
23
+
24
+ ## Назначение
25
+
26
+ DXInputAddon предоставляет способ добавления дополнительных элементов (текста, иконок) слева или справа
27
+ от полей ввода в составе DXInputGroup. Компонент автоматически синхронизирует размер, состояние disabled/error
28
+ и правильно применяет border-radius для визуального единства группы.
29
+
30
+ ## Архитектура
31
+
32
+ ### Использует
33
+ - \`useSize\` composable - для унификации размеров (синхронизируется с DXInputGroup)
34
+ - \`provide/inject\` - для интеграции с DXInputGroup
35
+
36
+ ### Используется в
37
+ - \`DXInputGroup\` - группы полей с аддонами
38
+ - Префиксы для URL (https://)
39
+ - Суффиксы для валют (USD, EUR)
40
+ - Иконки в группах полей
41
+ - Любые места, требующие дополнительных элементов рядом с полями
42
+
43
+ ## Внутренняя логика
44
+
45
+ ### Интеграция с DXInputGroup
46
+ При использовании внутри \`DXInputGroup\`:
47
+ - Аддон автоматически регистрируется в группе через \`provide/inject\`
48
+ - Размер синхронизируется с размером группы
49
+ - Состояние \`disabled\` наследуется от группы
50
+ - Состояние \`error\` синхронизируется с группой (красная рамка)
51
+ - Border-radius адаптируется в зависимости от позиции:
52
+ - Первый аддон → \`rounded-l-xl\`
53
+ - Последний аддон → \`rounded-r-xl\`
54
+ - Средний аддон → \`rounded-none\`
55
+
56
+ ### Содержимое
57
+ Аддон может содержать:
58
+ - Текст через default slot (например, "https://", "USD")
59
+ - Иконку через \`icon\` prop (Heroicon компонент)
60
+ - Комбинацию текста и иконки
61
+
62
+ ### Визуальное оформление
63
+ - Фон: \`bg-slate-50\` (светло-серый)
64
+ - Текст: \`text-slate-600\`
65
+ - Рамка: синхронизируется с группой
66
+ - Padding: адаптируется к размеру группы
67
+
68
+ ## Особенности
69
+
70
+ ### Позиционирование
71
+ - Аддоны размещаются слева или справа от основного поля
72
+ - Может быть несколько аддонов (например, $ слева и USD справа)
73
+
74
+ ### Размеры
75
+ Размер автоматически синхронизируется с размером DXInputGroup:
76
+ - **sm** - маленький размер
77
+ - **md** - средний размер (по умолчанию)
78
+ - **lg** - крупный размер
79
+
80
+ ### Состояния
81
+ - **disabled** - наследуется от группы, аддон становится полупрозрачным
82
+ - **error** - наследуется от группы, рамка становится красной
83
+
84
+ ### Иконки
85
+ - Иконка отображается слева от текста (если есть)
86
+ - Размер иконки: \`w-4 h-4\`
87
+ - Можно использовать только иконку без текста
88
+
89
+ ### Использование
90
+ Аддоны всегда используются внутри DXInputGroup:
91
+ \`\`\`
92
+ <DXInputGroup label="Website">
93
+ <DXInputAddon>https://</DXInputAddon>
94
+ <DXInput v-model="url" placeholder="example.com" />
95
+ </DXInputGroup>
96
+ \`\`\`
97
+ `,
98
+ },
99
+ },
100
+ },
16
101
  argTypes: {
17
102
  icon: {
18
103
  control: false,
@@ -3,7 +3,68 @@ import DXLabel from './DXLabel.vue';
3
3
  export default {
4
4
  title: 'Atoms/DXLabel',
5
5
  component: DXLabel,
6
- tags: ['autodocs'],
6
+ tags: ['autodocs', 'category:typography'],
7
+ parameters: {
8
+ docs: {
9
+ description: {
10
+ component: `
11
+ # DXLabel
12
+
13
+ Компонент лейбла для форм с поддержкой различных размеров, весов и цветов.
14
+
15
+ ## Назначение
16
+
17
+ DXLabel предоставляет стандартизированный лейбл для форм с настраиваемыми параметрами типографики.
18
+ Компонент поддерживает различные размеры, веса шрифта, цвета и автоматическое отображение индикатора
19
+ обязательного поля.
20
+
21
+ ## Архитектура
22
+
23
+ ### Использует
24
+ - \`useVariantText\` composable - для цветовых вариантов
25
+
26
+ ### Используется в
27
+ - Формы с полями ввода
28
+ - Связанные с input элементами лейблы
29
+ - Любые места, требующие текстовых меток
30
+
31
+ ## Внутренняя логика
32
+
33
+ ### Размеры
34
+ Поддерживает 4 размера:
35
+ - **xs** - очень маленький текст
36
+ - **sm** - маленький текст (по умолчанию)
37
+ - **md** - средний текст
38
+ - **lg** - большой текст
39
+
40
+ ### Веса шрифта
41
+ Поддерживает 3 веса:
42
+ - **normal** - обычный вес
43
+ - **medium** - средний вес (по умолчанию)
44
+ - **semibold** - полужирный
45
+
46
+ ### Цвета
47
+ Поддерживает 3 цветовых варианта:
48
+ - **default** - цвет по умолчанию
49
+ - **muted** - приглушенный цвет
50
+ - **primary** - основной цвет
51
+
52
+ ### Обязательное поле
53
+ При \`required={true}\` автоматически добавляется красная звездочка (*) справа от текста.
54
+
55
+ ## Особенности
56
+
57
+ ### Связь с input
58
+ Поддерживает \`htmlFor\` prop для связи с input элементом через \`id\`:
59
+ - Улучшает доступность
60
+ - Позволяет кликать на лейбл для фокуса на input
61
+
62
+ ### Семантика
63
+ Использует нативный HTML \`<label>\` тег для правильной семантики и доступности.
64
+ `,
65
+ },
66
+ },
67
+ },
7
68
  };
8
69
 
9
70
  export const Default = {
@@ -5,7 +5,7 @@ import { HomeIcon } from '@heroicons/vue/24/outline';
5
5
  export default {
6
6
  title: 'Atoms/DXLink',
7
7
  component: DXLink,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'category:navigation'],
9
9
  parameters: {
10
10
  docs: {
11
11
  description: {
@@ -51,10 +51,13 @@ DXLink - атомарный компонент для создания ссыл
51
51
  - \`rel="noopener noreferrer"\` - для защиты от tabnabbing атак
52
52
  - Иконка внешней ссылки (если \`showExternalIcon={true}\`)
53
53
 
54
- ### Disabled состояние
55
- - Блокирует клик через \`preventDefault\` и \`stopPropagation\`
56
- - Применяет визуальные стили (opacity, cursor)
57
- - Отключает pointer-events
54
+ ### Варианты стилизации
55
+ - \`link\` (по умолчанию) - обычные текстовые ссылки без padding и border-radius
56
+ - \`primary\`, \`secondary\`, \`ghost\`, \`outline\` - варианты с небольшими отступами (padding) и скруглениями (rounded-lg)
57
+
58
+ ### Состояния
59
+ - **disabled**: Полностью отключает ссылку - блокирует клик, применяет визуальные стили (opacity, cursor-not-allowed), отключает pointer-events
60
+ - **inactive**: Визуально приглушенная ссылка, но остается кликабельной. Используется для текущих страниц, неактивных элементов навигации
58
61
 
59
62
  ## Особенности
60
63
 
@@ -72,11 +75,23 @@ DXLink - атомарный компонент для создания ссыл
72
75
  <DXLink href="/about">О нас</DXLink>
73
76
  \`\`\`
74
77
 
78
+ ## Особенности
79
+
80
+ ### Padding и Border-radius
81
+ Варианты (кроме \`link\`) автоматически получают:
82
+ - Небольшие отступы в зависимости от размера (xs: px-2 py-0.5, sm: px-2.5 py-1, md: px-3 py-1.5, lg: px-3.5 py-2, xl: px-4 py-2.5)
83
+ - Скругления \`rounded-lg\`
84
+
85
+ ### Разница между disabled и inactive
86
+ - **disabled**: Ссылка полностью неактивна, не кликабельна, визуально затемнена
87
+ - **inactive**: Ссылка визуально приглушена, но остается кликабельной. Подходит для текущих страниц в навигации
88
+
75
89
  ## Ограничения
76
90
 
77
91
  - Не используйте одновременно \`href\` и \`to\` - приоритет у \`to\`
78
92
  - Для Vue Router требуется установленный \`vue-router\`
79
93
  - Disabled ссылки не кликабельны, но остаются в DOM
94
+ - Inactive ссылки кликабельны, но визуально приглушены
80
95
  `,
81
96
  },
82
97
  },
@@ -84,8 +99,8 @@ DXLink - атомарный компонент для создания ссыл
84
99
  argTypes: {
85
100
  variant: {
86
101
  control: 'select',
87
- options: ['primary', 'secondary', 'ghost', 'link'],
88
- description: 'Вариант стилизации ссылки. Определяет цвет и стиль.',
102
+ options: ['link', 'primary', 'secondary', 'ghost', 'outline'],
103
+ description: 'Вариант стилизации ссылки. "link" - обычная ссылка без padding, остальные - с padding и border-radius.',
89
104
  table: {
90
105
  type: { summary: 'string' },
91
106
  defaultValue: { summary: 'link' },
@@ -104,7 +119,16 @@ DXLink - атомарный компонент для создания ссыл
104
119
  },
105
120
  disabled: {
106
121
  control: 'boolean',
107
- description: 'Отключенное состояние. Блокирует клик и применяет визуальные стили.',
122
+ description: 'Отключенное состояние. Блокирует клик и применяет визуальные стили. Ссылка не кликабельна.',
123
+ table: {
124
+ type: { summary: 'boolean' },
125
+ defaultValue: { summary: 'false' },
126
+ category: 'Behavior',
127
+ },
128
+ },
129
+ inactive: {
130
+ control: 'boolean',
131
+ description: 'Неактивное состояние. Визуально приглушенная ссылка, но остается кликабельной. Используется для текущих страниц.',
108
132
  table: {
109
133
  type: { summary: 'boolean' },
110
134
  defaultValue: { summary: 'false' },
@@ -192,7 +216,7 @@ export const Variants = {
192
216
  parameters: {
193
217
  docs: {
194
218
  description: {
195
- story: 'Все доступные варианты стилизации ссылок. Вариант "link" - стандартный для текстовых ссылок, остальные варианты делают ссылку похожей на кнопку.',
219
+ story: 'Все доступные варианты стилизации ссылок. Вариант "link" - стандартный для текстовых ссылок без padding и border-radius. Остальные варианты имеют небольшие отступы и скругления, делая ссылку похожей на кнопку.',
196
220
  },
197
221
  },
198
222
  },
@@ -207,10 +231,14 @@ export const Variants = {
207
231
  <DXLink href="/primary" variant="primary">Primary</DXLink>
208
232
  <DXLink href="/secondary" variant="secondary">Secondary</DXLink>
209
233
  <DXLink href="/ghost" variant="ghost">Ghost</DXLink>
234
+ <DXLink href="/outline" variant="outline">Outline</DXLink>
210
235
  </div>
211
236
  </div>
212
237
  <div class="text-sm text-slate-600">
213
- Все варианты: link | primary | secondary | ghost
238
+ Все варианты: link | primary | secondary | ghost | outline
239
+ </div>
240
+ <div class="text-xs text-slate-500">
241
+ Варианты (кроме link) имеют padding и border-radius
214
242
  </div>
215
243
  </div>
216
244
  `,
@@ -357,6 +385,43 @@ export const Disabled = {
357
385
  }),
358
386
  };
359
387
 
388
+ export const Inactive = {
389
+ parameters: {
390
+ docs: {
391
+ description: {
392
+ story: 'Неактивное состояние ссылки. Визуально приглушенная ссылка (opacity, приглушенные цвета), но остается кликабельной. Используется для текущих страниц в навигации, breadcrumb и других случаях, когда нужно показать неактивный элемент, но сохранить возможность клика.',
393
+ },
394
+ },
395
+ },
396
+ render: () => ({
397
+ components: { DXLink },
398
+ template: `
399
+ <div class="flex flex-col items-start gap-4">
400
+ <div class="flex flex-col gap-4">
401
+ <h3 class="text-sm font-semibold text-slate-700">Неактивные ссылки</h3>
402
+ <div class="flex items-center gap-4 flex-wrap">
403
+ <DXLink href="/current" inactive variant="link">
404
+ Текущая страница (link)
405
+ </DXLink>
406
+ <DXLink href="/current" inactive variant="primary">
407
+ Текущая страница (primary)
408
+ </DXLink>
409
+ <DXLink href="/current" inactive variant="ghost">
410
+ Текущая страница (ghost)
411
+ </DXLink>
412
+ </div>
413
+ <div class="text-sm text-slate-600">
414
+ Неактивные ссылки визуально приглушены, но остаются кликабельными
415
+ </div>
416
+ <div class="text-xs text-slate-500">
417
+ Используется для текущих страниц в breadcrumb и навигации
418
+ </div>
419
+ </div>
420
+ </div>
421
+ `,
422
+ }),
423
+ };
424
+
360
425
  export const WithIcons = {
361
426
  parameters: {
362
427
  docs: {