cleaning-native-kit
v0.14.0
Published
A React Native UI component library for Cleaning app.
Maintainers
Readme
cleaning-native-kit
cleaning-native-kit - библиотека UI-компонентов React Native для приложения Cleaning.
Что экспортируется
Компоненты:
TextAccordionButtonCheckboxBottomSheetDialogLayoutLoaderRefreshViewResendTimerStepsCrumbsSubHeaderTabsCapsuleHapticTabInputDatePickerEmptyScreenPhoneInputSelectInputBottomSheetWrapTextareaReviewStarRatingReviewStarRatingComponentCarouselPhotoPickerQuantityRadioGroupWeekCalendarVideoPreviewSettingItem
Дизайн-токены:
colorsEColorsEFontsStylingfontFamiliestextVariants
Иконки:
SvgAddSvgArrowLeftSvgArrowRightSvgCalendarSvgCashbackSvgCheckedSvgCloseSvgHeartSvgHeartFillSvgHomeSvgIceCleaningSvgLinkSvgNotificationSvgOtpSvgPencilSvgPercentileSvgPlaySvgProfileSvgSocialAppleSvgSocialGoogleSvgSupportSvgWaiting
Установка
Установите пакет:
npm install cleaning-native-kitПриложение должно также предоставить peer dependencies:
npm install react react-native react-native-svg react-native-portalize react-native-safe-area-contextЕсли приложение использует Expo и рендерит Checkbox, дополнительно установите:
npx expo install @expo/vector-iconsИспользование
Text
import { EColors, EFontsStyling, Text } from 'cleaning-native-kit';
export function ExampleText() {
return (
<Text styling={EFontsStyling.TEXT_BODY_2_REGULAR} color={EColors.TEXT_GREY}>
Чистый дом, спокойная голова.
</Text>
);
}Accordion
import { Accordion } from 'cleaning-native-kit';
export function ExampleAccordion() {
return (
<Accordion
title='Что входит в уборку?'
content='Кухня, санузел, поверхности, полы и зоны общего пользования.'
/>
);
}Если нужна кастомная иконка, передайте её через renderIcon:
import { Text } from 'react-native';
import { Accordion } from 'cleaning-native-kit';
export function ExampleAccordionIcon() {
return (
<Accordion
title='Подробности заказа'
content='Вы можете изменить дату и время до подтверждения клинера.'
renderIcon={({ isOpen }) => <Text>{isOpen ? '-' : '+'}</Text>}
/>
);
}Checkbox
import { Checkbox } from 'cleaning-native-kit';
export function ExampleCheckbox() {
return (
<Checkbox
label='Согласен с условиями обработки данных'
description='Мы используем данные только для сопровождения заказа.'
checked
onChange={value => {
console.log(value);
}}
/>
);
}Button
import { Button, SvgArrowRight } from 'cleaning-native-kit';
export function ExampleButton() {
return (
<Button
variant='primary'
icon={<SvgArrowRight color='#FFFFFF' />}
onPress={() => {
console.log('pressed');
}}
>
Продолжить
</Button>
);
}Доступные варианты:
primaryorangeblackwhiteOutlineflatlink
BottomSheet
BottomSheet использует react-native-portalize и react-native-safe-area-context, поэтому его нужно рендерить внутри провайдеров приложения.
import { useState } from 'react';
import { Pressable, View } from 'react-native';
import { Host } from 'react-native-portalize';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { BottomSheet, EFontsStyling, Text } from 'cleaning-native-kit';
export function ExampleBottomSheet() {
const [visible, setVisible] = useState(false);
return (
<SafeAreaProvider>
<Host>
<View>
<Pressable onPress={() => setVisible(true)}>
<Text styling={EFontsStyling.TEXT_BODY_2}>Открыть sheet</Text>
</Pressable>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
header={
<Text styling={EFontsStyling.TEXT_SUBHEADER_2}>
Подтверждение заказа
</Text>
}
footer={
<Pressable onPress={() => setVisible(false)}>
<Text styling={EFontsStyling.TEXT_BODY_2}>Закрыть</Text>
</Pressable>
}
>
<Text styling={EFontsStyling.TEXT_BODY_2_REGULAR}>
Контент листа можно скроллить.
</Text>
</BottomSheet>
</View>
</Host>
</SafeAreaProvider>
);
}Dialog
Dialog подходит для подтверждений, предупреждений и коротких сценариев с одним или двумя действиями.
import { useState } from 'react';
import { Dialog } from 'cleaning-native-kit';
export function ExampleDialog() {
const [visible, setVisible] = useState(false);
return (
<Dialog
visible={visible}
onClose={() => setVisible(false)}
title='Удалить адрес?'
description='Это действие нельзя отменить.'
primaryButton={{
label: 'Удалить',
onPress: () => setVisible(false),
}}
secondaryButton={{
label: 'Отмена',
onPress: () => setVisible(false),
}}
/>
);
}Основные пропсы Dialog:
visible- управляет видимостью модального окнаonClose- вызывается при закрытииtitle- заголовокdescription- описаниеprimaryButton- основное действиеsecondaryButton- второстепенное действиеshowCloseIcon- показывает кнопку закрытияcloseOnBackdropPress- закрывает dialog по нажатию на фонcloseOnBackButton- закрывает dialog по системной кнопке "назад"
Layout
Layout - базовый контейнер экрана с поддержкой safe-area, прокрутки, pull-to-refresh, subHeader и фиксированного footer.
import { Pressable, View } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { EFontsStyling, Layout, Text } from 'cleaning-native-kit';
export function ExampleLayout() {
return (
<SafeAreaProvider>
<Layout
subHeader={
<View>
<Text styling={EFontsStyling.TEXT_SUBHEADER_2}>Мои адреса</Text>
</View>
}
footer={
<Pressable>
<Text styling={EFontsStyling.TEXT_BODY_2}>Добавить адрес</Text>
</Pressable>
}
>
<Text styling={EFontsStyling.TEXT_BODY_2_REGULAR}>
Здесь находится основной контент экрана.
</Text>
</Layout>
</SafeAreaProvider>
);
}Основные пропсы Layout:
children- основной контент экранаsubHeader- верхний дополнительный блок под safe-areafooter- нижний фиксированный блокscrollable- включает или выключает обёртку вScrollViewrefreshing- состояние pull-to-refreshonRefresh- обработчик обновленияedges- список safe-area edges дляSafeAreaView
Colors
colors и EColors дают доступ к цветовым токенам библиотеки. Их удобно использовать в собственных экранах и при стилизации вокруг UI-kit.
import { colors, EColors } from 'cleaning-native-kit';
const accent = colors[EColors.BUTTON_DARK_TURQUOISE];Что экспортируется из пакета colors:
colors- объект со значениями цветовEColors- enum с ключами цветовых токенов
Loader
Loader отображает стандартный индикатор загрузки и подходит для локальных состояний ожидания: загрузка списка, отправка формы или обновление данных.
import { Loader } from 'cleaning-native-kit';
export function ExampleLoader() {
return <Loader color='#00969C' />;
}Основные пропсы Loader:
color- цветActivityIndicator
RefreshView
RefreshView - облегчённая scroll-обёртка с поддержкой pull-to-refresh. Подходит для экранов и секций, где нужен ScrollView с RefreshControl, но без полного Layout.
import { RefreshView, Text } from 'cleaning-native-kit';
export function ExampleRefreshView() {
return (
<RefreshView refreshing={false} onRefresh={() => {}}>
<Text>Список заказов обновляется по свайпу вниз.</Text>
</RefreshView>
);
}Основные пропсы RefreshView:
children- основной контент внутри scroll-областиsubHeader- необязательный верхний блок перед контентомrefreshing- текущее состояние обновленияonRefresh- обработчик pull-to-refresh
ResendTimer
ResendTimer помогает в сценариях подтверждения по коду: показывает обратный отсчёт до повторной отправки и затем даёт пользователю повторно запросить код.
import { ResendTimer } from 'cleaning-native-kit';
export function ExampleResendTimer() {
return (
<ResendTimer
initialSeconds={60}
onResend={() => {
console.log('resend code');
}}
/>
);
}Основные пропсы ResendTimer:
initialSeconds- длительность обратного отсчёта в секундахonResend- обработчик повторной отправкиisResending- блокирует повторное нажатие, пока идёт запросautoStart- запускает таймер автоматически при монтировании
StepsCrumbs
StepsCrumbs показывает прогресс по шагам в виде ряда индикаторов. Компонент полезен в онбординге, многошаговых формах и сценариях оформления заказа.
import { StepsCrumbs } from 'cleaning-native-kit';
export function ExampleStepsCrumbs() {
return <StepsCrumbs total={4} activeIndex={1} />;
}Основные пропсы StepsCrumbs:
total- общее количество шаговactiveIndex- индекс активного шага, начиная с0
SubHeader
SubHeader - декоративный верхний блок для экранов и секций. Он отображает заголовок и может содержать произвольный дополнительный контент над ним.
import { SubHeader, Text } from 'cleaning-native-kit';
export function ExampleSubHeader() {
return (
<SubHeader title='Мои заказы'>
<Text>Актуальные статусы и история уборок</Text>
</SubHeader>
);
}Основные пропсы SubHeader:
title- основной заголовок блокаchildren- дополнительный контент над заголовком
TabsCapsule
TabsCapsule отображает горизонтальный список вкладок в виде капсул и автоматически прокручивает список к активному элементу. Подходит для фильтров, сегментов и компактной навигации по разделам.
import { TabsCapsule } from 'cleaning-native-kit';
export function ExampleTabsCapsule() {
return (
<TabsCapsule
tabs={[
{ label: 'Все', value: 'all' },
{ label: 'Активные', value: 'active' },
{ label: 'Завершённые', value: 'done' },
]}
value='all'
onChange={value => {
console.log(value);
}}
/>
);
}Основные пропсы TabsCapsule:
tabs- список вкладок сlabelиvaluevalue- значение активной вкладкиonChange- вызывается при выборе новой вкладки
HapticTab
HapticTab - обёртка для кнопки таб-бара react-navigation, которая добавляет лёгкий haptic feedback на iOS при нажатии на вкладку.
import { HapticTab } from 'cleaning-native-kit';
export const screenOptions = {
tabBarButton: props => <HapticTab {...props} />,
};Основные особенности HapticTab:
- принимает стандартные пропсы
BottomTabBarButtonProps - пробрасывает обработчики в
PlatformPressable - вызывает лёгкий haptic feedback на iOS через
expo-haptics
Input
Input - текстовое поле с label, description и отображением ошибки. Подходит для форм авторизации, профиля и многошаговых сценариев оформления заказа.
import { Input } from 'cleaning-native-kit';
export function ExampleInput() {
return (
<Input
label='Телефон'
placeholder='+7 999 123-45-67'
value=''
onChangeText={value => {
console.log(value);
}}
/>
);
}Основные пропсы Input:
label- заголовок поляdescription- дополнительный текст под labellabelPosition- позиция label:topилиleftvalue- текущее значение поляonChangeText- обработчик изменения текстаplaceholder- плейсхолдерdisabled- делает поле неактивнымerror- текст ошибки под полем
DatePicker
DatePicker - поле выбора даты с нативным системным пикером. На Android открывает системный date picker, на iOS показывает модальное окно с выбором даты и подтверждением.
import { DatePicker } from 'cleaning-native-kit';
export function ExampleDatePicker() {
return (
<DatePicker
label='Дата рождения'
value='1998-03-25'
onChange={value => {
console.log(value);
}}
/>
);
}Основные пропсы DatePicker:
label- заголовок поляvalue- выбранная дата в форматеYYYY-MM-DDonChange- обработчик изменения датыplaceholder- текст для пустого значенияminimumDate- минимально доступная датаmaximumDate- максимально доступная датаdisabled- блокирует открытие пикераerror- текст ошибки под полем
EmptyScreen
EmptyScreen отображает простое пустое состояние с центрированным сообщением. Подходит для экранов без данных: нет заказов, адресов или истории операций.
import { EmptyScreen } from 'cleaning-native-kit';
export function ExampleEmptyScreen() {
return <EmptyScreen message='Пока здесь ничего нет' />;
}Основные пропсы EmptyScreen:
message- текст пустого состояния
PhoneInput
PhoneInput - специализированное поле для российского номера телефона. Внутри отображает форматированный номер, а наружу возвращает значение в формате E.164.
import { PhoneInput } from 'cleaning-native-kit';
export function ExamplePhoneInput() {
return (
<PhoneInput
label='Телефон'
value='+79991234567'
onChangeText={value => {
console.log(value);
}}
/>
);
}Основные пропсы PhoneInput:
value- значение телефона в формате E.164, например+79991234567onChangeText- обработчик, который получает E.164-значениеlabel- заголовок поляdescription- дополнительный текст под заголовкомdisabled- делает поле неактивнымerror- текст ошибки под полем
SelectInputBottomSheet
SelectInputBottomSheet - селект, который открывает список вариантов в BottomSheet. Подходит для выбора адреса, тарифа, интервала или любого фиксированного набора значений.
import { SelectInputBottomSheet } from 'cleaning-native-kit';
export function ExampleSelectInputBottomSheet() {
return (
<SelectInputBottomSheet
label='Тариф'
placeholder='Выберите тариф'
value='standard'
options={[
{ value: 'standard', label: 'Стандартная уборка' },
{ value: 'general', label: 'Генеральная уборка' },
]}
onChange={value => {
console.log(value);
}}
/>
);
}Основные пропсы SelectInputBottomSheet:
label- заголовок поляvalue- выбранное значениеplaceholder- текст для пустого состоянияoptions- список опций сvalue,labelи необязательнымrightLabelonChange- вызывается при выборе нового значенияsheetTitle- заголовок внутриBottomSheetdisabled- блокирует открытие селектаerror- текст ошибки под полем
Wrap
Wrap - простой layout-контейнер для группировки элементов в строку или колонку с настраиваемым расстоянием между ними.
import { Wrap } from 'cleaning-native-kit';
export function ExampleWrap() {
return <Wrap direction='row' gaps={12}>{/* элементы */}</Wrap>;
}Основные пропсы Wrap:
direction- направление:rowилиcolgaps- расстояние между дочерними элементамиchildren- содержимое контейнера
Textarea
Textarea - многострочное текстовое поле для комментариев, инструкций и заметок. Подходит для описания деталей заказа, пожеланий к уборке или обратной связи.
import { Textarea } from 'cleaning-native-kit';
export function ExampleTextarea() {
return (
<Textarea
label='Комментарий'
placeholder='Напишите важные детали для клинера'
value=''
onChangeText={value => {
console.log(value);
}}
/>
);
}Основные пропсы Textarea:
label- заголовок поляdescription- дополнительный текст под заголовкомvalue- текущее значениеonChangeText- обработчик изменения текстаplaceholder- плейсхолдерdisabled- делает поле неактивнымerror- текст ошибки под полемmaxLength- ограничение по количеству символовnumberOfLines- рекомендуемое количество строк
ReviewStarRating
ReviewStarRatingComponent и ReviewStarRating показывают выбор оценки по звёздам. Компонент подходит для отзывов, оценки качества уборки и быстрых rating-сценариев.
import { ReviewStarRating } from 'cleaning-native-kit';
export function ExampleReviewStarRating() {
return <ReviewStarRating value={4} onChange={value => console.log(value)} />;
}Основные пропсы ReviewStarRatingComponent:
value- текущая оценка от0до5onChange- вызывается при выборе новой оценкиsize- размер иконок звёздdisabled- блокирует изменение оценкиstyleStars- дополнительные стили для кнопок со звёздамиneedDescription- показывает или скрывает текстовую подпись оценки
Carousel
Carousel показывает горизонтальную ленту карточек с snap-прокруткой. Компонент больше не зависит от внутренних enum и картинок: изображение каждой карточки передаётся извне через imageSource.
import { Carousel } from 'cleaning-native-kit';
const data = [
{
id: 'silver',
title: 'Silver',
subtitle: 'Подробнее',
imageSource: { uri: 'https://example.com/silver-card.png' },
},
];
export function ExampleCarousel() {
return <Carousel data={data} onActiveChange={(item) => console.log(item.id)} />;
}Основные пропсы Carousel:
data- массив карточек сid,title,imageSourceи необязательнымиsubtitleиonPressSubtitleinitialIndex- индекс стартовой карточкиonActiveChange- вызывается при смене активной карточки
Формат элемента Carousel:
id- внешний идентификатор карточки, например строка или числоtitle- заголовок карточкиimageSource- источник изображения для фона карточкиsubtitle- необязательный дополнительный текстonPressSubtitle- обработчик нажатия на subtitle, получаетitemиindex
PhotoPicker
PhotoPicker позволяет выбрать одну или несколько фотографий из галереи, показывает превью и даёт удалить уже добавленные изображения. Подходит для прикрепления фото до/после уборки, проблемных зон или чек-листов.
import { PhotoPicker } from 'cleaning-native-kit';
export function ExamplePhotoPicker() {
return <PhotoPicker value={[]} onChange={value => console.log(value)} />;
}Основные пропсы PhotoPicker:
value- массив выбранных фото в формате{ uri: string }onChange- обработчик изменения списка фотографийmax- максимальное количество изображенийallowMultiple- разрешает множественный выборquality- качество сжатия от0до1allowsEditing- включает системное редактирование перед выбором
Quantity
Quantity - контрол количества с кнопками уменьшения и увеличения значения. Подходит для выбора числа комнат, санузлов, окон или любых счётчиков в форме заказа.
import { Quantity } from 'cleaning-native-kit';
export function ExampleQuantity() {
return <Quantity label='Комнаты' value={2} onChange={value => console.log(value)} />;
}Основные пропсы Quantity:
label- заголовок поляdescription- дополнительный текстlabelPosition- позиция label:topилиleftvalue- текущее количествоonChange- обработчик изменения значенияmin- минимальное значениеmax- максимальное значениеstep- шаг измененияdisabled- блокирует изменениеerror- текст ошибки под контролом
RadioGroup
RadioGroup - группа взаимоисключающих вариантов выбора. Подходит для выбора тарифа, способа оплаты, частоты уборки и других одиночных опций.
import { RadioGroup } from 'cleaning-native-kit';
export function ExampleRadioGroup() {
return (
<RadioGroup
value='weekly'
onChange={value => console.log(value)}
options={[
{ value: 'once', label: 'Разовая уборка' },
{ value: 'weekly', label: 'Каждую неделю' },
]}
/>
);
}Основные пропсы RadioGroup:
options- список вариантов сvalue,labelи опциональнымdisabledvalue- текущее выбранное значениеonChange- вызывается при выборе нового значенияdisabled- блокирует всю группуitemGap- расстояние между элементамиactiveColor- цвет выбранного состоянияinactiveColor- цвет невыбранного состоянияdisabledColor- цвет disabled-состоянияrenderAction- кастомный action справа от элементаonPressAction- обработчик для action
WeekCalendar
WeekCalendar - компактный недельный календарь с переключением по неделям. Подходит для выбора даты визита, окна доставки или ближайшего слота записи.
import { WeekCalendar } from 'cleaning-native-kit';
export function ExampleWeekCalendar() {
return (
<WeekCalendar
value={new Date()}
onChange={date => console.log(date)}
/>
);
}Основные пропсы WeekCalendar:
value- выбранная датаonChange- вызывается при выборе нового дняminDate- минимально доступная датаmaxDate- максимально доступная датаlocale- локаль для подписей месяца и дней неделиweekStartsOn- начало недели:1для понедельника или0для воскресенья
VideoPreview
VideoPreview показывает превью видео и открывает воспроизведение по нажатию. Подходит для обучающих роликов, видеоинструкций и медиавложений в карточках заказа.
import { VideoPreview } from 'cleaning-native-kit';
export function ExampleVideoPreview() {
return (
<VideoPreview
source='/media/videos/intro.mp4'
previewUri='/media/previews/intro.jpg'
authHeader='Bearer token'
resolveUri={uri => `https://api.example.com${uri}`}
/>
);
}Основные пропсы VideoPreview:
source- источник видео дляexpo-videopreviewUri- ссылка на изображение-превьюpreviewSource- локальныйImageSourcePropType, если не нужен URIstyle- кастомные стили контейнераloop- включает зацикливание видеоauthHeader- заголовок авторизации для защищённых видеоresolveUri- функция для преобразования относительных URL в абсолютные
SettingItem
SettingItem - компактный элемент списка настроек с лейблом и стрелкой. Подходит для перехода в детали профиля, уведомлений, способов оплаты и других экранов настроек.
import { SettingItem } from 'cleaning-native-kit';
export function ExampleSettingItem() {
return <SettingItem label='Уведомления' onPress={() => console.log('open')} />;
}Основные пропсы SettingItem:
label- текст пункта настроекonPress- обработчик нажатияdisabled- блокирует взаимодействие с элементом
Icons
import { SvgHome, SvgNotification } from 'cleaning-native-kit';
export function ExampleIcons() {
return (
<>
<SvgHome color='#00969C' />
<SvgNotification hasBadge />
</>
);
}Если нужен более эффективный tree-shaking, используйте прямые импорты для отдельных сущностей:
import { Button } from 'cleaning-native-kit/button';
import { SvgHome } from 'cleaning-native-kit/icons/home-icon';Шрифты
Библиотека не загружает шрифты автоматически.
Если компоненты опираются на Poppins, загрузите его до рендера UI-кита.
Пример для Expo-приложения:
import { useFonts } from 'expo-font';
import {
Poppins_100Thin,
Poppins_200ExtraLight,
Poppins_300Light,
Poppins_400Regular,
Poppins_500Medium,
Poppins_600SemiBold,
Poppins_700Bold,
Poppins_800ExtraBold,
Poppins_900Black,
} from '@expo-google-fonts/poppins';
export function useLoadFonts() {
const [loaded, error] = useFonts({
Poppins_100Thin,
Poppins_200ExtraLight,
Poppins_300Light,
Poppins_400Regular,
Poppins_500Medium,
Poppins_600SemiBold,
Poppins_700Bold,
Poppins_800ExtraBold,
Poppins_900Black,
});
return { loaded, error };
}Рекомендуемый подход:
- загружать шрифты на уровне приложения
- рендерить UI-kit только после
loaded === true
Локальная разработка
Установка зависимостей:
npm installПроверка типов:
npm run lint:typesЗапуск ESLint:
npm run lint:eslintПолная проверка линтинга и типов:
npm run lintСборка библиотеки:
npm run buildЗапуск Storybook:
npm run storybookStorybook будет доступен по адресу http://localhost:6006.
Сборка Storybook:
npm run storybook:buildВерсионирование
Команды для изменения версии пакета:
npm run release:patch
npm run release:minor
npm run release:majorЭти команды обновляют package.json локально и не создают git tag автоматически.
Публикация
Стабильные релизы публикуются из master.
Обычный сценарий:
- Обновить версию в
package.json. - Закоммитить и запушить изменения.
- Запустить workflow
Publish Packageсrelease_channel=stable.
Для стабильного релиза workflow:
- публикует пакет в npm
- создаёт git tag
v<version> - создаёт GitHub Release
Canary-релизы можно публиковать вручную из любой ветки, кроме master, через тот же workflow с release_channel=canary.
CI/CD
В репозитории настроены GitHub Actions workflows:
CIдляpushиpull_requestPublish Packageдля ручной публикацииstableиcanary
Подробности доступны в docs/ci-cd.md.
