@1337exp/taoui 1.2.2 → 1.3.3

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,108 +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 / header / footer. В `#cover` — фото или `TaoCarousel`
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
- - **TaoCombobox** — Select с полем: фильтр по вводу, `allow-create` пишет своё в `v-model`, `create` — чтобы родитель дополнил список
37
- - **TaoDate** — один день: `YYYY-MM-DD`, без часов и пояса. Календарь как у Select
38
- - **TaoFormField** — общие label / hint / error для полей формы
39
- - **TaoInputNumber** — число с min/max/step и кнопками ± справа. Пустое значение — `null`
40
- - **TaoQuantity** — количество в корзине: `− | поле | +`, целые штуки, сток, минус на минимуме может убрать строку
41
- - **TaoTextarea** — многострочное поле с авто-высотой. `maxlength` ограничивает ввод, `count` показывает «введено / максимум»
42
- - **TaoPinCode** — пин-код из N полей. По умолчанию клик стирает ячейку и все справа (`clear-on="focus"`); `clear-on="input"` заменяет цифру только при вводе. Последняя ячейка снимает фокус и эмитит `complete`
43
- - **TaoSlider** — слайдер: мышь, тач и стрелки. Опциональный точный ввод по правому клику
44
- - **TaoFileDrop** — зона загрузки файлов (drag & drop + клик). Текст внутри — слот
45
-
46
- ### Отображение данных
47
-
48
- - **TaoTable** — простая таблица: колонки, empty, loading, сортировка через `v-model:sort`. Не datagrid.
49
- - **TaoPagination** — страницы с многоточием. Клик по «…» прыгает на `jump` страниц (5 по умолчанию)
50
- - **TaoEmpty** — пустой список, нет результатов, нет прав
51
- - **TaoStages** — список стадий: `wait` / `work` / `ok` / `bad`. Не линейный степпер
52
- - **TaoSkeleton** — плейсхолдер загрузки (text / title / circle / rect)
53
- - **TaoCounter** — витрина числа с переворотом цифр (не инпут)
54
- - **TaoCarousel** — лента: целый слайд с `autoplay`, карточка с `peek`, полоса с `per-view`. Стрелки через `controls` или `#prev` / `#next`, точки — `dots`
55
- - **TaoAvatar** — фото или инициалы, размеры `small` / `medium` / `large`. Точка `dot` и счётчик `count`
56
- - **TaoTag** — тег/бейдж со статусами (neutral, success, danger, warning, info)
57
- - **TaoAlert** — инлайн-баннер страницы или ошибки формы (success / error / warning / info)
58
- - **TaoProgress** — статичная полоса (`progress` в %). Проценты сверху по центру или `showPercentage="right"` справа; слоты `#left` / `#right` — подписи, тогда процент справа в скобках. `false` прячет. Ширина — `minWidth` / `maxWidth`, не диапазон значения
59
- - **TaoLoader** — анимированный лоадер (четыре точки)
60
- - **TaoImage** — обёртка над `<img>` с плавным fade-in при загрузке и плейсхолдером
61
- - **TaoIcon** — обёртка для icon-шрифта (см. раздел «Иконки» ниже)
62
-
63
- ### Навигация и взаимодействие
64
-
65
- - **TaoLink** — ссылка, использующая `<NuxtLink>` в Nuxt-проекте и обычный `<a>` вне его — без дополнительной настройки
66
- - **TaoBreadcrumb** — крошки: последний пункт — текущая страница
67
- - **TaoDropdownMenu** — выпадающее меню с авто-позиционированием у края экрана
68
- - **TaoScrollTop** — плавающая кнопка «наверх» с ripple. Появляется при обратном скролле после `boundary`
69
-
70
- ### Обратная связь
71
-
72
- - **toast()** — fluent-уведомления: `toast().success().message('Сохранено')`
73
- - **confirm()** — вопрос с оверлеем: тот же fluent + `await`. Не тост — ждёт ответ, не исчезает сам.
74
- - **TaoToastViewport** / **TaoConfirmHost** — контейнеры; если их нет в разметке, первый вызов сам монтирует их в `body`
75
-
76
- ## Соглашения
77
-
78
- Тоны визуала: `success` | `danger` | `warning` | `info` | `neutral`.
79
- `error` у Alert, Tag и `toast()` — синоним `danger`. Button уже `danger`.
80
- Stages — это процесс, не тон: `wait` / `work` / `ok` / `bad` (`danger` принимается как `bad`).
81
-
82
- Размеры контролов: `small` | `medium` | `large`.
83
- Avatar понимает и короткие `s` / `m` / `l`. Divider `gap` раньше называл крупный размер `big` — это алиас `large`.
84
- Container живёт на другой оси: `wide` / `slim` / `ultra-slim`.
85
-
86
- ## Иконки
87
-
88
- `TaoIcon` не поставляет собственный набор иконок — он рендерит класс `icon-<name>`
89
- по соглашению, рассчитанному на подключение внешнего icon-шрифта (например,
90
- собранного через IcoMoon/Fontello). Чтобы иконки отображались, подключите
91
- свой шрифт с классами вида `.icon-arrow-up { ... }` в проекте.
92
-
93
- ## Установка
94
-
95
- Или локально из папки:
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:
96
105
 
97
106
  ```bash
98
107
  npm install ../path-to-tao-ui
99
108
  ```
100
109
 
101
- ## Использование
110
+ ## Usage
102
111
 
103
- ### Подключение в Nuxt 3
112
+ ### Nuxt 3
104
113
 
105
- Создайте плагин `plugins/tao-ui.ts`:
114
+ Create `plugins/tao-ui.ts`:
106
115
 
107
116
  ```typescript
108
117
  import { defineNuxtPlugin } from '#app'
@@ -113,7 +122,7 @@ export default defineNuxtPlugin((nuxtApp) => {
113
122
  })
114
123
  ```
115
124
 
116
- Импортируйте стили в `app.vue` или layout:
125
+ Import styles in `app.vue` or a layout:
117
126
 
118
127
  ```vue
119
128
  <script setup>
@@ -121,7 +130,7 @@ import '@1337exp/taoui/styles.css'
121
130
  </script>
122
131
  ```
123
132
 
124
- ### Подключение в Vue 3 проекте
133
+ ### Vue 3
125
134
 
126
135
  ```javascript
127
136
  // main.js
@@ -135,7 +144,7 @@ app.use(TaoUI)
135
144
  app.mount('#app')
136
145
  ```
137
146
 
138
- ### Использование отдельных компонентов
147
+ ### Individual components
139
148
 
140
149
  ```vue
141
150
  <script setup>
@@ -144,41 +153,41 @@ import '@1337exp/taoui/styles.css'
144
153
  </script>
145
154
 
146
155
  <template>
147
- <TaoButton variant="primary">Нажми меня</TaoButton>
148
- <TaoInput v-model="text" label="Введите текст" />
149
- <TaoModal v-model="isOpen" title="Заголовок">
150
- Содержимое модального окна
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
151
160
  </TaoModal>
152
161
  </template>
153
162
  ```
154
163
 
155
164
  ## Toast
156
165
 
157
- Вызов — цепочка в одном тике, `setTimeout(0)` отправляет уведомление.
166
+ The chain runs in the same tick; `setTimeout(0)` actually shows the toast.
158
167
 
159
168
  ```javascript
160
169
  import { toast } from '@1337exp/taoui'
161
170
 
162
- toast().success().message('Сохранено')
163
- toast().error().title('Сеть').timeout(5000).message('Нет соединения')
164
- toast.success('Сохранено')
165
- 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 })
166
175
  ```
167
176
 
168
- Позиция по умолчанию — `topCenter`. Глобально:
177
+ Default position is `topCenter`. Globally:
169
178
 
170
179
  ```javascript
171
180
  toast.defaults({ position: 'bottomRight' })
172
181
  toast.byBottomRight()
173
182
  ```
174
183
 
175
- `question` с оверлеем в kit нет — это confirm, не toast. Кнопки в тосте, если нужны:
184
+ There is no overlay `question` in this kit — that is confirm, not toast. Buttons on a toast, if needed:
176
185
 
177
186
  ```javascript
178
- toast().info().message('Удалить файл?').action('Удалить', onRemove)
187
+ toast().info().message('Delete the file?').action('Delete', onRemove)
179
188
  ```
180
189
 
181
- Viewport можно не вставлять: первый вызов сам создаст его. Если нужен явный контроль (тесты, свой layout):
190
+ You can skip the viewport: the first call creates it. For explicit control (tests, a custom layout):
182
191
 
183
192
  ```vue
184
193
  <TaoToastViewport />
@@ -186,62 +195,62 @@ Viewport можно не вставлять: первый вызов сам со
186
195
 
187
196
  ## Confirm
188
197
 
189
- Вопрос с оверлеем: всплывает по центру и спрашивает. Это не 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.
190
199
 
191
200
  ```javascript
192
201
  import { confirm } from '@1337exp/taoui'
193
202
 
194
- if (await confirm().title('Удалить файл?').message('Это нельзя отменить').danger()) {
203
+ if (await confirm().title('Delete the file?').message('This cannot be undone').danger()) {
195
204
  remove()
196
205
  }
197
206
 
198
- const ok = await confirm('Выйти без сохранения?', {
199
- ok: 'Выйти',
200
- cancel: 'Остаться',
207
+ const ok = await confirm('Leave without saving?', {
208
+ ok: 'Leave',
209
+ cancel: 'Stay',
201
210
  })
202
211
  ```
203
212
 
204
- Очередь: второй `confirm()`, пока открыт первый, подождёт. Подписи по умолчанию — «ОК» / «Отмена»:
213
+ Queue: a second `confirm()` while the first is open will wait. Default labels are “OK” / “Cancel”:
205
214
 
206
215
  ```javascript
207
216
  confirm.defaults({ ok: 'Yes', cancel: 'No' })
208
217
  ```
209
218
 
210
- ## Формы
219
+ ## Forms
211
220
 
212
- `TaoFormField` вешает общий label / hint / error и прокидывает `id` во вложенный контрол.
221
+ `TaoFormField` attaches a shared label / hint / error and forwards `id` to the nested control.
213
222
 
214
223
  ```vue
215
- <TaoFormField label="Город" hint="Необязательно">
224
+ <TaoFormField label="City" hint="Optional">
216
225
  <TaoSelect v-model="city" :options="cities" />
217
226
  </TaoFormField>
218
227
 
219
- <TaoSwitch v-model="dark" label="Тёмная тема" />
228
+ <TaoSwitch v-model="dark" label="Dark theme" />
220
229
 
221
- <TaoRadioGroup v-model="plan" legend="Тариф">
230
+ <TaoRadioGroup v-model="plan" legend="Plan">
222
231
  <TaoRadio value="free" label="Free" />
223
232
  <TaoRadio value="pro" label="Pro" />
224
233
  </TaoRadioGroup>
225
234
 
226
- <TaoAlert type="warning" title="Черновик">Сохраните, прежде чем уйти.</TaoAlert>
235
+ <TaoAlert type="warning" title="Draft">Save before you leave.</TaoAlert>
227
236
  ```
228
237
 
229
- `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`.
230
239
 
231
- `TaoCombobox` — то же меню, но с полем. Печатаете — варианты режутся. `allow-create` пишет введённое в `v-model`, если точного совпадения нет. Список сам не меняется: слушайте `create` и добавьте option снаружи.
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.
232
241
 
233
- `TaoFormField` также оборачивает `TaoTextarea` и `TaoCheckbox` — id, hint и error прокидываются сами.
242
+ `TaoFormField` also wraps `TaoTextarea` and `TaoCheckbox` — id, hint, and error are forwarded for you.
234
243
 
235
- ## Таблица и пагинация
244
+ ## Table and pagination
236
245
 
237
- Таблица рендерит то, что передали: сама данные не режет и не сортирует. Это удобно и для серверной выборки, и для клиентской — страница режется снаружи.
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.
238
247
 
239
248
  ```vue
240
249
  <TaoTable
241
250
  :columns="columns"
242
251
  :rows="pageRows"
243
252
  v-model:sort="sort"
244
- empty-text="Пока нет записей"
253
+ empty-text="No records yet"
245
254
  >
246
255
  <template #cell-status="{ row }">
247
256
  <TaoTag :type="row.status === 'active' ? 'success' : 'neutral'">
@@ -255,21 +264,21 @@ confirm.defaults({ ok: 'Yes', cancel: 'No' })
255
264
 
256
265
  ```javascript
257
266
  const columns = [
258
- { key: 'name', label: 'Имя', sortable: true },
259
- { key: 'city', label: 'Город' },
260
- { key: 'status', label: 'Статус' },
267
+ { key: 'name', label: 'Name', sortable: true },
268
+ { key: 'city', label: 'City' },
269
+ { key: 'status', label: 'Status' },
261
270
  ]
262
271
  ```
263
272
 
264
- Слот `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`.
265
274
 
266
- ## Пустые состояния и загрузка
275
+ ## Empty states and loading
267
276
 
268
277
  ```vue
269
- <TaoEmpty title="Ничего не нашлось">
270
- Измените фильтр или сбросьте поиск.
278
+ <TaoEmpty title="Nothing found">
279
+ Change the filter or reset search.
271
280
  <template #action>
272
- <TaoButton variant="secondary">Сбросить</TaoButton>
281
+ <TaoButton variant="secondary">Reset</TaoButton>
273
282
  </template>
274
283
  </TaoEmpty>
275
284
 
@@ -278,14 +287,14 @@ const columns = [
278
287
  <TaoSkeleton variant="circle" />
279
288
 
280
289
  <TaoStages :items="[
281
- { key: 'pay', label: 'Оплата', status: 'ok' },
282
- { key: 'pack', label: 'Сборка', status: 'work' },
283
- { 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' },
284
293
  ]" />
285
294
  ```
286
295
 
287
296
  ```vue
288
- <TaoInput v-model="q" placeholder="Найти…">
297
+ <TaoInput v-model="q" placeholder="Search…">
289
298
  <template #prefix>⌕</template>
290
299
  </TaoInput>
291
300
 
@@ -293,7 +302,7 @@ const columns = [
293
302
  <template #before>https://</template>
294
303
  <TaoInput v-model="host" placeholder="example.com" />
295
304
  <template #after>
296
- <TaoButton>Проверить</TaoButton>
305
+ <TaoButton>Check</TaoButton>
297
306
  </template>
298
307
  </TaoInputGroup>
299
308
 
@@ -301,19 +310,23 @@ const columns = [
301
310
  <TaoFormField label="Email">
302
311
  <TaoInput v-model="email" type="email" />
303
312
  </TaoFormField>
304
- <TaoButton type="submit">Сохранить</TaoButton>
313
+ <TaoButton type="submit">Save</TaoButton>
305
314
  </form>
306
315
 
307
- <TaoFormField label="Количество">
316
+ <TaoFormField label="Quantity">
308
317
  <TaoInputNumber v-model="qty" :min="1" :max="99" />
309
318
  </TaoFormField>
310
319
 
311
320
  <TaoQuantity v-model="qty" :max="12" @dec="onDec" />
312
321
 
313
- <TaoFormField label="День доставки" hint="В модели всегда YYYY-MM-DD">
322
+ <TaoFormField label="Delivery day" hint="The model is always YYYY-MM-DD">
314
323
  <TaoDate v-model="day" min="2026-09-01" max="2026-09-30" />
315
324
  </TaoFormField>
316
325
 
326
+ <TaoFormField label="Stay">
327
+ <TaoDateRange v-model="stay" min="2026-09-01" max="2026-09-30" />
328
+ </TaoFormField>
329
+
317
330
  <TaoCounter :value="score" :max-digits="6" />
318
331
 
319
332
  <TaoCarousel :autoplay="4000" loop dots>
@@ -326,49 +339,48 @@ const columns = [
326
339
  <TaoCarousel v-model="slide" :per-view="5" :peek="28">
327
340
  <template #prev></template>
328
341
  <template #next="{ go, disabled }">
329
- <button type="button" :disabled="disabled" @click="go">вперёд</button>
342
+ <button type="button" :disabled="disabled" @click="go">next</button>
330
343
  </template>
331
344
  <article v-for="item in products" :key="item.id">…</article>
332
345
  </TaoCarousel>
333
346
  ```
334
347
 
335
- `TaoDrawer` — лист сбоку, не модалка по центру:
348
+ `TaoDrawer` is a side sheet, not a centered modal:
336
349
 
337
350
  ```vue
338
- <TaoDrawer v-model="open" title="Фильтры">
351
+ <TaoDrawer v-model="open" title="Filters">
339
352
  ...
340
353
  </TaoDrawer>
341
354
  ```
342
355
 
343
- ## Дизайн-токены и темизация
356
+ ## Design tokens and theming
344
357
 
345
- Стили библиотеки построены в три слоя. Компоненты **никогда** не обращаются
346
- к цветам/размерам напрямую — только через переменные из семантического слоя.
347
- Это и есть механизм темизации: переопределяете 20-30 переменных — меняется
348
- внешний вид всех компонентов сразу, без правок самих компонентов.
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.
349
361
 
350
362
  ```
351
- primitives.css → semantic.css → themes/*.css (опционально)
352
- сырые цвета публичный API готовые темы поверх
353
- и размеры, темизации: semantic — пример: light
354
- не трогать вот что менять
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
355
367
  ```
356
368
 
357
- ### Слои
369
+ ### Layers
358
370
 
359
- | Файл | Назначение | Трогать? |
371
+ | File | Role | Touch it? |
360
372
  |---|---|---|
361
- | `primitives.css` | Сырая палитра, шкалы отступов/радиусов/теней (`--tao-orange-400`, `--tao-space-3`...) | Обычно нет |
362
- | `semantic.css` | Токены темы по умолчанию (dark): `--tao-color-accent`, `--tao-color-surface`, `--tao-color-danger` и т.д. | **Да — это и есть API темизации** |
363
- | `themes/light.css` | Пример альтернативной темы через `[data-tao-theme="light"]` | Да, как образец |
364
- | `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 |
365
377
 
366
- Все четыре подключаются одним файлом `@1337exp/taoui/styles.css`.
378
+ All four come in through `@1337exp/taoui/styles.css`.
367
379
 
368
- ### Как сделать свою тему
380
+ ### Your own theme
369
381
 
370
- Тема — это просто переопределение семантических токенов под своим селектором.
371
- Ничего в компонентах менять не нужно:
382
+ A theme is just semantic tokens under your selector.
383
+ Nothing in the components needs to change:
372
384
 
373
385
  ```css
374
386
  /* my-brand-theme.css */
@@ -380,7 +392,7 @@ primitives.css → semantic.css → themes/*.css (опционально
380
392
  --tao-color-surface-raised: #1a1a2e;
381
393
  --tao-color-text: #d6d6e8;
382
394
  --tao-color-text-strong: #ffffff;
383
- /* остальные токены см. semantic.css */
395
+ /* remaining tokens: see semantic.css */
384
396
  }
385
397
  ```
386
398
 
@@ -393,40 +405,39 @@ primitives.css → semantic.css → themes/*.css (опционально
393
405
  </template>
394
406
  ```
395
407
 
396
- Или переключайте тему целиком на `<html>`, чтобы стилизовать модалки/тултипы,
397
- которые телепортируются в `body`:
408
+ Or switch the theme on `<html>` so modals/tooltips teleported to `body` pick it up:
398
409
 
399
410
  ```javascript
400
411
  document.documentElement.setAttribute('data-tao-theme', 'light')
401
412
  ```
402
413
 
403
- ### Ключевые группы токенов
414
+ ### Token groups
404
415
 
405
- - `--tao-color-accent*` — акцентный/брендовый цвет (кнопки primary, активные вкладки, ссылки)
406
- - `--tao-color-on-accent` — текст на акцентном фоне (`--tao-color-text-on-accent` — алиас)
407
- - `--tao-color-selection`, `--tao-color-selection-text` — выделение текста (`::selection`)
408
- - `--tao-color-surface*` — фоны контейнеров (обычный / приподнятый / утопленный / hover)
409
- - `--tao-color-border*` — границы
410
- - `--tao-color-text*` — текст (обычный / усиленный / приглушённый / disabled)
411
- - `--tao-color-danger*`, `--tao-color-success*`, `--tao-color-warning*`, `--tao-color-info*` — статусные цвета
412
- - `--tao-color-input-*` — поля ввода отдельно, т.к. фон/текст полей часто не совпадают с surface/text
413
- - `--tao-radius-control`, `--tao-radius-panel` — скругления (мелкие контролы vs крупные панели)
414
- - `--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
415
426
 
416
- Полный список — в `src/styles/semantic.css`, он же единственный файл,
417
- который стоит открыть, чтобы понять весь доступный API темизации.
427
+ The full list lives in `src/styles/semantic.css` — the only file worth opening
428
+ to see the whole theming API.
418
429
 
419
- ### Если нужна тема с нуля, без primitives
430
+ ### A theme from scratch, without primitives
420
431
 
421
432
  ```javascript
422
- import '@1337exp/taoui/styles/primitives.css' // шкалы можно оставить
423
- 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
424
435
  import '@1337exp/taoui/styles/base.css'
425
436
  ```
426
437
 
427
- ## Демонстрация
438
+ ## Showcase
428
439
 
429
- Для просмотра всех компонентов запустите showcase:
440
+ To browse every component:
430
441
 
431
442
  ```bash
432
443
  cd showcase
@@ -434,45 +445,43 @@ npm install
434
445
  npm run dev
435
446
  ```
436
447
 
437
- В showcase есть переключатель темы (dark / light) в шапке — так виден
438
- эффект переопределения токенов без правок кода компонентов.
448
+ The showcase has a dark / light switch in the header, so you can see token
449
+ overrides without editing component code.
439
450
 
440
- Showcase смотрит прямо в `src/`, поэтому правки компонентов видны без
441
- `npm run build`. Сборка `dist/` нужна для публикации и для чужих проектов,
442
- которые ставят пакет.
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.
443
454
 
444
- ## Разработка
455
+ ## Development
445
456
 
446
457
  ```bash
447
- # Сборка библиотеки
458
+ # Build the library
448
459
  npm run build
449
460
 
450
- # Режим разработки (watch)
461
+ # Watch mode
451
462
  npm run dev
452
463
 
453
- # Проверка типов
464
+ # Type check
454
465
  npm run type-check
455
466
  ```
456
467
 
457
- ## Публикация в npm
468
+ ## Publishing to npm
458
469
 
459
- Публикуется только `dist/` (собранная библиотека) и `src/styles/` (сырые
460
- токены — чтобы можно было подключить `primitives.css` отдельно при
461
- кастомной теме). Исходники компонентов (`src/components/*.vue`),
462
- конфиги сборки и `showcase/` в пакет не попадают — они остаются в
463
- репозитории; чтобы их получить, репозиторий клонируют.
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.
464
474
 
465
- `npm publish` **сам** прогоняет проверку типов и полную пересборку перед
466
- публикацией (хук `prepublishOnly` в `package.json`) — так в реестр не
467
- уедет пакет со старым или отсутствующим `dist/`. Собирать вручную перед
468
- `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`.
469
478
 
470
- Проверить, что именно попадёт в пакет, без реальной публикации:
479
+ See what would go into the tarball, without publishing:
471
480
 
472
481
  ```bash
473
482
  npm pack --dry-run
474
483
  ```
475
484
 
476
- ## Лицензия
485
+ ## License
477
486
 
478
487
  MIT