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-stepper

v1.0.11

Published

Адаптивный индикатор прогресса для многошаговых сценариев — единый render-prop API, раскладка из AdaptiveProvider.

Readme

Stepper

@cloud-ru/ds-stepper — Адаптивный индикатор прогресса для многошаговых сценариев — единый render-prop API, раскладка из AdaptiveProvider.

Индикатор прогресса для многошаговых сценариев — список шагов с номером, заголовком и (опционально) описанием. Управляется через render-prop, поддерживает controlled и uncontrolled режимы. Stepper адаптивен: раскладку берёт из AdaptiveProvider (@cloud-ru/ds-adaptive) — на desktop горизонтальный ряд шагов, на mobile компактный.

Когда использовать

  • Многошаговые формы, где пользователю важно видеть прогресс и (на desktop) описание каждого шага.
  • Процессы с валидацией между шагами (submit → backend check → next).

Анатомия

Step state

Состояние шага: completed — пройден, current — текущий, loading — в процессе, waiting — ещё не пройден, rejected — отклонён/ошибка.

Layout type

Раскладка: desktop — горизонтальная с подписями, mobile — компактная вертикальная.

Установка

pnpm add @cloud-ru/ds-stepper
import { Stepper } from '@cloud-ru/ds-stepper'

Примеры использования

Базовый flow

Три шага с Next/Prev

import { Button } from '@cloud-ru/ds-button';
import { Stepper } from '@cloud-ru/ds-stepper';

export function BasicFlow() {
  return (
    <Stepper steps={[{ title: 'Данные' }, { title: 'Проверка' }, { title: 'Готово' }]}>
      {({ stepper, goNext, goPrev, currentStepIndex, stepCount, isCompleted }) => (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {stepper}
          <div style={{ display: 'flex', gap: 8 }}>
            <Button
              label='Назад'
              view='outline'
              appearance='neutral'
              size='s'
              onClick={() => goPrev()}
              disabled={currentStepIndex === 0}
            />
            <Button
              label={currentStepIndex === stepCount - 1 ? 'Завершить' : 'Далее'}
              appearance='primary'
              size='s'
              onClick={() => goNext()}
              disabled={isCompleted}
            />
          </div>
        </div>
      )}
    </Stepper>
  );
}

С валидатором

Первая попытка реджектится, вторая проходит

import { Button } from '@cloud-ru/ds-button';
import { Stepper, StepsValidator } from '@cloud-ru/ds-stepper';
import { useRef } from 'react';

export function WithValidator() {
  const attempts = useRef(0);
  const validator: StepsValidator = async () => {
    attempts.current += 1;
    return attempts.current >= 2;
  };

  return (
    <Stepper steps={[{ title: 'Данные' }, { title: 'Проверка' }, { title: 'Готово' }]} validator={validator}>
      {({ stepper, goNext, resetValidation }) => (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {stepper}
          <div style={{ display: 'flex', gap: 8 }}>
            <Button label='Сброс' view='outline' appearance='neutral' size='s' onClick={resetValidation} />
            <Button label='Далее' appearance='primary' size='s' onClick={() => goNext()} />
          </div>
        </div>
      )}
    </Stepper>
  );
}

Props

StepperProps

| Prop | Type | Default | Description | |------|------|---------|-------------| | allowFreeNavigation | boolean | — | Позволяет свободно переключаться между разными шагами без валидации | | children | StepperApi | — | Render function. Принимает stepper — JSX-элемент степпера, а также api: goNext, goPrev, resetValidation, setValidator, isCompleted, currentStepIndex, stepCount. | | className | string | — | CSS-класс | | data-test-id | string | — | data-test-id | | defaultCurrentStepIndex | number | — | Индекс текущего шага по-дефолту | | onChangeCurrentStep | ((newValue: number, prevValue: number) => void) | — | Колбек смены текущего степа | | onCompleteChange | ((isCompleted: boolean) => void) | — | Колбек изменения завершённости | | steps | StepData | — | Массив шагов | | validator | StepsValidator | — | Валидатор шагов. Выполняется при смене шага. Принимает первым аргументом индекс текущего, вторым — индекс нового шага. Возвращает Promise: false → шаг помечается как Rejected. |

Related types

StepData

| Prop | Type | Default | Description | |------|------|---------|-------------| | description | string \| undefined | — | | | title | string | — | |

StepperApi

| Prop | Type | Default | Description | |------|------|---------|-------------| | currentStepIndex | number | — | | | goNext | (stepIndex?: number) => void | — | | | goPrev | (stepIndex?: number) => void | — | | | isCompleted | boolean | — | | | resetValidation | () => void | — | | | setValidator | StepsValidator | — | | | stepCount | number | — | | | stepper | ReactElement<any, string \| JSXElementConstructor<any>> | — | |

  • StepsValidator = (prevStepIndex: number, newStepIndex: number) => Promise<boolean>

Адаптивность

Stepper — адаптивный компонент с переключением поверхности (surface-swap). Раскладку он берёт из AdaptiveProvider (контекст @cloud-ru/ds-adaptive); публичный API единый для обеих платформ:

  • desktop (по умолчанию) — горизонтальный ряд шагов с номером, заголовком и описанием.
  • mobile — компактный вертикальный индикатор: номер текущего шага и прогресс без полного ряда подписей.

Верстайте под desktop и поставьте один <AdaptiveProvider> в корне приложения — mobile-поверхность включается автоматически (desktop-first). Пропа layoutType у компонента нет: источник раскладки — только контекст.

Как форсировать платформу

Форс — только контекстом, не пропом:

  • Поддерево — вложенный провайдер:
    import { AdaptiveProvider } from '@cloud-ru/ds-adaptive'
    
    <AdaptiveProvider layoutType='mobile'>
      <Stepper steps={steps}>{renderStep}</Stepper>
    </AdaptiveProvider>
  • Отдельный компонент — withLayoutType (module-scope, сахар над провайдером):
    import { withLayoutType } from '@cloud-ru/ds-adaptive'
    import { Stepper } from '@cloud-ru/ds-stepper'
    
    const MobileStepper = withLayoutType(Stepper, 'mobile')

Платформенных пропов у Stepper нет — обе поверхности используют один набор пропсов.

Mobile — компактный индикатор

Раскладка форсирована в mobile: вместо горизонтального ряда — компактный вертикальный индикатор шага.

import { AdaptiveProvider, LAYOUT_TYPE } from '@cloud-ru/ds-adaptive';
import { Button } from '@cloud-ru/ds-button';
import { Stepper } from '@cloud-ru/ds-stepper';

export function MobileLayout() {
  return (
    <AdaptiveProvider layoutType={LAYOUT_TYPE.Mobile}>
      <Stepper steps={[{ title: 'Данные' }, { title: 'Проверка' }, { title: 'Готово' }]}>
        {({ stepper, goNext, goPrev, currentStepIndex, stepCount, isCompleted }) => (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
            {stepper}
            <div style={{ display: 'flex', gap: 8 }}>
              <Button
                label='Назад'
                view='outline'
                appearance='neutral'
                size='s'
                onClick={() => goPrev()}
                disabled={currentStepIndex === 0}
              />
              <Button
                label={currentStepIndex === stepCount - 1 ? 'Завершить' : 'Далее'}
                appearance='primary'
                size='s'
                onClick={() => goNext()}
                disabled={isCompleted}
              />
            </div>
          </div>
        )}
      </Stepper>
    </AdaptiveProvider>
  );
}

Подробнее о модели адаптивности — Адаптивность — паттерн.