Кроссплатформенный и мобильный интерфейс · Новый ресурс

Дизайн-система Tamagui.

Изучите актуальные категории токенов Tamagui версии v5 и светлую и тёмную синие темы на примере полноценной доски привычек из нативных компонентов: с валидацией, прогрессом и восстановлением после пустого состояния.

Руководство OpenDesign8 глав50 справочных записейАвторское руководство по приложению
01

Tamagui Предварительный просмотр интерфейса дизайн-системы

Добавляйте привычки, отмечайте прогресс, фильтруйте незавершённые дела и переключайте синюю тему.

Создайте доску небольших привычекОткрыть полный пример
Tamagui Веб-компоненты native версии 2.7.7, конфигурация v5 и исходное локальное состояние. · Справочник по реализации
02

Tamagui Проектная документация дизайн-системы

Значения из @tamagui/config/v5 и @tamagui/themes версии 2.7.7, а также проверенные контракты native-компонентов.

Токены размера v5

Источник
Название / правилоЗначение / конфигурацияПрименение
size.$120Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
size.$228Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
size.$336Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
size.$444Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
size.$552Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
size.$664Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.

Токены интервалов v5

Источник
Название / правилоЗначение / конфигурацияПрименение
space.$12Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$1.54Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$27Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$2.510Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$313Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$3.516Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$418Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$524Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
space.$632Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.

Токены радиуса v5

Источник
Название / правилоЗначение / конфигурацияПрименение
radius.00Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
radius.13Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
radius.25Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
radius.37Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
radius.49Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
radius.510Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.
radius.616Фактическое значение конфигурации v5. Одинаковая числовая метка токена имеет разный смысл для размера, интервала и радиуса; не считайте $4 универсальным значением в пикселях.

Семантическая тема light_blue

Источник
Название / правилоЗначение / конфигурацияПрименение
light_blue.backgroundhsla(207, 100%, 98%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
light_blue.backgroundHoverhsla(210, 100%, 99%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
light_blue.backgroundPresshsla(205, 92%, 95%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
light_blue.colorhsla(216, 71%, 23%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
light_blue.borderColorhsla(203, 100%, 92%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
light_blue.borderColorFocushsla(203, 100%, 92%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
light_blue.placeholderColorhsla(206, 100%, 50%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.

Семантическая тема dark_blue

Источник
Название / правилоЗначение / конфигурацияПрименение
dark_blue.backgroundhsla(218, 39%, 11%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
dark_blue.backgroundHoverhsla(212, 69%, 16%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
dark_blue.backgroundPresshsla(215, 42%, 9%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
dark_blue.colorhsla(205, 100%, 88%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
dark_blue.borderColorhsla(209, 100%, 19%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
dark_blue.borderColorFocushsla(209, 100%, 19%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.
dark_blue.placeholderColorhsla(206, 100%, 50%, 1)Разрешённая семантическая роль синей темы v5. Для состояний наведения, нажатия или активации компонент может выбрать более конкретную дочернюю тему.

Роли системных шрифтов

Источник
Название / правилоЗначение / конфигурацияПрименение
body.family-apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serifДля системного стека v5 не требуется загружать шрифты из сети.
body.$213px / 20pxРазмер шрифта и высота строки образуют пару типографических ролей и не зависят от токена размера компонента с той же меткой.
body.$314px / 21pxРазмер шрифта и высота строки образуют пару типографических ролей и не зависят от токена размера компонента с той же меткой.
body.$415px / 23pxРазмер шрифта и высота строки образуют пару типографических ролей и не зависят от токена размера компонента с той же меткой.
body.$516px / 24pxРазмер шрифта и высота строки образуют пару типографических ролей и не зависят от токена размера компонента с той же меткой.
body.$618px / 27pxРазмер шрифта и высота строки образуют пару типографических ролей и не зависят от токена размера компонента с той же меткой.
body.$826px / 38pxРазмер шрифта и высота строки образуют пару типографических ролей и не зависят от токена размера компонента с той же меткой.

Контракты native-композиции

Источник
Название / правилоЗначение / конфигурацияПрименение
createTamaguidefaultConfig from @tamagui/config/v5Один экземпляр конфигурации за пределами React; getCSS() предоставляет веб-тему CSS.
TamaguiProviderconfig + defaultThemeПриложение выбирает светлый или тёмный режим, сохраняя состояние доски.
Themename="blue"Разрешает синюю дочернюю тему для текущего режима оформления.
Checkboxchecked + onCheckedChangeДоска считает задачу выполненной, только если value === true; неопределённое состояние не означает выполнение.
Inputvalue + onChangeTextКонтролируемый черновик, проверка после удаления пробелов по краям и явная обработка дубликатов.
Progressvalue from 0 to 100Индикатор вычисляется как отношение числа выполненных задач к общему числу строк.
YStack / XStackdirectional layout with token gapСохраняйте адаптивную компоновку для чтения без отдельной имитационной таблицы стилей.
03

Полное руководство по дизайн-системе Tamagui

Практическое руководство по выбору, применению и оценке этой системы для реального интерфейса.

DESIGN-tamagui.md

Подробные рекомендации, отправная точка для реализации и ссылки на источники.

Скачать руководство

Дизайн-система Tamagui: версионируемая конфигурация и CSS

Используйте предустановку с указанной версией v5

В этом примере версии tamagui и @tamagui/config зафиксированы на 2.7.7, а defaultConfig импортируется из @tamagui/config/v5. Имя конфигурации — v5, а не номер основной версии npm-пакета. Если смешать эти два номера, читатель получит неверную команду установки. createTamagui вызывается один раз за пределами компонента, а сгенерированный CSS добавляется до отрисовки доски, чтобы переменные темы и стили native имели реальное определение для веба.

Из этого руководства OpenDesign

Явно укажите небольшое переопределение конфигурации

В предоставленном исходном коде для onlyAllowShorthands задано значение false, поскольку в этом учебном примере используются понятные свойства с полными названиями, например padding и backgroundColor. Это решение приложения поверх предустановки. Базовая конфигурация v5 не включает драйвер анимации, и в примере он не придумывается и не заявляется наличие анимированных переходов. Простые действия с прогрессом и флажками работают без отдельной зависимости для анимации.

Дизайн-система Tamagui: токены размера, интервалов и скругления

Не путайте одинаковые метки токенов

В зафиксированной конфигурации v5 размер $4 равен 44, интервал $4 — 18, а радиус 4 — 9. Поэтому для размера компонента, промежутка в компоновке и радиуса скругления нельзя использовать одно общее правило пересчёта. В справочнике эти категории приведены отдельно, а в примере их значения используются с учётом категории через реальные свойства Tamagui. Это полезнее, чем список универсальных шагов по 4px, которых в конфигурации нет.

  • size.$4 = 44
  • space.$4 = 18
  • radius.4 = 9
  • Основной шрифт $4: 15px, высота строки — 23px

Типографическую шкалу тоже учитывайте отдельно

Основной шрифт $4 имеет размер 15px и высоту строки 23px, а размер компонента $4 по-прежнему равен 44. Системный стек шрифтов входит в v5, поэтому загружать шрифт не нужно. Для H1, H2 и Text заданы собственные контексты шрифтов; иерархию исходной доски определяют явно указанные в коде значения fontSize и lineHeight. Ширина внешнего контейнера 880px — локальное решение для компоновки, а не глобальный токен Tamagui.

Tamagui Семантические темы и внешний вид дизайн-системы

Сочетайте светлую или тёмную тему с синей дочерней темой

TamaguiProvider получает выбранное значение defaultTheme, а Theme name="blue" разрешает соответствующую дочернюю тему. Вместо повторения буквальных hex-значений по всему дереву компонентов в исходном коде используются роли background, backgroundHover, color и borderColor. В таблице приведены фактические значения light_blue и dark_blue, чтобы читатель мог сравнить разрешённую конфигурацию, а не предполагать, что палитра бренда всегда одна и та же.

Сохраняйте состояние доски при смене оформления

Флаг dark не зависит от строк, черновика в поле ввода и фильтра. При переключении оформления обновляются native-компоненты, а содержимое доски сохраняется. Для кнопок и флажков могут выбираться собственные значения дочерних тем компонентов, поэтому вычисленный цвет не обязательно совпадает с токеном фона родительской темы. Перед сведением иерархии к пользовательским CSS проверьте отрисованное состояние.

Дизайн-система Tamagui: флажки и вычисляемый прогресс

Храните состояние выполнения в коллекции строк

У каждой строки есть стабильный ID, понятный текст и логическое значение done. Для Checkbox задаются checked и onCheckedChange; задача считается выполненной только при значении true. Checkbox.Indicator отображает отметку. Соседний текст и доступное имя обозначают одну и ту же привычку, а зачёркивание дополнительно показывает её выполнение. В исходном коде отдельный счётчик, который мог бы рассинхронизироваться со строками, не создаётся.

Рассчитывайте прогресс по всей доске

Дизайн-система Tamagui: проверка черновика и обработка дубликатов

Добавьте полноценное контролируемое поле ввода

Input хранит текущий черновик в value и onChangeText. Действие «Добавить привычку» удаляет пробелы по краям и отклоняет пустое значение, показывая сообщение, aria-invalid и описание ошибки. После отправки пустого значения фокус возвращается в поле ввода. Проверка на дубликаты без учёта регистра не позволяет добавить ещё одну строку с тем же текстом и оставляет черновик для исправления. Эти правила относятся к исходной доске, а не к библиотеке.

Обновляйте доску только после успешной проверки

Валидный черновик добавляет новую незавершённую строку, очищает поле ввода и убирает сообщение об ошибке. Знаменатель для прогресса сразу меняется, поскольку он вычисляется по новой коллекции. Добавление привычки не создаёт напоминание и не регистрирует учётную запись. Доска намеренно хранится в локальном состоянии React; после перезагрузки документа снова отобразится пример.

Дизайн-система Tamagui: отфильтрованные представления и выход из пустого состояния

Уточните, к чему применяется фильтр

Фильтр «Показывать только незавершённые» скрывает выполненные строки, сохраняя их в коллекции. Если в этом представлении ничего не осталось, текст пустого состояния поясняет, что полный список по-прежнему доступен, и предлагает прямой переход обратно. Такое пустое состояние возникает в результате выбора пользователя, а не из-за декоративного переключателя, произвольно заменяющего карточки-заполнители.

Отделите сброс от смены оформления

Действие «Сбросить доску к исходному виду» восстанавливает три начальные строки, очищает черновик и сообщение об ошибке, а также возвращает полный список. Текущее оформление не меняется. Поскольку каждое изменение хранится как явное состояние, для сброса не нужно перезагружать документ или удалять настроенный provider. Восстановление темы и содержимого можно проверять независимо.

Дизайн-система Tamagui: адаптивные стеки и удобство чтения

Позвольте содержимому стека определять его высоту

YStack задаёт основную последовательность содержимого, а XStack выравнивает элементы управления в заголовке, строки с флажками и кнопки действий. Группы элементов управления переносятся, а не требуют фиксированной ширины для настольного экрана. Ширина внешнего контейнера не превышает 880px; для внутренних отступов используется реальный токен интервалов $4. Текст в каждой строке может сжиматься и переноситься, а элементы управления остаются доступными при ширине 280px и на более широких экранах.

Проверьте взаимодействие после изменения компоновки

При проверке в браузере добавляют привычку, отмечают её выполненной, фильтруют список и переключают оформление, а затем измеряют переполнение. Один снимок начального состояния не покажет, не нарушают ли узкую компоновку сообщение об ошибке, длинная подпись или отфильтрованное представление. Семантику native-флажков и видимый текст проверяли вместе с вычисляемым прогрессом, а не считали их работающими только на основании наличия в интерфейсе.

Дизайн-система Tamagui: полная сборка для браузера

Добавьте provider, CSS и определения сборки

Для локального изучения веб-версии достаточно трёх предоставленных файлов. JSX содержит провайдер, одну конфигурацию, сгенерированную тему CSS и всю доску. build.mjs фиксирует целевую веб-платформу и производственное окружение, а также задаёт пустое значение по умолчанию для process.env на случай других обращений к переменным окружения, доступным только в браузере. Без этого последнего определения обычная сборка может завершиться ошибкой process is not defined, даже если компиляция проходит.

  1. Сохраните tamagui.jsx, build.mjs и index.html в одной папке.
  2. Установите зафиксированные версии пакетов React и Tamagui.
  3. Соберите и запустите локальную папку.
  4. Проверьте добавление пустых и повторяющихся элементов, выполнение, фильтры, тему и сброс.

Разделяйте внедрение для нативных приложений и веба

Примеры компонентов дизайн-системы Tamagui

tamagui.jsx

Конфигурация, сгенерированная CSS, нативные компоненты и полное состояние доски.

jsx
import React,{useState} from 'react';import{createRoot}from'react-dom/client';
import{createTamagui,TamaguiProvider,Theme,YStack,XStack,Text,H1,H2,Button,Input,Checkbox,Progress,Separator}from'tamagui';import{defaultConfig}from'@tamagui/config/v5';
const config=createTamagui({...defaultConfig,settings:{...defaultConfig.settings,onlyAllowShorthands:false}});const sheet=document.createElement('style');sheet.textContent=config.getCSS();document.head.append(sheet);
const initial=[{id:1,text:'Read ten pages',done:false},{id:2,text:'Step outside for a break',done:true},{id:3,text:'Write one useful note',done:false}];
function App(){const[dark,setDark]=useState(false),[rows,setRows]=useState(initial),[draft,setDraft]=useState(''),[error,setError]=useState(''),[filter,setFilter]=useState(false);const done=rows.filter(x=>x.done).length;let shown=rows.filter(x=>!filter||!x.done);function add(){let text=draft.trim();if(!text){setError('Write a small habit before adding it.');document.querySelector('#habit-input')?.focus();return}if(rows.some(x=>x.text.toLowerCase()===text.toLowerCase())){setError('That habit is already in this list.');return}setRows([...rows,{id:Date.now(),text,done:false}]);setDraft('');setError('')}return <TamaguiProvider config={config} defaultTheme={dark?'dark':'light'}><Theme name="blue"><YStack backgroundColor="$background" color="$color" padding="$4" gap="$4" maxWidth={880} margin="auto" width="100%" minHeight={0}><XStack justifyContent="space-between" alignItems="center" flexWrap="wrap" gap="$3"><Text fontSize="$2" fontWeight="700">TAMAGUI / ORIGINAL HABIT BOARD</Text><Button size="$3" onPress={()=>setDark(!dark)}>{dark?'Light appearance':'Dark appearance'}</Button></XStack><H1 fontSize="$8" lineHeight="$8">A little progress, every day.</H1><Text fontSize="$4" lineHeight="$5">A local board built with Tamagui 2.7.7 and its v5 blue theme. Your changes stay in this page; no account or daily reminder is connected.</Text><YStack backgroundColor="$backgroundHover" borderWidth={1} borderColor="$borderColor" borderRadius="$4" padding="$4" gap="$3"><XStack justifyContent="space-between" gap="$3" flexWrap="wrap"><H2 fontSize="$5">Today’s small steps</H2><Text id="progress-count" aria-live="polite">{done} of {rows.length} complete</Text></XStack><Progress value={rows.length?done/rows.length*100:0} size="$2" aria-label="Completed habits"><Progress.Indicator animation={undefined}/></Progress><Button size="$3" alignSelf="flex-start" onPress={()=>setFilter(!filter)}>{filter?'Show all habits':'Show unfinished only'}</Button><Separator/>{shown.length?shown.map(row=><XStack key={row.id} gap="$3" alignItems="center" paddingVertical="$2"><Checkbox id={'habit-'+row.id} checked={row.done} onCheckedChange={value=>setRows(rows.map(x=>x.id===row.id?{...x,done:value===true}:x))} aria-label={row.text} size="$4"><Checkbox.Indicator><Text fontWeight="700">✓</Text></Checkbox.Indicator></Checkbox><Text flex={1} fontSize="$4" lineHeight="$5" textDecorationLine={row.done?'line-through':'none'} opacity={row.done?.65:1}>{row.text}</Text></XStack>):<YStack gap="$3"><Text fontWeight="700">Nothing unfinished in this view</Text><Text>All your habits remain in the full list. You can revisit any completed item.</Text><Button onPress={()=>setFilter(false)}>Return to all habits</Button></YStack>}</YStack><YStack gap="$3"><Text htmlFor="habit-input" tag="label" fontWeight="700">Add one small habit</Text><Input id="habit-input" value={draft} onChangeText={v=>{setDraft(v);setError('')}} placeholder="For example, stretch for five minutes" aria-describedby={error?'habit-error':undefined} aria-invalid={!!error} onKeyPress={e=>{if(e.nativeEvent.key==='Enter')add()}}/><Text id="habit-error" color="$color" aria-live="polite">{error}</Text><XStack gap="$3" flexWrap="wrap"><Button theme="active" onPress={add}>Add habit</Button><Button onPress={()=>{setRows(initial);setDraft('');setError('');setFilter(false)}}>Reset sample board</Button></XStack></YStack><Text fontSize="$2" lineHeight="$3">Native Checkbox, Input, Button and Progress components; original board content and state. Theme changes preserve the current board.</Text></YStack></Theme></TamaguiProvider>}
createRoot(document.getElementById('root')).render(<App/>);

Справочник по коду

  • Используйте вместе все три готовых файла.

build.mjs

Определения браузерного окружения, используемые в проверенной сборке.

javascript
import {build} from 'esbuild';
await build({entryPoints:['tamagui.jsx'],bundle:true,minify:true,outfile:'tamagui.bundle.js',define:{'process.env.NODE_ENV':'"production"','process.env.TAMAGUI_TARGET':'"web"','process.env':'{}'}});

Справочник по коду

  • Используйте вместе все три готовых файла.

index.html

Автономный корневой документ и импорт сборки.

html
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Small habits board</title><style>body{margin:0}*{box-sizing:border-box}button,input{max-width:100%}</style></head><body><div id="root"></div><script src="./tamagui.bundle.js"></script></body></html>

Справочник по коду

  • Используйте вместе все три готовых файла.
04

Настройка агента дизайн-системы Tamagui

Отправная точка для реализации

Сначала сохраните предоставленные файлы, затем откройте http://localhost:8000/. Эта конфигурация предназначена только для браузера.

sh
npm init -y
npm install [email protected] [email protected] [email protected] @tamagui/[email protected]
npm install --save-dev esbuild
node build.mjs
python3 -m http.server 8000

Запрос для вашего проекта

Промпт для AI-агента
Реализуйте полноценную веб-доску привычек на Tamagui 2.7.7 с пресетом v5. Разделяйте категории токенов размера, пространства, радиуса и шрифта; сохраните сгенерированную тему CSS, дочерние светлую и тёмную синие темы, управляемые флажки, проверку с обрезкой пробелов и дубликатов, знаменатель прогресса по всем строкам, восстановление в представлении незавершённых задач и сброс без изменения внешнего вида.
05

Источники и область применения дизайн-системы Tamagui

Реальные веб-компоненты Tamagui 2.7.7 с пресетом v5. Доска привычек и правила состояния — оригинальный код OpenDesign; функции учётных записей, напоминаний и взаимодействия с нативными устройствами не подключены.