@1337exp/taoui 1.1.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,107 +1,117 @@
1
1
  # Tao UI
2
2
 
3
- Библиотека Vue 3 компонентов для Nuxt/Vue проектов с системой дизайн-токенов:
4
- поменял несколько CSS-переменных — поменялась тема всего набора компонентов.
3
+ **English** · [Русский](README.RU.md)
5
4
 
6
- ## Компоненты
5
+ A Vue 3 component library for Nuxt/Vue apps, driven by design tokens:
6
+ change a handful of CSS variables and the whole kit follows.
7
7
 
8
- ### Базовые
8
+ ## Components
9
9
 
10
- - **TaoBlock** — базовый контейнер с настраиваемыми отступами и скруглением
11
- - **TaoButton** — кнопка с вариантами (primary, secondary, ghost, danger), размерами и состояниями
12
- - **TaoCard** — карточка с поддержкой слотов (cover, headerTitle, header/headerSecondary, title/sub, footer)
13
- - **TaoCopy** — кнопка копирования текста в буфер обмена
14
- - **TaoInput** — поле ввода с поддержкой v-model, валидации и слотов `#prefix` / `#suffix` (иконка или текст внутри рамки)
15
- - **TaoInputGroup** — склейка снаружи: `#before` | поле | `#after` (протокол, единица, кнопка)
16
- - **TaoModal** — модальное окно с анимацией и слотами
17
- - **TaoDrawer** — боковая панель (фильтры, настройки). Esc, клик по фону, ловушка фокуса — как у модалки
18
- - **TaoSpoiler** — раскрывающийся блок. `v-model` и `aria-expanded`; несколько подряд — не exclusive-аккордеон
19
- - **TaoTabs** — вкладки для переключения между секциями контента
20
- - **TaoTooltip** — всплывающая подсказка при наведении
10
+ ### Basics
11
+
12
+ - **TaoBlock** — container with padding and radius
13
+ - **TaoButton** — `primary` / `secondary` / `ghost` / `danger`, sizes and states
14
+ - **TaoCard** — card with cover / header / footer slots. `#cover` can be a photo or `TaoCarousel`
15
+ - **TaoCopy** — clipboard icon. After a click, a “Copied” tooltip; if the trigger is gone, the tooltip is too
16
+ - **TaoInput** — text field with v-model, validation, and `#prefix` / `#suffix` slots (icon or text inside the frame)
17
+ - **TaoInputGroup** — outer glue: `#before` | field | `#after` (protocol, unit, button)
18
+ - **TaoModal** — modal with animation and slots
19
+ - **TaoDrawer** — side panel (filters, settings). Esc, backdrop click, focus trap — same as the modal
20
+ - **TaoSpoiler** — disclosure. `v-model` and `aria-expanded`. Neighbours do not close each other
21
+ - **TaoSpoilerGroup** — accordion: `v-model` is the open panel key (`null` = all closed); spoilers take `name`
22
+ - **TaoTabs** — tabbed sections
23
+ - **TaoTooltip** — hover hint
24
+ - **TaoPopover** — click panel with any slot content, Esc and outside click. Not a tooltip, not an action menu
21
25
 
22
26
  ### Layout
23
27
 
24
- - **TaoContainer** — контейнер с ограничением ширины (wide/slim/ultra-slim) и авто-центровкой
25
- - **TaoFlex** — обёртка над flexbox с пропами justify/align/direction/wrap/gap
26
- - **TaoSpace** — авто-расстановка дочерних элементов с равномерным gap
27
- - **TaoDivider** — разделитель: line (тонкая линия), text (линия с текстом), gap (пустой отступ, size: small/medium/large)
28
- - **TaoAnimatedBorder** — контейнер с анимированной радужной рамкой (декоративный, не завязан на тему)
29
-
30
- ### Формы и ввод
31
-
32
- - **TaoCheckbox** — чекбокс с v-model, слотами pre/post и `indeterminate` (частично выбран)
33
- - **TaoSwitch** — переключатель для булевых настроек (`role="switch"`)
34
- - **TaoRadio** / **TaoRadioGroup** — взаимоисключающий выбор из 2–5 вариантов
35
- - **TaoSelect** — выпадающий список с клавиатурой, тот же визуал, что у Input. Сброс — «Очистить» в списке или Delete
36
- - **TaoDate** — один день: `YYYY-MM-DD`, без часов и пояса. Календарь как у Select
37
- - **TaoFormField** — общие label / hint / error для полей формы
38
- - **TaoInputNumber** — число с min/max/step и кнопками ± справа. Пустое значение — `null`
39
- - **TaoQuantity** — количество в корзине: `− | поле | +`, целые штуки, сток, минус на минимуме может убрать строку
40
- - **TaoTextarea** — многострочное поле с авто-высотой. `maxlength` ограничивает ввод, `count` показывает «введено / максимум»
41
- - **TaoPinCode** — пин-код из N полей. По умолчанию клик стирает ячейку и все справа (`clear-on="focus"`); `clear-on="input"` заменяет цифру только при вводе. Последняя ячейка снимает фокус и эмитит `complete`
42
- - **TaoSlider** — слайдер: мышь, тач и стрелки. Опциональный точный ввод по правому клику
43
- - **TaoFileDrop** — зона загрузки файлов (drag & drop + клик). Текст внутри — слот
44
-
45
- ### Отображение данных
46
-
47
- - **TaoTable** — простая таблица: колонки, empty, loading, сортировка через `v-model:sort`. Не datagrid.
48
- - **TaoPagination** — страницы с многоточием. Клик по «…» прыгает на `jump` страниц (5 по умолчанию)
49
- - **TaoEmpty** — пустой список, нет результатов, нет прав
50
- - **TaoStages** — список стадий: `wait` / `work` / `ok` / `bad`. Не линейный степпер
51
- - **TaoSkeleton** — плейсхолдер загрузки (text / title / circle / rect)
52
- - **TaoCounter** — витрина числа с переворотом цифр (не инпут)
53
- - **TaoCarousel** — лента: целый слайд с `autoplay`, карточка с `peek`, полоса с `per-view`. Стрелки через `controls` или `#prev` / `#next`, точки — `dots`
54
- - **TaoAvatar** — фото или инициалы, размеры `small` / `medium` / `large`. Точка `dot` и счётчик `count`
55
- - **TaoTag** — тег/бейдж со статусами (neutral, success, danger, warning, info)
56
- - **TaoAlert** — инлайн-баннер страницы или ошибки формы (success / error / warning / info)
57
- - **TaoProgress** — статичная полоса (`progress` в %). Проценты сверху по центру или `showPercentage="right"` справа; слоты `#left` / `#right` — подписи, тогда процент справа в скобках. `false` прячет. Ширина — `minWidth` / `maxWidth`, не диапазон значения
58
- - **TaoLoader** — анимированный лоадер (четыре точки)
59
- - **TaoImage** — обёртка над `<img>` с плавным fade-in при загрузке и плейсхолдером
60
- - **TaoIcon** — обёртка для icon-шрифта (см. раздел «Иконки» ниже)
61
-
62
- ### Навигация и взаимодействие
63
-
64
- - **TaoLink** — ссылка, использующая `<NuxtLink>` в Nuxt-проекте и обычный `<a>` вне его — без дополнительной настройки
65
- - **TaoBreadcrumb** — крошки: последний пункт — текущая страница
66
- - **TaoDropdownMenu** — выпадающее меню с авто-позиционированием у края экрана
67
- - **TaoScrollTop** — плавающая кнопка «наверх» с ripple. Появляется при обратном скролле после `boundary`
68
-
69
- ### Обратная связь
70
-
71
- - **toast()** — fluent-уведомления: `toast().success().message('Сохранено')`
72
- - **confirm()** — вопрос с оверлеем: тот же fluent + `await`. Не тост — ждёт ответ, не исчезает сам.
73
- - **TaoToastViewport** / **TaoConfirmHost** — контейнеры; если их нет в разметке, первый вызов сам монтирует их в `body`
74
-
75
- ## Соглашения
76
-
77
- Тоны визуала: `success` | `danger` | `warning` | `info` | `neutral`.
78
- `error` у Alert, Tag и `toast()` — синоним `danger`. Button уже `danger`.
79
- Stages — это процесс, не тон: `wait` / `work` / `ok` / `bad` (`danger` принимается как `bad`).
80
-
81
- Размеры контролов: `small` | `medium` | `large`.
82
- Avatar понимает и короткие `s` / `m` / `l`. Divider `gap` раньше называл крупный размер `big` — это алиас `large`.
83
- Container живёт на другой оси: `wide` / `slim` / `ultra-slim`.
84
-
85
- ## Иконки
86
-
87
- `TaoIcon` не поставляет собственный набор иконок — он рендерит класс `icon-<name>`
88
- по соглашению, рассчитанному на подключение внешнего icon-шрифта (например,
89
- собранного через IcoMoon/Fontello). Чтобы иконки отображались, подключите
90
- свой шрифт с классами вида `.icon-arrow-up { ... }` в проекте.
91
-
92
- ## Установка
93
-
94
- Или локально из папки:
28
+ - **TaoContainer** — max-width (wide / slim / ultra-slim) and centering
29
+ - **TaoFlex** — flexbox wrapper: justify / align / direction / wrap / gap
30
+ - **TaoSpace** — even gap between children
31
+ - **TaoDivider** — `line` (hairline), `text` (line with a label), `gap` (empty space, size: small / medium / large)
32
+ - **TaoFieldset** — grouped frame: `legend` sits on the top border, `align` is start / center / end
33
+ - **TaoAnimatedBorder** — rainbow border wrapper (decorative, not tied to the theme)
34
+
35
+ ### Forms
36
+
37
+ - **TaoCheckbox** — checkbox with v-model, pre/post slots, and `indeterminate`
38
+ - **TaoSwitch** — boolean toggle (`role="switch"`)
39
+ - **TaoRadio** / **TaoRadioGroup** — exclusive choice among 2–5 options
40
+ - **TaoSelect** — dropdown with keyboard, same chrome as Input. Clear via “Clear” in the list or Delete
41
+ - **TaoCombobox** — Select with a field: type to filter, `allow-create` writes a custom value into `v-model`, `create` lets the parent append the list
42
+ - **TaoDate** — a single day: `YYYY-MM-DD`, no time, no timezone. Calendar popup like Select
43
+ - **TaoDateRange** — a period: `v-model` is `{ start, end }` or `null`. First click is start, second is end (they swap if end is earlier). An incomplete pick is not written to the model
44
+ - **TaoFormField** — shared label / hint / error for form controls
45
+ - **TaoInputNumber** — number with min/max/step and ± on the right. Empty value is `null`
46
+ - **TaoQuantity** — cart quantity: `− | field | +`, integers, stock; minus at the minimum can remove the row
47
+ - **TaoTextarea** — autosizing multiline. `maxlength` caps input, `count` shows “entered / max”
48
+ - **TaoPinCode** — N cells. By default a click clears the cell and everything to the right (`clear-on="focus"`); `clear-on="input"` replaces the digit only when typing. The last cell blurs and emits `complete`
49
+ - **TaoSlider** — mouse, touch, and arrows. Optional precise input on right-click
50
+ - **TaoFileDrop** — drop zone (drag & drop + click). File names listed under the zone, `v-model` is `File[]`. Clearing the whole batch is the parent’s job (`clear-request`)
51
+
52
+ ### Data display
53
+
54
+ - **TaoTable** — simple table: columns, empty, loading, sort via `v-model:sort`. Not a datagrid.
55
+ - **TaoPagination** — pages with ellipsis. Clicking “…” jumps `jump` pages (5 by default)
56
+ - **TaoEmpty** — empty list, no results, no access
57
+ - **TaoStages** — stage list: `wait` / `work` / `ok` / `bad`. Not a linear stepper
58
+ - **TaoSkeleton** — loading placeholder (text / title / circle / rect)
59
+ - **TaoCounter** — flipping digits (not an input)
60
+ - **TaoCarousel** — strip: full slide with `autoplay`, card with `peek`, row with `per-view`. Arrows via `controls` or `#prev` / `#next`, dots via `dots`
61
+ - **TaoAvatar** — photo or initials, sizes `small` / `medium` / `large`. Status `dot` and `count`
62
+ - **TaoTag** — badge with tones (neutral, success, danger, warning, info)
63
+ - **TaoAlert** — inline page/form banner (success / error / warning / info)
64
+ - **TaoProgress** — static bar (`progress` in %). Percent centered on top, or `showPercentage="right"`; `#left` / `#right` slots are captions, then the percent sits in parentheses on the right. `false` hides it. Width is `minWidth` / `maxWidth`, not the value domain
65
+ - **TaoLoader** — four-dot spinner
66
+ - **TaoImage** — `<img>` wrapper: fade-in and placeholder. `lazy` turns on native `loading="lazy"`
67
+ - **TaoIcon** — icon-font wrapper (see Icons below)
68
+
69
+ ### Navigation
70
+
71
+ - **TaoLink** — uses `<NuxtLink>` in Nuxt and a plain `<a>` elsewhere, with no extra setup
72
+ - **TaoBreadcrumb** — crumbs: the last item is the current page
73
+ - **TaoDropdownMenu** — dropdown that flips at the viewport edge
74
+ - **TaoScrollTop** — floating “back to top” with a ripple. Appears on reverse scroll after `boundary`
75
+
76
+ ### Feedback
77
+
78
+ - **toast()** — fluent toasts: `toast().success().message('Saved')`
79
+ - **confirm()** — overlay question: the same fluent API plus `await`. Not a toast — it waits for an answer and does not dismiss itself.
80
+ - **TaoToastViewport** / **TaoConfirmHost** — hosts; if they are missing from the tree, the first call mounts them on `body`
81
+
82
+ ## Conventions
83
+
84
+ Visual tones: `success` | `danger` | `warning` | `info` | `neutral`.
85
+ `error` on Alert, Tag, and `toast()` is an alias of `danger`. Button already uses `danger`.
86
+ Stages describe a process, not a tone: `wait` / `work` / `ok` / `bad` (`danger` is accepted as `bad`).
87
+
88
+ Control sizes: `small` | `medium` | `large`.
89
+ Avatar also accepts short `s` / `m` / `l`. Divider `gap` used to call the large size `big` — that is an alias of `large`.
90
+ Container lives on another axis: `wide` / `slim` / `ultra-slim`.
91
+
92
+ ## Icons
93
+
94
+ `TaoIcon` does not ship its own set — it renders `icon-<name>`
95
+ for an external icon font (IcoMoon / Fontello and the like). Connect a font
96
+ with classes such as `.icon-arrow-up { ... }` in the host app.
97
+
98
+ ## Install
99
+
100
+ ```bash
101
+ npm install @1337exp/taoui
102
+ ```
103
+
104
+ From a local folder:
95
105
 
96
106
  ```bash
97
107
  npm install ../path-to-tao-ui
98
108
  ```
99
109
 
100
- ## Использование
110
+ ## Usage
101
111
 
102
- ### Подключение в Nuxt 3
112
+ ### Nuxt 3
103
113
 
104
- Создайте плагин `plugins/tao-ui.ts`:
114
+ Create `plugins/tao-ui.ts`:
105
115
 
106
116
  ```typescript
107
117
  import { defineNuxtPlugin } from '#app'
@@ -112,7 +122,7 @@ export default defineNuxtPlugin((nuxtApp) => {
112
122
  })
113
123
  ```
114
124
 
115
- Импортируйте стили в `app.vue` или layout:
125
+ Import styles in `app.vue` or a layout:
116
126
 
117
127
  ```vue
118
128
  <script setup>
@@ -120,7 +130,7 @@ import '@1337exp/taoui/styles.css'
120
130
  </script>
121
131
  ```
122
132
 
123
- ### Подключение в Vue 3 проекте
133
+ ### Vue 3
124
134
 
125
135
  ```javascript
126
136
  // main.js
@@ -134,7 +144,7 @@ app.use(TaoUI)
134
144
  app.mount('#app')
135
145
  ```
136
146
 
137
- ### Использование отдельных компонентов
147
+ ### Individual components
138
148
 
139
149
  ```vue
140
150
  <script setup>
@@ -143,41 +153,41 @@ import '@1337exp/taoui/styles.css'
143
153
  </script>
144
154
 
145
155
  <template>
146
- <TaoButton variant="primary">Нажми меня</TaoButton>
147
- <TaoInput v-model="text" label="Введите текст" />
148
- <TaoModal v-model="isOpen" title="Заголовок">
149
- Содержимое модального окна
156
+ <TaoButton variant="primary">Press me</TaoButton>
157
+ <TaoInput v-model="text" label="Your text" />
158
+ <TaoModal v-model="isOpen" title="Title">
159
+ Modal body
150
160
  </TaoModal>
151
161
  </template>
152
162
  ```
153
163
 
154
164
  ## Toast
155
165
 
156
- Вызов — цепочка в одном тике, `setTimeout(0)` отправляет уведомление.
166
+ The chain runs in the same tick; `setTimeout(0)` actually shows the toast.
157
167
 
158
168
  ```javascript
159
169
  import { toast } from '@1337exp/taoui'
160
170
 
161
- toast().success().message('Сохранено')
162
- toast().error().title('Сеть').timeout(5000).message('Нет соединения')
163
- toast.success('Сохранено')
164
- toast.warning('Черновик', { timeout: 1000 })
171
+ toast().success().message('Saved')
172
+ toast().error().title('Network').timeout(5000).message('No connection')
173
+ toast.success('Saved')
174
+ toast.warning('Draft', { timeout: 1000 })
165
175
  ```
166
176
 
167
- Позиция по умолчанию — `topCenter`. Глобально:
177
+ Default position is `topCenter`. Globally:
168
178
 
169
179
  ```javascript
170
180
  toast.defaults({ position: 'bottomRight' })
171
181
  toast.byBottomRight()
172
182
  ```
173
183
 
174
- `question` с оверлеем в kit нет — это confirm, не toast. Кнопки в тосте, если нужны:
184
+ There is no overlay `question` in this kit — that is confirm, not toast. Buttons on a toast, if needed:
175
185
 
176
186
  ```javascript
177
- toast().info().message('Удалить файл?').action('Удалить', onRemove)
187
+ toast().info().message('Delete the file?').action('Delete', onRemove)
178
188
  ```
179
189
 
180
- Viewport можно не вставлять: первый вызов сам создаст его. Если нужен явный контроль (тесты, свой layout):
190
+ You can skip the viewport: the first call creates it. For explicit control (tests, a custom layout):
181
191
 
182
192
  ```vue
183
193
  <TaoToastViewport />
@@ -185,60 +195,62 @@ Viewport можно не вставлять: первый вызов сам со
185
195
 
186
196
  ## Confirm
187
197
 
188
- Вопрос с оверлеем: всплывает по центру и спрашивает. Это не toast — нет прогресс-бара и автозакрытия, есть `await`, Esc и клик по оверлею = отмена.
198
+ An overlay question in the center of the screen. This is not a toast: no progress bar, no auto-close, `await`, Esc and overlay click = cancel.
189
199
 
190
200
  ```javascript
191
201
  import { confirm } from '@1337exp/taoui'
192
202
 
193
- if (await confirm().title('Удалить файл?').message('Это нельзя отменить').danger()) {
203
+ if (await confirm().title('Delete the file?').message('This cannot be undone').danger()) {
194
204
  remove()
195
205
  }
196
206
 
197
- const ok = await confirm('Выйти без сохранения?', {
198
- ok: 'Выйти',
199
- cancel: 'Остаться',
207
+ const ok = await confirm('Leave without saving?', {
208
+ ok: 'Leave',
209
+ cancel: 'Stay',
200
210
  })
201
211
  ```
202
212
 
203
- Очередь: второй `confirm()`, пока открыт первый, подождёт. Подписи по умолчанию — «ОК» / «Отмена»:
213
+ Queue: a second `confirm()` while the first is open will wait. Default labels are “OK” / “Cancel”:
204
214
 
205
215
  ```javascript
206
216
  confirm.defaults({ ok: 'Yes', cancel: 'No' })
207
217
  ```
208
218
 
209
- ## Формы
219
+ ## Forms
210
220
 
211
- `TaoFormField` вешает общий label / hint / error и прокидывает `id` во вложенный контрол.
221
+ `TaoFormField` attaches a shared label / hint / error and forwards `id` to the nested control.
212
222
 
213
223
  ```vue
214
- <TaoFormField label="Город" hint="Необязательно">
224
+ <TaoFormField label="City" hint="Optional">
215
225
  <TaoSelect v-model="city" :options="cities" />
216
226
  </TaoFormField>
217
227
 
218
- <TaoSwitch v-model="dark" label="Тёмная тема" />
228
+ <TaoSwitch v-model="dark" label="Dark theme" />
219
229
 
220
- <TaoRadioGroup v-model="plan" legend="Тариф">
230
+ <TaoRadioGroup v-model="plan" legend="Plan">
221
231
  <TaoRadio value="free" label="Free" />
222
232
  <TaoRadio value="pro" label="Pro" />
223
233
  </TaoRadioGroup>
224
234
 
225
- <TaoAlert type="warning" title="Черновик">Сохраните, прежде чем уйти.</TaoAlert>
235
+ <TaoAlert type="warning" title="Draft">Save before you leave.</TaoAlert>
226
236
  ```
227
237
 
228
- `TaoSelect` открывается с клавиатуры (стрелки, Enter, Esc), список переворачивается у края экрана. Delete или «Очистить» внизу списка сбрасывает значение в `null`.
238
+ `TaoSelect` opens from the keyboard (arrows, Enter, Esc); the list flips at the viewport edge. Delete or “Clear” at the bottom of the list resets the value to `null`.
239
+
240
+ `TaoCombobox` is the same menu with a field. Typing filters options. `allow-create` writes the typed string into `v-model` when there is no exact match. The list does not mutate itself: listen to `create` and append an option from the parent.
229
241
 
230
- `TaoFormField` также оборачивает `TaoTextarea` и `TaoCheckbox` — id, hint и error прокидываются сами.
242
+ `TaoFormField` also wraps `TaoTextarea` and `TaoCheckbox` — id, hint, and error are forwarded for you.
231
243
 
232
- ## Таблица и пагинация
244
+ ## Table and pagination
233
245
 
234
- Таблица рендерит то, что передали: сама данные не режет и не сортирует. Это удобно и для серверной выборки, и для клиентской — страница режется снаружи.
246
+ The table renders what you pass in: it does not slice or sort the data. That works for both server-side and client-side paging — the page is cut outside.
235
247
 
236
248
  ```vue
237
249
  <TaoTable
238
250
  :columns="columns"
239
251
  :rows="pageRows"
240
252
  v-model:sort="sort"
241
- empty-text="Пока нет записей"
253
+ empty-text="No records yet"
242
254
  >
243
255
  <template #cell-status="{ row }">
244
256
  <TaoTag :type="row.status === 'active' ? 'success' : 'neutral'">
@@ -252,21 +264,21 @@ confirm.defaults({ ok: 'Yes', cancel: 'No' })
252
264
 
253
265
  ```javascript
254
266
  const columns = [
255
- { key: 'name', label: 'Имя', sortable: true },
256
- { key: 'city', label: 'Город' },
257
- { key: 'status', label: 'Статус' },
267
+ { key: 'name', label: 'Name', sortable: true },
268
+ { key: 'city', label: 'City' },
269
+ { key: 'status', label: 'Status' },
258
270
  ]
259
271
  ```
260
272
 
261
- Слот `cell-<ключ>` перекрывает ячейку. `loading` показывает оверлей, пустой список — текст или слот `#empty`. Клик по шапке с `sortable` крутит `asc → desc → сброс`.
273
+ The `cell-<key>` slot replaces a cell. `loading` shows an overlay; an empty list shows text or the `#empty` slot. Clicking a `sortable` header cycles `asc → desc → off`.
262
274
 
263
- ## Пустые состояния и загрузка
275
+ ## Empty states and loading
264
276
 
265
277
  ```vue
266
- <TaoEmpty title="Ничего не нашлось">
267
- Измените фильтр или сбросьте поиск.
278
+ <TaoEmpty title="Nothing found">
279
+ Change the filter or reset search.
268
280
  <template #action>
269
- <TaoButton variant="secondary">Сбросить</TaoButton>
281
+ <TaoButton variant="secondary">Reset</TaoButton>
270
282
  </template>
271
283
  </TaoEmpty>
272
284
 
@@ -275,14 +287,14 @@ const columns = [
275
287
  <TaoSkeleton variant="circle" />
276
288
 
277
289
  <TaoStages :items="[
278
- { key: 'pay', label: 'Оплата', status: 'ok' },
279
- { key: 'pack', label: 'Сборка', status: 'work' },
280
- { key: 'ship', label: 'Доставка', status: 'wait' },
290
+ { key: 'pay', label: 'Payment', status: 'ok' },
291
+ { key: 'pack', label: 'Packing', status: 'work' },
292
+ { key: 'ship', label: 'Shipping', status: 'wait' },
281
293
  ]" />
282
294
  ```
283
295
 
284
296
  ```vue
285
- <TaoInput v-model="q" placeholder="Найти…">
297
+ <TaoInput v-model="q" placeholder="Search…">
286
298
  <template #prefix>⌕</template>
287
299
  </TaoInput>
288
300
 
@@ -290,7 +302,7 @@ const columns = [
290
302
  <template #before>https://</template>
291
303
  <TaoInput v-model="host" placeholder="example.com" />
292
304
  <template #after>
293
- <TaoButton>Проверить</TaoButton>
305
+ <TaoButton>Check</TaoButton>
294
306
  </template>
295
307
  </TaoInputGroup>
296
308
 
@@ -298,19 +310,23 @@ const columns = [
298
310
  <TaoFormField label="Email">
299
311
  <TaoInput v-model="email" type="email" />
300
312
  </TaoFormField>
301
- <TaoButton type="submit">Сохранить</TaoButton>
313
+ <TaoButton type="submit">Save</TaoButton>
302
314
  </form>
303
315
 
304
- <TaoFormField label="Количество">
316
+ <TaoFormField label="Quantity">
305
317
  <TaoInputNumber v-model="qty" :min="1" :max="99" />
306
318
  </TaoFormField>
307
319
 
308
320
  <TaoQuantity v-model="qty" :max="12" @dec="onDec" />
309
321
 
310
- <TaoFormField label="День доставки" hint="В модели всегда YYYY-MM-DD">
322
+ <TaoFormField label="Delivery day" hint="The model is always YYYY-MM-DD">
311
323
  <TaoDate v-model="day" min="2026-09-01" max="2026-09-30" />
312
324
  </TaoFormField>
313
325
 
326
+ <TaoFormField label="Stay">
327
+ <TaoDateRange v-model="stay" min="2026-09-01" max="2026-09-30" />
328
+ </TaoFormField>
329
+
314
330
  <TaoCounter :value="score" :max-digits="6" />
315
331
 
316
332
  <TaoCarousel :autoplay="4000" loop dots>
@@ -323,49 +339,48 @@ const columns = [
323
339
  <TaoCarousel v-model="slide" :per-view="5" :peek="28">
324
340
  <template #prev></template>
325
341
  <template #next="{ go, disabled }">
326
- <button type="button" :disabled="disabled" @click="go">вперёд</button>
342
+ <button type="button" :disabled="disabled" @click="go">next</button>
327
343
  </template>
328
344
  <article v-for="item in products" :key="item.id">…</article>
329
345
  </TaoCarousel>
330
346
  ```
331
347
 
332
- `TaoDrawer` — лист сбоку, не модалка по центру:
348
+ `TaoDrawer` is a side sheet, not a centered modal:
333
349
 
334
350
  ```vue
335
- <TaoDrawer v-model="open" title="Фильтры">
351
+ <TaoDrawer v-model="open" title="Filters">
336
352
  ...
337
353
  </TaoDrawer>
338
354
  ```
339
355
 
340
- ## Дизайн-токены и темизация
356
+ ## Design tokens and theming
341
357
 
342
- Стили библиотеки построены в три слоя. Компоненты **никогда** не обращаются
343
- к цветам/размерам напрямую — только через переменные из семантического слоя.
344
- Это и есть механизм темизации: переопределяете 20-30 переменных — меняется
345
- внешний вид всех компонентов сразу, без правок самих компонентов.
358
+ Library styles are three layers. Components **never** touch raw colors or sizes —
359
+ only semantic variables. That is the theming mechanism: override 20–30 variables
360
+ and every component follows, with no edits inside the components themselves.
346
361
 
347
362
  ```
348
- primitives.css → semantic.css → themes/*.css (опционально)
349
- сырые цвета публичный API готовые темы поверх
350
- и размеры, темизации: semantic — пример: light
351
- не трогать вот что менять
363
+ primitives.css → semantic.css → themes/*.css (optional)
364
+ raw colors public theming ready-made themes on top
365
+ and scales, API: this is of semantic — light is
366
+ leave them alone what you change the example
352
367
  ```
353
368
 
354
- ### Слои
369
+ ### Layers
355
370
 
356
- | Файл | Назначение | Трогать? |
371
+ | File | Role | Touch it? |
357
372
  |---|---|---|
358
- | `primitives.css` | Сырая палитра, шкалы отступов/радиусов/теней (`--tao-orange-400`, `--tao-space-3`...) | Обычно нет |
359
- | `semantic.css` | Токены темы по умолчанию (dark): `--tao-color-accent`, `--tao-color-surface`, `--tao-color-danger` и т.д. | **Да — это и есть API темизации** |
360
- | `themes/light.css` | Пример альтернативной темы через `[data-tao-theme="light"]` | Да, как образец |
361
- | `base.css` | Глобальный reset (скроллбар, ссылки, box-sizing) | Редко |
373
+ | `primitives.css` | Raw palette, space / radius / shadow scales (`--tao-orange-400`, `--tao-space-3`…) | Usually no |
374
+ | `semantic.css` | Default (dark) theme tokens: `--tao-color-accent`, `--tao-color-surface`, `--tao-color-danger`, etc. | **Yes — this is the theming API** |
375
+ | `themes/light.css` | Alternate theme via `[data-tao-theme="light"]` | Yes, as a sample |
376
+ | `base.css` | Global reset (scrollbar, links, box-sizing) | Rarely |
362
377
 
363
- Все четыре подключаются одним файлом `@1337exp/taoui/styles.css`.
378
+ All four come in through `@1337exp/taoui/styles.css`.
364
379
 
365
- ### Как сделать свою тему
380
+ ### Your own theme
366
381
 
367
- Тема — это просто переопределение семантических токенов под своим селектором.
368
- Ничего в компонентах менять не нужно:
382
+ A theme is just semantic tokens under your selector.
383
+ Nothing in the components needs to change:
369
384
 
370
385
  ```css
371
386
  /* my-brand-theme.css */
@@ -377,7 +392,7 @@ primitives.css → semantic.css → themes/*.css (опционально
377
392
  --tao-color-surface-raised: #1a1a2e;
378
393
  --tao-color-text: #d6d6e8;
379
394
  --tao-color-text-strong: #ffffff;
380
- /* остальные токены см. semantic.css */
395
+ /* remaining tokens: see semantic.css */
381
396
  }
382
397
  ```
383
398
 
@@ -390,40 +405,39 @@ primitives.css → semantic.css → themes/*.css (опционально
390
405
  </template>
391
406
  ```
392
407
 
393
- Или переключайте тему целиком на `<html>`, чтобы стилизовать модалки/тултипы,
394
- которые телепортируются в `body`:
408
+ Or switch the theme on `<html>` so modals/tooltips teleported to `body` pick it up:
395
409
 
396
410
  ```javascript
397
411
  document.documentElement.setAttribute('data-tao-theme', 'light')
398
412
  ```
399
413
 
400
- ### Ключевые группы токенов
414
+ ### Token groups
401
415
 
402
- - `--tao-color-accent*` — акцентный/брендовый цвет (кнопки primary, активные вкладки, ссылки)
403
- - `--tao-color-on-accent` — текст на акцентном фоне (`--tao-color-text-on-accent` — алиас)
404
- - `--tao-color-selection`, `--tao-color-selection-text` — выделение текста (`::selection`)
405
- - `--tao-color-surface*` — фоны контейнеров (обычный / приподнятый / утопленный / hover)
406
- - `--tao-color-border*` — границы
407
- - `--tao-color-text*` — текст (обычный / усиленный / приглушённый / disabled)
408
- - `--tao-color-danger*`, `--tao-color-success*`, `--tao-color-warning*`, `--tao-color-info*` — статусные цвета
409
- - `--tao-color-input-*` — поля ввода отдельно, т.к. фон/текст полей часто не совпадают с surface/text
410
- - `--tao-radius-control`, `--tao-radius-panel` — скругления (мелкие контролы vs крупные панели)
411
- - `--tao-shadow-panel`, `--tao-shadow-overlay` — тени
416
+ - `--tao-color-accent*` — brand/accent (primary buttons, active tabs, links)
417
+ - `--tao-color-on-accent` — text on the accent (`--tao-color-text-on-accent` is an alias)
418
+ - `--tao-color-selection`, `--tao-color-selection-text` — text selection (`::selection`)
419
+ - `--tao-color-surface*` — container backgrounds (default / raised / sunken / hover)
420
+ - `--tao-color-border*` — borders
421
+ - `--tao-color-text*` — text (default / strong / muted / disabled)
422
+ - `--tao-color-danger*`, `--tao-color-success*`, `--tao-color-warning*`, `--tao-color-info*` — status colors
423
+ - `--tao-color-input-*` — fields, because input bg/text often differs from surface/text
424
+ - `--tao-radius-control`, `--tao-radius-panel` — radii (small controls vs large panels)
425
+ - `--tao-shadow-panel`, `--tao-shadow-overlay` — shadows
412
426
 
413
- Полный список — в `src/styles/semantic.css`, он же единственный файл,
414
- который стоит открыть, чтобы понять весь доступный API темизации.
427
+ The full list lives in `src/styles/semantic.css` — the only file worth opening
428
+ to see the whole theming API.
415
429
 
416
- ### Если нужна тема с нуля, без primitives
430
+ ### A theme from scratch, without primitives
417
431
 
418
432
  ```javascript
419
- import '@1337exp/taoui/styles/primitives.css' // шкалы можно оставить
420
- import './my-semantic.css' // свой семантический слой вместо @1337exp/taoui/styles/semantic.css
433
+ import '@1337exp/taoui/styles/primitives.css' // keep the scales if you want
434
+ import './my-semantic.css' // your semantic layer instead of @1337exp/taoui/styles/semantic.css
421
435
  import '@1337exp/taoui/styles/base.css'
422
436
  ```
423
437
 
424
- ## Демонстрация
438
+ ## Showcase
425
439
 
426
- Для просмотра всех компонентов запустите showcase:
440
+ To browse every component:
427
441
 
428
442
  ```bash
429
443
  cd showcase
@@ -431,45 +445,43 @@ npm install
431
445
  npm run dev
432
446
  ```
433
447
 
434
- В showcase есть переключатель темы (dark / light) в шапке — так виден
435
- эффект переопределения токенов без правок кода компонентов.
448
+ The showcase has a dark / light switch in the header, so you can see token
449
+ overrides without editing component code.
436
450
 
437
- Showcase смотрит прямо в `src/`, поэтому правки компонентов видны без
438
- `npm run build`. Сборка `dist/` нужна для публикации и для чужих проектов,
439
- которые ставят пакет.
451
+ The showcase points at `src/` directly, so component edits show up without
452
+ `npm run build`. Building `dist/` is for publishing and for other projects
453
+ that install the package.
440
454
 
441
- ## Разработка
455
+ ## Development
442
456
 
443
457
  ```bash
444
- # Сборка библиотеки
458
+ # Build the library
445
459
  npm run build
446
460
 
447
- # Режим разработки (watch)
461
+ # Watch mode
448
462
  npm run dev
449
463
 
450
- # Проверка типов
464
+ # Type check
451
465
  npm run type-check
452
466
  ```
453
467
 
454
- ## Публикация в npm
468
+ ## Publishing to npm
455
469
 
456
- Публикуется только `dist/` (собранная библиотека) и `src/styles/` (сырые
457
- токены — чтобы можно было подключить `primitives.css` отдельно при
458
- кастомной теме). Исходники компонентов (`src/components/*.vue`),
459
- конфиги сборки и `showcase/` в пакет не попадают — они остаются в
460
- репозитории; чтобы их получить, репозиторий клонируют.
470
+ Only `dist/` (the built library) and `src/styles/` (raw tokens, so you can
471
+ import `primitives.css` on its own for a custom theme) are published.
472
+ Component sources (`src/components/*.vue`), build configs, and `showcase/`
473
+ stay in the repo — clone it to get them.
461
474
 
462
- `npm publish` **сам** прогоняет проверку типов и полную пересборку перед
463
- публикацией (хук `prepublishOnly` в `package.json`) — так в реестр не
464
- уедет пакет со старым или отсутствующим `dist/`. Собирать вручную перед
465
- `npm publish` не нужно.
475
+ `npm publish` **itself** runs the type check and a full rebuild first
476
+ (`prepublishOnly` in `package.json`), so a stale or missing `dist/` cannot
477
+ reach the registry. You do not need to build by hand before `npm publish`.
466
478
 
467
- Проверить, что именно попадёт в пакет, без реальной публикации:
479
+ See what would go into the tarball, without publishing:
468
480
 
469
481
  ```bash
470
482
  npm pack --dry-run
471
483
  ```
472
484
 
473
- ## Лицензия
485
+ ## License
474
486
 
475
487
  MIT