К содержимому

SusSkin ​

SusSkin

Механика скина — применяет обнаруженный дескриптор скина к живому дереву VisualElement: layout-листы остаются прикреплены независимо от того, включён скин или нет, поэтому классы композиции .sharq продолжают разрешаться; brand-листы (токены/переопределения) прикрепляются только пока скин включён — именно это означает «выключено → стандартный вид SUS». Необязательный слой component приносит небольшие листы переопределений в каждый компонент, пока скин включён. Классы root/surface переключаются обычным USS, переключая поверхность между glass и paper.

Пакет

SusKit · Сервисы (коммерческий)

SusSkin — обычный статический класс C#, не компонент .sharq. Сам Kit никогда не называет конкретный скин — каждый скин поставляется как собственный ассет-дескриптор (SusSkinAsset) и подключается через ту же механику, будь то бесплатный layout-only скин или платный brand-скин-набор.

Использование ​

csharp
// Fluent SusApp entry — layout sheets always, brand + component sheets and fonts only when enabled
SusApp.Create(document)
    .UseSkin(mySkinAsset, enabled: true)
    .Run();

// Re-apply on a live root (surface defaults to the descriptor's DefaultSurface)
SusSkin.Apply(root, mySkinAsset, enabled: true, SusSkinSurface.Glass);

// Remove the skin entirely — classes off, layout, brand AND component sheets detached
SusSkin.Off(root, mySkinAsset);
ЧленРоль
UseSkin(skin, enabled)Fluent-вход SusApp — layout-листы всегда, brand- и component-листы и шрифты при включении
Apply(root, skin, enabled, surface?)Переключает классы root/surface, (пере)прикрепляет листы на живом корне, добавляет или снимает слой component — идемпотентно
Off(root, skin)Отсоединяет всё, включая layout-листы и слой component — для окончательного ухода из дерева
AttachLayoutSheets(element, skin)Только layout-листы, для поддеревьев вне корневой панели приложения

Дескриптор скина ​

Скин — это данные: дескриптор sus-skin.<id>.json (схема sus-skin/v1), который разбирает SusSkinAsset. Элементы листов — пути Resources.

json
{
  "schema": "sus-skin/v1",
  "id": "myskin",
  "class": "myskin-skin",
  "sheets": {
    "layout":    ["SusRuntime/myskin-screens"],
    "brand":     ["SusRuntime/myskin-tokens", "SusRuntime/myskin-overrides"],
    "component": ["SusRuntime/myskin-component-overrides"]
  },
  "surfaces": { "glass": "myskin-skin--glass", "paper": "myskin-skin--paper" },
  "defaultSurface": "glass"
}
СлойКуда прикрепляетсяКогдаЧто в нём лежит
sheets.layoutКорень скинаВсегда, пока скин присутствует, включён он или нетКлассы композиции для собственного .sharq-обрамления скина
sheets.brandКорень скинаТолько пока скин включёнДизайн-токены (custom properties) и переопределения, написанные под классом скина
sheets.component (необязательный)Каждый стилизованный компонент под корнем скина, после собственного сгенерированного листа компонентаТолько пока скин включёнНебольшие листы только с переопределениями, написанные без префикса класса скина, — без токенов

Дескриптор без sheets.component оставляет листы стилей каждого компонента ровно такими же, как без скина.

Как побеждают правила бренда ​

UI Toolkit разрешает конфликт между правилами из разных листов сначала по специфичности. Только при равной специфичности побеждает лист, прикреплённый ниже по иерархии. Каждый стилизованный компонент Kit несёт собственный сгенерированный лист (.g.uss) на самом элементе компонента, поэтому правило бренда на корне с той же специфичностью, что и правило Kit, ему проигрывает — остаётся вид Kit.

Заставить правило бренда победить можно двумя способами.

По умолчанию: переопределения под классом скина ​

Предваряйте каждое переопределение корневым классом скина (class дескриптора). Один лишний класс поднимает специфичность выше одноклассового правила Kit, и правило побеждает с корня. Это ничего не стоит в рантайме и не требует дополнительного слоя.

css
/* Loses: (0,1,0) on the root ties with (0,1,0) on the component itself */
.sus-menu-button { border-width: 1px; }

/* Wins: (0,2,0) beats the kit's (0,1,0) */
.myskin-skin .sus-menu-button { border-width: 1px; }

Если правило Kit само составное, повторите под префиксом весь селектор Kit. Одноклассового префикса там недостаточно: .myskin-skin .sus-menu-button — это (0,2,0), столько же, сколько у составного .sus-menu-button--flat.sus-menu-button--color-primary в Kit, а ничья достаётся собственному листу компонента.

css
/* Wins: (0,3,0) beats the kit's compound (0,2,0) */
.myskin-skin .sus-menu-button--flat.sus-menu-button--color-primary { background-color: var(--myskin-accent); }

Выключение скина (Apply(root, skin, enabled: false)) снимает класс скина и brand-листы, так что ни одно переопределение с префиксом больше не совпадает, и возвращается вид Kit.

По выбору: слой component ​

Скин, написанный как веб-CSS — переопределения без префикса класса скина в расчёте на то, что правило равной специфичности победит, — перечисляет такие листы в sheets.component. Пока скин включён, SusSkin добавляет их после собственного сгенерированного листа каждого стилизованного компонента под корнем скина, так что правило равной специфичности побеждает:

css
/* In a sheets.component sheet, on a SusMenuButton that carries the class my-screen__back-btn:
   (0,1,0) now beats the kit's .sus-menu-button (0,1,0) */
.my-screen__back-btn { border-width: 1px; }
  • Только переопределения, без токенов. Слой добавляется на каждом уровне вложенности, так что держите его небольшим. Custom properties, заданные в sheets.brand на корне, и так наследуются до каждого компонента.
  • Выключение возвращает вид Kit. Отключение или снятие скина убирает слой из каждого компонента, в который он был добавлен.
  • Применяйте скин к корню приложения. Оверлеи (меню, диалоги, тултипы) получают слой, только если слой оверлеев находится под корнем, к которому применён скин, — используйте UseSkin на SusApp или Apply на SusApp.Root. Компонент, смонтированный прямо в слой оверлеев вне корня скина, слоя не получает; оверлеи, открытые из компонента под корнем, получают.
  • Компоненты, созданные позже, подхватывают слой, когда прикрепляются к панели.

Заметки ​

  • Surface — двусторонний выбор — SusSkinSurface.Glass или SusSkinSurface.Paper — объявляется в дескрипторе скина как DefaultSurface, переопределяется на вызов Apply.
  • Storybook story Skin (skin): обнаруживает любой пакет скина, который линкует проект (так же, как окно Skins), и показывает его рядом со стандартным видом SUS, с переключателем «Skin enabled» и переключателем поверхности glass/paper.
  • Hub shot kit-skin.png — витрина (ожидает съёмки).