npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cloud-ru/ds-materials

v2.0.2

Published

SCSS materials (acrylic, stateLayer) для дизайн-системы

Readme

Materials

@cloud-ru/ds-materials — SCSS-миксины для материалов (акрил, state layer) — вспомогательные стили для компонентов дизайн-системы.

Пакет экспортирует SCSS-миксины без JS runtime — используется другими пакетами как @use '@cloud-ru/ds-materials' as m.

Установка

pnpm add @cloud-ru/ds-materials

Состав

  • material/_acrylic.scss — акриловый эффект (blur + полупрозрачный фон)
  • stateLayer/index.scss — state-layer для hover/pressed состояний
  • focusFrame/index.scss — рамка фокуса (with-focus-frame)
  • utils/_mixins.scss — вспомогательные миксины (has-state-layer-as-child, has-content-with-text-opacity)

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

// packages/button/src/styles.module.scss
@use '@cloud-ru/ds-materials' as m;

.root {
  @include m.has-state-layer-as-child(#{stateLayer});
}

Overview

Пакет построен вокруг корневого миксина материалов и двух наборов миксинов:

  • Material (корень) — миксин with-material($material, $props...) применяет выбранный материал к элементу; аргументы после $material передаются в реализацию материала (для 'acrylic' — селекторы дочерних слоёв). Со временем появятся другие материалы (например gradient). Разметка и параметры зависят от материала.
  • Acrylic — материал «матового стекла» (backdrop blur + полупрозрачный слой). Вызывается через with-material('acrylic', …) с селекторами слоёв. На корне — data-acrylic-appearance и data-acrylic-level; фон и опциональный эффект — дочерние элементы с классами, имена которых передаются вторым и третьим аргументом. На эти классы пакет навешивает только «акриловые» свойства (opacity, фон, blend modes); position: relative на корне с материалом пакет не задаёт — его при необходимости добавляет потребитель (например, для абсолютно позиционированных слоёв и стека). Позиционирование и pointer-events самих слоёв тоже задаёт потребитель.
  • State layer — слой состояний (hover, active) для кнопок, карточек и других интерактивных элементов. Поддерживает варианты: обычный фон/бордер, активированный, onColor, onAccent и прозрачность текста/иконок (textOpacity). Использует переменные из @cloud-ru/ds-figma-variables.

Подключение в SCSS:

@use '@design-system/materials' as m;

Через namespace m доступны миксины материалов (with-material), state layer (has-state-layer-as-child, has-content-with-text-opacity) и при необходимости низкоуровневые утилиты.

Usage

Material (корень) и Acrylic

Акрил подключают вызовом with-material('acrylic', $bgLayerSelector, $effectLayerSelector?):

  • $bgLayerSelector (обязательный) — имя локального класса дочернего фонового слоя в том же SCSS-модуле, обычно в CSS Modules задают как #{acrylic} при классе .acrylic в разметке.
  • $effectLayerSelector (опциональный) — то же для слоя color-dodge; если не передавать, стили эффекта не генерируются.

На корневом элементе задайте атрибуты:

  • data-acrylic-appearance — вариант оформления: 'primary', 'neutral', 'blue', 'red', 'yellow', 'green'.
  • data-acrylic-level — уровень глубины: 'default', '1Level', '2Level'.

Миксин акрила не выставляет на этом корне position: relative (чтобы не ломать layout в сложных обёртках, например у Drawer). Если дочерние слои позиционируются относительно корня (position: absolute и т.п.) или нужен явный контекст наложения — задайте position: relative (или иной подходящий position) на классе того же элемента, куда подключаете with-material, в своём SCSS.

В разметке обязателен один дочерний элемент с классом, совпадающим с первым аргументом (например <div className={styles.acrylic} />). Опционально — второй дочерний элемент с классом для эффекта. Контент размещайте поверх фонового слоя (например, в отдельном блоке с position: relative и z-index).

Внутри with-material для слоёв вызываются миксины has-acrylic-background-layer-as-child и при необходимости has-acrylic-effect-layer-as-child. Они не подключают absolute-layer и не выставляют pointer-events: none — только opacity / background для фона и режимы наложения для эффекта. Чтобы слой заполнял корень и не перехватывал события, задайте на своих классах слоёв позиционирование (часто position: absolute, inset: 0), при необходимости border-radius: inherit, pointer-events: none и порядок в стеке — как в примере ниже для .acrylic.

Разметка (JSX):

<div className={styles.card} data-acrylic-appearance='neutral' data-acrylic-level='1Level'>
  <div className={styles.acrylic} />
  <div className={styles.content}>{children}</div>
</div>

SCSS:

@use '@design-system/materials' as m;

.acrylic {
  pointer-events: none;
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.card {
  position: relative;
  @include m.with-material('acrylic', #{acrylic});
}

.content {
  position: relative;
  z-index: 1;
}

С опциональным слоем эффекта (третий аргумент и второй декоративный div с собственным классом в том же модуле). Для слоя эффекта так же задайте позиционирование и при необходимости pointer-events: none в своём модуле — пакет добавляет только blend modes.

.acrylicEffect {
  pointer-events: none;
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

@include m.with-material('acrylic', #{acrylic}, #{acrylicEffect});

State layer — слой состояний

Миксин has-state-layer-as-child($stateLayerSelector) подключают в классе корневого элемента, с которым пользователь взаимодействует (hover, active и т.д.): в этот момент стили применяются к потомку, чей класс передан аргументом. В CSS Modules аргумент задают как #{stateLayer}, если в том же файле объявлен класс .stateLayer.

На элементе слоя указывают data-state — имя совпадает с именем сета в Figma (material/stateLayer/<имя>):

  • emptyNeutralOnBackground — нейтральный слой поверх фона страницы, по умолчанию прозрачный.
  • borderOnBackground — слой обводки вместо заливки.
  • activatedOnBackground — слой выбранного (активированного) элемента.
  • versionOnColor / emptyVersionOnColor — слой поверх цветной подложки; вариант с префиксом empty прозрачен по умолчанию.
  • inversionOnColor / emptyInversionOnColor — то же для инверсной подложки.
  • emptyDarkOnAccent — тёмный слой поверх акцентной подложки: filled/tonal-кнопки, теги, промотеги, ручка слайдера.
  • textOpacity — не заливка, а прозрачность текста и иконок (миксин has-content-with-text-opacity).

Набор состояний из пропа нельзя сгенерировать автоматически — только ручной маппинг к структуре Figma Variables.

Примеры: Playground, SampleBlock, StateSquare (packages/materials/stories/…).

Разметка (JSX):

<button type='button' className={styles.button}>
  <span className={styles.stateLayer} data-state='emptyNeutralOnBackground' aria-hidden />
  <span className={styles.label}>Текст кнопки</span>
</button>

SCSS:

@use '@design-system/materials' as m;

.button {
  position: relative;
  @include m.has-state-layer-as-child(#{stateLayer});
}

.label {
  position: relative;
  z-index: 1;
}

State layer — прозрачность текста (textOpacity)

Миксин has-content-with-text-opacity($contentLayerSelector) подключают в классе корневого элемента: при взаимодействии с ним меняется внешний вид потомка с классом из аргумента. На элементах внутри этого потомка, отмеченных [data-text-opacity], задаётся opacity (default / hover / active).

Пример: Playground, SampleBlock (#{contentLayer}).

Разметка (JSX):

<div className={styles.button}>
  <div className={styles.contentLayer}>
    <span data-text-opacity>Click me</span>
    <Icon data-text-opacity />
  </div>
</div>

SCSS:

@use '@design-system/materials' as m;

.button {
  position: relative;
  @include m.has-content-with-text-opacity(#{contentLayer});
}

API миксинов

Material (корень)

| миксин | параметры | описание | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | with-material($material, $props...) | $material — название материала (сейчас только 'acrylic'). Для 'acrylic' в $props: обязательный $bgLayerSelector, опционально $effectLayerSelector (имена классов дочерних слоёв) | Применяет выбранный материал к элементу. Для acrylic: на корне data-acrylic-appearance и data-acrylic-level; дочерний слой фона — элемент с классом, совпадающим с $bgLayerSelector (в модулях — #{имяКласса}); опционально слой эффекта — класс $effectLayerSelector. Blur на корне, opacity/фон на фоновом классе и blend modes на классе эффекта берутся из @cloud-ru/ds-figma-variables и внутренних миксинов слоёв. position: relative на корне с материалом не выставляется — при необходимости задайте сами. Позиционирование и pointer-events для дочерних слоёв пакет не задаёт — их описывает потребитель на тех же классах. |

Acrylic

Акрил подключается только через with-material('acrylic', …) из публичного API пакета. Атрибуты на корне задают appearance и level; селекторы слоёв — строки имён классов для вложенных правил вида .$bgLayerSelector / .$effectLayerSelector относительно корня с материалом.

  • Разметка: корень с data-acrylic-appearance и data-acrylic-level; один дочерний элемент с классом фона; опционально дочерний элемент с классом слоя эффекта (color-dodge), если передан третий аргумент в with-material.
  • Корень: position: relative с акрилом не приходит из пакета; задавайте на классе корня при необходимости (типичный случай — абсолютные дочерние слои фона/эффекта).
  • Стили слоёв: пакетные миксины слоёв не дублируют absolute-layer и не выставляют pointer-events: none; эти и другие layout-правила добавляйте на классах .acrylic / слоя эффекта в своём SCSS.

State layer

| миксин | параметры | разметка | описание | | ------------------------------------------------------ | ------------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | has-state-layer-as-child($stateLayerSelector) | Имя класса целевого потомка в том же модуле (часто #{stateLayer}) | Корень (миксин здесь) + потомок с этим классом и data-state | При взаимодействии с корнем стили state layer уходят на потомка $stateLayerSelector | | has-content-with-text-opacity($contentLayerSelector) | Имя класса обёртки (часто #{contentLayer}) | Корень + потомок с этим классом; у его потомков — [data-text-opacity] | При взаимодействии с корнем opacity меняется у [data-text-opacity] внутри $contentLayerSelector |

Переменные цветов и состояний берутся из @cloud-ru/ds-figma-variables (stateLayer подключает этот пакет внутри себя).

Focus frame

| миксин | параметры | описание | | --- | --- | --- | | with-focus-frame($appearance, $position) | $appearance — regular (по умолчанию), primary, destructive, warning, success, regularInversion. $position — inside, outside (по умолчанию), outsideOffset | Основной путь. Выводит правило &:focus-visible целиком — рамка появляется только на клавиатурном фокусе | | focus-frame-styles($appearance, $position) | те же | Те же свойства без селектора — когда рамка вешается не на сам фокусируемый элемент |

Обычный случай — миксин ставит псевдокласс сам:

@use '@cloud-ru/ds-materials' as m;

.root {
  @include m.with-focus-frame('regular', 'outside');
}

Когда рамка не на самом фокусируемом элементе — на потомке, на соседе, на псевдоэлементе или по собственному флагу — берут focus-frame-styles и пишут селектор руками:

.root:focus-visible .container {
  @include m.focus-frame-styles('primary', 'inside');
}
  • Положение. inside — штрих внутрь бокса, outside — наружу вплотную, outsideOffset — наружу с зазором в толщину штриха. Соответствуют мастерам focusedFrame/…/inside|outside|outsideOffset.
  • Радиус не задаётся: outline повторяет border-radius элемента, а мастер помечен «apply radius» — скругление приходит от потребителя.
  • outline-offset выводится всегда, включая нулевой. Без явного значения Chromium подставляет собственный отступ в 1px, которого в макете нет.
  • regularInversion — белый штрих для тёмных поверхностей.

Accessibility

  • Разметка с декоративными слоями акрила (фон/эффект) и state layer не меняет семантику: у визуальных слоёв по возможности задавайте aria-hidden; на корне используйте корректные теги и атрибуты (button, aria-*, role).
  • Слои состояний визуально не должны подменять индикацию фокуса: сохраняйте видимый focus outline для клавиатурной навигации.
  • Контент поверх акрилового фона должен сохранять достаточный контраст для читаемости.

Best practices

  1. Один фоновый слой — в одном блоке один дочерний элемент с классом, переданным в with-material('acrylic', #{…}) как фон; контент размещайте в соседних дочерних элементах с вышележащим z-index. Для декоративного фона/эффекта явно задавайте заполнение корня и pointer-events: none на классах слоёв — пакет этого не делает. Если слои абсолютные, на корне с with-material обычно нужен свой position: relative (пакет его не добавляет).
  2. Корень взаимодействия — has-state-layer-as-child и has-content-with-text-opacity вешайте на класс того элемента, с которым пользователь взаимодействует; аргумент — класс целевого потомка в разметке. Несколько state-слоёв — разные классы и при необходимости несколько вызовов первого миксина.
  3. Переменные дизайн-системы — для acrylic используйте значения data-acrylic-appearance и data-acrylic-level из палитры дизайн-системы; пакет подставляет blur, opacity и цвета из @cloud-ru/ds-figma-variables.
  4. textOpacity только для нужного контента — помечайте data-text-opacity только у текста и иконок, которые должны менять прозрачность при наведении/нажатии.
  5. Не дублировать логику — если используете готовый компонент (например, Block из @cloud-ru/ds-block), он уже может использовать эти миксины; не подключайте materials повторно для того же визуального эффекта.