This commit is contained in:
2025-12-27 18:25:15 +03:00
parent 63a9425680
commit fde5f9de58
23 changed files with 688 additions and 0 deletions

78
docs/README.md Normal file
View File

@@ -0,0 +1,78 @@
# Tria UI
**Tria UI** — UIкит и набор паттернов для разработки интерфейсов с единым дизайном под:
- Web
- VK Mini Apps
- Telegram Mini Apps
Цель: единый API компонентов и единый подход к токенам/темам (`theme/platform/skin`), чтобы ваш интерфейс выглядел нативно (в том числе **Cupertinoощущение** на iOS).
---
## Быстрый старт
1) Установите пакет:
```bash
pnpm add @tria/ui
# или npm i @tria/ui / yarn add @tria/ui
```
2) Подключите стили (рекомендуется):
```ts
import "@tria/ui/styles";
```
3) Оберните приложение провайдером:
```tsx
import React from "react";
import { UIProvider } from "@tria/ui";
export function App() {
return (
<UIProvider config={{ theme: "dark", platform: "web", skin: "ios" }}>
{/* ... */}
</UIProvider>
);
}
```
---
## Два способа подключения стилей
### Вариант A: отдельный импорт CSS (рекомендуется)
```ts
import "@tria/ui/styles";
import { UIProvider, Button } from "@tria/ui";
```
### Вариант B: autoentry
Если вы хотите одним импортом подтянуть и JS и CSS:
```ts
import "@tria/ui/auto";
import { UIProvider, Button } from "@tria/ui";
```
> Не используйте `@tria/ui/styles` вместе с `@tria/ui/auto`, чтобы не получить двойную загрузку CSS.
---
## Ключевые понятия
- **theme**: `light | dark`
- **platform**: `web | vk | tg`
- **skin**: `web | ios | android`
Комбинации параметров управляют пресетами (`presets.css`) и компонентными токенами (`--btn-*`, `--input-*`, `--cell-*`, `--tabbar-*`, …).
---
## Контакты и вклад в проект
См. раздел **Contributing**.

36
docs/SUMMARY.md Normal file
View File

@@ -0,0 +1,36 @@
# Summary
* [Tria UI](README.md)
## Getting Started
* [Installation](getting-started/installation.md)
* [Styles & Bundling](getting-started/styles.md)
* [Theming (theme/platform/skin)](getting-started/theming.md)
## Design System
* [Tokens overview](design-system/tokens.md)
* [Presets: web/vk/tg × ios/android × light/dark](design-system/presets.md)
* [Customization without forking](design-system/customization.md)
## Providers
* [UIProvider](providers/uiprovider.md)
* [Snackbar Provider](providers/snackbar.md)
## Components
* [Button](components/button.md)
* [TabBar](components/tabbar.md)
* [Cells & Lists](components/cells-and-lists.md)
* [Forms](components/forms.md)
* [Feedback](components/feedback.md)
* [Modals & Overlays](components/modals.md)
* [Dates](components/dates.md)
* [Display](components/display.md)
## Patterns & Recipes
* [VK Mini Apps](patterns/vk-miniapps.md)
* [Telegram Mini Apps](patterns/tg-miniapps.md)
* [Responsive layout](patterns/responsive-layout.md)
## Contributing
* [Local development](contributing/development.md)
* [Release & versioning](contributing/release.md)

27
docs/components/button.md Normal file
View File

@@ -0,0 +1,27 @@
# Button
## Import
```ts
import { Button } from "@tria/ui";
```
## Variants
Рекомендуемая модель:
- `data-variant="primary" | "outline" | "ghost" | "danger"`
- `data-size="sm" | "md" | "lg"`
## Example
```tsx
<Button data-variant="primary" data-size="md">Continue</Button>
<Button data-variant="outline" data-size="md">Cancel</Button>
```
## Design tokens
- `--btn-h-sm/md/lg`
- `--btn-px-sm/md/lg`
- `--btn-radius`
- `--btn-gap`

View File

@@ -0,0 +1,24 @@
# Cells & Lists
Списки и ячейки — основной паттерн для настроек и навигации.
## Import
```ts
import { List, Cell, SimpleCell, RichCell } from "@tria/ui";
```
## Examples
```tsx
<List>
<Cell title="Profile" subtitle="Account settings" chevron />
<Cell title="Notifications" after="12" chevron />
</List>
```
## Design tokens
- `--cell-h`, `--cell-px`, `--cell-gap`
- `--cell-before`, `--cell-chev`
- `--cell-badge-*`

13
docs/components/dates.md Normal file
View File

@@ -0,0 +1,13 @@
# Dates
Calendar / CalendarRange / DateInput / DateRangeInput.
## Import
```ts
import { Calendar, CalendarRange, DateInput, DateRangeInput } from "@tria/ui";
```
## Tokens
- `--cal-day`, `--cal-day-radius`, `--cal-gap`, `--cal-p`

View File

@@ -0,0 +1,15 @@
# Display
Компоненты отображения: GridAvatar, Gallery, Accordion и др.
## Import
```ts
import { GridAvatar, Gallery, Accordion } from "@tria/ui";
```
## Examples
```tsx
<GridAvatar items={[{ id:"u1", title:"Alex", initials:"A" }]} cols={2} size={36} />
```

View File

@@ -0,0 +1,16 @@
# Feedback
Компоненты обратной связи: alert/progress/spinner/skeleton/snackbar/pull-to-refresh.
## Import
```ts
import { Alert, Progress, Spinner, Skeleton, Snackbar, PullToRefresh } from "@tria/ui";
```
## Snackbar
```tsx
const [open, setOpen] = useState(false);
<Snackbar open={open} onOpenChange={setOpen} text="Saved" />
```

25
docs/components/forms.md Normal file
View File

@@ -0,0 +1,25 @@
# Forms
Набор форм‑компонентов: input/select/chips/segmented/file/writebar.
## Import (examples)
```ts
import {
Input, Textarea, Switch, Checkbox, Radio,
Slider, SegmentedControl,
NativeSelect, CustomSelect, SelectMimicry,
ChipsInput, ChipsSelect,
DropZone, File,
WriteBar
} from "@tria/ui";
```
## Controlled inputs
Все поля предпочтительно держать controlled (через state), чтобы унифицировать поведение на платформах.
## Design tokens
- `--input-h-*`, `--input-radius`, `--input-px`
- `--chip-*`, `--chipsbox-*` (если применимо)

28
docs/components/modals.md Normal file
View File

@@ -0,0 +1,28 @@
# Modals & Overlays
Набор оверлеев: ActionSheet, ModalCard, ModalPage, Popover/Tooltip.
## Import
```ts
import { ActionSheet, ModalCard, ModalPage, Popover, Tooltip } from "@tria/ui";
```
## ActionSheet
```tsx
<ActionSheet
open={open}
onOpenChange={setOpen}
title="Actions"
actions={[
{ title: "Save", onClick: () => {} },
{ title: "Delete", tone: "destructive", onClick: () => {} },
]}
/>
```
## Tokens
- `--modal-w`, `--modal-p`, `--modal-radius`
- `--modal-overlay`, `--modal-blur`

37
docs/components/tabbar.md Normal file
View File

@@ -0,0 +1,37 @@
# TabBar
TabBar — навигация нижнего уровня (в стиле mobile). В web/tablet режимах может менять размещение.
## Import
```ts
import { TabBar } from "@tria/ui";
```
## Basic
```tsx
<TabBar
items={[
{ id: "home", label: "Home" },
{ id: "search", label: "Search" },
{ id: "profile", label: "Profile" },
]}
value={tab}
onChange={setTab}
placement="bottom"
/>
```
## Responsive placement
- mobile portrait → `bottom`
- desktop/tablet landscape → `right-top | right-center | right-bottom`
## Design tokens
- `--tabbar-h`
- `--tabbar-radius`
- `--tabbar-w`
- `--tabbar-gap`
- `--safe-bottom/right`

View File

@@ -0,0 +1,15 @@
# Local development
Рекомендуемая схема для монорепо (pnpm):
```bash
pnpm i
pnpm -C packages/ui dev
pnpm -C apps/web dev
```
## Vite library mode
Tria UI собирается через Vite library mode. Для docs важны:
- корректные `exports` в `package.json`
- запрет deep-imports (`@tria/ui/src/...`) в приложениях

View File

@@ -0,0 +1,14 @@
# Release & versioning
Semver рекомендации:
- **patch**: bugfix, не меняющий API и имена токенов
- **minor**: новые компоненты, новые токены (обратно совместимо)
- **major**: изменения публичного контракта (имена токенов, props, dataатрибуты)
## Public contract
Часть публичного API:
- экспортируемые компоненты из `@tria/ui`
- имена токенов (`--ui-*`, `--btn-*`, `--input-*`, …)
- `data-theme/platform/skin`

View File

@@ -0,0 +1,41 @@
# Customization without forking
Цель: дать пользователю возможность менять дизайн **не изменяя библиотеку**.
Есть три уровня кастомизации:
## 1) Switch theme/platform/skin
```tsx
<UIProvider config={{ theme: "dark", platform: "vk", skin: "ios" }} />
```
## 2) Runtime overrides (vars)
```tsx
<UIProvider
config={{
vars: {
"--ui-primary": "#ff2d55",
"--btn-radius": "18px",
"--input-h-md": "46px",
}
}}
/>
```
## 3) App-level CSS layer
```css
:root[data-platform="web"]{
--ui-primary: #8b5cf6;
}
```
## Contract (совместимость)
Мы считаем частью публичного контракта:
- имена токенов `--ui-*` и `--btn-*`/`--input-*`/…
- data attributes `data-theme`, `data-platform`, `data-skin`
Изменения этих сущностей должны быть semvermajor.

View File

@@ -0,0 +1,33 @@
# Presets: web/vk/tg × ios/android × light/dark
`presets.css` — слой, который задаёт значения токенов в зависимости от:
- `data-theme`
- `data-platform`
- `data-skin`
## iOS (Cupertino feel)
Для `data-skin="ios"` характерно:
- выше контролы (`--btn-h-md: 44px`, `--input-h-md: 44px`)
- более мягкие радиусы (`--ui-radius: 16px`)
- более “воздушные” отступы
- умеренный blur/overlay в модалках
## Android (Material feel)
Для `data-skin="android"` характерно:
- более компактные радиусы (`--ui-radius: 12px`)
- высоты ближе к material baseline
- более “плоское” ощущение
## Platform accents
- `vk``--ui-primary: #2d81e0`
- `tg``--ui-primary: #3390ec`
## Debug checklist
1) Проверьте, что `UIProvider` ставит `data-*` на `documentElement`.
2) Проверьте, что компоненты используют токены, а не захардкоженные px.
3) Убедитесь, что `@tria/ui/styles` импортируется один раз.

View File

@@ -0,0 +1,43 @@
# Tokens overview
Tria UI строится на CSS переменных. База начинается с `--ui-*`, а компоненты используют специализированные токены.
## Global tokens (`--ui-*`)
- `--ui-bg`, `--ui-panel`, `--ui-fg`, `--ui-muted`
- `--ui-border`, `--ui-shadow`
- `--ui-primary`, `--ui-primary-fg`
- `--ui-radius`, `--ui-radius-sm`, `--ui-radius-lg`
- `--ui-space-1..4`
- `--ui-ease`, `--ui-duration*`
- `--safe-top/right/bottom/left`
## Component tokens (examples)
### Button
- `--btn-h-sm/md/lg`
- `--btn-px-sm/md/lg`
- `--btn-radius`
- `--btn-gap`
### Input
- `--input-h-sm/md/lg`
- `--input-px`
- `--input-radius`
### Cell
- `--cell-h`, `--cell-px`, `--cell-gap`
- `--cell-before`, `--cell-chev`
- `--cell-badge-*`
### Modal
- `--modal-w`, `--modal-p`, `--modal-radius`, `--modal-overlay`, `--modal-blur`
### Calendar
- `--cal-day`, `--cal-day-radius`, `--cal-gap`
## Where tokens are set
- `tokens.css` — базовые значения и алиасы
- `presets.css` — значения под theme/platform/skin
- кастомизация — через `UIProvider.config.vars` или отдельным CSS слоем в приложении

View File

@@ -0,0 +1,49 @@
# Installation
## Requirements
- React 18+
- TypeScript 5+ (рекомендуется)
- Vite 5+ (для dev/примера)
## Install
```bash
pnpm add @tria/ui
```
## Import styles
Рекомендуемый способ:
```ts
import "@tria/ui/styles";
```
Альтернатива:
```ts
import "@tria/ui/auto";
```
## First render
```tsx
import React from "react";
import { UIProvider, Button } from "@tria/ui";
export function App() {
return (
<UIProvider config={{ theme: "dark", platform: "web", skin: "ios" }}>
<Button data-variant="primary">Hello Tria</Button>
</UIProvider>
);
}
```
## Monorepo note (pnpm workspaces)
Если `@tria/ui` подключён как workspaceпакет, и вы используете `package.json#exports`,
избегайте deepimports вида `@tria/ui/src/...`. Все публичные сущности должны импортироваться из `@tria/ui`:
`import { TabBar } from "@tria/ui";`
`import { TabBar } from "@tria/ui/src/components/tabbar/TabBar";`

View File

@@ -0,0 +1,36 @@
# Styles & Bundling
Tria UI использует **CSS tokens** и глобальные классы компонентов. Предпочтительная схема — один импорт CSSпакета.
## Recommended: global styles pack
```ts
import "@tria/ui/styles";
```
Преимущества:
- предсказуемый порядок слоёв (base → tokens → presets → components)
- меньше дублей CSS
- проще кастомизация (вы добавляете свой слой после `@tria/ui/styles`)
## Auto entry
```ts
import "@tria/ui/auto";
```
Подходит для быстрых прототипов. В production чаще используют отдельный импорт `@tria/ui/styles`.
## CSS entry layout
Внутри пакета (ориентир):
- `styles/base.css` — reset/база
- `styles/tokens.css` — базовые токены (`--ui-*`)
- `styles/presets.css` — platform/skin/theme значения
- `styles/components/*.css` — стили конкретных компонентов
## Dont do
- Не импортируйте CSS из каждого компонента (можно получить дубли и хаос порядка).
- Не смешивайте `@tria/ui/auto` и `@tria/ui/styles` одновременно.

View File

@@ -0,0 +1,41 @@
# Theming (theme/platform/skin)
Tria UI использует три измерения конфигурации:
- `theme`: `light | dark`
- `platform`: `web | vk | tg`
- `skin`: `web | ios | android`
Комбинация управляет *CSS пресетами* и компонентными токенами.
## UIProvider
```tsx
import { UIProvider } from "@tria/ui";
<UIProvider config={{ theme: "dark", platform: "vk", skin: "ios" }}>
...
</UIProvider>
```
UIProvider устанавливает `data-theme`, `data-platform`, `data-skin` на `document.documentElement`
(или на `config.root`), и может применить `config.vars` — набор CSS variables.
## Runtime switching
```tsx
const [theme, setTheme] = useState<"light"|"dark">("dark");
<UIProvider config={{ theme, platform, skin }} />
```
## Which combos matter
- `platform="vk" + skin="ios"` — VK iOSвид (Cupertinoощущение)
- `platform="vk" + skin="android"` — VK Androidвид (Materialощущение)
- `platform="tg"` — более “telegramui” акценты
- `platform="web"` — нейтральный web preset
## Troubleshooting
Если визуально не меняется “skin”, значит компоненты ещё используют жёсткие px.
Нужно заменить размеры на токены (`--btn-*`, `--input-*`, `--cell-*`, `--tabbar-*`) и т.п.

View File

@@ -0,0 +1,15 @@
# Responsive layout
## TabBar placement
- mobile portrait → bottom
- tablet/desktop landscape → right-top / right-center / right-bottom
## Testing matrix
Минимум:
- iOS dark / light
- Android dark / light
- VK iOS / VK Android
- TG iOS / TG Android
- Web desktop

View File

@@ -0,0 +1,11 @@
# Telegram Mini Apps
## Recommended config
```tsx
<UIProvider config={{ platform: "tg", skin: "ios", theme: "dark" }} />
```
## Safe areas
Используйте `--safe-bottom`, чтобы TabBar/WriteBar не упирались в системные зоны.

View File

@@ -0,0 +1,24 @@
# VK Mini Apps
## Recommended config
```tsx
<UIProvider config={{ platform: "vk", skin: "ios", theme: "dark" }} />
```
Для Android:
```tsx
<UIProvider config={{ platform: "vk", skin: "android", theme: "dark" }} />
```
## Safe areas
Используйте токены `--safe-*` (или задайте их через vars), если окружение отдаёт insets.
## Navigation
Паттерн:
- верхняя панель с backкнопкой
- TabBar на главных разделах
- list/cell для настроек

View File

@@ -0,0 +1,33 @@
# Snackbar Provider
Tria UI поддерживает Snackbar как компонент и (опционально) как глобальный провайдер/хук.
## Component usage
```tsx
import { Snackbar } from "@tria/ui";
const [open, setOpen] = useState(false);
<Snackbar
open={open}
onOpenChange={setOpen}
text="Saved"
action={{ label: "Undo", onClick: () => {} }}
/>
```
## Provider usage (optional)
Если у вас есть `SnackbarProvider` и `useSnackbar()`:
```tsx
<SnackbarProvider>
<App/>
</SnackbarProvider>
```
```ts
const { push } = useSnackbar();
push({ text: "Saved", action: { label: "OK", onClick: ... }});
```

View File

@@ -0,0 +1,34 @@
# UIProvider
`UIProvider` — точка управления темой/платформой/скином и CSS overrides.
## Import
```ts
import { UIProvider } from "@tria/ui";
```
## Config
```ts
type UIConfig = Partial<{
theme: "light" | "dark";
platform: "web" | "vk" | "tg";
skin: "web" | "ios" | "android";
root: HTMLElement;
vars: Record<`--${string}`, string>;
}>;
```
## Example
```tsx
<UIProvider config={{ theme: "light", platform: "vk", skin: "ios" }}>
...
</UIProvider>
```
## Notes
- избегайте deep-import UIProvider из внутренних путей — импортируйте из `@tria/ui`
- для `vars` используйте `useMemo`, чтобы не создавать новый объект на каждый рендер