# @skbkontur/react-ui > A comprehensive React component library providing UI components, validation tools, and design utilities for building user interfaces. > Version: 5.x | Homepage: https://tech.skbkontur.ru/kontur-ui | npm: @skbkontur/react-ui ## Installation ```bash npm install @skbkontur/react-ui # or yarn add @skbkontur/react-ui ``` Import components directly: ```jsx import { Button, Input, Modal } from '@skbkontur/react-ui'; ``` --- # DataTids Аттрибуты data-tid экспортируются для компонентов в виде объекта. При необходимости добавления аттрибута data-tid необходимо создать пулл-реквест. У всех компонентов также есть проп data-tid, которым можно переопределять корневые дата-тиды. # Feature flags Фича-флаги позволяют заранее применять будущие **breaking changes** (ломающие изменения) до выхода очередного мажорного релиза библиотеки. При выходе очередной мажорной версии, например, `5.x.x` → `6.x.x`, будет применено новое поведение, а сами фича-флаги будут удалены. ## Подключение фича-флагов Чтобы применить доработку/исправление нужно указать фича-флаги в `` ```jsx static import { ReactUIFeatureFlagsContext } from '@skbkontur/react-ui'; function ExampleComponent() { return ( {/* Внутри будут работать все фича-флаги с true */} ); } ``` Механизм работы: новая функциональность применяется или не применяется в зависимости от того, был ли передан со значением true соответствующий флаг или нет. Флаги задаются с помощью `ValidationsFeatureFlagsContext.Provider`. ```jsx static import { ReactUIFeatureFlagsContext } from '@skbkontur/react-ui'; {/* ... */}; ``` ## Объект со всеми флагами Для получения объекта со списком всех фича-флагов необходимо применить вспомогательные функции к объектам заданных флагов ```typescript static import { getFullReactUIFlagsContext } from '@skbkontur/react-ui'; getFullReactUIFlagsContext(useContext(ReactUIFeatureFlagsContext)); ``` ### Выпадающие элементы и несколько React root React позволяет создавать root внутри root, но контекст между ними не прокидывается. Это вызывает проблемы в работе различных выпадашек, типа `Hint`, `Tooltip`, `Select`, `Modal` и других. В версии `4.26.0` появился мехнизм, который решает большинство этих проблем. Если вложенный root является виджетом, то будет достаточно обновить библиотеку только в нём. Однако, при удалении HTML-элемента, который был root, его необходимо предварительно явно размонтировать: ```tsx static React.useLayoutEffect( () => () => { if (Number(React.version) === 17) { rootRef.current && ReactDOM.unmountComponentAtNode(rootRef.current); } else if (Number(React.version) >= 18) { setTimeout(() => reactRoot.current?.unmount()); } }, [], ); ``` ## Отключение анимаций во время тестирования Анимации в компонентах отключаются любой из следующих глобальных переменных: ```static REACT_UI_TEST process.env.NODE_ENV === 'test' process.env.REACT_UI_TEST process.env.REACT_APP_REACT_UI_TEST process.env.STORYBOOK_REACT_UI_TEST ``` ## Прокидывание className и style компонентам Начиная с версии 2.14.0, стало возможным передавать в компоненты свои css-классы для дополнительной стилизации. Однако, не стоит пользоваться этой возможностью для вмешательства во внутренние стили компонентов. Верстка компонентов может быть изменена в любой момент без предупреждения, что приведет к поломке ваших переопределенных стилей. # StrictMode Начиная с версий `@skbkontur/react-ui@3.10.0` и `@skbkontur/react-ui-validations@1.7.0` поддерживается `React.StrictMode`. Некоторым компонентам библиотеки необходимо иметь доступ до корневой DOM-ноды своих children. Ранее для этого использовался метод `findDomNode`, который в `StrictMode` запрещён. Теперь получение DOM-ноды реализовано в библиотеке через `ref`, из-за чего появились некоторые требования к компонентам, передаваемым в `Hint`, `Tooltip`, `Popup` или `Tab`: ## Использование с forwardRef При передаче функциональных компонентов в `react <= 18`, они должны использовать `React.forwardRef`: ## Использование с useImperativeHandle При использовании хука `useImperativeHandle`, возвращаемый объект должен реализовывать метод `getRootNode`, возвращающий DOM-ноду: ## Использование с классовыми компонентами В классовых компонентах инстанс должен реализовывать метод `getRootNode`, возвращающий DOM-ноду: ## Использование с компонентами React UI При оборачивании компонентов React UI нужно брать DOM-ноду через `getRootNode` у инстанса компонента: ## Без StrictMode Без `StrictMode` будет применяться метод `findDomNode`, который несовместим со `StrictMode`. [Подробнее в pull request →](https://github.com/skbkontur/retail-ui/pull/2518) # Локализации компонентов через контекст `React.Context` ```typescript static interface LocaleContextProps { locale?: LocaleControls; langCode?: LangCodes; } ``` ## Доступные языки ```typescript static enum LangCodes { ru_RU = 'ru_RU', en_GB = 'en_GB', } ``` ## LocaleControls ```typescript static interface LocaleControls { [key: string]: any; TokenInput?: Partial; Token?: Partial; ComboBox?: Partial; Select?: Partial; Paging?: Partial; DatePicker?: Partial; Calendar?: Partial; FileUploader?: Partial; PasswordInput?: Partial; SidePage?: Partial; } ``` ## Использование Дефолтная локализация `` Кастомная локализация `` Некоторые контролы используют компоненты других контролов. Для инкапсуляции локализации можно использовать несколько контекстов. Локализация функционального компонента через useContext. ## Локализация @skbkontur/react-ui-addons Компоненты `@skbkontur/react-ui-addons` так же поддерживают локализацию через `LocaleContext` из `@skbkontur/react-ui`. См. пример с кастомной локализацией. Дефолтные локали описаны для каждого компонента в [докумендации аддонов](https://ui.gitlab-pages.kontur.host/docs/#/react-ui-addons). # Server Side Rendering Контролы поддерживают рендеринг на стороне сервера начиная с версии `2.12.0`. Но для предварительного рендеринга стилей понадобится установить пакеты `@emotion/react` и `@emotion/server`. И импортировать `cache` из библиотеки контролов. Подробнее - [https://emotion.sh](https://emotion.sh/docs/ssr) Условный файл `server.js` будет выглядеть примерно так: ```typescript static import React from 'react'; import { renderToString } from 'react-dom/server'; import { CacheProvider } from '@emotion/react'; import createEmotionServer, { EmotionCritical } from '@emotion/server/create-instance'; import { cache } from '@skbkontur/react-ui/lib/theming/Emotion'; import { App } from './App'; const { extractCritical } = createEmotionServer(cache); const element = ( ); const { html, css, ids } = extractCritical(renderToString(element)); res.status(200).header('Content-Type', 'text/html').send(`
${html}
`); ``` `client.js` ```typescript static import React from 'react'; import ReactDOM from 'react-dom'; import { CacheProvider } from '@emotion/react'; import { cache } from '@skbkontur/react-ui/lib/theming/Emotion'; import { App } from './App'; ReactDOM.hydrate( , document.getElementById('root'), ); ``` Для `react-ui` версии `2.x` актуален [старый пример](https://github.com/skbkontur/retail-ui/blob/2.x/packages/react-ui/SSR.md) с Emotion 10. # SizeControl Контекст для управления размерами контролов `React.Context`, позволяет единообразно задать дефолтный размер для большинства компонентов библиотеки. Это: - упрощает конфигурирование размеров на уровне экрана/модуля; - избавляет от дублирования пропа `size` у каждого компонента; - помогает быстро переключать плотность интерфейса (например, small ↔ medium ↔ large) Если компонент принимает проп `size`, он использует значение из контекста по умолчанию. При необходимости размер можно переопределить пропом. ## Подключение ```tsx static import { SizeControlContext } from '@skbkontur/react-ui'; export function Page() { return ( {/* Внутри провайдера все компоненты по умолчанию будут medium */} ); } ``` ## Поддерживаемые размеры ```ts static type SizeProp = 'small' | 'medium' | 'large'; ``` ## Быстрый пример В примере ниже компонент внутри провайдера автоматически принимают размер из контекста. ## Интерактивный переключатель размера Потестируйте разные значения `size` и посмотрите, как меняются компоненты. ## Набор типовых компонентов Пример показывает, как единый размер влияет на разные компоненты одновременно. ## Переопределение размера пропом Даже внутри провайдера можно задать конкретный размер компоненту через проп `size`. Это удобно для редких исключений. # Theme Темы в React UI позволяют переключаться между светлой и темной темами, а также кастомизировать внешний вид компонентов. Например, для гибкой настройки цветов, размеров, отступов, теней и др. параметров.



---
Для кастомизации компонентов используется ``. Динамические стили генерируются в зависимости от темы в процессе render'а с помощью @emotion/css, полученные классы добавляются в `className` соответствующих элементов. Тема задается с помощью ``: ```jsx static import { ThemeContext } from '@skbkontur/react-ui'; import { DARK_THEME } from '@skbkontur/react-ui/lib/theming/themes/DarkTheme'; {/* ... */}; ``` Объект со значениями темы доступен через ``: ```jsx static import { ThemeContext, Button } from '@skbkontur/react-ui'; {theme => /* ... */ } ``` В функцониальных компонентах применяется хук `useContext` ```typescript static const theme = useContext(ThemeContext); ``` В классовых компонентах объект с темой доступен через `contextType` ```typescript static public static contextType = ThemeContext; public context: Theme = this.context; ``` ## Создание/редактирование темы Кастомные значения нужно передать в `ThemeFactory.create` и получившуюся тему можно использовать в `ThemeContext.Provider`. `ThemeFactory` расширяет переданный объект, задавая в качестве прототипа объект темы по умолчанию. Вторым аргументом `ThemeFactory.create` может принимать объект, который будет использован в качестве базовой темы. ```jsx static import { ThemeFactory, LIGHT_THEME } from '@skbkontur/react-ui'; const myFlatTheme = ThemeFactory.create({ btnBorderRadiusSmall: '10px' }, LIGHT_THEME); ``` ## Добавление своих переменных Для дополнения существующей темы новыми переменными для своих компонентов, можно создать отдельный контекст с расширенным объектом темы ## Кастомизация legacy-приложений В случае, если контролы рендерятся через какую-то общую обертку, достаточно добавить в нее `ThemeContext.Provider` с вашей темой. В противном случае, вам подойдет метод `ThemeFactory.overrideDefaultTheme()`. ```typescript static import theme from './theme/theme'; import { ThemeFactory } from '@skbkontur/react-ui/lib/theming/ThemeFactory'; ThemeFactory.overrideDefaultTheme(theme); ``` ## Несколько тем вместе ```jsx harmony import { ThemeContext, LIGHT_THEME, DARK_THEME } from '@skbkontur/react-ui'; import { ShowcaseGroup } from '@skbkontur/react-ui/internal/ThemePlayground/ShowcaseGroup'; const CombinedComponents = () => ( <>
); ; ``` ## Темы @skbkontur/react-ui-addons Компоненты `@skbkontur/react-ui-addons` так же поддерживают кастомизацию через `ThemeContext` из `@skbkontur/react-ui`. Достаточно переопределить нужные переменные, которые перечислены на страницах компонентов в [докумендации аддонов](https://ui.gitlab-pages.kontur.host/docs/#/react-ui-addons). ```tsx static import { ThemeContext, ThemeFactory } from '@skbkontur/react-ui'; import { Logotype, AddonsThemeIn } from '@skbkontur/react-ui-addons'; const myTheme = ThemeFactory.create({ logoColor: 'black', }); ; ``` ## Дополнительно: утилиты для цветов и размеров В библиотеке есть несколько утилит для работы с цветами при создании своих тем ```typescript static import { ColorFunctions } from '@skbkontur/react-ui' ColorFunctions.lighten(colorString: string, amount: number | string, method?: 'absolute' | 'relative'): string ColorFunctions.darken(colorString: string, amount: number | string, method?: 'absolute' | 'relative'): string ColorFunctions.contrast(colorString: string, darkString?: string, lightString?: string, threshold: number = 0.43): string ColorFunctions.red(colorString: string): string ColorFunctions.green(colorString: string): string ColorFunctions.blue(colorString: string): string ColorFunctions.alpha(colorString: string): string ColorFunctions.isValid(colorString: string): boolean // проверяет, можно ли распарсить строку в цвет ``` Документацию по их работе можно найти на сайте [less](http://lesscss.org/functions/#color-operations). В качестве colorString можно передать цвет в одном из форматов: `keyword`, `hex`, `rgb(r, g, b)`, `rgba(r, g, b, a)`, `hsl(h, s, l)`, `hsla(h, s, l, a)`. В качестве `amount` можно передать строку вида 'N%' или число от 0 до 1. Все значения больше или меньше возможных обрезаются. Например, для `rgba(300, -100, 123, 20)` `r=255, g=0, b=123, a=1`. Если распарсить `colorString` не получилось - выбрасывается исключение. Если это возможно, результат возвращается в том же виде, что и входная строка: ```typescript static import { ColorFunctions } from '@skbkontur/react-ui'; ColorFunctions.lighten('hsl(90, 0.8, 0.2)', '20%') === 'hsl(90, 0.8, 0.4)'; ColorFunctions.lighten('rgba(50, 50, 50, 0.2)', '20%') === 'rgba(102, 102, 102, 0.2)'; ColorFunctions.lighten('#80e619', 0.2) === '#b3f075'; ColorFunctions.lighten('crimson', '20%') === '#f16581'; ``` Для работы с размерами предусмотрена одна функция (_DimensionFunctions.ts_): ```typescript static shift(value: string, shift: string): string // пример import { DimensionFunctions } from '@skbkontur/react-ui' DimensionFunctions.shift('100%', '-20') === '80%' DimensionFunctions.shift('2em', '+2') === '4em' DimensionFunctions.shift('12', '+1') === '13px' //если единица измерения не указана - используется px DimensionFunctions.shift('10.2', '12.333451') === '22.5335px' //дробная часть округляется до 4 знаков ``` ## Версии тем С версии 5.0 в библиотеке появилось версионирование тем для облегчения обновления библиотеки. Версии тем позволяют откатывать визуальные изменения компоенентов к предыдущим минорным версиям, отложив их на будущее. Помимо `LIGHT_THEME` и `DARK_THEME` с актуальным фирменным стилем, в пакете содержатся темы с фиксированными минорными версиями (например, `LIGHT_THEME_5_1` или `DARK_THEME_5_2`). ``` import { ThemeContext } from '@skbkontur/react-ui/lib/theming/ThemeContext'; import { LIGHT_THEME, LIGHT_THEME_5_2 } from '@skbkontur/react-ui/lib/theming/themes/LightTheme'; // Тема последней версии библиотеки {/* ... */} // Тема фиксированной версии библиотеки 5.2 {/* ... */} ``` ⚠️ Вы можете использовать промежуточную версию темы неограниченно долго в рамках одной мажорной версии библиотеки. Однако, в момент выхода новой мажорной версии, все предыдущие промежуточные версии тем из нее удаляются. Это значит, что при миграции на новую мажорную версию, придется применить все отложенные визуальные изменения.
Подробнее о версиях Представим, что текущая версия библиотеки пользователя: `5.5.0`. Он решает обновить библиотеку до `5.10.0`, в которой есть визуальные изменения по сравнению с его текущей темой, но которые он пока не хочет применять. При этом, он не пользовался версионированием тем до этого момента, используя просто `LIGHT_THEME`. В версии `5.10.0` набор тем может выглядеть примерно так: - LIGHT_THEME - LIGHT_THEME_5_0 - LIGHT_THEME_5_4 - LIGHT_THEME_5_8 - LIGHT_THEME_5_10 Чтобы исключить все визуальные изменения, которых у пользователя нет на момент обновления, ему следует выбрать версию темы, наиболее близкую, но не превышающую ту, что он использовал до обновления. Т.е. на момент использования им версии `5.5.0` и дефолтной `LIGHT_THEME` внутри нее, он по факту использует `LIGHT_THEME_5_4`. И ему следует переключиться именно на нее, чтобы отложить применение визуальных изменений после обновления на `5.10.0`.
# ThemePlayground На странице собраны все переменные для кастомизации компонентов # Адаптивность компонентов Начиная с версии 4.0 многие компоненты, такие как {/* prettier-ignore-start */} стали адаптивными, получив новую верстку, которая активируются на мобильных устройствах. {/* prettier-ignore-end */} Механизм адаптивности основан на [медиазапросах](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries) и управляется переменной темы `mobileMediaQuery`. В зависимости от того, удовлетворяет текущее устройство медиазапросу из переменной или нет, компоненты переходят в мобильный режим и обратно. По умолчанию, значение переменной равно `(max-width: 576px)`. Так же можно передавать свои медиазапросы в хук `useResponsiveLayout` или через проп `options` в ResponsiveLayout. ## Настройка адаптивности Управлять значением переменной `mobileMediaQuery` можно через `ThemeContext`. ```jsx static import { ThemeContext, ThemeFactory } from '@skbkontur/react-ui'; /* ... */ ; ``` ### Отключение адаптивности Чтобы полностью отключить адаптивность компонентов достаточно изменить значение переменной на `not all`. ## Определение текущего режима Для определения текущего режима предусмотрен хук `useResponsiveLayout`. Он возвращает объект с флагами активности текущих режимов, по умолчанию пока реализован только мобильный флаг. ```ts static interface ResponsiveLayoutFlags { isMobile: boolean; } jsx static import { useResponsiveLayout } from '@skbkontur/react-ui'; function SomeComponent(props) { const { isMobile } = useResponsiveLayout(); if (isMobile) { return; /* ... */ } else { return; /* ... */ } } ``` Так же можно передать в него параметр `options: ResponsiveLayoutOptions`, значения из которого дополнят список флагов в `ResponsiveLayoutFlags`: ```ts static export type MediaQueriesType = Record; export interface ResponsiveLayoutOptions { customMediaQueries?: MQ; } ``` На основе `useResponsiveLayout` можно создать свой специфичный хук: ```jsx static import { useResponsiveLayout as useResponsiveLayoutOrigin } from '@skbkontur/react-ui'; const customMediaQueries = { isTablet: '(min-width: 577px)', isDesktop: '(min-width: 1280px)', }; const useResponsiveLayout = () => { return useResponsiveLayoutOrigin({ customMediaQueries }); }; function SomeComponent(props) { const { isMobile, isTablet, isDesktop } = useResponsiveLayout(); if (isMobile) { return; /* ... */ } else if (isTablet) { return; /* ... */ } else { return; /* ... */ } } ``` Как альтернативу можно использовать отдельный компонент ResponsiveLayout. --- ## Autocomplete ```jsx import { Autocomplete } from '@skbkontur/react-ui'; ``` ### Props - **renderItem?**: Отрисовывает элементы результата поиска. - **source?**: Задаёт функцию поиска элементов, которая должна возвращать Promise с массивом значений. - **disablePortal?**: По умолчанию выпадающий список рендерится через [паттерн Portal](https://react.dev/reference/react-dom/createPortal). Проп отключает использование Portal и список рендерится как обычный блок с абсолютным позиционированием внутри компонента. - **hasShadow?**: Определяет, нужно ли показывать тень у выпадающего списка. - **menuAlign?**: Выравнивание выпадающего списка. - **menuMaxHeight?**: Максимальная высота выпадающего списка. - **menuWidth?**: Ширина выпадающего списка. - **preventWindowScroll?**: Отключает скролл окна, когда выпадающий список раскрыт. - **onValueChange**: Событие изменения `value`. - **onBlur?**: Событие потери автокомплитом фокуса. - **size?**: Размер автокомплита. - **value**: Значение автокомплита. - **mobileMenuHeaderText?**: Текст заголовка выпадающего списка в мобильной версии. - **menuPos?**: Расположение выпадающего списка — над или под полем. ### Usage ```jsx import { Autocomplete } from '@skbkontur/react-ui'; ``` ## Использование В отличие от [комбобокса](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-combobox--docs) у поля нет стрелки и список со значениями нельзя открыть вручную. Подробнее об отличиях читайте в [Гайде](https://guides.kontur.ru/components/input-fields/combobox). Подсказки определяются в пропе `source` — задаёт функцию поиска элементов, которая должна возвращать `Promise` с массивом значений. ## Доступность Компонент поддерживает aria-атрибуты, если вам необходимо переопределить стандартное поведение. ## Валидация С помощью пакета [React UI Validations](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui-validations_api-reference) можно добавить валидацию для компонента. Подробнее о том, как настроить тип, уровень валидации, формат сообщения об ошибке и другие параметры поведения, смотрите в документации пакета [React UI Validations](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui-validations_displaying-getting-started--docs). ## Адаптивность Автокомплит адаптивен: на мобильных устройствах поле с выпадающим список открывается на весь экран устройства и становится фокусным активным элементом, что упрощает работу с ним. Мобильный режим активируется при ширине вьюпорта `(max-width: 576px)` и наличии сенсорного экрана `(pointer: coarse)`. Вы можете передавать свои медиазапросы, больше о настройке адаптивности читайте в статье [Адаптивность компонентов](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_information-mobiles--docs). ### Examples ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [value, setValue] = React.useState(''); return ; ``` **ExampleSize**: Размер автокомплита задаётся пропом `size`. По умолчанию `"small"`. ```tsx const items = ['Маленький', 'Средний', 'Большой']; const [valueSmall, setValueSmall] = React.useState('Маленький'); const [valueMedium, setValueMedium] = React.useState('Средний'); const [valueLarge, setValueLarge] = React.useState('Большой'); return ( ); ``` **ExampleMenuWidth**: Проп `menuWidth` задаёт ширину выпадающего списка. ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [valuePercent, setValuePercent] = React.useState(''); const [valueNumber, setValueNumber] = React.useState(''); return ( ); ``` **ExampleMenuMaxHeight**: Проп `menuMaxHeight` фиксирует максимальную высоту выпадающего списка. ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [value, setValue] = React.useState(''); return ( ); ``` **ExampleMenuPos**: По умолчанию список раскрывается под полем, а если список находится близко к нижней границе страницы, то он динамически меняет расположение и раскрывается над полем. Расположение выпадающего списка можно зафиксировать вручную через проп `menuPos`. Оно может быть под полем — `"bottom"` или над полем — `"top"`. В таком случае расположение будет зафиксировано и не будет меняться при близости к границе страницы. ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [value, setValue] = React.useState(''); return ( ); ``` **ExampleMenuAlign**: Проп `menuAlign` выравнивает выпадающий список. Выпадающий список может быть прикреплен к левому краю — "left" или к правому — "right". ```tsx const items = ['Выпадающее меню выравнивается по левому краю', 'Выпадающее меню выравнивается по правому краю']; const [valueLeft, setValueLeft] = React.useState('Выпадающее меню выравнивается по левому краю'); const [valueRight, setValueRight] = React.useState('Выпадающее меню выравнивается по правому краю'); return ( ); ``` **ExampleBorderless**: Проп `borderless` убирает обводку у поля. ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [value, setValue] = React.useState('Амурская область'); return ( ); ``` **ExampleAlign**: Проп `align` задаёт выравнивание текста в поле. Выравнивается только текст внутри поля, проп не влияет на выравнивание значений в выпадающем списке. ```tsx const items = ['Слева', 'По центру', 'Справа']; const [valueSmall, setValueSmall] = React.useState('Слева'); const [valueMedium, setValueMedium] = React.useState('По центру'); const [valueLarge, setValueLarge] = React.useState('Справа'); return ( ); ``` **ExampleMask**: Для автокомплита может быть задана маска. Автокомплит наследует от [MaskedInput](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-maskedinput--docs) пропсы: - `mask` — определяет шаблон маски, используемый для форматирования и проверки корректности вводимых данных в поле. - `maskChar` — задаёт cимвол маски. Он отображается в шаблоне маски в качестве плейсхолдера - `formatChars` — задаёт словарь символов-регулярок. С помощью него вы можете настроить собственный словарь символов. ```tsx const [value, setValue] = React.useState(''); const getOnlyDigits = (value: string) => value.match(/\d+/g)?.join('') || ''; const items: string[] = ['+7 912 043-98-27', '+7 912 999-11-22', '+7 912 444-55-99']; return ( { const numbers = getOnlyDigits(pattern); return new Promise((resolve) => { resolve(items.filter((item) => getOnlyDigits(item).startsWith(numbers))); }); }} onValueChange={setValue} /> ); ``` **ExampleSelectAllOnFocus**: Проп `selectAllOnFocus` добавляет автовыделение значения: всё значение внутри поля выделяется при фокусе на нем. Может быть полезно для полей, в которых пользователи могут часто копировать значение. ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [value, setValue] = React.useState('Амурская область'); return ; ``` **ExampleIcon**: В поле можно передать иконку. Иконка может находиться в начале поля — проп `leftIcon`, в конце — проп `rightIcon`. Под разный размер полей используйте подходящие начертания и размер иконок: - Small — Light 16 - Medium — Light 20 - Large — Regular 24 ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [valueLeft, setValueLeft] = React.useState(''); const [valueRight, setValueRight] = React.useState(''); return ( } /> } /> ); ``` **ExampleClear**: Очистить значение в поле можно только с помощью пустой строки. ```tsx const items = ['Абакан', 'Алексин', 'Алматы', 'Альметьевск', 'Алтайский край', 'Амурская область']; const [value, setValue] = React.useState('Алматы'); return ( ); ``` **ExampleShowClearIcon**: Проп `showClearIcon` добавляет в поле иконку очистки, по нажатию на иконку поле будет очищаться. Доступные значения: - `"always"` — всегда показывает иконку очистки в заполненном поле, при очистке значения возвращается стрелка для раскрытия списка; - `"auto"` — показывает иконку в заполненном поле, только когда оно в состоянии hover или focus; - `"never"` (по умолчанию) — не показывает иконку очистки. При одновременной настройке `rightIcon` и `showClearIcon` иконка очистки заменит иконку справа. ```tsx const items = [ 'showClearIcon="auto"', 'showClearIcon="always"', 'showClearIcon="never"', 'showClearIcon="auto" + rightIcon', ]; const [valueAlways, setValueAlways] = React.useState(items[0]); const [valueAuto, setValueAuto] = React.useState(items[1]); const [valueNever, setValueNever] = React.useState(items[2]); const [valueWithIcon, setValueWithIcon] = React.useState(items[3]); return (
} />
); ``` --- ## Button ```jsx import { Button } from '@skbkontur/react-ui'; ``` ### Usage ```jsx import { Button } from '@skbkontur/react-ui'; ``` ## Использование По умолчанию кнопка принимает все стандартные атрибуты и обработчики, которые доступны для обычного `HTMLButtonElement`. То есть вы можете передавать в этот компонент те же пропсы, что и в обычный ` ``` **Адаптивная верстка** В адаптивной верстке для кнопок, в особенности кнопок-иконок, используйте размеры Medium и Large. Если все же используете компактный размер, увеличивайте кликабельную область. [Подробнее в Контур.Гайдах](https://guides.kontur.ru/principles/base/adaptivity/#32). ℹ️ **Полезно:** [Чек-лист доступности](https://tech.skbkontur.ru/kontur-ui/?path=/docs/accessibility--docs) ## Адаптивность По умолчанию кнопка не меняет свой вид и поведение на мобильных устройствах. ℹ️ **Полезно:** [Адаптивность компонентов](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_information-mobiles--docs) ### Examples ```tsx return ; ``` **ExampleStyles**: Проп `use` задаёт стиль кнопки. Список доступных: - outline — кнопка второстепенного действия с обводкой, но без заливки - fill — кнопка второстепенного действия с заливкой, но без обводки - text — кнопка второстепенного действия без заливки и обводки - accent — кнопка основного действия - danger — кнопка деструктивного действия - success — кнопка позитивного действия - pay — кнопка, связанная с оплатой ⚠️ Deprecated-стили, будут удалены в следующих мажорных версиях: - use="primary" → use="accent" - use="backless" → use="outline" - use="link" → <Link component="button"> - use="default" → use="outline" для границ или use="fill" для фона ```tsx return (
); ``` **ExampleSize**: Проп `size` задаёт размер. По умолчанию: `'small'`. ```tsx return (
); ``` **ExampleWidth**: Пропом `width` можно задать свою ширину кнопки. Может принимать как абсолютные значения — например, 150, так и относительные — например, 50%. ```tsx return ; ``` **ExampleAlign**: Задаётся пропом `align`. ```tsx return (
); ``` **ExampleIcon**: В кнопку можно передать иконку. Иконка может находиться слева от текста кнопки — проп `icon`, справа — проп `rightIcon`, в обоих позициях одновременно. Если не передавать текст кнопки, будет отображаться кнопка-иконка. Для кнопки-иконки есть рекомендации по соблюдению доступности, изучите раздел
Доступность . Под разный размер кнопок используйте подходящие начертания и размер иконок: - Small — Light 16 - Medium — Light 20 - Large — Regular 24 ```tsx return ( ); ``` **ExampleArrow**: Проп `arrow` создаёт кнопку со стрелкой. Рекомендуется использовать для пошаговых мастеров. При указании `arrow` без значения будет добавлена кнопка со стрелкой вправо, для кнопки со стрелкой влево укажите значение `arrow="left"`. При изменении ширины кнопки стрелка будет оставаться прикреплена к внешнему краю кнопки, а не к тексту, как это происходит при добавлении отдельной иконки. ```tsx return ( ); ``` **ExampleLoading**: Проп `loading` переводит кнопку в состояние загрузки. Кнопка на время загрузки отключается. Если в кнопке есть иконка, на время загрузки иконка заменяется на спиннер, если иконки нет — весь контент кнопки заменяется на спиннер. Когда иконки две — заменяется только левая. ```tsx const [loading, setLoading] = React.useState(false); const delay = (time: number) => (args?: unknown) => new Promise((resolve) => setTimeout(resolve, time, args)); const handleLoadingStart = () => { delay(2000)().then(() => { setLoading(false); }); }; const handleClick = () => { setLoading(true); handleLoadingStart(); }; return ( ); ``` **ExampleDisabled**: Проп `disabled` блокирует кнопку. Кнопка меняет цвет на серый и становится недоступна для нажатия. ```tsx return ; ``` **ExampleLink**: Кнопка может рендерить ссылку в качестве корневого элемента. Переопределить корневой элемент можно c помощью пропа `component`. Кнопка принимает все пропсы переданного компонента. ```tsx return ( ); ``` **ExampleTheme**: Проп `theme` позволяет кастомизировать кнопку через свойства темы. Заданные переменные будут объединены с темой из ``. Общие переменные темы и переменные для кнопки (с префиксом `btn`) смотрите на странице [ThemePlayground](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_information-themeplayground--docs) . ```tsx return ( ); tsx return ( ); ``` --- ## Calendar ```jsx import { Calendar } from '@skbkontur/react-ui'; ``` ### Props - **onValueChange?**: Задает функцию, которая вызывается при изменении value. - **value**: Задает текущую дату в формате `dd.mm.yyyy`. - **maxDate?**: Задает максимальную возможную дату в формате `dd.mm.yyyy`. - **minDate?**: Задает минимальную возможную дату в формате `dd.mm.yyyy`. - **periodStartDate?**: Задает начальную дату периода в формате `dd.mm.yyyy`. - **periodEndDate?**: Задает конечную дату периода в формате `dd.mm.yyyy`. - **isHoliday?**: Задает функцию для определения праздничных дней. (default: `(_day, isWeekend) => isWeekend.`) - **initialMonth?**: Задает начальный месяц. - **initialYear?**: Задает начальный год. - **renderDay?**: Задает метод отрисовки дат в календаре. (default: `(props: CalendarDayProps) => `) - **onMonthChange?**: Задает функцию, которая вызывается при каждом изменении месяца. `month: number` - номер текущего отображаемого месяца от 1 до 12, `year: number` - отображаемый год. ### Examples ```tsx const [date, setDate] = React.useState('01.11.2021'); return ; ``` **Example2**: Вне зависимости от того, какая дата выбрана в календаре в данный момент - можно изменить отображение начального года и месяца с помощью пропсов `initialMonth` и `initialYear` ```tsx const [date, setDate] = React.useState('11.12.2021'); const initialMonth = 7; const initialYear = 2000; return (

Выбранная дата: {date}

Начальный месяц: {initialMonth}

Начальный год: {initialYear}

); ``` **Example3**: В компонент можно передать функцию `isHoliday`, которая будет получать день строкой формата `dd.mm.yyyy` и флаг `isWeekend`, и должна вернуть `true` для выходного и `false` для рабочего дня. ```tsx const [date, setDate] = React.useState(); const createRandomHolidays = () => { const holidays = new Array(10); const today = new Date(); for (let index = 0; index < holidays.length; index++) { const day = new Date(today.setDate(today.getDate() + 1 + index).valueOf()); const holiday = { date: day.getDate(), month: day.getMonth(), year: day.getFullYear(), }; holidays[index] = DatePickerHelpers.formatDate(holiday); } return holidays; }; const holidays = createRandomHolidays(); const isHoliday = (day: string, isWeekend: boolean) => { if (holidays.includes(day)) { return !isWeekend; } return isWeekend; }; return ; ``` **Example4**: Календарю можно задать кастомную высоту с помощью переменной темы `calendarWrapperHeight` - Базовая высота календаря - `330px` - Максимальная высота календаря - `450px` ```tsx const [date, setDate] = React.useState('01.11.2021'); const theme = React.useContext(ThemeContext); return ( ); ``` **Example5**: Для кастомнизации дней в календаре используется проп `renderDay`. Корректная работа подразумевает обязательное использование компонента `` и передачу в него всех приходящих в функцию пропсов: ` } />`. ```tsx const initialValue = '02.09.2023'; const [value, setValue] = React.useState(initialValue); const renderDay = (props: CalendarDayProps) => { const [date, month] = props.date.split('.').map(Number); if (month === 9 && date > 12 && date < 16) { return ( 'Кастомный день'}> ); } if (month === 8 && date === 20) { return ( # ); } return ; }; return ; ``` **Example6**: Пример с кастомизацией темы и кастомным рендером дня. ```tsx const theme = React.useContext(ThemeContext); function renderDay(props: CalendarDayProps) { const [date, month] = props.date.split('.').map(Number); const randomDay = date % 6 === 0 || date % 7 === 0 || date % 8 === 0; const randomPrice = Math.round((date / month) * 1000); return (
{date}
{randomDay ? <>{randomPrice} ₽ : }
); } const [value, setValue] = React.useState(null); return ( ); tsx const initialValue = '02.09.2023'; const [value, setValue] = React.useState(initialValue); const calendarRef = React.useRef(null); return ( <> ); ``` --- ## Center ```jsx import { Center } from '@skbkontur/react-ui'; ``` ### Props - **align?**: Задает выравнивание контента по горизонтали ### Examples ```tsx const [alignAt, setAlignAt] = React.useState<'left' | 'center' | 'right'>('center'); return ( setAlignAt(value as 'left' | 'center' | 'right')} />
); ``` --- ## Checkbox ```jsx import { Checkbox } from '@skbkontur/react-ui'; ``` ### Props - **error?**: Переводит контрол в состояние валидации "ошибка". - **warning?**: Переводит контрол в состояние валидации "предупреждение". - **size?**: Задает размер. - **onValueChange?**: Задает функцию, вызывающуюся при изменении value. - **initialIndeterminate?**: Устанавливает начальное [неопределенное состояние чекбокса](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#attr-indeterminate). ### Examples ```tsx const [checked, setChecked] = React.useState(false); return ( Обычный чекбокс ); tsx const CheckboxWithState = ({ children, ...props }: { children: React.ReactNode; [key: string]: unknown }) => { const [checked, setChecked] = React.useState(false); return ( {children} ); }; return ( Обычный чекбокс Чекбокс в состоянии ошибки Чекбокс в состоянии предупреждения ); tsx return ( Маленький Средний Большой ); tsx const [checked, setChecked] = React.useState(false); const checkboxInstance = React.useRef(null); return ( Пример чекбокса с программным фокусом ); ``` **Example5**: Чекбокс может находится в неопределённом состоянии.
Это состояние полностью копирует поведение состояния `indeterminate` ([подробнее](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#indeterminate_state_checkboxes)) из HTML. Это состояние влияет только на внешний вид и не влияет на состояние `checked`. ```tsx const [checked, setChecked] = React.useState(false); const checkboxInstance = React.useRef(null); return ( { checkboxInstance.current = el; }} > Неопределённый чекбокс ); tsx const [checkedSiblings, setCheckedSiblings] = React.useState([]); const siblingCheckboxes = [1, 2]; const parentCheckboxRef = React.useRef(null); React.useEffect(() => { if (checkedSiblings.length === 0 || checkedSiblings.length === siblingCheckboxes.length) { parentCheckboxRef.current?.resetIndeterminate(); } else if (checkedSiblings.length !== 0) { parentCheckboxRef.current?.setIndeterminate(); } }, [JSON.stringify(checkedSiblings)]); return ( <> { if (checkedSiblings.length === siblingCheckboxes.length) { setCheckedSiblings(() => []); } else { setCheckedSiblings(() => [...siblingCheckboxes]); } }} > Родитель
{siblingCheckboxes.map((id) => { return ( { const siblingIndex = checkedSiblings.indexOf(id); if (siblingIndex === -1) { setCheckedSiblings((prev) => [...prev, id]); } else { setCheckedSiblings((prev) => prev.filter((siblingId) => { return siblingId !== id; }), ); } }} > Ребёнок ({id}) ); })}
); ``` --- ## ComboBox ```jsx import { ComboBox } from '@skbkontur/react-ui'; ``` ### Props - **showClearIcon?**: Показывает иконку очистки значения в заполненном поле. (default: `never`) - **align?**: Ввыравнивание текста в поле. - **searchOnFocus?**: Вызывает функцию поиска `getItems` при фокусе и очистке поля ввода. - **drawArrow?**: Отображает справа иконку в виде стрелки. - **autoFocus?**: Устанавливает фокус на комбобоксе после окончания загрузки страницы. - **borderless?**: Убирает обводку поля. - **disablePortal?**: По умолчанию выпадающий список рендерится через [паттерн Portal](https://react.dev/reference/react-dom/createPortal). Проп отключает использование Portal и список рендерится как обычный блок с абсолютным позиционированием внутри компонента. - **disabled?**: Поле становится недоступно для редактирования. - **error?**: Меняет визуальное отображение поля на состояние «ошибка». - **leftIcon?**: Добавляет иконку слева. При использовании `ReactNode` применяются дефолтные стили для иконки. При использовании `() => ReactNode` применяются только стили для позиционирования. - **rightIcon?**: Добавляет иконку справа. При использовании `ReactNode` применяются дефолтные стили для иконки. При использовании `() => ReactNode` применяются только стили для позиционирования. - **getItems**: Задаёт функцию поиска элементов, которая должна возвращать Promise с массивом значений. По умолчанию ожидаются объекты с типом `{ value: string, label: string }`. Элементы могут быть любого типа. В этом случае необходимо определить свойства `itemToId`, `renderValue`, `renderItem`, `valueToString`. - **itemToId?**: Сравнивает полученные результаты с `value`. - **maxLength?**: Mаксимальная длина значения, которое пользователь может ввести в поле. - **menuPos?**: Расположение выпадающего списка — над или под полем. - **menuAlign?**: Выравнивание выпадающего меню. - **onBlur?**: Событие потери комбобоксом фокуса. - **onValueChange?**: Событие изменения значения (`value`) в поле. - **onFocus?**: Событие получения комбобоксом фокуса. - **onInputValueChange?**: Событие, которое вызывается при изменении текста в поле ввода, если результатом функции будет строка, то она станет следующим состоянием полем ввода. **Не рекомендуется менять значение, передаваемое в проп `value`, внутри этой функции. Используйте для этих целей `onValueChange` или `onUnexpectedInput`. Иначе возможно неожиданное поведение компонента.** - **onUnexpectedInput?**: Событие обработки ввода строки в поле ввода и последующей потерей фокуса компонентом. Функция срабатывает с аргументом поля строки. Если при потере фокуса в выпадающем списке будет только один элемент и результат `valueToString` с этим элементом будет совпадать со значение в текстовом поле, то сработает `onValueChange` со значением данного элемента. Сама функция также может вернуть значение, не равное undefined, с которым будет вызван `onValueChange`. Если возвращаемое значение будет равно null, то сработает очистка текущего значения поля, а в режиме редактирования токен будет удален. - **placeholder?**: Текст, который отображается если не введено никакое значение. - **renderItem?**: Отрисовывает элементы результата поиска. Не применяется, если элемент является функцией или React-элементом. (default: `item => item.label`) - **itemWrapper?**: Устанавливает компонент, заменяющий собой обёртку элементов результата поиска. По умолчанию все элементы результата поиска оборачиваются в тег ); ``` **ExampleShowClearIcon**: Проп `showClearIcon` добавляет в поле иконку очистки, по нажатию на иконку поле будет очищаться. Доступные значения: - `"never"` (по умолчанию) — не показывает иконку очистки; - `"always"` — всегда показывает иконку очистки в заполненном поле, при очистке значения возвращается стрелка для раскрытия списка; - `"auto"` — показывает иконку в заполненном поле, только когда оно в состоянии hover или focus. ```tsx const items = [ { value: 'always', label: 'showClearIcon="always"' }, { value: 'auto', label: 'showClearIcon="auto"' }, { value: 'never', label: 'showClearIcon="never"' }, ]; const [valueAlways, setValueAlways] = React.useState(items[0]); const [valueAuto, setValueAuto] = React.useState(items[1]); const [valueNever, setValueNever] = React.useState(items[2]); const getItems = (q: string) => Promise.resolve(items.filter((x) => x.label.toLowerCase().includes(q.toLowerCase()))); return ( ); ``` **ExampleReset**: Метод `reset()` позволяет сбросить введённое пользователем вручную значение без изменения `value`. ```tsx const [selected, setSelected] = React.useState({ value: 2, label: 'Алексин' }); const ref = React.useRef>(null); const handleReset = () => { if (ref.current) { ref.current.reset(); } }; const getItems = (q: string) => Promise.resolve( [ { value: 1, label: 'Абакан' }, { value: 2, label: 'Алексин' }, { value: 3, label: 'Алматы' }, { value: 4, label: 'Альметьевск' }, { value: 5, label: 'Алтайский край' }, { value: 6, label: 'Амурская область' }, ].filter((x) => x.label.toLowerCase().includes(q.toLowerCase()) || x.value.toString(10) === q), ); return ( ); ``` **ExampleDisabled**: Проп `disabled` переводит комбообокс в состояние блокировки. Поле визуально приглушается и становится недоступно для редактирования. ```tsx const getItems = (q: string) => { return Promise.resolve( [ { value: 1, label: 'Абакан' }, { value: 2, label: 'Алексин' }, { value: 3, label: 'Алматы' }, { value: 4, label: 'Альметьевск' }, { value: 5, label: 'Алтайский край' }, { value: 6, label: 'Амурская область' }, ].filter((x) => x.label.toLowerCase().includes(q.toLowerCase()) || x.value.toString(10) === q), ); }; const [value, setValue] = React.useState>(); return ( ); ``` **ExampleError**: Проп `error` переводит комбобокс в состояние ошибки. ```tsx const delay = (time: number) => (args: Selected[]): Promise => new Promise((resolve) => setTimeout(() => resolve(args), time)); const maybeReject = (x: Selected[]) => (Math.random() * 3 < 1 ? Promise.reject() : Promise.resolve(x)); const getItems = (q: string) => Promise.resolve( [ { value: 1, label: 'Абакан' }, { value: 2, label: 'Алексин' }, { value: 3, label: 'Алматы' }, { value: 4, label: 'Альметьевск' }, { value: 5, label: 'Алтайский край' }, { value: 6, label: 'Амурская область' }, { value: 7, label: 'Анадырь' }, { value: 8, label: 'Анапа' }, { value: 9, label: 'Архангельск' }, { value: 10, label: 'Архангельская область' }, { value: 11, label: 'Астраханская область' }, { value: 12, label: 'Астрахань' }, ].filter((x) => x.label.toLowerCase().includes(q.toLowerCase()) || x.value.toString(10) === q), ) .then(delay(500)) .then(maybeReject); const [selected, setSelected] = React.useState>(); const [error, setError] = React.useState(true); const handleValueChange = (value: Selected) => { setSelected(value); setError(false); }; const handleUnexpectedInput = () => { setSelected(null); setError(true); }; const handleFocus = () => setError(false); return ( 'Выберите значение из списка'} trigger={error ? 'opened' : 'closed'}> ); ``` **ExampleCounter**: Пропсы `totalCount` и `renderTotalCount` позволяют добавить в выпадающий список счётчик найденных значений. - `renderTotalCount` — задаёт функцию, которая отображает сообщение о количестве значений. - `totalCount` — определяет общее количество значений. ```tsx const [foundLength, setFoundLength] = React.useState(0); const items: ComboBoxItem[] = []; for (const key in document.body.style) { if (Object.hasOwnProperty.call(document.body.style, key)) { items.push({ value: key, label: key, }); } } const getItems = (query: string) => { const found: Array> = items.filter(({ value }) => value.toLowerCase().includes(query.toLowerCase()), ); const filtered = found.slice(0, 5); setFoundLength(found.length); return Promise.resolve(filtered); }; return ( `Показано ${found} из ${total} найденных свойств`} /> ); ``` **ExampleExtendedItems**: В массиве, возвращаемом `getItems`, могут быть переданы React-компоненты: ``, ``, `` и любые другие. В таких случаях поиск необходимо контролировать дополнительно. ```tsx interface Item { value: number; label: string; } const delay = (time: number) => (args: T): Promise => new Promise((resolve) => setTimeout(resolve, time, args)); const maybeReject = (x: T) => (Math.random() * 3 < 1 ? Promise.reject() : Promise.resolve(x)); const getItems = (q: string): Promise>> => Promise.resolve>>( [ MenuHeader, { value: 1, label: 'Абакан' }, { value: 2, label: 'Алексин' }, { value: 3, label: 'Алматы' }, { value: 4, label: 'Альметьевск' }, { value: 5, label: 'Алтайский край' }, { value: 6, label: 'Амурская область' }, , { value: 7, label: 'Анадырь' }, { value: 8, label: 'Анапа' }, { value: 9, label: 'Архангельск' }, { value: 10, label: 'Архангельская область' }, { value: 11, label: 'Астраханская область' }, { value: 12, label: 'Астрахань' }, MenuFooter, ].filter((x) => ('label' in x ? x.label.toLowerCase().includes(q.toLowerCase()) : q === '')), ) .then(delay(500)) .then(maybeReject); const [selected, setSelected] = React.useState(null); const [error, setError] = React.useState(false); const handleValueChange = (value: Item | null) => { setSelected(value); setError(false); }; const handleUnexpectedInput = () => { setSelected(null); setError(true); }; const handleFocus = () => setError(false); return ( 'Выберите значение из списка'} trigger={error ? 'opened' : 'closed'}> error={error} getItems={getItems} onValueChange={handleValueChange} onFocus={handleFocus} onUnexpectedInput={handleUnexpectedInput} placeholder="Введите или выберите из списка" value={selected} /> ); ``` **ExampleCustom**: В примере с помощью пропсов `renderValue`, `renderItem` и `itemWrapper` переопределён внешний вид элементов списка и выбранного значения, задано отображение галочки для одобренных элементов. ```tsx type ExtendedSelected = Selected & { approved: boolean; label: string; email: string; }; const delay = (time: number) => (args: ExtendedSelected[]): Promise => new Promise((resolve) => setTimeout(() => resolve(args), time)); const getItems = (q: string): Promise => Promise.resolve( [ { approved: true, value: 1, label: 'Леонид Долецкий', email: 'first@skbkontur.ru' }, { approved: true, value: 2, label: 'Владислав Нашкодивший', email: 'second@skbkontur.ru' }, { approved: false, value: 3, label: 'Розенкранц Харитонов', email: 'third@skbkontur.ru' }, { approved: false, value: 4, label: 'Надежда Дубова', email: 'fourth@skbkontur.ru' }, { approved: true, value: 5, label: 'Владислав Сташкеевич', email: 'fifth@skbkontur.ru' }, { approved: true, value: 6, label: 'Василиса Александровна Поволоцкая', email: 'sixth@skbkontur.ru' }, ].filter((x) => x.label.toLowerCase().includes(q.toLowerCase()) || x.value.toString(10) === q), ).then(delay(500)); const [selected, setSelected] = React.useState>({ approved: false, value: 3, label: 'Розенкранц Харитонов', email: 'third@skbkontur.ru', }); const [error, setError] = React.useState(false); const handleValueChange = (value: ExtendedSelected) => { setSelected(value); setError(false); }; const handleUnexpectedInput = () => { setSelected(null); setError(true); }; const handleFocus = () => setError(false); const customRenderItem = (item: ExtendedSelected) => (
{item.approved ? : null} {item.label}
{item.email}
); const customItemWrapper = (item: { value: number }) => { if (item.value === 3) { return (props: React.HTMLAttributes) =>
; } return (props: React.HTMLAttributes) => ); ``` **ExampleCurrency**: Знак валюты можно прокидывать как внутрь поля с помощью пропа `rightIcon`, так и вне поля с помощью элемента `label`. ```tsx const [value, setValue] = React.useState(); return ( ); ``` --- ## CurrencyLabel ```jsx import { CurrencyLabel } from '@skbkontur/react-ui'; ``` ### Props - **fractionDigits?**: Минимальное количество отображаемых знаков после запятой. (default: `2`) - **value**: Значение. - **currencySymbol?**: Символ валюты. - **hideTrailingZeros?**: Убирает лишние нули после запятой. ### Usage ```jsx import { CurrencyLabel } from '@skbkontur/react-ui'; ``` ### Examples ```tsx return ; ``` **ExampleCurrencySymbol**: В пропе `currencySymbol` указывается нужный символ валюты. ```tsx return ( ); ``` **ExampleFractionDigits**: Проп `fractionDigits` устанавливает минимальное количество знаков после запятой. ```tsx return ; ``` **ExampleHideTrailingZeros**: Проп `hideTrailingZeros` удаляет лишние нули, если они есть в конце значения. ```tsx return ; ``` --- ## DateInput ```jsx import { DateInput } from '@skbkontur/react-ui'; ``` ### Props - **autoFocus?**: Устанавливает фокус на контроле после окончания загрузки страницы. - **value?**: Устанавливает значение датаинпута. - **error?**: Переводит контрол в состояние валидации "ошибка". - **warning?**: Переводит контрол в состояние валидации "предупреждение". - **disabled?**: Делает компонент недоступным. - **minDate?**: Задает минимальную возможную дату в формате `dd.mm.yyyy`. - **maxDate?**: Задает максимальную возможную дату в формате `dd.mm.yyyy` - **width?**: Задает ширину поля. - **withIcon?**: Добавляет иконку календаря. - **size?**: Задает размер поля. - **onBlur?**: Задает функцию, которая вызывается при потере датаинпутом фокуса. - **onClick?**: Задает функцию, которая вызывается при клике на датаинпут. - **onFocus?**: Задает функцию, которая вызывается при получении датаинпутом фокуса. - **onValueChange?**: Задает функцию, которая вызывается при изменении value. - **onKeyDown?**: Задает функцию, которая вызывается при нажатии кнопки на клавиатуре. ### Examples ```tsx return ; tsx const [value, setValue] = React.useState(); return ; tsx return ; tsx class DateInputFormatting2 extends React.Component, { langCode: LangCodes; value: string }> { constructor(props: Record) { super(props); this.state = { langCode: LangCodes.ru_RU, value: '21.12.2012', }; } render() { return (
Локаль (LangCodes) this.setState({ order })} />
Разделитель (DateSeparator) this.setState({ order })} />
Разделитель (DateSeparator) setOrder(order)} />
Разделитель (DateSeparator) ); ``` **UsageInDateRangePicker**: Пример с группой полей без разделителя в `DateRangePicker`. ```tsx const [valueStart, setValueStart] = React.useState(''); const [valueEnd, setValueEnd] = React.useState(''); return ( ); tsx const [value, setValue] = React.useState('Foo'); return ( 'Hi!'} trigger="opened" pos="bottom"> ); ``` --- ## Hint ```jsx import { Hint } from '@skbkontur/react-ui'; ``` ### Props - **manual?**: Переводит отображение подсказки в _"ручной режим"_. В _"ручном режиме"_ подсказку можно активировать только задав значение пропу `opened`. - **maxWidth?**: Задает максимальную ширину подсказки. - **onMouseEnter?**: Задает функцию, которая вызывается при наведении мышкой (событие `onmouseenter`). - **onMouseLeave?**: Задает функцию, которая вызывается при уходе мышки с объекта (событие `onmouseleave`). - **opened?**: Открывает подсказку. Работает только при `manual=true`. - **pos?**: Задает приоритетное расположение подсказки относительно текста. - **text**: Задает текст подсказки. - **allowedPositions?**: Задает список позиций, которые будет занимать хинт. Если положение хинта в определенной позиции будет выходить за край экрана, то будет выбрана следующая позиция. Обязательно должен включать позицию указанную в `pos`. - **disableAnimations?**: Отключает анимацию. - **useWrapper?**: Явно указывает, что вложенные элементы должны быть обёрнуты в ``. Используется для корректного позиционирования хинта при двух и более вложенных элементах. _Примечание_: при **двух и более** вложенных элементах обёртка будет добавлена автоматически. ### Examples ```tsx return Базовая; tsx return ( ); tsx return ( Всегда всплывает слева ); tsx return ( Очень непонятный элемент ); tsx const [isOpen, setIsOpen] = React.useState(false); return ( ); tsx return ( Есть анимация? ); ``` **Example7**: Подсказка должна отображаться даже на отключённых компонентах. Из коробки это работает только с контролами `react-ui`. Нативные элементы, поддерживающие атрибут `disabled`, отключают необходимые события мыши. В подобных случаях следуют использовать проп `useWrapper`: ```tsx return ( ); ``` **Example8**: Т.к. встроённая обёртка это `` без стилей, то она может работать некорректно в определённых ситуациях. В таких случаях стоит использовать собственную обётку: ```tsx return ( <> ); ``` --- ## Input ```jsx import { Input } from '@skbkontur/react-ui'; ``` ### Props - **showClearIcon?**: Показывает иконку очистки значения в заполненном поле. (default: `never`) - **leftIcon?**: Добавляет иконку слева. При использовании `ReactNode` применяются дефолтные стили для иконки. При использовании `() => ReactNode` применяются только стили для позиционирования. - **rightIcon?**: Добавляет иконку справа. При использовании `ReactNode` применяются дефолтные стили для иконки. При использовании `() => ReactNode` применяются только стили для позиционирования. - **error?**: Меняет визуальное отображение поля на состояние «ошибка». Может быть полезен при разработке собственной валидации, если вы не используете пакет [React UI Validations](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui-validations_displaying-getting-started--docs). - **warning?**: Меняет визуальное отображение поля на состояние «предупреждение». Может быть полезен при разработке собственной валидации, если вы не используете пакет [React UI Validations](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui-validations_displaying-getting-started--docs). - **borderless?**: Убирает обводку поля. - **align?**: Выравнивает контент внутри поля. - **size?**: Размер поля. (default: `small`) - **onValueChange?**: Событие изменения значения `value` в поле. - **type?**: Тип поля ввода. - **value?**: Значение внутри поля. - **prefix?**: Устанавливает префикс `ReactNode` перед значением, но после иконки. - **suffix?**: Устанавливает суффикс `ReactNode` после значения, но перед правой иконкой. - **selectAllOnFocus?**: Выделяет введённое значение при фокусе в поле. Работает с типами `text`, `password`, `tel`, `search`, `url`. - **onUnexpectedInput?**: Устанавливает обработчик на случай некорректного ввода. Если передан onUnexpectedInput, он будет вызван при ошибке, а эффект мигания можно запустить вручную через публичный метод blink. - **element?**: Устанавливает элемент, заменяющий нативный input. Должен иметь пропсы `InputElementProps` и тип `InputElement`. ### Usage ```jsx import { Input } from '@skbkontur/react-ui'; ``` ## Использование Используйте поле ввода для коротких текстовых или цифровых значений без предсказуемого формата — не больше 5 слов. По умолчанию поле ввода принимает все стандартные атрибуты, которые доступны для обычного [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input). **Альтернативы и дополнения** Для полей с длинными текстовыми комментариями используйте [Textarea](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-textarea--docs). Для ввода значений в определенном формате, используйте специальную версию поля: - [PasswordInput](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-passwordinput--docs) — поле для ввода пароля, в котором символы заменяются на точки. - [CurrencyInput](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-currencyinput--docs) — поле для ввода денежных сумм в разной валюте. - [MaskedInput](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-maskedinput--docs) — поле с маской. - [FxInput](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-fxinput--docs) — автополе. Если же список значений заранее определен и должен отображаться пользователю для выбора, подойдут поля с подсказками: - [Autocomplete](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-autocomplete--docs) - [Combobox](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-combobox--docs) - [TokenInput](https://tech.skbkontur.ru/kontur-ui/?path=/docs/react-ui_input-data-tokeninput-tokeninput--docs) ## Доступность Компонент поддерживает стандартные aria-атрибуты, если вам необходимо переопределить его поведение. **Рекомендации** - Указывайте `