Глобальная конфигурация
CDS 4 позволяет задать значения пропсов по умолчанию — глобально, для конкретного компонента или только внутри определённого поддерева. Так вы один раз описываете «как выглядят кнопки в нашем продукте» и перестаёте дублировать одни и те же пропсы в каждом шаблоне.
Настройка
Значения по умолчанию задаются опцией defaults в createCds. Ключ global действует на все компоненты, ключ с именем компонента — только на него.
import { createApp } from 'vue';
import '@central-design-system/components/styles';
import { createCds, components, directives } from '@central-design-system/components';
import App from './App.vue';
const cds = createCds({
components,
directives,
defaults: {
global: {
size: 'sm'
},
CdsButton: {
appearance: 'secondary'
},
CdsTextInput: {
hideDetails: 'auto'
}
}
});
createApp(App).use(cds);Важно. Пропсы в defaults пишутся в camelCase: hideDetails, а не hide-details.
Ключ компонента — это его имя из defineOptions({ name }), то есть CdsButton, CdsTextInput, CdsCardActions и так далее. Имена подкомпонентов (CdsCardTitle, CdsListItem) работают так же, как имена корневых.
Порядок разрешения значения
Для каждого пропса CDS берёт первое подходящее значение:
- проп, явно переданный в шаблоне;
defaults.<ИмяКомпонента>.<проп>из ближайшего контекста дефолтов;defaults.global.<проп>;- значение по умолчанию, объявленное в самом компоненте.
Явно переданный проп всегда выигрывает — дефолты не могут «перебить» шаблон.
Изменение дефолтов в рантайме
createCds возвращает инстанс, у которого дефолты лежат в реактивной ссылке. Их можно менять на лету — все смонтированные компоненты пересчитаются:
const cds = createCds({ components, directives });
// например, включить компактный режим по настройке пользователя
cds.defaults.value = {
...cds.defaults.value,
global: { size: 'sm' }
};Контекстные дефолты
Дефолты можно задать для компонентов, вложенных в другой компонент. Например, чтобы все кнопки внутри карточки по умолчанию были вторичными:
createCds({
defaults: {
CdsCard: {
CdsButton: { appearance: 'secondary' }
}
}
});Правило простое: ключ с заглавной буквы — это имя вложенного компонента, ключ со строчной — проп текущего компонента. Вложенность не ограничена одним уровнем:
createCds({
defaults: {
CdsCard: {
CdsCardActions: {
CdsButton: { appearance: 'tertiary', size: 'sm' }
}
}
}
});Тот же механизм библиотека использует внутри себя, чтобы группирующие компоненты раздавали свои настройки детям:
CdsButtonGroupзадаёт вложеннымCdsButtonпропсыappearance,color,baseColor,size;CdsTagGroupзадаётCdsTagпропсыcolor,activeColor,disabled,filter;CdsSelectionControlGroupраздаёт настройки контролам, имя целевого компонента задаётся пропомdefaultsTarget(CdsCheckbox,CdsRadioи т. д.);- так же работают
CdsTabs,CdsSteps,CdsList,CdsBreadcrumbs,CdsButtonToggle,CdsExpandablePanels,CdsOtpInput.
Поэтому <CdsButtonGroup size="sm"> делает маленькими все кнопки внутри — вам не нужно проставлять size каждой.
Глобальные класс и стиль
В дефолтах компонента, помимо пропсов, можно задать class и style. Это удобный способ навесить продуктовые правила на все экземпляры компонента, не трогая шаблоны:
createCds({
defaults: {
CdsButton: {
class: 'my-button'
}
}
});Работает любое значение, которое принимает Vue, — строка, объект, массив:
createCds({
defaults: {
CdsButton: {
style: [{ textTransform: 'none' }]
}
}
});В отличие от обычных пропсов, class и style не перезаписываются шаблоном, а объединяются с ним. То есть <CdsButton class="mt-2"> получит и my-button, и mt-2.
Важно. class и style работают только в ключе конкретного компонента. В global они игнорируются.
Алиасы
Алиас — это тот же компонент, зарегистрированный под другим именем и со своими дефолтами. Из алиасов удобно собирать «продуктовые» варианты компонентов.
import { createCds, components, directives, CdsButton } from '@central-design-system/components';
const cds = createCds({
components,
directives,
aliases: {
CdsButtonPrimary: CdsButton,
CdsButtonDanger: CdsButton
},
defaults: {
CdsButtonPrimary: {
appearance: 'primary',
class: 'my-button--primary'
},
CdsButtonDanger: {
appearance: 'primary',
color: 'red',
class: 'my-button--danger'
}
}
});Алиасы регистрируются глобально, поэтому в шаблоне их можно использовать сразу:
<template>
<CdsButtonPrimary>Сохранить</CdsButtonPrimary>
<CdsButtonDanger class="ml-2">Удалить</CdsButtonDanger>
</template>Важно. Алиас не наследует дефолты базового компонента. Если в конфигурации есть defaults.CdsButton, к <CdsButtonPrimary> они не применятся — дефолты ищутся по имени алиаса. Общие настройки для обоих выносите в global или дублируйте в ключе алиаса.
Дефолты для части приложения
Чтобы задать дефолты не глобально, а в поддереве, используйте компонент CdsDefaultsProvider. На нём же построена панель Controls в Storybook: значения из панели применяются к компонентам примера как дефолты.
<script setup lang="ts">
import { CdsButton, CdsDefaultsProvider } from '@central-design-system/components';
</script>
<template>
<CdsDefaultsProvider :defaults="{ CdsButton: { appearance: 'tertiary', size: 'sm' } }">
<CdsButton>Второстепенная маленькая кнопка</CdsButton>
</CdsDefaultsProvider>
</template>| Проп | Тип | Назначение |
|---|---|---|
defaults | DefaultsOptions | Дефолты для поддерева; по умолчанию мержатся с унаследованными |
scoped | boolean | Не смешивать с родительскими дефолтами — действуют только заданные здесь |
reset | number | string | Подняться на N уровней вверх по цепочке дефолтов |
root | boolean | string | Вернуться к корневым дефолтам из createCds; строкой — к именованной группе внутри них |
disabled | boolean | Ничего не провайдить — поддерево получает дефолты родителя как есть |
Типичный сценарий scoped — «островок» в чужом окружении: вложенные группы (например, CdsButtonGroup) не должны навязывать свои настройки вашему блоку.
Свои компоненты
Собственные компоненты приложения тоже могут участвовать в системе дефолтов. Для этого пропустите пропсы через useDefaults:
<script setup lang="ts">
import { useDefaults } from '@central-design-system/components';
const _props = defineProps<{ foo?: string }>();
const props = useDefaults(_props, 'MyComponent');
</script>
<template>
<div>Я {{ props.foo }}</div>
</template>У useDefaults два аргумента, оба опциональные:
props— объект пропсов, возвращённыйdefineProps;name— имя компонента, по которому ищется ключ вdefaults. Если не передать, берётся имя изdefineOptions({ name }), а при его отсутствии — имя файла.
Теперь компонент настраивается из общей конфигурации:
createCds({
defaults: {
MyComponent: { foo: 'бар' }
}
});Важно. В шаблоне обращайтесь к props.foo, а не к foo. useDefaults возвращает прокси над пропсами, и распакованные defineProps переменные его минуют:
-<div>Я {{ foo }}</div>
+<div>Я {{ props.foo }}</div>Вложенные дефолты в своих компонентах
Чтобы ваш компонент раздавал дефолты детям (как это делает CdsButtonGroup), достаточно вызвать useDefaults() без аргументов — вложенные ключи из его секции defaults уйдут в дочерний контекст:
<script setup lang="ts">
import { useDefaults } from '@central-design-system/components';
useDefaults();
</script>
<template>
<div class="my-panel">
<slot />
</div>
</template>createCds({
defaults: {
MyPanel: {
CdsButton: { appearance: 'tertiary' }
}
}
});Если дефолты детей зависят от пропсов компонента, используйте provideDefaults напрямую:
<script setup lang="ts">
import { provideDefaults } from '@central-design-system/components';
import { toRef } from 'vue';
const props = defineProps<{ size?: 'sm' | 'md' }>();
provideDefaults({
CdsButton: {
size: toRef(() => props.size)
}
});
</script>
<template>
<div class="my-toolbar">
<slot />
</div>
</template>Blueprint — пресет конфигурации
Если один и тот же набор опций нужен нескольким приложениям, вынесите его в blueprint: это обычный объект опций createCds, на который сверху накладывается остальная конфигурация.
import { createCds, components, directives } from '@central-design-system/components';
import type { Blueprint } from '@central-design-system/components';
const productBlueprint: Blueprint = {
theme: { defaultTheme: 'b2bLight' },
defaults: {
CdsButton: { appearance: 'secondary' }
}
};
const cds = createCds({
blueprint: productBlueprint,
components,
directives,
// перекрывает значение из blueprint
defaults: {
CdsButton: { size: 'sm' }
}
});Опции сливаются глубоко (mergeDeep), поэтому в примере выше у кнопок останется appearance: 'secondary' из пресета и добавится size: 'sm'.