@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.RU.md +492 -0
- package/README.md +214 -202
- package/dist/index.cjs +1872 -435
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +558 -212
- package/dist/index.mjs +1873 -436
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +459 -71
- package/package.json +1 -1
- package/src/styles/date-popup.css +178 -0
package/README.RU.md
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
# Tao UI
|
|
2
|
+
|
|
3
|
+
[English](README.md) · **Русский**
|
|
4
|
+
|
|
5
|
+
Библиотека Vue 3 компонентов для Nuxt/Vue проектов с системой дизайн-токенов:
|
|
6
|
+
поменял несколько CSS-переменных — поменялась тема всего набора компонентов.
|
|
7
|
+
|
|
8
|
+
## Компоненты
|
|
9
|
+
|
|
10
|
+
### Базовые
|
|
11
|
+
|
|
12
|
+
- **TaoBlock** — базовый контейнер с настраиваемыми отступами и скруглением
|
|
13
|
+
- **TaoButton** — кнопка с вариантами (primary, secondary, ghost, danger), размерами и состояниями
|
|
14
|
+
- **TaoCard** — карточка со слотами cover / header / footer. В `#cover` — фото или `TaoCarousel`
|
|
15
|
+
- **TaoCopy** — иконка копирования в буфер. После клика сверху тултип «Скопировано»; если кнопку убрали — тултип тоже
|
|
16
|
+
- **TaoInput** — поле ввода с поддержкой v-model, валидации и слотов `#prefix` / `#suffix` (иконка или текст внутри рамки)
|
|
17
|
+
- **TaoInputGroup** — склейка снаружи: `#before` | поле | `#after` (протокол, единица, кнопка)
|
|
18
|
+
- **TaoModal** — модальное окно с анимацией и слотами
|
|
19
|
+
- **TaoDrawer** — боковая панель (фильтры, настройки). Esc, клик по фону, ловушка фокуса — как у модалки
|
|
20
|
+
- **TaoSpoiler** — раскрывающийся блок. `v-model` и `aria-expanded`. Несколько подряд сами друг друга не закрывают
|
|
21
|
+
- **TaoSpoilerGroup** — аккордеон: `v-model` — ключ открытой панели (`null` — все закрыты), у спойлера `name`
|
|
22
|
+
- **TaoTabs** — вкладки для переключения между секциями контента
|
|
23
|
+
- **TaoTooltip** — всплывающая подсказка при наведении
|
|
24
|
+
- **TaoPopover** — панель по клику: слот с любым контентом, Esc и клик снаружи. Не тултип и не меню действий
|
|
25
|
+
|
|
26
|
+
### Layout
|
|
27
|
+
|
|
28
|
+
- **TaoContainer** — контейнер с ограничением ширины (wide/slim/ultra-slim) и авто-центровкой
|
|
29
|
+
- **TaoFlex** — обёртка над flexbox с пропами justify/align/direction/wrap/gap
|
|
30
|
+
- **TaoSpace** — авто-расстановка дочерних элементов с равномерным gap
|
|
31
|
+
- **TaoDivider** — разделитель: line (тонкая линия), text (линия с текстом), gap (пустой отступ, size: small/medium/large)
|
|
32
|
+
- **TaoFieldset** — рамка-группа: `legend` сидит на верхней границе, `align` — start / center / end
|
|
33
|
+
- **TaoAnimatedBorder** — контейнер с анимированной радужной рамкой (декоративный, не завязан на тему)
|
|
34
|
+
|
|
35
|
+
### Формы и ввод
|
|
36
|
+
|
|
37
|
+
- **TaoCheckbox** — чекбокс с v-model, слотами pre/post и `indeterminate` (частично выбран)
|
|
38
|
+
- **TaoSwitch** — переключатель для булевых настроек (`role="switch"`)
|
|
39
|
+
- **TaoRadio** / **TaoRadioGroup** — взаимоисключающий выбор из 2–5 вариантов
|
|
40
|
+
- **TaoSelect** — выпадающий список с клавиатурой, тот же визуал, что у Input. Сброс — «Очистить» в списке или Delete
|
|
41
|
+
- **TaoCombobox** — Select с полем: фильтр по вводу, `allow-create` пишет своё в `v-model`, `create` — чтобы родитель дополнил список
|
|
42
|
+
- **TaoDate** — один день: `YYYY-MM-DD`, без часов и пояса. Календарь как у Select
|
|
43
|
+
- **TaoDateRange** — период: `v-model` — `{ start, end }` или `null`. Первый клик — начало, второй — конец (если конец раньше — меняются местами). Неполный выбор в модель не пишется
|
|
44
|
+
- **TaoFormField** — общие label / hint / error для полей формы
|
|
45
|
+
- **TaoInputNumber** — число с min/max/step и кнопками ± справа. Пустое значение — `null`
|
|
46
|
+
- **TaoQuantity** — количество в корзине: `− | поле | +`, целые штуки, сток, минус на минимуме может убрать строку
|
|
47
|
+
- **TaoTextarea** — многострочное поле с авто-высотой. `maxlength` ограничивает ввод, `count` показывает «введено / максимум»
|
|
48
|
+
- **TaoPinCode** — пин-код из N полей. По умолчанию клик стирает ячейку и все справа (`clear-on="focus"`); `clear-on="input"` заменяет цифру только при вводе. Последняя ячейка снимает фокус и эмитит `complete`
|
|
49
|
+
- **TaoSlider** — слайдер: мышь, тач и стрелки. Опциональный точный ввод по правому клику
|
|
50
|
+
- **TaoFileDrop** — зона загрузки (drag & drop + клик). Список имён под зоной, `v-model` — `File[]`. Очистку всей пачки решает родитель (`clear-request`)
|
|
51
|
+
|
|
52
|
+
### Отображение данных
|
|
53
|
+
|
|
54
|
+
- **TaoTable** — простая таблица: колонки, empty, loading, сортировка через `v-model:sort`. Не datagrid.
|
|
55
|
+
- **TaoPagination** — страницы с многоточием. Клик по «…» прыгает на `jump` страниц (5 по умолчанию)
|
|
56
|
+
- **TaoEmpty** — пустой список, нет результатов, нет прав
|
|
57
|
+
- **TaoStages** — список стадий: `wait` / `work` / `ok` / `bad`. Не линейный степпер
|
|
58
|
+
- **TaoSkeleton** — плейсхолдер загрузки (text / title / circle / rect)
|
|
59
|
+
- **TaoCounter** — витрина числа с переворотом цифр (не инпут)
|
|
60
|
+
- **TaoCarousel** — лента: целый слайд с `autoplay`, карточка с `peek`, полоса с `per-view`. Стрелки через `controls` или `#prev` / `#next`, точки — `dots`
|
|
61
|
+
- **TaoAvatar** — фото или инициалы, размеры `small` / `medium` / `large`. Точка `dot` и счётчик `count`
|
|
62
|
+
- **TaoTag** — тег/бейдж со статусами (neutral, success, danger, warning, info)
|
|
63
|
+
- **TaoAlert** — инлайн-баннер страницы или ошибки формы (success / error / warning / info)
|
|
64
|
+
- **TaoProgress** — статичная полоса (`progress` в %). Проценты сверху по центру или `showPercentage="right"` справа; слоты `#left` / `#right` — подписи, тогда процент справа в скобках. `false` прячет. Ширина — `minWidth` / `maxWidth`, не диапазон значения
|
|
65
|
+
- **TaoLoader** — анимированный лоадер (четыре точки)
|
|
66
|
+
- **TaoImage** — обёртка над `<img>`: fade-in и плейсхолдер. `lazy` включает нативный `loading="lazy"`
|
|
67
|
+
- **TaoIcon** — обёртка для icon-шрифта (см. раздел «Иконки» ниже)
|
|
68
|
+
|
|
69
|
+
### Навигация и взаимодействие
|
|
70
|
+
|
|
71
|
+
- **TaoLink** — ссылка, использующая `<NuxtLink>` в Nuxt-проекте и обычный `<a>` вне его — без дополнительной настройки
|
|
72
|
+
- **TaoBreadcrumb** — крошки: последний пункт — текущая страница
|
|
73
|
+
- **TaoDropdownMenu** — выпадающее меню с авто-позиционированием у края экрана
|
|
74
|
+
- **TaoScrollTop** — плавающая кнопка «наверх» с ripple. Появляется при обратном скролле после `boundary`
|
|
75
|
+
|
|
76
|
+
### Обратная связь
|
|
77
|
+
|
|
78
|
+
- **toast()** — fluent-уведомления: `toast().success().message('Сохранено')`
|
|
79
|
+
- **confirm()** — вопрос с оверлеем: тот же fluent + `await`. Не тост — ждёт ответ, не исчезает сам.
|
|
80
|
+
- **TaoToastViewport** / **TaoConfirmHost** — контейнеры; если их нет в разметке, первый вызов сам монтирует их в `body`
|
|
81
|
+
|
|
82
|
+
## Соглашения
|
|
83
|
+
|
|
84
|
+
Тоны визуала: `success` | `danger` | `warning` | `info` | `neutral`.
|
|
85
|
+
`error` у Alert, Tag и `toast()` — синоним `danger`. Button уже `danger`.
|
|
86
|
+
Stages — это процесс, не тон: `wait` / `work` / `ok` / `bad` (`danger` принимается как `bad`).
|
|
87
|
+
|
|
88
|
+
Размеры контролов: `small` | `medium` | `large`.
|
|
89
|
+
Avatar понимает и короткие `s` / `m` / `l`. Divider `gap` раньше называл крупный размер `big` — это алиас `large`.
|
|
90
|
+
Container живёт на другой оси: `wide` / `slim` / `ultra-slim`.
|
|
91
|
+
|
|
92
|
+
## Иконки
|
|
93
|
+
|
|
94
|
+
`TaoIcon` не поставляет собственный набор иконок — он рендерит класс `icon-<name>`
|
|
95
|
+
по соглашению, рассчитанному на подключение внешнего icon-шрифта (например,
|
|
96
|
+
собранного через IcoMoon/Fontello). Чтобы иконки отображались, подключите
|
|
97
|
+
свой шрифт с классами вида `.icon-arrow-up { ... }` в проекте.
|
|
98
|
+
|
|
99
|
+
## Установка
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm install @1337exp/taoui
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Или локально из папки:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npm install ../path-to-tao-ui
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Использование
|
|
112
|
+
|
|
113
|
+
### Подключение в Nuxt 3
|
|
114
|
+
|
|
115
|
+
Создайте плагин `plugins/tao-ui.ts`:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { defineNuxtPlugin } from '#app'
|
|
119
|
+
import TaoUI from '@1337exp/taoui'
|
|
120
|
+
|
|
121
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
122
|
+
nuxtApp.vueApp.use(TaoUI)
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Импортируйте стили в `app.vue` или layout:
|
|
127
|
+
|
|
128
|
+
```vue
|
|
129
|
+
<script setup>
|
|
130
|
+
import '@1337exp/taoui/styles.css'
|
|
131
|
+
</script>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Подключение в Vue 3 проекте
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
// main.js
|
|
138
|
+
import { createApp } from 'vue'
|
|
139
|
+
import App from './App.vue'
|
|
140
|
+
import TaoUI from '@1337exp/taoui'
|
|
141
|
+
import '@1337exp/taoui/styles.css'
|
|
142
|
+
|
|
143
|
+
const app = createApp(App)
|
|
144
|
+
app.use(TaoUI)
|
|
145
|
+
app.mount('#app')
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Использование отдельных компонентов
|
|
149
|
+
|
|
150
|
+
```vue
|
|
151
|
+
<script setup>
|
|
152
|
+
import { TaoButton, TaoInput, TaoModal } from '@1337exp/taoui'
|
|
153
|
+
import '@1337exp/taoui/styles.css'
|
|
154
|
+
</script>
|
|
155
|
+
|
|
156
|
+
<template>
|
|
157
|
+
<TaoButton variant="primary">Нажми меня</TaoButton>
|
|
158
|
+
<TaoInput v-model="text" label="Введите текст" />
|
|
159
|
+
<TaoModal v-model="isOpen" title="Заголовок">
|
|
160
|
+
Содержимое модального окна
|
|
161
|
+
</TaoModal>
|
|
162
|
+
</template>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Toast
|
|
166
|
+
|
|
167
|
+
Вызов — цепочка в одном тике, `setTimeout(0)` отправляет уведомление.
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
import { toast } from '@1337exp/taoui'
|
|
171
|
+
|
|
172
|
+
toast().success().message('Сохранено')
|
|
173
|
+
toast().error().title('Сеть').timeout(5000).message('Нет соединения')
|
|
174
|
+
toast.success('Сохранено')
|
|
175
|
+
toast.warning('Черновик', { timeout: 1000 })
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Позиция по умолчанию — `topCenter`. Глобально:
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
toast.defaults({ position: 'bottomRight' })
|
|
182
|
+
toast.byBottomRight()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`question` с оверлеем в kit нет — это confirm, не toast. Кнопки в тосте, если нужны:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
toast().info().message('Удалить файл?').action('Удалить', onRemove)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Viewport можно не вставлять: первый вызов сам создаст его. Если нужен явный контроль (тесты, свой layout):
|
|
192
|
+
|
|
193
|
+
```vue
|
|
194
|
+
<TaoToastViewport />
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Confirm
|
|
198
|
+
|
|
199
|
+
Вопрос с оверлеем: всплывает по центру и спрашивает. Это не toast — нет прогресс-бара и автозакрытия, есть `await`, Esc и клик по оверлею = отмена.
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
import { confirm } from '@1337exp/taoui'
|
|
203
|
+
|
|
204
|
+
if (await confirm().title('Удалить файл?').message('Это нельзя отменить').danger()) {
|
|
205
|
+
remove()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const ok = await confirm('Выйти без сохранения?', {
|
|
209
|
+
ok: 'Выйти',
|
|
210
|
+
cancel: 'Остаться',
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Очередь: второй `confirm()`, пока открыт первый, подождёт. Подписи по умолчанию — «ОК» / «Отмена»:
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
confirm.defaults({ ok: 'Yes', cancel: 'No' })
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Формы
|
|
221
|
+
|
|
222
|
+
`TaoFormField` вешает общий label / hint / error и прокидывает `id` во вложенный контрол.
|
|
223
|
+
|
|
224
|
+
```vue
|
|
225
|
+
<TaoFormField label="Город" hint="Необязательно">
|
|
226
|
+
<TaoSelect v-model="city" :options="cities" />
|
|
227
|
+
</TaoFormField>
|
|
228
|
+
|
|
229
|
+
<TaoSwitch v-model="dark" label="Тёмная тема" />
|
|
230
|
+
|
|
231
|
+
<TaoRadioGroup v-model="plan" legend="Тариф">
|
|
232
|
+
<TaoRadio value="free" label="Free" />
|
|
233
|
+
<TaoRadio value="pro" label="Pro" />
|
|
234
|
+
</TaoRadioGroup>
|
|
235
|
+
|
|
236
|
+
<TaoAlert type="warning" title="Черновик">Сохраните, прежде чем уйти.</TaoAlert>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`TaoSelect` открывается с клавиатуры (стрелки, Enter, Esc), список переворачивается у края экрана. Delete или «Очистить» внизу списка сбрасывает значение в `null`.
|
|
240
|
+
|
|
241
|
+
`TaoCombobox` — то же меню, но с полем. Печатаете — варианты режутся. `allow-create` пишет введённое в `v-model`, если точного совпадения нет. Список сам не меняется: слушайте `create` и добавьте option снаружи.
|
|
242
|
+
|
|
243
|
+
`TaoFormField` также оборачивает `TaoTextarea` и `TaoCheckbox` — id, hint и error прокидываются сами.
|
|
244
|
+
|
|
245
|
+
## Таблица и пагинация
|
|
246
|
+
|
|
247
|
+
Таблица рендерит то, что передали: сама данные не режет и не сортирует. Это удобно и для серверной выборки, и для клиентской — страница режется снаружи.
|
|
248
|
+
|
|
249
|
+
```vue
|
|
250
|
+
<TaoTable
|
|
251
|
+
:columns="columns"
|
|
252
|
+
:rows="pageRows"
|
|
253
|
+
v-model:sort="sort"
|
|
254
|
+
empty-text="Пока нет записей"
|
|
255
|
+
>
|
|
256
|
+
<template #cell-status="{ row }">
|
|
257
|
+
<TaoTag :type="row.status === 'active' ? 'success' : 'neutral'">
|
|
258
|
+
{{ row.status }}
|
|
259
|
+
</TaoTag>
|
|
260
|
+
</template>
|
|
261
|
+
</TaoTable>
|
|
262
|
+
|
|
263
|
+
<TaoPagination v-model:page="page" :total="rows.length" :page-size="8" />
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
const columns = [
|
|
268
|
+
{ key: 'name', label: 'Имя', sortable: true },
|
|
269
|
+
{ key: 'city', label: 'Город' },
|
|
270
|
+
{ key: 'status', label: 'Статус' },
|
|
271
|
+
]
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Слот `cell-<ключ>` перекрывает ячейку. `loading` показывает оверлей, пустой список — текст или слот `#empty`. Клик по шапке с `sortable` крутит `asc → desc → сброс`.
|
|
275
|
+
|
|
276
|
+
## Пустые состояния и загрузка
|
|
277
|
+
|
|
278
|
+
```vue
|
|
279
|
+
<TaoEmpty title="Ничего не нашлось">
|
|
280
|
+
Измените фильтр или сбросьте поиск.
|
|
281
|
+
<template #action>
|
|
282
|
+
<TaoButton variant="secondary">Сбросить</TaoButton>
|
|
283
|
+
</template>
|
|
284
|
+
</TaoEmpty>
|
|
285
|
+
|
|
286
|
+
<TaoSkeleton variant="title" />
|
|
287
|
+
<TaoSkeleton :lines="3" />
|
|
288
|
+
<TaoSkeleton variant="circle" />
|
|
289
|
+
|
|
290
|
+
<TaoStages :items="[
|
|
291
|
+
{ key: 'pay', label: 'Оплата', status: 'ok' },
|
|
292
|
+
{ key: 'pack', label: 'Сборка', status: 'work' },
|
|
293
|
+
{ key: 'ship', label: 'Доставка', status: 'wait' },
|
|
294
|
+
]" />
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
```vue
|
|
298
|
+
<TaoInput v-model="q" placeholder="Найти…">
|
|
299
|
+
<template #prefix>⌕</template>
|
|
300
|
+
</TaoInput>
|
|
301
|
+
|
|
302
|
+
<TaoInputGroup>
|
|
303
|
+
<template #before>https://</template>
|
|
304
|
+
<TaoInput v-model="host" placeholder="example.com" />
|
|
305
|
+
<template #after>
|
|
306
|
+
<TaoButton>Проверить</TaoButton>
|
|
307
|
+
</template>
|
|
308
|
+
</TaoInputGroup>
|
|
309
|
+
|
|
310
|
+
<form @submit.prevent="onSave">
|
|
311
|
+
<TaoFormField label="Email">
|
|
312
|
+
<TaoInput v-model="email" type="email" />
|
|
313
|
+
</TaoFormField>
|
|
314
|
+
<TaoButton type="submit">Сохранить</TaoButton>
|
|
315
|
+
</form>
|
|
316
|
+
|
|
317
|
+
<TaoFormField label="Количество">
|
|
318
|
+
<TaoInputNumber v-model="qty" :min="1" :max="99" />
|
|
319
|
+
</TaoFormField>
|
|
320
|
+
|
|
321
|
+
<TaoQuantity v-model="qty" :max="12" @dec="onDec" />
|
|
322
|
+
|
|
323
|
+
<TaoFormField label="День доставки" hint="В модели всегда YYYY-MM-DD">
|
|
324
|
+
<TaoDate v-model="day" min="2026-09-01" max="2026-09-30" />
|
|
325
|
+
</TaoFormField>
|
|
326
|
+
|
|
327
|
+
<TaoFormField label="Даты поездки">
|
|
328
|
+
<TaoDateRange v-model="stay" min="2026-09-01" max="2026-09-30" />
|
|
329
|
+
</TaoFormField>
|
|
330
|
+
|
|
331
|
+
<TaoCounter :value="score" :max-digits="6" />
|
|
332
|
+
|
|
333
|
+
<TaoCarousel :autoplay="4000" loop dots>
|
|
334
|
+
<article v-for="item in banners" :key="item.id" class="hero">
|
|
335
|
+
<strong>{{ item.title }}</strong>
|
|
336
|
+
<span>{{ item.text }}</span>
|
|
337
|
+
</article>
|
|
338
|
+
</TaoCarousel>
|
|
339
|
+
<TaoCarousel :peek="72" :controls="false" dots>…</TaoCarousel>
|
|
340
|
+
<TaoCarousel v-model="slide" :per-view="5" :peek="28">
|
|
341
|
+
<template #prev></template>
|
|
342
|
+
<template #next="{ go, disabled }">
|
|
343
|
+
<button type="button" :disabled="disabled" @click="go">вперёд</button>
|
|
344
|
+
</template>
|
|
345
|
+
<article v-for="item in products" :key="item.id">…</article>
|
|
346
|
+
</TaoCarousel>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
`TaoDrawer` — лист сбоку, не модалка по центру:
|
|
350
|
+
|
|
351
|
+
```vue
|
|
352
|
+
<TaoDrawer v-model="open" title="Фильтры">
|
|
353
|
+
...
|
|
354
|
+
</TaoDrawer>
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Дизайн-токены и темизация
|
|
358
|
+
|
|
359
|
+
Стили библиотеки построены в три слоя. Компоненты **никогда** не обращаются
|
|
360
|
+
к цветам/размерам напрямую — только через переменные из семантического слоя.
|
|
361
|
+
Это и есть механизм темизации: переопределяете 20-30 переменных — меняется
|
|
362
|
+
внешний вид всех компонентов сразу, без правок самих компонентов.
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
primitives.css → semantic.css → themes/*.css (опционально)
|
|
366
|
+
сырые цвета публичный API готовые темы поверх
|
|
367
|
+
и размеры, темизации: semantic — пример: light
|
|
368
|
+
не трогать вот что менять
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Слои
|
|
372
|
+
|
|
373
|
+
| Файл | Назначение | Трогать? |
|
|
374
|
+
|---|---|---|
|
|
375
|
+
| `primitives.css` | Сырая палитра, шкалы отступов/радиусов/теней (`--tao-orange-400`, `--tao-space-3`...) | Обычно нет |
|
|
376
|
+
| `semantic.css` | Токены темы по умолчанию (dark): `--tao-color-accent`, `--tao-color-surface`, `--tao-color-danger` и т.д. | **Да — это и есть API темизации** |
|
|
377
|
+
| `themes/light.css` | Пример альтернативной темы через `[data-tao-theme="light"]` | Да, как образец |
|
|
378
|
+
| `base.css` | Глобальный reset (скроллбар, ссылки, box-sizing) | Редко |
|
|
379
|
+
|
|
380
|
+
Все четыре подключаются одним файлом `@1337exp/taoui/styles.css`.
|
|
381
|
+
|
|
382
|
+
### Как сделать свою тему
|
|
383
|
+
|
|
384
|
+
Тема — это просто переопределение семантических токенов под своим селектором.
|
|
385
|
+
Ничего в компонентах менять не нужно:
|
|
386
|
+
|
|
387
|
+
```css
|
|
388
|
+
/* my-brand-theme.css */
|
|
389
|
+
[data-tao-theme="my-brand"] {
|
|
390
|
+
--tao-color-accent: #6c5ce7;
|
|
391
|
+
--tao-color-accent-hover: #5a4bd1;
|
|
392
|
+
--tao-color-bg: #0f0f1a;
|
|
393
|
+
--tao-color-surface: #0f0f1a;
|
|
394
|
+
--tao-color-surface-raised: #1a1a2e;
|
|
395
|
+
--tao-color-text: #d6d6e8;
|
|
396
|
+
--tao-color-text-strong: #ffffff;
|
|
397
|
+
/* остальные токены см. semantic.css */
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
```vue
|
|
402
|
+
<!-- app.vue -->
|
|
403
|
+
<template>
|
|
404
|
+
<div data-tao-theme="my-brand">
|
|
405
|
+
<NuxtPage />
|
|
406
|
+
</div>
|
|
407
|
+
</template>
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Или переключайте тему целиком на `<html>`, чтобы стилизовать модалки/тултипы,
|
|
411
|
+
которые телепортируются в `body`:
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
document.documentElement.setAttribute('data-tao-theme', 'light')
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Ключевые группы токенов
|
|
418
|
+
|
|
419
|
+
- `--tao-color-accent*` — акцентный/брендовый цвет (кнопки primary, активные вкладки, ссылки)
|
|
420
|
+
- `--tao-color-on-accent` — текст на акцентном фоне (`--tao-color-text-on-accent` — алиас)
|
|
421
|
+
- `--tao-color-selection`, `--tao-color-selection-text` — выделение текста (`::selection`)
|
|
422
|
+
- `--tao-color-surface*` — фоны контейнеров (обычный / приподнятый / утопленный / hover)
|
|
423
|
+
- `--tao-color-border*` — границы
|
|
424
|
+
- `--tao-color-text*` — текст (обычный / усиленный / приглушённый / disabled)
|
|
425
|
+
- `--tao-color-danger*`, `--tao-color-success*`, `--tao-color-warning*`, `--tao-color-info*` — статусные цвета
|
|
426
|
+
- `--tao-color-input-*` — поля ввода отдельно, т.к. фон/текст полей часто не совпадают с surface/text
|
|
427
|
+
- `--tao-radius-control`, `--tao-radius-panel` — скругления (мелкие контролы vs крупные панели)
|
|
428
|
+
- `--tao-shadow-panel`, `--tao-shadow-overlay` — тени
|
|
429
|
+
|
|
430
|
+
Полный список — в `src/styles/semantic.css`, он же единственный файл,
|
|
431
|
+
который стоит открыть, чтобы понять весь доступный API темизации.
|
|
432
|
+
|
|
433
|
+
### Если нужна тема с нуля, без primitives
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
import '@1337exp/taoui/styles/primitives.css' // шкалы можно оставить
|
|
437
|
+
import './my-semantic.css' // свой семантический слой вместо @1337exp/taoui/styles/semantic.css
|
|
438
|
+
import '@1337exp/taoui/styles/base.css'
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Демонстрация
|
|
442
|
+
|
|
443
|
+
Для просмотра всех компонентов запустите showcase:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
cd showcase
|
|
447
|
+
npm install
|
|
448
|
+
npm run dev
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
В showcase есть переключатель темы (dark / light) в шапке — так виден
|
|
452
|
+
эффект переопределения токенов без правок кода компонентов.
|
|
453
|
+
|
|
454
|
+
Showcase смотрит прямо в `src/`, поэтому правки компонентов видны без
|
|
455
|
+
`npm run build`. Сборка `dist/` нужна для публикации и для чужих проектов,
|
|
456
|
+
которые ставят пакет.
|
|
457
|
+
|
|
458
|
+
## Разработка
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
# Сборка библиотеки
|
|
462
|
+
npm run build
|
|
463
|
+
|
|
464
|
+
# Режим разработки (watch)
|
|
465
|
+
npm run dev
|
|
466
|
+
|
|
467
|
+
# Проверка типов
|
|
468
|
+
npm run type-check
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
## Публикация в npm
|
|
472
|
+
|
|
473
|
+
Публикуется только `dist/` (собранная библиотека) и `src/styles/` (сырые
|
|
474
|
+
токены — чтобы можно было подключить `primitives.css` отдельно при
|
|
475
|
+
кастомной теме). Исходники компонентов (`src/components/*.vue`),
|
|
476
|
+
конфиги сборки и `showcase/` в пакет не попадают — они остаются в
|
|
477
|
+
репозитории; чтобы их получить, репозиторий клонируют.
|
|
478
|
+
|
|
479
|
+
`npm publish` **сам** прогоняет проверку типов и полную пересборку перед
|
|
480
|
+
публикацией (хук `prepublishOnly` в `package.json`) — так в реестр не
|
|
481
|
+
уедет пакет со старым или отсутствующим `dist/`. Собирать вручную перед
|
|
482
|
+
`npm publish` не нужно.
|
|
483
|
+
|
|
484
|
+
Проверить, что именно попадёт в пакет, без реальной публикации:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
npm pack --dry-run
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Лицензия
|
|
491
|
+
|
|
492
|
+
MIT
|