From e6f6bfb06922bdb0cec4336d0226a62324e0e86d Mon Sep 17 00:00:00 2001 From: "e.viskunov@cdek.ru" Date: Wed, 24 Jun 2026 16:42:34 +0700 Subject: [PATCH 1/3] +add tailwind configs build & publishing --- README.md | 42 +++ package-lock.json | 1 + package.json | 3 +- scripts/copy-tailwind-to-dist.mjs | 62 ++++ scripts/generate-tailwind.mjs | 316 +++++++++++++++++++++ src/tailwind/preset.cjs | 452 ++++++++++++++++++++++++++++++ src/tailwind/preset.d.ts | 3 + src/tailwind/theme.css | 401 ++++++++++++++++++++++++++ 8 files changed, 1279 insertions(+), 1 deletion(-) create mode 100644 scripts/copy-tailwind-to-dist.mjs create mode 100644 scripts/generate-tailwind.mjs create mode 100644 src/tailwind/preset.cjs create mode 100644 src/tailwind/preset.d.ts create mode 100644 src/tailwind/theme.css diff --git a/README.md b/README.md index 9eaf1e4d..c0783f00 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,48 @@ import { ExtraButtonComponent, ExtraTagComponent } from '@cdek-it/angular-ui-kit export class AppExample {} ``` +## Tailwind: цвета и тема из кита + +Кит публикует готовую Tailwind-тему, **сгенерированную из своих дизайн-токенов** (`tokens.json` — +тот же источник, что и тема PrimeNG). Это значит: обновили палитру в ките → consumer'у достаточно +bump'нуть версию, чтобы получить новые цвета, согласованные с компонентами `extra-*`. + +Генерация: `npm run generate:tailwind` (входит в `build:lib`). Артефакты: `tailwind/theme.css` +(Tailwind v4 CSS-first `@theme`) и `tailwind/preset.cjs` (JS-пресет). + +### Подключение (новый, простой способ) + +**Tailwind v4 (CSS-first)** — одна строка в `styles.scss`: + +```scss +@use "tailwindcss"; +@use "@cdek-it/angular-ui-kit/tailwind"; +``` + +После этого доступны утилиты, согласованные с китом: `bg-primary`, `text-danger`, `bg-surface-ground`, +`border-surface-border`, `text-text-muted`, `font-heading`, `rounded-200` и т.д. Semantic-цвета +(`primary`, `surface-ground`, `text` и др.) ссылаются на runtime-переменные PrimeNG (`--p-*`) и +**трекают `provideExtraThemes()`**; оттенки палитры — статический слепок (их runtime-имена +нестандартны, поэтому зафиксированы в ките). + +**Tailwind v4 (`@config`) / v3 (JS-пресет)** — `tailwind.config.js`: + +```js +const uiKit = require('@cdek-it/angular-ui-kit/tailwind/preset'); +module.exports = { + presets: [uiKit], + content: ['./index.html', './src/**/*.{html,ts}'], +}; +``` + +### Прежний способ + +Можно не использовать пресет кита и задавать палитру самостоятельно в `tailwind.config.js` / +`styles.scss` (например, мостом legacy-переменных → `--p-*`). Кит ничего не навязывает — +публикация темы **аддитивна**. + +--- + ## Используемые технологии и связанные зависимости --- diff --git a/package-lock.json b/package-lock.json index 5fe8bcf3..f0dafe55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@angular/router": "20.3.15", "@compodoc/compodoc": "1.1.32", "@primeng/themes": "20.4.0", + "@primeuix/themes": "1.2.5", "@storybook/addon-a11y": "10.1.8", "@storybook/addon-docs": "10.1.8", "@storybook/addon-themes": "^10.1.8", diff --git a/package.json b/package.json index 8fa837c7..03ec60af 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "format:check": "prettier --check \"**/*.{js,ts,d.ts}\"", "build:check": "npm run format:check && npm run security:check", "build:storybook": "ng run angular-ui-kit:build-storybook", - "build:lib": "ng build angular-ui-kit-lib", + "build:lib": "ng build angular-ui-kit-lib && npm run generate:tailwind && node scripts/copy-tailwind-to-dist.mjs", + "generate:tailwind": "node scripts/generate-tailwind.mjs", "security:check": "npm audit --production --audit-level high", "copy:dist": "cpx 'src/lib/providers/prime-preset/**/*.{json,ts}' dist/ && cpx 'src-tokens/theme.preset.ts' dist/" }, diff --git a/scripts/copy-tailwind-to-dist.mjs b/scripts/copy-tailwind-to-dist.mjs new file mode 100644 index 00000000..09df6eb7 --- /dev/null +++ b/scripts/copy-tailwind-to-dist.mjs @@ -0,0 +1,62 @@ +/** + * Postbuild: кладёт сгенерированные Tailwind-артефакты в dist/ и патчит dist/package.json, + * чтобы subpath'ы `@cdek-it/angular-ui-kit/tailwind` (CSS) и `/tailwind/preset` (JS) + * резолвились у consumer'а. Запускается в конце `build:lib`. + * + * ng-packagr генерирует `exports`-карту из entry-points и НЕ знает про наши CSS/JS-артефакты; + * без этой правки `exports` заблокировал бы subpath `./tailwind/*` (exports — закрытое множество). + */ +import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..'); +const SRC = resolve(ROOT, 'src/tailwind'); +const DIST = resolve(ROOT, 'dist'); +const DIST_TW = resolve(DIST, 'tailwind'); +const DIST_PKG = resolve(DIST, 'package.json'); + +if (!existsSync(DIST)) { + console.error('✗ dist/ не найден — запустите после `ng build angular-ui-kit-lib`.'); + process.exit(1); +} +if (!existsSync(DIST_PKG)) { + console.error('✗ dist/package.json не найден — ожидается, что его сгенерировал ng-packagr.'); + process.exit(1); +} + +// 1) Копируем артефакты +mkdirSync(DIST_TW, { recursive: true }); +for (const f of ['theme.css', 'preset.cjs', 'preset.d.ts']) { + const from = resolve(SRC, f); + if (!existsSync(from)) { + console.error(`✗ ${from} не найден — выполните \`npm run generate:tailwind\` сначала.`); + process.exit(1); + } + copyFileSync(from, resolve(DIST_TW, f)); +} + +// 2) Патчим dist/package.json: добавляем exports для tailwind subpath'ов +const pkg = JSON.parse(readFileSync(DIST_PKG, 'utf8')); +pkg.exports = pkg.exports || {}; + +const cssEntry = { default: './tailwind/theme.css' }; +pkg.exports['./tailwind'] = cssEntry; +pkg.exports['./tailwind/theme.css'] = cssEntry; +pkg.exports['./tailwind/preset'] = { + types: './tailwind/preset.d.ts', + default: './tailwind/preset.cjs' +}; + +// CSS не должен вырезаться tree-shaking'ом при JS-импорте (для тех, кто импортит css через bundler). +// Sass @use инлайнит CSS на этапе сборки — для основного сценария это не обязательно, но безопасно. +if (pkg.sideEffects === undefined || pkg.sideEffects === false) { + pkg.sideEffects = ['**/*.css']; +} else if (Array.isArray(pkg.sideEffects) && !pkg.sideEffects.some((s) => s.includes('.css'))) { + pkg.sideEffects.push('**/*.css'); +} + +writeFileSync(DIST_PKG, JSON.stringify(pkg, null, 2) + '\n'); + +console.log('✓ dist/tailwind/{theme.css,preset.cjs,preset.d.ts} + exports patched'); diff --git a/scripts/generate-tailwind.mjs b/scripts/generate-tailwind.mjs new file mode 100644 index 00000000..0074b002 --- /dev/null +++ b/scripts/generate-tailwind.mjs @@ -0,0 +1,316 @@ +/** + * Генератор Tailwind-артефактов из дизайн-токенов кита. + * + * Источник правды: src/lib/providers/prime-preset/tokens/tokens.json (тот же, что кормит + * provideExtraThemes() / пресет Aura). На выходе: + * - src/tailwind/theme.css — Tailwind v4 CSS-first (@theme) + * - src/tailwind/preset.cjs — JS-пресет (v4-@config / v3) + * + * Запуск: `npm run generate:tailwind`. Включён в `build:lib`. НЕ правьте сгенерированные файлы руками. + * + * Почему primitive-палитра идёт статическим hex-слепком: у кита она вложена в `colors.solid.*` + * (поверх Aura), поэтому runtime-имена `--p-*` у оттенков нестандартные/непредсказуемые. Только кит + * знает свои токены — поэтому маппинг генерируется здесь, в одном месте. Semantic-токены, напротив, + * имеют стабильные `--p-*` имена → линкуем на runtime-тему (цвет трекает provideExtraThemes). + */ +import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..'); +const TOKENS_PATH = resolve(ROOT, 'src/lib/providers/prime-preset/tokens/tokens.json'); +const OUT_DIR = resolve(ROOT, 'src/tailwind'); + +const tokens = JSON.parse(readFileSync(TOKENS_PATH, 'utf8')); +const primitive = tokens.primitive; +const semantic = tokens.semantic.colorScheme.light; + +const SOLID = primitive.colors.solid; // 22 цвета × 50..950 +const ALPHA = primitive.colors.alpha; // { white, black } × 100..1000 + +const SOLID_ORDER = [ + 'slate', + 'gray', + 'zinc', + 'neutral', + 'stone', + 'red', + 'orange', + 'amber', + 'yellow', + 'lime', + 'green', + 'emerald', + 'teal', + 'cyan', + 'sky', + 'blue', + 'indigo', + 'violet', + 'purple', + 'fuchsia', + 'pink', + 'rose' +]; + +/** Разрешить значение токена: литерал отдаём как есть, "{ref.path}" — раскрываем. */ +function resolveToken(value, scope = tokens) { + if (typeof value !== 'string') return value; + const m = value.match(/^\{(.+)\}$/); + if (!m) return value; + const path = m[1]; + // {colors.solid.green.500} → primitive.colors.solid.green.500 + // {text.color} / {form.borderColor} → semantic.colorScheme.light.* + const solidMatch = path.match(/^colors\.solid\.(.+)$/); + if (solidMatch) { + const [color, shade] = solidMatch[1].split('.'); + return SOLID[color]?.[shade]; + } + const alphaMatch = path.match(/^colors\.alpha\.(.+)$/); + if (alphaMatch) { + const [color, shade] = alphaMatch[1].split('.'); + return ALPHA[color]?.[shade]; + } + const semanticMatch = path.match( + /^(text|form|content|surface|primary|navigation|overlay|highlight|focusRing|mask|list)\.(.+)$/ + ); + if (semanticMatch) { + const obj = walk(semantic[semanticMatch[1]], semanticMatch[2].split('.')); + return typeof obj === 'string' ? resolveToken(obj) : obj; + } + return value; +} + +function walk(obj, keys) { + return keys.reduce((acc, k) => (acc == null ? acc : acc[k]), obj); +} + +function solidHex(color, shade) { + return SOLID[color]?.[shade]; +} + +// ── semantic → линк на runtime --p-* + hex-fallback из tokens.json ────────── +// Имена --p-* — стандартные PrimeNG styled-mode (semantic.* => --p-*, camelCase → kebab). +const SEMANTIC_LINKS = [ + // [tailwind var, runtime --p-* name, fallback hex/value] + ['--color-primary', 'var(--p-primary-color)', solidHex('green', '500')], + ['--color-on-primary', 'var(--p-primary-contrast-color)', ALPHA.white[1000]], + ['--color-primary-hover', 'var(--p-primary-hover-color)', solidHex('green', '600')], + ['--color-primary-active', 'var(--p-primary-active-color)', solidHex('green', '700')], + ['--color-surface-ground', 'var(--p-content-background)', ALPHA.white[1000]], + ['--color-surface-section', 'var(--p-content-hover-background)', solidHex('zinc', '100')], + ['--color-surface-card', 'var(--p-content-background)', ALPHA.white[1000]], + ['--color-surface-overlay', 'var(--p-overlay-background)', ALPHA.white[1000]], + ['--color-surface-border', 'var(--p-content-border-color)', solidHex('zinc', '200')], + ['--color-surface-hover', 'var(--p-content-hover-background)', solidHex('zinc', '100')], + ['--color-text', 'var(--p-text-color)', solidHex('zinc', '900')], + ['--color-text-muted', 'var(--p-text-muted-color)', solidHex('zinc', '500')], + ['--color-text-secondary', 'var(--p-text-secondary-color)', solidHex('zinc', '600')], + ['--color-text-disabled', 'var(--p-text-disabled-color)', solidHex('zinc', '300')], + ['--color-form-border', 'var(--p-form-field-border-color)', solidHex('zinc', '300')], + ['--color-form-bg', 'var(--p-form-field-background)', ALPHA.white[1000]], + ['--color-danger', 'var(--p-text-danger-color)', solidHex('red', '600')], + ['--color-success', 'var(--p-text-success-color)', solidHex('green', '700')], + ['--color-warning', 'var(--p-text-warning-color)', solidHex('yellow', '600')], + ['--color-info', 'var(--p-text-info-color)', solidHex('blue', '600')], + ['--color-help', 'var(--p-text-help-color)', solidHex('purple', '600')] +]; + +// ── service colors: семантика кита → какой solid-цвет несёт полный рейнж ───── +const SERVICE_TO_SOLID = { + danger: 'red', + success: 'green', + warning: 'yellow', + info: 'blue', + help: 'purple' +}; + +// ── fonts / radius ────────────────────────────────────────────────────────── +const FONT_HEADING = primitive.fonts.fontFamily.heading; // 'TT Fellows' +const FONT_BASE = primitive.fonts.fontFamily.base; // 'PT Sans' +const RADIUS = primitive.borderRadius; // {100,200,...,none,max} + +const HEADER = `/** + * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. + * Регенерация: \`npm run generate:tailwind\`. + * + * Tailwind v4 CSS-first тема кита @cdek-it/angular-ui-kit. + * Подключение в проекте: + * @use "tailwindcss"; + * @use "@cdek-it/angular-ui-kit/tailwind"; + * + * Semantic-токены ссылаются на runtime-переменные PrimeNG (--p-*) — цвет трекает + * provideExtraThemes(). Primitive-оттенки — статический слепок палитры кита + * (их runtime-имена --p-* нестандартны, поэтому заморожены здесь). + */ +`; + +// ── theme.css (@theme) ────────────────────────────────────────────────────── +function buildThemeCss() { + const lines = []; + lines.push('@theme {'); + + // semantic links + lines.push(' /* semantic — линк на runtime тему кита (--p-*) + hex-fallback */'); + for (const [twVar, runtime, fallback] of SEMANTIC_LINKS) { + lines.push(` ${twVar}: ${runtime.replace(')', `, ${fallback})`)};`); + } + + // primary = green-палитра (primary кита это green.500). DEFAULT уже задан в semantic-блоке выше. + lines.push(''); + lines.push(' /* primary — фирменный цвет кита (= green-палитра), оттенки */'); + for (const shade of shadesOf('green')) { + lines.push(` --color-primary-${shade}: ${solidHex('green', shade)};`); + } + + // service colors (полные рейнжи) + lines.push(''); + lines.push(' /* service colors (полные рейнжи из палитры кита) */'); + for (const [name, solid] of Object.entries(SERVICE_TO_SOLID)) { + for (const shade of shadesOf(solid)) { + lines.push(` --color-${name}-${shade}: ${solidHex(solid, shade)};`); + } + } + + // surface ramp (zinc + surface.0) + lines.push(''); + lines.push(' /* surface — zinc-палитра + surface.0 (white) */'); + lines.push(` --color-surface-0: ${ALPHA.white[1000]};`); + for (const shade of shadesOf('zinc')) { + lines.push(` --color-surface-${shade}: ${solidHex('zinc', shade)};`); + } + + // вся solid-палитра (22 цвета) + lines.push(''); + lines.push(' /* полная primitive-палитра кита (colors.solid.*) */'); + for (const color of SOLID_ORDER) { + if (!SOLID[color]) continue; + for (const shade of shadesOf(color)) { + lines.push(` --color-${color}-${shade}: ${solidHex(color, shade)};`); + } + } + + // alpha white/black + lines.push(''); + lines.push(' /* alpha white/black (colors.alpha.*) */'); + for (const shade of Object.keys(ALPHA.white)) { + lines.push(` --color-white-${shade === '1000' ? 'DEFAULT' : shade}: ${ALPHA.white[shade]};`); + } + for (const shade of Object.keys(ALPHA.black)) { + lines.push(` --color-black-${shade === '1000' ? 'DEFAULT' : shade}: ${ALPHA.black[shade]};`); + } + + // fonts + lines.push(''); + lines.push(' /* fonts (шрифтовые файлы китом не публикуются — без них fallback) */'); + lines.push(` --font-heading: '${FONT_HEADING}', sans-serif;`); + lines.push(` --font-base: '${FONT_BASE}', sans-serif;`); + + // radius + lines.push(''); + lines.push(' /* border-radius */'); + for (const [k, v] of Object.entries(RADIUS)) { + lines.push(` --radius-${k}: ${v};`); + } + + lines.push('}'); + return lines.join('\n'); +} + +function shadesOf(color) { + return Object.keys(SOLID[color] || {}); +} + +// ── preset.cjs (JS, v4-@config / v3) ──────────────────────────────────────── +function buildPresetCjs() { + // Строим colors-объект для theme.extend.colors + const colors = {}; + + // semantic DEFAULTs + const semanticDefaults = { + primary: `var(--p-primary-color, ${solidHex('green', '500')})`, + 'on-primary': `var(--p-primary-contrast-color, ${ALPHA.white[1000]})`, + 'surface-ground': `var(--p-content-background, ${ALPHA.white[1000]})`, + 'surface-section': `var(--p-content-hover-background, ${solidHex('zinc', '100')})`, + 'surface-card': `var(--p-content-background, ${ALPHA.white[1000]})`, + 'surface-overlay': `var(--p-overlay-background, ${ALPHA.white[1000]})`, + 'surface-border': `var(--p-content-border-color, ${solidHex('zinc', '200')})`, + 'surface-hover': `var(--p-content-hover-background, ${solidHex('zinc', '100')})`, + color: `var(--p-text-color, ${solidHex('zinc', '900')})`, + 'color-muted': `var(--p-text-muted-color, ${solidHex('zinc', '500')})`, + 'color-secondary': `var(--p-text-secondary-color, ${solidHex('zinc', '600')})`, + danger: `var(--p-text-danger-color, ${solidHex('red', '600')})`, + success: `var(--p-text-success-color, ${solidHex('green', '700')})`, + warning: `var(--p-text-warning-color, ${solidHex('yellow', '600')})`, + info: `var(--p-text-info-color, ${solidHex('blue', '600')})`, + help: `var(--p-text-help-color, ${solidHex('purple', '600')})` + }; + Object.assign(colors, semanticDefaults); + + // primary ramp + colors.primary = { DEFAULT: semanticDefaults.primary }; + for (const shade of shadesOf('green')) colors.primary[shade] = solidHex('green', shade); + + // service ramps + for (const [name, solid] of Object.entries(SERVICE_TO_SOLID)) { + colors[name] = {}; + for (const shade of shadesOf(solid)) colors[name][shade] = solidHex(solid, shade); + } + + // surface ramp + colors.surface = { DEFAULT: semanticDefaults['surface-ground'] }; + colors.surface[0] = ALPHA.white[1000]; + for (const shade of shadesOf('zinc')) colors.surface[shade] = solidHex('zinc', shade); + + // full solid palette + for (const color of SOLID_ORDER) { + if (!SOLID[color]) continue; + colors[color] = {}; + for (const shade of shadesOf(color)) colors[color][shade] = solidHex(color, shade); + } + + // white/black + colors.white = { DEFAULT: ALPHA.white[1000] }; + for (const shade of Object.keys(ALPHA.white)) if (shade !== '1000') colors.white[shade] = ALPHA.white[shade]; + colors.black = { DEFAULT: ALPHA.black[1000] }; + for (const shade of Object.keys(ALPHA.black)) if (shade !== '1000') colors.black[shade] = ALPHA.black[shade]; + + const fontFamily = { + heading: [`'${FONT_HEADING}'`, 'sans-serif'], + base: [`'${FONT_BASE}'`, 'sans-serif'] + }; + const borderRadius = {}; + for (const [k, v] of Object.entries(RADIUS)) borderRadius[k === 'none' ? 'none' : k] = v; + + const preset = { + theme: { extend: { colors, fontFamily, borderRadius } } + }; + + return `/** + * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. + * Регенерация: \`npm run generate:tailwind\`. + * + * JS-пресет Tailwind для @cdek-it/angular-ui-kit (v4-@config / v3). + * Подключение в tailwind.config.js: + * const uiKit = require('@cdek-it/angular-ui-kit/tailwind/preset'); + * module.exports = { presets: [uiKit], content: [...] }; + * + * Для v4 CSS-first предпочтительнее theme.css (@use "@cdek-it/angular-ui-kit/tailwind"). + */ +module.exports = ${JSON.stringify(preset, null, 2)}; +`; +} + +// ── write ─────────────────────────────────────────────────────────────────── +mkdirSync(OUT_DIR, { recursive: true }); +const themeCss = `${HEADER}\n${buildThemeCss()}\n`; +const presetCjs = buildPresetCjs(); +writeFileSync(resolve(OUT_DIR, 'theme.css'), themeCss); +writeFileSync(resolve(OUT_DIR, 'preset.cjs'), presetCjs); +writeFileSync( + resolve(OUT_DIR, 'preset.d.ts'), + `import type { Config } from 'tailwindcss';\ndeclare const preset: Pick;\nexport default preset;\n` +); + +console.log('✓ Generated src/tailwind/theme.css, preset.cjs, preset.d.ts'); diff --git a/src/tailwind/preset.cjs b/src/tailwind/preset.cjs new file mode 100644 index 00000000..048a0ca0 --- /dev/null +++ b/src/tailwind/preset.cjs @@ -0,0 +1,452 @@ +/** + * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. + * Регенерация: `npm run generate:tailwind`. + * + * JS-пресет Tailwind для @cdek-it/angular-ui-kit (v4-@config / v3). + * Подключение в tailwind.config.js: + * const uiKit = require('@cdek-it/angular-ui-kit/tailwind/preset'); + * module.exports = { presets: [uiKit], content: [...] }; + * + * Для v4 CSS-first предпочтительнее theme.css (@use "@cdek-it/angular-ui-kit/tailwind"). + */ +module.exports = { + "theme": { + "extend": { + "colors": { + "primary": { + "50": "#fafffb", + "100": "#f0fff3", + "200": "#d4fedc", + "300": "#aafbb7", + "400": "#77f48a", + "500": "#44e858", + "600": "#1dc831", + "700": "#168322", + "800": "#12611b", + "900": "#0e4514", + "950": "#0c3b11", + "DEFAULT": "var(--p-primary-color, #44e858)" + }, + "on-primary": "var(--p-primary-contrast-color, #ffffff)", + "surface-ground": "var(--p-content-background, #ffffff)", + "surface-section": "var(--p-content-hover-background, #f0f0f1)", + "surface-card": "var(--p-content-background, #ffffff)", + "surface-overlay": "var(--p-overlay-background, #ffffff)", + "surface-border": "var(--p-content-border-color, #e2e2e4)", + "surface-hover": "var(--p-content-hover-background, #f0f0f1)", + "color": "var(--p-text-color, #2b2e33)", + "color-muted": "var(--p-text-muted-color, #85888e)", + "color-secondary": "var(--p-text-secondary-color, #6d7076)", + "danger": { + "50": "#fffafa", + "100": "#fff0f0", + "200": "#fed4d4", + "300": "#fbacaa", + "400": "#f47f77", + "500": "#e85244", + "600": "#db3424", + "700": "#8d2218", + "800": "#611912", + "900": "#45120e", + "950": "#3b100c" + }, + "success": { + "50": "#fafffb", + "100": "#f0fff3", + "200": "#d4fedc", + "300": "#aafbb7", + "400": "#77f48a", + "500": "#44e858", + "600": "#1dc831", + "700": "#168322", + "800": "#12611b", + "900": "#0e4514", + "950": "#0c3b11" + }, + "warning": { + "50": "#fffdfa", + "100": "#fff9f0", + "200": "#ffeed4", + "300": "#fddeaa", + "400": "#facb75", + "500": "#f5b83d", + "600": "#dc9710", + "700": "#9d6d0e", + "800": "#6d4c0b", + "900": "#4f3709", + "950": "#453008" + }, + "info": { + "50": "#fafdff", + "100": "#f0f9ff", + "200": "#d4ecfe", + "300": "#aad7fb", + "400": "#77baf4", + "500": "#4496e8", + "600": "#1e76cd", + "700": "#18538d", + "800": "#123a61", + "900": "#0e2a45", + "950": "#0c243b" + }, + "help": { + "50": "#faf5ff", + "100": "#f3e8ff", + "200": "#e9d5ff", + "300": "#d8b4fe", + "400": "#c084fc", + "500": "#a855f7", + "600": "#9333ea", + "700": "#7e22ce", + "800": "#6b21a8", + "900": "#581c87", + "950": "#3b0764" + }, + "surface": { + "0": "#ffffff", + "50": "#fafafa", + "100": "#f0f0f1", + "200": "#e2e2e4", + "300": "#cecfd2", + "400": "#a2a5a9", + "500": "#85888e", + "600": "#6d7076", + "700": "#56595f", + "800": "#404348", + "900": "#2b2e33", + "950": "#181a1f", + "DEFAULT": "var(--p-content-background, #ffffff)" + }, + "slate": { + "50": "#f8fafc", + "100": "#f1f5f9", + "200": "#e2e8f0", + "300": "#cbd5e1", + "400": "#94a3b8", + "500": "#64748b", + "600": "#475569", + "700": "#334155", + "800": "#1e293b", + "900": "#0f172a", + "950": "#020617" + }, + "gray": { + "50": "#f9fafb", + "100": "#f3f4f6", + "200": "#e5e7eb", + "300": "#d1d5db", + "400": "#9ca3af", + "500": "#6b7280", + "600": "#4b5563", + "700": "#374151", + "800": "#1f2937", + "900": "#111827", + "950": "#030712" + }, + "zinc": { + "50": "#fafafa", + "100": "#f0f0f1", + "200": "#e2e2e4", + "300": "#cecfd2", + "400": "#a2a5a9", + "500": "#85888e", + "600": "#6d7076", + "700": "#56595f", + "800": "#404348", + "900": "#2b2e33", + "950": "#181a1f" + }, + "neutral": { + "50": "#fafafa", + "100": "#f5f5f5", + "200": "#e5e5e5", + "300": "#d4d4d4", + "400": "#a3a3a3", + "500": "#737373", + "600": "#525252", + "700": "#404040", + "800": "#262626", + "900": "#171717", + "950": "#0a0a0a" + }, + "stone": { + "50": "#fafaf9", + "100": "#f5f5f4", + "200": "#e7e5e4", + "300": "#d6d3d1", + "400": "#a8a29e", + "500": "#78716c", + "600": "#57534e", + "700": "#44403c", + "800": "#292524", + "900": "#1c1917", + "950": "#0c0a09" + }, + "red": { + "50": "#fffafa", + "100": "#fff0f0", + "200": "#fed4d4", + "300": "#fbacaa", + "400": "#f47f77", + "500": "#e85244", + "600": "#db3424", + "700": "#8d2218", + "800": "#611912", + "900": "#45120e", + "950": "#3b100c" + }, + "orange": { + "50": "#fffbfa", + "100": "#fff3f0", + "200": "#ffddd5", + "300": "#ffbca9", + "400": "#ff9273", + "500": "#fe6434", + "600": "#d53f0b", + "700": "#a83107", + "800": "#752506", + "900": "#561c05", + "950": "#4b1905" + }, + "amber": { + "50": "#fffbeb", + "100": "#fef3c7", + "200": "#fde68a", + "300": "#fcd34d", + "400": "#fbbf24", + "500": "#f59e0b", + "600": "#d97706", + "700": "#b45309", + "800": "#92400e", + "900": "#78350f", + "950": "#451a03" + }, + "yellow": { + "50": "#fffdfa", + "100": "#fff9f0", + "200": "#ffeed4", + "300": "#fddeaa", + "400": "#facb75", + "500": "#f5b83d", + "600": "#dc9710", + "700": "#9d6d0e", + "800": "#6d4c0b", + "900": "#4f3709", + "950": "#453008" + }, + "lime": { + "50": "#f7fee7", + "100": "#ecfccb", + "200": "#d9f99d", + "300": "#bef264", + "400": "#a3e635", + "500": "#84cc16", + "600": "#65a30d", + "700": "#4d7c0f", + "800": "#3f6212", + "900": "#365314", + "950": "#1a2e05" + }, + "green": { + "50": "#fafffb", + "100": "#f0fff3", + "200": "#d4fedc", + "300": "#aafbb7", + "400": "#77f48a", + "500": "#44e858", + "600": "#1dc831", + "700": "#168322", + "800": "#12611b", + "900": "#0e4514", + "950": "#0c3b11" + }, + "emerald": { + "50": "#ecfdf5", + "100": "#d1fae5", + "200": "#a7f3d0", + "300": "#6ee7b7", + "400": "#34d399", + "500": "#10b981", + "600": "#059669", + "700": "#047857", + "800": "#065f46", + "900": "#064e3b", + "950": "#022c22" + }, + "teal": { + "50": "#f0fdfa", + "100": "#ccfbf1", + "200": "#99f6e4", + "300": "#5eead4", + "400": "#2dd4bf", + "500": "#14b8a6", + "600": "#0d9488", + "700": "#0f766e", + "800": "#115e59", + "900": "#134e4a", + "950": "#042f2e" + }, + "cyan": { + "50": "#ecfeff", + "100": "#cffafe", + "200": "#a5f3fc", + "300": "#67e8f9", + "400": "#22d3ee", + "500": "#06b6d4", + "600": "#0891b2", + "700": "#0e7490", + "800": "#155e75", + "900": "#164e63", + "950": "#013138" + }, + "sky": { + "50": "#f0f9ff", + "100": "#e0f2fe", + "200": "#bae6fd", + "300": "#7dd3fc", + "400": "#38bdf8", + "500": "#0ea5e9", + "600": "#0284c7", + "700": "#0369a1", + "800": "#075985", + "900": "#0c4a6e", + "950": "#082f49" + }, + "blue": { + "50": "#fafdff", + "100": "#f0f9ff", + "200": "#d4ecfe", + "300": "#aad7fb", + "400": "#77baf4", + "500": "#4496e8", + "600": "#1e76cd", + "700": "#18538d", + "800": "#123a61", + "900": "#0e2a45", + "950": "#0c243b" + }, + "indigo": { + "50": "#eef2ff", + "100": "#e0e7ff", + "200": "#c7d2fe", + "300": "#a5b4fc", + "400": "#818cf8", + "500": "#6366f1", + "600": "#4f46e5", + "700": "#4338ca", + "800": "#3730a3", + "900": "#312e81", + "950": "#1e1b4b" + }, + "violet": { + "50": "#fcfaff", + "100": "#f6f0ff", + "200": "#e5d4fe", + "300": "#cbaafb", + "400": "#b284f5", + "500": "#a265ec", + "600": "#9457ea", + "700": "#48188d", + "800": "#321261", + "900": "#240e45", + "950": "#1f0c3b" + }, + "purple": { + "50": "#faf5ff", + "100": "#f3e8ff", + "200": "#e9d5ff", + "300": "#d8b4fe", + "400": "#c084fc", + "500": "#a855f7", + "600": "#9333ea", + "700": "#7e22ce", + "800": "#6b21a8", + "900": "#581c87", + "950": "#3b0764" + }, + "fuchsia": { + "50": "#fdf4ff", + "100": "#fae8ff", + "200": "#f5d0fe", + "300": "#f0abfc", + "400": "#e879f9", + "500": "#d946ef", + "600": "#c026d3", + "700": "#a21caf", + "800": "#86198f", + "900": "#701a75", + "950": "#4a044e" + }, + "pink": { + "50": "#fdf2f8", + "100": "#fce7f3", + "200": "#fbcfe8", + "300": "#f9a8d4", + "400": "#f472b6", + "500": "#ec4899", + "600": "#db2777", + "700": "#be185d", + "800": "#9d174d", + "900": "#831843", + "950": "#500724" + }, + "rose": { + "50": "#fff1f2", + "100": "#ffe4e6", + "200": "#fecdd3", + "300": "#fda4af", + "400": "#fb7185", + "500": "#f43f5e", + "600": "#e11d48", + "700": "#be123c", + "800": "#9f1239", + "900": "#881337", + "950": "#4c0519" + }, + "white": { + "100": "rgba(255, 255, 255, 0.1000)", + "200": "rgba(255, 255, 255, 0.2000)", + "300": "rgba(255, 255, 255, 0.3000)", + "400": "rgba(255, 255, 255, 0.4000)", + "500": "rgba(255, 255, 255, 0.5000)", + "600": "rgba(255, 255, 255, 0.6000)", + "700": "rgba(255, 255, 255, 0.7000)", + "800": "rgba(255, 255, 255, 0.8000)", + "900": "rgba(255, 255, 255, 0.9000)", + "DEFAULT": "#ffffff" + }, + "black": { + "100": "rgba(0, 0, 0, 0.1000)", + "200": "rgba(0, 0, 0, 0.2000)", + "300": "rgba(0, 0, 0, 0.3000)", + "400": "rgba(0, 0, 0, 0.4000)", + "500": "rgba(0, 0, 0, 0.5000)", + "600": "rgba(0, 0, 0, 0.6000)", + "700": "rgba(0, 0, 0, 0.7000)", + "800": "rgba(0, 0, 0, 0.8000)", + "900": "rgba(0, 0, 0, 0.9000)", + "DEFAULT": "#000000" + } + }, + "fontFamily": { + "heading": [ + "'TT Fellows'", + "sans-serif" + ], + "base": [ + "'PT Sans'", + "sans-serif" + ] + }, + "borderRadius": { + "100": "0.25rem", + "200": "0.5rem", + "300": "0.75rem", + "400": "1rem", + "500": "1.5rem", + "none": "0rem", + "max": "71.3571rem" + } + } + } +}; diff --git a/src/tailwind/preset.d.ts b/src/tailwind/preset.d.ts new file mode 100644 index 00000000..af6315c5 --- /dev/null +++ b/src/tailwind/preset.d.ts @@ -0,0 +1,3 @@ +import type { Config } from 'tailwindcss'; +declare const preset: Pick; +export default preset; diff --git a/src/tailwind/theme.css b/src/tailwind/theme.css new file mode 100644 index 00000000..f2146b33 --- /dev/null +++ b/src/tailwind/theme.css @@ -0,0 +1,401 @@ +/** + * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. + * Регенерация: `npm run generate:tailwind`. + * + * Tailwind v4 CSS-first тема кита @cdek-it/angular-ui-kit. + * Подключение в проекте: + * @use "tailwindcss"; + * @use "@cdek-it/angular-ui-kit/tailwind"; + * + * Semantic-токены ссылаются на runtime-переменные PrimeNG (--p-*) — цвет трекает + * provideExtraThemes(). Primitive-оттенки — статический слепок палитры кита + * (их runtime-имена --p-* нестандартны, поэтому заморожены здесь). + */ + +@theme { + /* semantic — линк на runtime тему кита (--p-*) + hex-fallback */ + --color-primary: var(--p-primary-color, #44e858); + --color-on-primary: var(--p-primary-contrast-color, #ffffff); + --color-primary-hover: var(--p-primary-hover-color, #1dc831); + --color-primary-active: var(--p-primary-active-color, #168322); + --color-surface-ground: var(--p-content-background, #ffffff); + --color-surface-section: var(--p-content-hover-background, #f0f0f1); + --color-surface-card: var(--p-content-background, #ffffff); + --color-surface-overlay: var(--p-overlay-background, #ffffff); + --color-surface-border: var(--p-content-border-color, #e2e2e4); + --color-surface-hover: var(--p-content-hover-background, #f0f0f1); + --color-text: var(--p-text-color, #2b2e33); + --color-text-muted: var(--p-text-muted-color, #85888e); + --color-text-secondary: var(--p-text-secondary-color, #6d7076); + --color-text-disabled: var(--p-text-disabled-color, #cecfd2); + --color-form-border: var(--p-form-field-border-color, #cecfd2); + --color-form-bg: var(--p-form-field-background, #ffffff); + --color-danger: var(--p-text-danger-color, #db3424); + --color-success: var(--p-text-success-color, #168322); + --color-warning: var(--p-text-warning-color, #dc9710); + --color-info: var(--p-text-info-color, #1e76cd); + --color-help: var(--p-text-help-color, #9333ea); + + /* primary — фирменный цвет кита (= green-палитра), оттенки */ + --color-primary-50: #fafffb; + --color-primary-100: #f0fff3; + --color-primary-200: #d4fedc; + --color-primary-300: #aafbb7; + --color-primary-400: #77f48a; + --color-primary-500: #44e858; + --color-primary-600: #1dc831; + --color-primary-700: #168322; + --color-primary-800: #12611b; + --color-primary-900: #0e4514; + --color-primary-950: #0c3b11; + + /* service colors (полные рейнжи из палитры кита) */ + --color-danger-50: #fffafa; + --color-danger-100: #fff0f0; + --color-danger-200: #fed4d4; + --color-danger-300: #fbacaa; + --color-danger-400: #f47f77; + --color-danger-500: #e85244; + --color-danger-600: #db3424; + --color-danger-700: #8d2218; + --color-danger-800: #611912; + --color-danger-900: #45120e; + --color-danger-950: #3b100c; + --color-success-50: #fafffb; + --color-success-100: #f0fff3; + --color-success-200: #d4fedc; + --color-success-300: #aafbb7; + --color-success-400: #77f48a; + --color-success-500: #44e858; + --color-success-600: #1dc831; + --color-success-700: #168322; + --color-success-800: #12611b; + --color-success-900: #0e4514; + --color-success-950: #0c3b11; + --color-warning-50: #fffdfa; + --color-warning-100: #fff9f0; + --color-warning-200: #ffeed4; + --color-warning-300: #fddeaa; + --color-warning-400: #facb75; + --color-warning-500: #f5b83d; + --color-warning-600: #dc9710; + --color-warning-700: #9d6d0e; + --color-warning-800: #6d4c0b; + --color-warning-900: #4f3709; + --color-warning-950: #453008; + --color-info-50: #fafdff; + --color-info-100: #f0f9ff; + --color-info-200: #d4ecfe; + --color-info-300: #aad7fb; + --color-info-400: #77baf4; + --color-info-500: #4496e8; + --color-info-600: #1e76cd; + --color-info-700: #18538d; + --color-info-800: #123a61; + --color-info-900: #0e2a45; + --color-info-950: #0c243b; + --color-help-50: #faf5ff; + --color-help-100: #f3e8ff; + --color-help-200: #e9d5ff; + --color-help-300: #d8b4fe; + --color-help-400: #c084fc; + --color-help-500: #a855f7; + --color-help-600: #9333ea; + --color-help-700: #7e22ce; + --color-help-800: #6b21a8; + --color-help-900: #581c87; + --color-help-950: #3b0764; + + /* surface — zinc-палитра + surface.0 (white) */ + --color-surface-0: #ffffff; + --color-surface-50: #fafafa; + --color-surface-100: #f0f0f1; + --color-surface-200: #e2e2e4; + --color-surface-300: #cecfd2; + --color-surface-400: #a2a5a9; + --color-surface-500: #85888e; + --color-surface-600: #6d7076; + --color-surface-700: #56595f; + --color-surface-800: #404348; + --color-surface-900: #2b2e33; + --color-surface-950: #181a1f; + + /* полная primitive-палитра кита (colors.solid.*) */ + --color-slate-50: #f8fafc; + --color-slate-100: #f1f5f9; + --color-slate-200: #e2e8f0; + --color-slate-300: #cbd5e1; + --color-slate-400: #94a3b8; + --color-slate-500: #64748b; + --color-slate-600: #475569; + --color-slate-700: #334155; + --color-slate-800: #1e293b; + --color-slate-900: #0f172a; + --color-slate-950: #020617; + --color-gray-50: #f9fafb; + --color-gray-100: #f3f4f6; + --color-gray-200: #e5e7eb; + --color-gray-300: #d1d5db; + --color-gray-400: #9ca3af; + --color-gray-500: #6b7280; + --color-gray-600: #4b5563; + --color-gray-700: #374151; + --color-gray-800: #1f2937; + --color-gray-900: #111827; + --color-gray-950: #030712; + --color-zinc-50: #fafafa; + --color-zinc-100: #f0f0f1; + --color-zinc-200: #e2e2e4; + --color-zinc-300: #cecfd2; + --color-zinc-400: #a2a5a9; + --color-zinc-500: #85888e; + --color-zinc-600: #6d7076; + --color-zinc-700: #56595f; + --color-zinc-800: #404348; + --color-zinc-900: #2b2e33; + --color-zinc-950: #181a1f; + --color-neutral-50: #fafafa; + --color-neutral-100: #f5f5f5; + --color-neutral-200: #e5e5e5; + --color-neutral-300: #d4d4d4; + --color-neutral-400: #a3a3a3; + --color-neutral-500: #737373; + --color-neutral-600: #525252; + --color-neutral-700: #404040; + --color-neutral-800: #262626; + --color-neutral-900: #171717; + --color-neutral-950: #0a0a0a; + --color-stone-50: #fafaf9; + --color-stone-100: #f5f5f4; + --color-stone-200: #e7e5e4; + --color-stone-300: #d6d3d1; + --color-stone-400: #a8a29e; + --color-stone-500: #78716c; + --color-stone-600: #57534e; + --color-stone-700: #44403c; + --color-stone-800: #292524; + --color-stone-900: #1c1917; + --color-stone-950: #0c0a09; + --color-red-50: #fffafa; + --color-red-100: #fff0f0; + --color-red-200: #fed4d4; + --color-red-300: #fbacaa; + --color-red-400: #f47f77; + --color-red-500: #e85244; + --color-red-600: #db3424; + --color-red-700: #8d2218; + --color-red-800: #611912; + --color-red-900: #45120e; + --color-red-950: #3b100c; + --color-orange-50: #fffbfa; + --color-orange-100: #fff3f0; + --color-orange-200: #ffddd5; + --color-orange-300: #ffbca9; + --color-orange-400: #ff9273; + --color-orange-500: #fe6434; + --color-orange-600: #d53f0b; + --color-orange-700: #a83107; + --color-orange-800: #752506; + --color-orange-900: #561c05; + --color-orange-950: #4b1905; + --color-amber-50: #fffbeb; + --color-amber-100: #fef3c7; + --color-amber-200: #fde68a; + --color-amber-300: #fcd34d; + --color-amber-400: #fbbf24; + --color-amber-500: #f59e0b; + --color-amber-600: #d97706; + --color-amber-700: #b45309; + --color-amber-800: #92400e; + --color-amber-900: #78350f; + --color-amber-950: #451a03; + --color-yellow-50: #fffdfa; + --color-yellow-100: #fff9f0; + --color-yellow-200: #ffeed4; + --color-yellow-300: #fddeaa; + --color-yellow-400: #facb75; + --color-yellow-500: #f5b83d; + --color-yellow-600: #dc9710; + --color-yellow-700: #9d6d0e; + --color-yellow-800: #6d4c0b; + --color-yellow-900: #4f3709; + --color-yellow-950: #453008; + --color-lime-50: #f7fee7; + --color-lime-100: #ecfccb; + --color-lime-200: #d9f99d; + --color-lime-300: #bef264; + --color-lime-400: #a3e635; + --color-lime-500: #84cc16; + --color-lime-600: #65a30d; + --color-lime-700: #4d7c0f; + --color-lime-800: #3f6212; + --color-lime-900: #365314; + --color-lime-950: #1a2e05; + --color-green-50: #fafffb; + --color-green-100: #f0fff3; + --color-green-200: #d4fedc; + --color-green-300: #aafbb7; + --color-green-400: #77f48a; + --color-green-500: #44e858; + --color-green-600: #1dc831; + --color-green-700: #168322; + --color-green-800: #12611b; + --color-green-900: #0e4514; + --color-green-950: #0c3b11; + --color-emerald-50: #ecfdf5; + --color-emerald-100: #d1fae5; + --color-emerald-200: #a7f3d0; + --color-emerald-300: #6ee7b7; + --color-emerald-400: #34d399; + --color-emerald-500: #10b981; + --color-emerald-600: #059669; + --color-emerald-700: #047857; + --color-emerald-800: #065f46; + --color-emerald-900: #064e3b; + --color-emerald-950: #022c22; + --color-teal-50: #f0fdfa; + --color-teal-100: #ccfbf1; + --color-teal-200: #99f6e4; + --color-teal-300: #5eead4; + --color-teal-400: #2dd4bf; + --color-teal-500: #14b8a6; + --color-teal-600: #0d9488; + --color-teal-700: #0f766e; + --color-teal-800: #115e59; + --color-teal-900: #134e4a; + --color-teal-950: #042f2e; + --color-cyan-50: #ecfeff; + --color-cyan-100: #cffafe; + --color-cyan-200: #a5f3fc; + --color-cyan-300: #67e8f9; + --color-cyan-400: #22d3ee; + --color-cyan-500: #06b6d4; + --color-cyan-600: #0891b2; + --color-cyan-700: #0e7490; + --color-cyan-800: #155e75; + --color-cyan-900: #164e63; + --color-cyan-950: #013138; + --color-sky-50: #f0f9ff; + --color-sky-100: #e0f2fe; + --color-sky-200: #bae6fd; + --color-sky-300: #7dd3fc; + --color-sky-400: #38bdf8; + --color-sky-500: #0ea5e9; + --color-sky-600: #0284c7; + --color-sky-700: #0369a1; + --color-sky-800: #075985; + --color-sky-900: #0c4a6e; + --color-sky-950: #082f49; + --color-blue-50: #fafdff; + --color-blue-100: #f0f9ff; + --color-blue-200: #d4ecfe; + --color-blue-300: #aad7fb; + --color-blue-400: #77baf4; + --color-blue-500: #4496e8; + --color-blue-600: #1e76cd; + --color-blue-700: #18538d; + --color-blue-800: #123a61; + --color-blue-900: #0e2a45; + --color-blue-950: #0c243b; + --color-indigo-50: #eef2ff; + --color-indigo-100: #e0e7ff; + --color-indigo-200: #c7d2fe; + --color-indigo-300: #a5b4fc; + --color-indigo-400: #818cf8; + --color-indigo-500: #6366f1; + --color-indigo-600: #4f46e5; + --color-indigo-700: #4338ca; + --color-indigo-800: #3730a3; + --color-indigo-900: #312e81; + --color-indigo-950: #1e1b4b; + --color-violet-50: #fcfaff; + --color-violet-100: #f6f0ff; + --color-violet-200: #e5d4fe; + --color-violet-300: #cbaafb; + --color-violet-400: #b284f5; + --color-violet-500: #a265ec; + --color-violet-600: #9457ea; + --color-violet-700: #48188d; + --color-violet-800: #321261; + --color-violet-900: #240e45; + --color-violet-950: #1f0c3b; + --color-purple-50: #faf5ff; + --color-purple-100: #f3e8ff; + --color-purple-200: #e9d5ff; + --color-purple-300: #d8b4fe; + --color-purple-400: #c084fc; + --color-purple-500: #a855f7; + --color-purple-600: #9333ea; + --color-purple-700: #7e22ce; + --color-purple-800: #6b21a8; + --color-purple-900: #581c87; + --color-purple-950: #3b0764; + --color-fuchsia-50: #fdf4ff; + --color-fuchsia-100: #fae8ff; + --color-fuchsia-200: #f5d0fe; + --color-fuchsia-300: #f0abfc; + --color-fuchsia-400: #e879f9; + --color-fuchsia-500: #d946ef; + --color-fuchsia-600: #c026d3; + --color-fuchsia-700: #a21caf; + --color-fuchsia-800: #86198f; + --color-fuchsia-900: #701a75; + --color-fuchsia-950: #4a044e; + --color-pink-50: #fdf2f8; + --color-pink-100: #fce7f3; + --color-pink-200: #fbcfe8; + --color-pink-300: #f9a8d4; + --color-pink-400: #f472b6; + --color-pink-500: #ec4899; + --color-pink-600: #db2777; + --color-pink-700: #be185d; + --color-pink-800: #9d174d; + --color-pink-900: #831843; + --color-pink-950: #500724; + --color-rose-50: #fff1f2; + --color-rose-100: #ffe4e6; + --color-rose-200: #fecdd3; + --color-rose-300: #fda4af; + --color-rose-400: #fb7185; + --color-rose-500: #f43f5e; + --color-rose-600: #e11d48; + --color-rose-700: #be123c; + --color-rose-800: #9f1239; + --color-rose-900: #881337; + --color-rose-950: #4c0519; + + /* alpha white/black (colors.alpha.*) */ + --color-white-100: rgba(255, 255, 255, 0.1000); + --color-white-200: rgba(255, 255, 255, 0.2000); + --color-white-300: rgba(255, 255, 255, 0.3000); + --color-white-400: rgba(255, 255, 255, 0.4000); + --color-white-500: rgba(255, 255, 255, 0.5000); + --color-white-600: rgba(255, 255, 255, 0.6000); + --color-white-700: rgba(255, 255, 255, 0.7000); + --color-white-800: rgba(255, 255, 255, 0.8000); + --color-white-900: rgba(255, 255, 255, 0.9000); + --color-white-DEFAULT: #ffffff; + --color-black-100: rgba(0, 0, 0, 0.1000); + --color-black-200: rgba(0, 0, 0, 0.2000); + --color-black-300: rgba(0, 0, 0, 0.3000); + --color-black-400: rgba(0, 0, 0, 0.4000); + --color-black-500: rgba(0, 0, 0, 0.5000); + --color-black-600: rgba(0, 0, 0, 0.6000); + --color-black-700: rgba(0, 0, 0, 0.7000); + --color-black-800: rgba(0, 0, 0, 0.8000); + --color-black-900: rgba(0, 0, 0, 0.9000); + --color-black-DEFAULT: #000000; + + /* fonts (шрифтовые файлы китом не публикуются — без них fallback) */ + --font-heading: 'TT Fellows', sans-serif; + --font-base: 'PT Sans', sans-serif; + + /* border-radius */ + --radius-100: 0.25rem; + --radius-200: 0.5rem; + --radius-300: 0.75rem; + --radius-400: 1rem; + --radius-500: 1.5rem; + --radius-none: 0rem; + --radius-max: 71.3571rem; +} From f1284d35ce3f906b711cf91980195301d92222e2 Mon Sep 17 00:00:00 2001 From: "e.viskunov@cdek.ru" Date: Thu, 25 Jun 2026 12:10:19 +0700 Subject: [PATCH 2/3] ~fix --- README.md | 63 +- package-lock.json | 1055 ++++++++++++++++------------- package.json | 4 +- postcss.config.js | 8 +- scripts/copy-tailwind-to-dist.mjs | 22 +- scripts/generate-tailwind.mjs | 158 ++--- src/styles.scss | 7 +- src/tailwind/preset.cjs | 452 ------------ src/tailwind/preset.d.ts | 3 - src/tailwind/theme.css | 53 ++ tailwind.config.js | 162 ----- 11 files changed, 766 insertions(+), 1221 deletions(-) delete mode 100644 src/tailwind/preset.cjs delete mode 100644 src/tailwind/preset.d.ts delete mode 100644 tailwind.config.js diff --git a/README.md b/README.md index c0783f00..1ec27c03 100644 --- a/README.md +++ b/README.md @@ -70,45 +70,60 @@ import { ExtraButtonComponent, ExtraTagComponent } from '@cdek-it/angular-ui-kit export class AppExample {} ``` -## Tailwind: цвета и тема из кита +## Tailwind v4: вся дизайн-система из кита -Кит публикует готовую Tailwind-тему, **сгенерированную из своих дизайн-токенов** (`tokens.json` — -тот же источник, что и тема PrimeNG). Это значит: обновили палитру в ките → consumer'у достаточно -bump'нуть версию, чтобы получить новые цвета, согласованные с компонентами `extra-*`. +Кит публикует готовую **Tailwind v4 CSS-first тему** (`@theme`), **полностью сгенерированную из +своих дизайн-токенов** (`tokens.json` — тот же источник, что и тема PrimeNG). Это единая точка +истины: поменяли токен в ките → consumer'у достаточно bump'нуть версию, чтобы получить обновление, +согласованное с компонентами `extra-*`. Никаких JS-пресетов/`@config`/v3 — только v4 CSS-first. -Генерация: `npm run generate:tailwind` (входит в `build:lib`). Артефакты: `tailwind/theme.css` -(Tailwind v4 CSS-first `@theme`) и `tailwind/preset.cjs` (JS-пресет). +Генерация: `npm run generate:tailwind` (входит в `build:lib`). Артефакт: `tailwind/theme.css`. -### Подключение (новый, простой способ) +### Подключение (одна строка) -**Tailwind v4 (CSS-first)** — одна строка в `styles.scss`: +В `styles.scss` проекта: ```scss @use "tailwindcss"; @use "@cdek-it/angular-ui-kit/tailwind"; ``` -После этого доступны утилиты, согласованные с китом: `bg-primary`, `text-danger`, `bg-surface-ground`, -`border-surface-border`, `text-text-muted`, `font-heading`, `rounded-200` и т.д. Semantic-цвета -(`primary`, `surface-ground`, `text` и др.) ссылаются на runtime-переменные PrimeNG (`--p-*`) и -**трекают `provideExtraThemes()`**; оттенки палитры — статический слепок (их runtime-имена +### Что отдаёт кит (утилиты из токенов) + +| Namespace | Токены | Утилиты | +|---|---|---| +| colors | палитра + semantic | `bg-primary`, `text-danger`, `bg-surface-ground`, `border-surface-border`, `text-zinc-500`, … | +| fonts | `fontFamily` | `font-heading` (TT Fellows), `font-base` (PT Sans) | +| font-weight | `fontWeight` | `font-regular/medium/demibold/bold` | +| text (font-size) | `fontSize` | `text-100…text-1000` | +| leading (line-height) | `lineHeight` | `leading-100…leading-1000`, `leading-auto` | +| radius | `borderRadius` | `rounded-100…rounded-500`, `rounded-none`, `rounded-max` | +| shadow | `shadows` | `shadow-100…shadow-500`, `shadow-none` | +| ease | `transition.easing` | `ease-in/out/inOut` (плюс дефолтный `ease-linear`) | +| spacing | `spacing["1x"]` | одна ручка `--spacing` (множитель); из неё v4 выводит `p/m/w/h/gap/inset/space/translate` | + +Semantic-цвета (`primary`, `surface-ground`, `text`, …) ссылаются на runtime-переменные PrimeNG +(`--p-*`) и **трекают `provideExtraThemes()`**; оттенки палитры — статический слепок (их runtime-имена нестандартны, поэтому зафиксированы в ките). -**Tailwind v4 (`@config`) / v3 (JS-пресет)** — `tailwind.config.js`: +> Не вошли в `@theme` (нет v4-namespace): `sizing`, `borderWidth` (только `--default-border-width`), +> `opacity`, `transition.duration`. Для них — дефолты v4 или произвольные значения +> (`border-[3px]`, `w-[15rem]`, `opacity-[.25]`). -```js -const uiKit = require('@cdek-it/angular-ui-kit/tailwind/preset'); -module.exports = { - presets: [uiKit], - content: ['./index.html', './src/**/*.{html,ts}'], -}; -``` +### Кастомизация (без болей) — локальный `@theme` поверх -### Прежний способ +```scss +@use "tailwindcss"; +@use "@cdek-it/angular-ui-kit/tailwind"; -Можно не использовать пресет кита и задавать палитру самостоятельно в `tailwind.config.js` / -`styles.scss` (например, мостом legacy-переменных → `--p-*`). Кит ничего не навязывает — -публикация темы **аддитивна**. +@theme { + --color-primary: #ff0000; /* перебить */ + --color-brand: #123456; /* добавить */ + --breakpoint-xs: 480px; /* расширить */ +} +``` +v4 мержит `@theme`-блоки (last-wins) — конфликта нет, кит править не нужно. Разделение: кит владеет +дизайн-токенами, проект — build-конфигом (`content`-сканирование в v4 автоматическое, плагины через `@plugin`). --- diff --git a/package-lock.json b/package-lock.json index f0dafe55..cd52793f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,9 +37,9 @@ "@storybook/addon-themes": "^10.1.8", "@storybook/angular": "10.1.8", "@tabler/icons-webfont": "3.35.0", + "@tailwindcss/postcss": "4.3.1", "@types/jasmine": "5.1.13", "@typescript-eslint/eslint-plugin": "7.18.0", - "autoprefixer": "10.4.22", "eslint": "8.57.1", "eslint-config-prettier": "9.1.2", "eslint-plugin-import": "2.32.0", @@ -57,7 +57,7 @@ "primeng": "20.4.0", "rxjs": "7.8.2", "storybook": "10.1.8", - "tailwindcss": "3.4.19", + "tailwindcss": "4.3.1", "tslib": "2.8.1", "typescript": "5.9.3", "zone.js": "0.15.1" @@ -6994,6 +6994,326 @@ "url": "https://github.com/sponsors/codecalm" } }, + "node_modules/@tailwindcss/node": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", + "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.1" + } + }, + "node_modules/@tailwindcss/node/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@tailwindcss/node/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", + "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-x64": "4.3.1", + "@tailwindcss/oxide-freebsd-x64": "4.3.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-x64-musl": "4.3.1", + "@tailwindcss/oxide-wasm32-wasi": "4.3.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", + "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", + "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", + "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", + "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", + "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", + "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", + "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", + "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", + "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", + "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", + "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", + "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.1.tgz", + "integrity": "sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.1", + "@tailwindcss/oxide": "4.3.1", + "postcss": "8.5.15", + "tailwindcss": "4.3.1" + } + }, + "node_modules/@tailwindcss/postcss/node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/@testing-library/dom": { "version": "10.4.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", @@ -8503,13 +8823,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -8570,13 +8883,6 @@ "node": ">=14" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "license": "MIT" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -8838,44 +9144,6 @@ "node": ">= 4.5.0" } }, - "node_modules/autoprefixer": { - "version": "10.4.22", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz", - "integrity": "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.27.0", - "caniuse-lite": "^1.0.30001754", - "fraction.js": "^5.3.4", - "normalize-range": "^0.1.2", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -9516,16 +9784,6 @@ "tslib": "^2.0.3" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001760", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", @@ -11401,13 +11659,6 @@ "dev": true, "license": "MIT" }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -11421,13 +11672,6 @@ "node": ">=8" } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "license": "MIT" - }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -11790,14 +12034,14 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.4", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", - "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" @@ -13534,20 +13778,6 @@ "node": ">= 0.6" } }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -16478,17 +16708,265 @@ } } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, "engines": { - "node": ">=14" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/antonk52" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/lines-and-columns": { @@ -17633,18 +18111,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/nan": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.24.0.tgz", @@ -17653,9 +18119,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", "dev": true, "funding": [ { @@ -18288,16 +18754,6 @@ "dev": true, "license": "MIT" }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -19238,26 +19694,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/piscina": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.3.tgz", @@ -19356,93 +19792,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, "node_modules/postcss-loader": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", @@ -19545,46 +19894,6 @@ "postcss": "^8.1.0" } }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-nested/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss-selector-parser": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", @@ -19932,16 +20241,6 @@ "license": "MIT", "peer": true }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -22489,39 +22788,6 @@ "minimist": "^1.1.0" } }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -22566,125 +22832,16 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tailwindcss/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tailwindcss/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tailwindcss/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", + "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } + "license": "MIT" }, "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -22871,29 +23028,6 @@ "dev": true, "license": "MIT" }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/thingies": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", @@ -23131,13 +23265,6 @@ "node": ">=6.10" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/ts-morph": { "version": "27.0.2", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-27.0.2.tgz", diff --git a/package.json b/package.json index 03ec60af..88fdf39a 100644 --- a/package.json +++ b/package.json @@ -51,9 +51,9 @@ "@storybook/addon-themes": "^10.1.8", "@storybook/angular": "10.1.8", "@tabler/icons-webfont": "3.35.0", + "@tailwindcss/postcss": "4.3.1", "@types/jasmine": "5.1.13", "@typescript-eslint/eslint-plugin": "7.18.0", - "autoprefixer": "10.4.22", "eslint": "8.57.1", "eslint-config-prettier": "9.1.2", "eslint-plugin-import": "2.32.0", @@ -72,7 +72,7 @@ "primeng": "20.4.0", "rxjs": "7.8.2", "storybook": "10.1.8", - "tailwindcss": "3.4.19", + "tailwindcss": "4.3.1", "tslib": "2.8.1", "typescript": "5.9.3", "zone.js": "0.15.1" diff --git a/postcss.config.js b/postcss.config.js index 67cdf1a5..390440a8 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,6 @@ +// Tailwind v4: движок + autoprefixer встроены в @tailwindcss/postcss. module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, + plugins: { + '@tailwindcss/postcss': {} + } }; diff --git a/scripts/copy-tailwind-to-dist.mjs b/scripts/copy-tailwind-to-dist.mjs index 09df6eb7..b2750253 100644 --- a/scripts/copy-tailwind-to-dist.mjs +++ b/scripts/copy-tailwind-to-dist.mjs @@ -26,28 +26,22 @@ if (!existsSync(DIST_PKG)) { process.exit(1); } -// 1) Копируем артефакты +// 1) Копируем артефакт (чистый v4 — только theme.css) mkdirSync(DIST_TW, { recursive: true }); -for (const f of ['theme.css', 'preset.cjs', 'preset.d.ts']) { - const from = resolve(SRC, f); - if (!existsSync(from)) { - console.error(`✗ ${from} не найден — выполните \`npm run generate:tailwind\` сначала.`); - process.exit(1); - } - copyFileSync(from, resolve(DIST_TW, f)); +const from = resolve(SRC, 'theme.css'); +if (!existsSync(from)) { + console.error(`✗ ${from} не найден — выполните \`npm run generate:tailwind\` сначала.`); + process.exit(1); } +copyFileSync(from, resolve(DIST_TW, 'theme.css')); -// 2) Патчим dist/package.json: добавляем exports для tailwind subpath'ов +// 2) Патчим dist/package.json: exports для tailwind subpath'ов (v4 CSS-first only) const pkg = JSON.parse(readFileSync(DIST_PKG, 'utf8')); pkg.exports = pkg.exports || {}; const cssEntry = { default: './tailwind/theme.css' }; pkg.exports['./tailwind'] = cssEntry; pkg.exports['./tailwind/theme.css'] = cssEntry; -pkg.exports['./tailwind/preset'] = { - types: './tailwind/preset.d.ts', - default: './tailwind/preset.cjs' -}; // CSS не должен вырезаться tree-shaking'ом при JS-импорте (для тех, кто импортит css через bundler). // Sass @use инлайнит CSS на этапе сборки — для основного сценария это не обязательно, но безопасно. @@ -59,4 +53,4 @@ if (pkg.sideEffects === undefined || pkg.sideEffects === false) { writeFileSync(DIST_PKG, JSON.stringify(pkg, null, 2) + '\n'); -console.log('✓ dist/tailwind/{theme.css,preset.cjs,preset.d.ts} + exports patched'); +console.log('✓ dist/tailwind/theme.css + exports patched'); diff --git a/scripts/generate-tailwind.mjs b/scripts/generate-tailwind.mjs index 0074b002..9007a743 100644 --- a/scripts/generate-tailwind.mjs +++ b/scripts/generate-tailwind.mjs @@ -1,12 +1,17 @@ /** - * Генератор Tailwind-артефактов из дизайн-токенов кита. + * Генератор Tailwind-темы кита (v4 CSS-first, @theme) из дизайн-токенов. * * Источник правды: src/lib/providers/prime-preset/tokens/tokens.json (тот же, что кормит - * provideExtraThemes() / пресет Aura). На выходе: - * - src/tailwind/theme.css — Tailwind v4 CSS-first (@theme) - * - src/tailwind/preset.cjs — JS-пресет (v4-@config / v3) + * provideExtraThemes() / пресет Aura). На выходе — src/tailwind/theme.css (@theme). + * Чистый v4: никакого JS-пресета/@config/v3. * - * Запуск: `npm run generate:tailwind`. Включён в `build:lib`. НЕ правьте сгенерированные файлы руками. + * Запуск: `npm run generate:tailwind`. Включён в `build:lib`. НЕ правьте сгенерированный файл руками. + * + * Что маппится в v4-namespace'ы (@theme → утилиты): colors (--color-*), fonts (--font-*), + * font-weight (--font-weight-*), font-size (--text-*), line-height (--leading-*), + * border-radius (--radius-*), shadow (--shadow-*), transition-easing (--ease-*). + * НЕ маппится (нет v4-namespace, либо одиночный множитель): spacing (= v4 --spacing, 0.25rem), + * sizing, border-width (только --default-border-width), opacity, transition-duration. * * Почему primitive-палитра идёт статическим hex-слепком: у кита она вложена в `colors.solid.*` * (поверх Aura), поэтому runtime-имена `--p-*` у оттенков нестандартные/непредсказуемые. Только кит @@ -90,6 +95,18 @@ function solidHex(color, shade) { return SOLID[color]?.[shade]; } +/** + * Разрешить все "{ref}" внутри строки (инлайн, напр. shadow "0 0 0.1rem {colors.alpha.black.200}"). + * Целостный "{...}" значения тоже раскрывает. Нераспознанные ref оставляет как есть. + */ +function resolveInline(value) { + if (typeof value !== 'string') return value; + return value.replace(/\{([^}]+)\}/g, (_m, path) => { + const resolved = resolveToken(`{${path}}`); + return resolved === `{${path}}` ? `{${path}}` : String(resolved); + }); +} + // ── semantic → линк на runtime --p-* + hex-fallback из tokens.json ────────── // Имена --p-* — стандартные PrimeNG styled-mode (semantic.* => --p-*, camelCase → kebab). const SEMANTIC_LINKS = [ @@ -126,10 +143,18 @@ const SERVICE_TO_SOLID = { help: 'purple' }; -// ── fonts / radius ────────────────────────────────────────────────────────── +// ── fonts / type / radius / shadow / easing / spacing ─────────────────────── const FONT_HEADING = primitive.fonts.fontFamily.heading; // 'TT Fellows' const FONT_BASE = primitive.fonts.fontFamily.base; // 'PT Sans' +const FONT_WEIGHT = primitive.fonts.fontWeight; // {regular,medium,demibold,bold} +const FONT_SIZE = primitive.fonts.fontSize; // {100..1000} +const LINE_HEIGHT = primitive.fonts.lineHeight; // {100..1000, auto} const RADIUS = primitive.borderRadius; // {100,200,...,none,max} +const SHADOWS = primitive.shadows; // {100..500, none} (со ссылками на alpha-цвета) +const EASING = primitive.transition.easing; // {linear, in, out, inOut} +// spacing: v4 отдаёт под spacing ОДНУ ручку --spacing (множитель). Базовый шаг кита — +// primitive.spacing["1x"] (= 0.25rem); вся шкала (p/m/w/h/gap/inset/...) выводится v4 как calc(var(--spacing)*N). +const SPACING_STEP = primitive.spacing['1x']; const HEADER = `/** * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. @@ -206,6 +231,20 @@ function buildThemeCss() { lines.push(' /* fonts (шрифтовые файлы китом не публикуются — без них fallback) */'); lines.push(` --font-heading: '${FONT_HEADING}', sans-serif;`); lines.push(` --font-base: '${FONT_BASE}', sans-serif;`); + lines.push(' /* font-weight (utilities: font-regular/medium/demibold/bold) */'); + for (const [k, v] of Object.entries(FONT_WEIGHT)) { + lines.push(` --font-weight-${k}: ${v};`); + } + + // type scale: font-size (--text-*) + line-height (--leading-*) + lines.push(''); + lines.push(' /* font-size (--text-*), line-height (--leading-*) из типошкалы кита */'); + for (const [k, v] of Object.entries(FONT_SIZE)) { + lines.push(` --text-${k}: ${v};`); + } + for (const [k, v] of Object.entries(LINE_HEIGHT)) { + lines.push(` --leading-${k}: ${v};`); + } // radius lines.push(''); @@ -214,103 +253,36 @@ function buildThemeCss() { lines.push(` --radius-${k}: ${v};`); } - lines.push('}'); - return lines.join('\n'); -} - -function shadesOf(color) { - return Object.keys(SOLID[color] || {}); -} - -// ── preset.cjs (JS, v4-@config / v3) ──────────────────────────────────────── -function buildPresetCjs() { - // Строим colors-объект для theme.extend.colors - const colors = {}; - - // semantic DEFAULTs - const semanticDefaults = { - primary: `var(--p-primary-color, ${solidHex('green', '500')})`, - 'on-primary': `var(--p-primary-contrast-color, ${ALPHA.white[1000]})`, - 'surface-ground': `var(--p-content-background, ${ALPHA.white[1000]})`, - 'surface-section': `var(--p-content-hover-background, ${solidHex('zinc', '100')})`, - 'surface-card': `var(--p-content-background, ${ALPHA.white[1000]})`, - 'surface-overlay': `var(--p-overlay-background, ${ALPHA.white[1000]})`, - 'surface-border': `var(--p-content-border-color, ${solidHex('zinc', '200')})`, - 'surface-hover': `var(--p-content-hover-background, ${solidHex('zinc', '100')})`, - color: `var(--p-text-color, ${solidHex('zinc', '900')})`, - 'color-muted': `var(--p-text-muted-color, ${solidHex('zinc', '500')})`, - 'color-secondary': `var(--p-text-secondary-color, ${solidHex('zinc', '600')})`, - danger: `var(--p-text-danger-color, ${solidHex('red', '600')})`, - success: `var(--p-text-success-color, ${solidHex('green', '700')})`, - warning: `var(--p-text-warning-color, ${solidHex('yellow', '600')})`, - info: `var(--p-text-info-color, ${solidHex('blue', '600')})`, - help: `var(--p-text-help-color, ${solidHex('purple', '600')})` - }; - Object.assign(colors, semanticDefaults); - - // primary ramp - colors.primary = { DEFAULT: semanticDefaults.primary }; - for (const shade of shadesOf('green')) colors.primary[shade] = solidHex('green', shade); + // spacing — единственная ручка v4; из неё выводятся p/m/w/h/gap/inset/space/translate. + lines.push(''); + lines.push(' /* spacing: множитель для p/m/w/h/gap/inset/… (v4: calc(var(--spacing)*N)) */'); + lines.push(` --spacing: ${SPACING_STEP};`); - // service ramps - for (const [name, solid] of Object.entries(SERVICE_TO_SOLID)) { - colors[name] = {}; - for (const shade of shadesOf(solid)) colors[name][shade] = solidHex(solid, shade); + // shadows (со ссылками на alpha-цвета раскрываем инлайн) + lines.push(''); + lines.push(' /* shadows (box-shadow, {colors.alpha.*} раскрыты) */'); + for (const [k, v] of Object.entries(SHADOWS)) { + lines.push(` --shadow-${k}: ${resolveInline(v)};`); } - // surface ramp - colors.surface = { DEFAULT: semanticDefaults['surface-ground'] }; - colors.surface[0] = ALPHA.white[1000]; - for (const shade of shadesOf('zinc')) colors.surface[shade] = solidHex('zinc', shade); - - // full solid palette - for (const color of SOLID_ORDER) { - if (!SOLID[color]) continue; - colors[color] = {}; - for (const shade of shadesOf(color)) colors[color][shade] = solidHex(color, shade); + // easing + lines.push(''); + lines.push(' /* transition easing (--ease-*) */'); + for (const [k, v] of Object.entries(EASING)) { + lines.push(` --ease-${k}: ${v};`); } - // white/black - colors.white = { DEFAULT: ALPHA.white[1000] }; - for (const shade of Object.keys(ALPHA.white)) if (shade !== '1000') colors.white[shade] = ALPHA.white[shade]; - colors.black = { DEFAULT: ALPHA.black[1000] }; - for (const shade of Object.keys(ALPHA.black)) if (shade !== '1000') colors.black[shade] = ALPHA.black[shade]; - - const fontFamily = { - heading: [`'${FONT_HEADING}'`, 'sans-serif'], - base: [`'${FONT_BASE}'`, 'sans-serif'] - }; - const borderRadius = {}; - for (const [k, v] of Object.entries(RADIUS)) borderRadius[k === 'none' ? 'none' : k] = v; - - const preset = { - theme: { extend: { colors, fontFamily, borderRadius } } - }; + lines.push('}'); + return lines.join('\n'); +} - return `/** - * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. - * Регенерация: \`npm run generate:tailwind\`. - * - * JS-пресет Tailwind для @cdek-it/angular-ui-kit (v4-@config / v3). - * Подключение в tailwind.config.js: - * const uiKit = require('@cdek-it/angular-ui-kit/tailwind/preset'); - * module.exports = { presets: [uiKit], content: [...] }; - * - * Для v4 CSS-first предпочтительнее theme.css (@use "@cdek-it/angular-ui-kit/tailwind"). - */ -module.exports = ${JSON.stringify(preset, null, 2)}; -`; +function shadesOf(color) { + return Object.keys(SOLID[color] || {}); } // ── write ─────────────────────────────────────────────────────────────────── mkdirSync(OUT_DIR, { recursive: true }); const themeCss = `${HEADER}\n${buildThemeCss()}\n`; -const presetCjs = buildPresetCjs(); writeFileSync(resolve(OUT_DIR, 'theme.css'), themeCss); -writeFileSync(resolve(OUT_DIR, 'preset.cjs'), presetCjs); -writeFileSync( - resolve(OUT_DIR, 'preset.d.ts'), - `import type { Config } from 'tailwindcss';\ndeclare const preset: Pick;\nexport default preset;\n` -); -console.log('✓ Generated src/tailwind/theme.css, preset.cjs, preset.d.ts'); +console.log('✓ Generated src/tailwind/theme.css'); diff --git a/src/styles.scss b/src/styles.scss index 9449e0df..5dfda6dd 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,6 +1,7 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +// Tailwind v4 CSS-first. Демо/бин кита «ест свой корм»: тема (цвета/типографика/radius/тени/easing) +// берётся из собственного сгенерированного @theme — того же, что кит публикует consumer'ам. +@use 'tailwindcss'; +@use '@cdek-it/angular-ui-kit/tailwind'; @import '@tabler/icons-webfont/dist/tabler-icons.min.css'; diff --git a/src/tailwind/preset.cjs b/src/tailwind/preset.cjs deleted file mode 100644 index 048a0ca0..00000000 --- a/src/tailwind/preset.cjs +++ /dev/null @@ -1,452 +0,0 @@ -/** - * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. - * Регенерация: `npm run generate:tailwind`. - * - * JS-пресет Tailwind для @cdek-it/angular-ui-kit (v4-@config / v3). - * Подключение в tailwind.config.js: - * const uiKit = require('@cdek-it/angular-ui-kit/tailwind/preset'); - * module.exports = { presets: [uiKit], content: [...] }; - * - * Для v4 CSS-first предпочтительнее theme.css (@use "@cdek-it/angular-ui-kit/tailwind"). - */ -module.exports = { - "theme": { - "extend": { - "colors": { - "primary": { - "50": "#fafffb", - "100": "#f0fff3", - "200": "#d4fedc", - "300": "#aafbb7", - "400": "#77f48a", - "500": "#44e858", - "600": "#1dc831", - "700": "#168322", - "800": "#12611b", - "900": "#0e4514", - "950": "#0c3b11", - "DEFAULT": "var(--p-primary-color, #44e858)" - }, - "on-primary": "var(--p-primary-contrast-color, #ffffff)", - "surface-ground": "var(--p-content-background, #ffffff)", - "surface-section": "var(--p-content-hover-background, #f0f0f1)", - "surface-card": "var(--p-content-background, #ffffff)", - "surface-overlay": "var(--p-overlay-background, #ffffff)", - "surface-border": "var(--p-content-border-color, #e2e2e4)", - "surface-hover": "var(--p-content-hover-background, #f0f0f1)", - "color": "var(--p-text-color, #2b2e33)", - "color-muted": "var(--p-text-muted-color, #85888e)", - "color-secondary": "var(--p-text-secondary-color, #6d7076)", - "danger": { - "50": "#fffafa", - "100": "#fff0f0", - "200": "#fed4d4", - "300": "#fbacaa", - "400": "#f47f77", - "500": "#e85244", - "600": "#db3424", - "700": "#8d2218", - "800": "#611912", - "900": "#45120e", - "950": "#3b100c" - }, - "success": { - "50": "#fafffb", - "100": "#f0fff3", - "200": "#d4fedc", - "300": "#aafbb7", - "400": "#77f48a", - "500": "#44e858", - "600": "#1dc831", - "700": "#168322", - "800": "#12611b", - "900": "#0e4514", - "950": "#0c3b11" - }, - "warning": { - "50": "#fffdfa", - "100": "#fff9f0", - "200": "#ffeed4", - "300": "#fddeaa", - "400": "#facb75", - "500": "#f5b83d", - "600": "#dc9710", - "700": "#9d6d0e", - "800": "#6d4c0b", - "900": "#4f3709", - "950": "#453008" - }, - "info": { - "50": "#fafdff", - "100": "#f0f9ff", - "200": "#d4ecfe", - "300": "#aad7fb", - "400": "#77baf4", - "500": "#4496e8", - "600": "#1e76cd", - "700": "#18538d", - "800": "#123a61", - "900": "#0e2a45", - "950": "#0c243b" - }, - "help": { - "50": "#faf5ff", - "100": "#f3e8ff", - "200": "#e9d5ff", - "300": "#d8b4fe", - "400": "#c084fc", - "500": "#a855f7", - "600": "#9333ea", - "700": "#7e22ce", - "800": "#6b21a8", - "900": "#581c87", - "950": "#3b0764" - }, - "surface": { - "0": "#ffffff", - "50": "#fafafa", - "100": "#f0f0f1", - "200": "#e2e2e4", - "300": "#cecfd2", - "400": "#a2a5a9", - "500": "#85888e", - "600": "#6d7076", - "700": "#56595f", - "800": "#404348", - "900": "#2b2e33", - "950": "#181a1f", - "DEFAULT": "var(--p-content-background, #ffffff)" - }, - "slate": { - "50": "#f8fafc", - "100": "#f1f5f9", - "200": "#e2e8f0", - "300": "#cbd5e1", - "400": "#94a3b8", - "500": "#64748b", - "600": "#475569", - "700": "#334155", - "800": "#1e293b", - "900": "#0f172a", - "950": "#020617" - }, - "gray": { - "50": "#f9fafb", - "100": "#f3f4f6", - "200": "#e5e7eb", - "300": "#d1d5db", - "400": "#9ca3af", - "500": "#6b7280", - "600": "#4b5563", - "700": "#374151", - "800": "#1f2937", - "900": "#111827", - "950": "#030712" - }, - "zinc": { - "50": "#fafafa", - "100": "#f0f0f1", - "200": "#e2e2e4", - "300": "#cecfd2", - "400": "#a2a5a9", - "500": "#85888e", - "600": "#6d7076", - "700": "#56595f", - "800": "#404348", - "900": "#2b2e33", - "950": "#181a1f" - }, - "neutral": { - "50": "#fafafa", - "100": "#f5f5f5", - "200": "#e5e5e5", - "300": "#d4d4d4", - "400": "#a3a3a3", - "500": "#737373", - "600": "#525252", - "700": "#404040", - "800": "#262626", - "900": "#171717", - "950": "#0a0a0a" - }, - "stone": { - "50": "#fafaf9", - "100": "#f5f5f4", - "200": "#e7e5e4", - "300": "#d6d3d1", - "400": "#a8a29e", - "500": "#78716c", - "600": "#57534e", - "700": "#44403c", - "800": "#292524", - "900": "#1c1917", - "950": "#0c0a09" - }, - "red": { - "50": "#fffafa", - "100": "#fff0f0", - "200": "#fed4d4", - "300": "#fbacaa", - "400": "#f47f77", - "500": "#e85244", - "600": "#db3424", - "700": "#8d2218", - "800": "#611912", - "900": "#45120e", - "950": "#3b100c" - }, - "orange": { - "50": "#fffbfa", - "100": "#fff3f0", - "200": "#ffddd5", - "300": "#ffbca9", - "400": "#ff9273", - "500": "#fe6434", - "600": "#d53f0b", - "700": "#a83107", - "800": "#752506", - "900": "#561c05", - "950": "#4b1905" - }, - "amber": { - "50": "#fffbeb", - "100": "#fef3c7", - "200": "#fde68a", - "300": "#fcd34d", - "400": "#fbbf24", - "500": "#f59e0b", - "600": "#d97706", - "700": "#b45309", - "800": "#92400e", - "900": "#78350f", - "950": "#451a03" - }, - "yellow": { - "50": "#fffdfa", - "100": "#fff9f0", - "200": "#ffeed4", - "300": "#fddeaa", - "400": "#facb75", - "500": "#f5b83d", - "600": "#dc9710", - "700": "#9d6d0e", - "800": "#6d4c0b", - "900": "#4f3709", - "950": "#453008" - }, - "lime": { - "50": "#f7fee7", - "100": "#ecfccb", - "200": "#d9f99d", - "300": "#bef264", - "400": "#a3e635", - "500": "#84cc16", - "600": "#65a30d", - "700": "#4d7c0f", - "800": "#3f6212", - "900": "#365314", - "950": "#1a2e05" - }, - "green": { - "50": "#fafffb", - "100": "#f0fff3", - "200": "#d4fedc", - "300": "#aafbb7", - "400": "#77f48a", - "500": "#44e858", - "600": "#1dc831", - "700": "#168322", - "800": "#12611b", - "900": "#0e4514", - "950": "#0c3b11" - }, - "emerald": { - "50": "#ecfdf5", - "100": "#d1fae5", - "200": "#a7f3d0", - "300": "#6ee7b7", - "400": "#34d399", - "500": "#10b981", - "600": "#059669", - "700": "#047857", - "800": "#065f46", - "900": "#064e3b", - "950": "#022c22" - }, - "teal": { - "50": "#f0fdfa", - "100": "#ccfbf1", - "200": "#99f6e4", - "300": "#5eead4", - "400": "#2dd4bf", - "500": "#14b8a6", - "600": "#0d9488", - "700": "#0f766e", - "800": "#115e59", - "900": "#134e4a", - "950": "#042f2e" - }, - "cyan": { - "50": "#ecfeff", - "100": "#cffafe", - "200": "#a5f3fc", - "300": "#67e8f9", - "400": "#22d3ee", - "500": "#06b6d4", - "600": "#0891b2", - "700": "#0e7490", - "800": "#155e75", - "900": "#164e63", - "950": "#013138" - }, - "sky": { - "50": "#f0f9ff", - "100": "#e0f2fe", - "200": "#bae6fd", - "300": "#7dd3fc", - "400": "#38bdf8", - "500": "#0ea5e9", - "600": "#0284c7", - "700": "#0369a1", - "800": "#075985", - "900": "#0c4a6e", - "950": "#082f49" - }, - "blue": { - "50": "#fafdff", - "100": "#f0f9ff", - "200": "#d4ecfe", - "300": "#aad7fb", - "400": "#77baf4", - "500": "#4496e8", - "600": "#1e76cd", - "700": "#18538d", - "800": "#123a61", - "900": "#0e2a45", - "950": "#0c243b" - }, - "indigo": { - "50": "#eef2ff", - "100": "#e0e7ff", - "200": "#c7d2fe", - "300": "#a5b4fc", - "400": "#818cf8", - "500": "#6366f1", - "600": "#4f46e5", - "700": "#4338ca", - "800": "#3730a3", - "900": "#312e81", - "950": "#1e1b4b" - }, - "violet": { - "50": "#fcfaff", - "100": "#f6f0ff", - "200": "#e5d4fe", - "300": "#cbaafb", - "400": "#b284f5", - "500": "#a265ec", - "600": "#9457ea", - "700": "#48188d", - "800": "#321261", - "900": "#240e45", - "950": "#1f0c3b" - }, - "purple": { - "50": "#faf5ff", - "100": "#f3e8ff", - "200": "#e9d5ff", - "300": "#d8b4fe", - "400": "#c084fc", - "500": "#a855f7", - "600": "#9333ea", - "700": "#7e22ce", - "800": "#6b21a8", - "900": "#581c87", - "950": "#3b0764" - }, - "fuchsia": { - "50": "#fdf4ff", - "100": "#fae8ff", - "200": "#f5d0fe", - "300": "#f0abfc", - "400": "#e879f9", - "500": "#d946ef", - "600": "#c026d3", - "700": "#a21caf", - "800": "#86198f", - "900": "#701a75", - "950": "#4a044e" - }, - "pink": { - "50": "#fdf2f8", - "100": "#fce7f3", - "200": "#fbcfe8", - "300": "#f9a8d4", - "400": "#f472b6", - "500": "#ec4899", - "600": "#db2777", - "700": "#be185d", - "800": "#9d174d", - "900": "#831843", - "950": "#500724" - }, - "rose": { - "50": "#fff1f2", - "100": "#ffe4e6", - "200": "#fecdd3", - "300": "#fda4af", - "400": "#fb7185", - "500": "#f43f5e", - "600": "#e11d48", - "700": "#be123c", - "800": "#9f1239", - "900": "#881337", - "950": "#4c0519" - }, - "white": { - "100": "rgba(255, 255, 255, 0.1000)", - "200": "rgba(255, 255, 255, 0.2000)", - "300": "rgba(255, 255, 255, 0.3000)", - "400": "rgba(255, 255, 255, 0.4000)", - "500": "rgba(255, 255, 255, 0.5000)", - "600": "rgba(255, 255, 255, 0.6000)", - "700": "rgba(255, 255, 255, 0.7000)", - "800": "rgba(255, 255, 255, 0.8000)", - "900": "rgba(255, 255, 255, 0.9000)", - "DEFAULT": "#ffffff" - }, - "black": { - "100": "rgba(0, 0, 0, 0.1000)", - "200": "rgba(0, 0, 0, 0.2000)", - "300": "rgba(0, 0, 0, 0.3000)", - "400": "rgba(0, 0, 0, 0.4000)", - "500": "rgba(0, 0, 0, 0.5000)", - "600": "rgba(0, 0, 0, 0.6000)", - "700": "rgba(0, 0, 0, 0.7000)", - "800": "rgba(0, 0, 0, 0.8000)", - "900": "rgba(0, 0, 0, 0.9000)", - "DEFAULT": "#000000" - } - }, - "fontFamily": { - "heading": [ - "'TT Fellows'", - "sans-serif" - ], - "base": [ - "'PT Sans'", - "sans-serif" - ] - }, - "borderRadius": { - "100": "0.25rem", - "200": "0.5rem", - "300": "0.75rem", - "400": "1rem", - "500": "1.5rem", - "none": "0rem", - "max": "71.3571rem" - } - } - } -}; diff --git a/src/tailwind/preset.d.ts b/src/tailwind/preset.d.ts deleted file mode 100644 index af6315c5..00000000 --- a/src/tailwind/preset.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { Config } from 'tailwindcss'; -declare const preset: Pick; -export default preset; diff --git a/src/tailwind/theme.css b/src/tailwind/theme.css index f2146b33..f15ef3fc 100644 --- a/src/tailwind/theme.css +++ b/src/tailwind/theme.css @@ -389,6 +389,42 @@ /* fonts (шрифтовые файлы китом не публикуются — без них fallback) */ --font-heading: 'TT Fellows', sans-serif; --font-base: 'PT Sans', sans-serif; + /* font-weight (utilities: font-regular/medium/demibold/bold) */ + --font-weight-regular: 400; + --font-weight-medium: 500; + --font-weight-demibold: 600; + --font-weight-bold: 700; + + /* font-size (--text-*), line-height (--leading-*) из типошкалы кита */ + --text-100: 0.75rem; + --text-200: 0.875rem; + --text-300: 1rem; + --text-400: 1.125rem; + --text-500: 1.25rem; + --text-600: 1.5rem; + --text-650: 1.875rem; + --text-700: 2.25rem; + --text-750: 3rem; + --text-800: 3.75rem; + --text-900: 4.5rem; + --text-1000: 6rem; + --leading-100: 0.7857rem; + --leading-150: 0.8571rem; + --leading-200: 0.9286rem; + --leading-250: 1rem; + --leading-300: 1.0714rem; + --leading-350: 1.1429rem; + --leading-400: 1.2857rem; + --leading-450: 1.4286rem; + --leading-500: 1.5rem; + --leading-550: 1.5714rem; + --leading-600: 1.7143rem; + --leading-700: 1.8571rem; + --leading-800: 2.2857rem; + --leading-850: 2.3571rem; + --leading-900: 2.7857rem; + --leading-1000: 3.3571rem; + --leading-auto: auto; /* border-radius */ --radius-100: 0.25rem; @@ -398,4 +434,21 @@ --radius-500: 1.5rem; --radius-none: 0rem; --radius-max: 71.3571rem; + + /* spacing: множитель для p/m/w/h/gap/inset/… (v4: calc(var(--spacing)*N)) */ + --spacing: 0.25rem; + + /* shadows (box-shadow, {colors.alpha.*} раскрыты) */ + --shadow-100: 0 0 0.1rem rgba(0, 0, 0, 0.2000); + --shadow-200: 0 0 0.25rem rgba(0, 0, 0, 0.2000); + --shadow-300: 0 0.1rem 0.25rem rgba(0, 0, 0, 0.2000); + --shadow-400: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.2000); + --shadow-500: 0 0.5rem 1rem 0 rgba(0, 0, 0, 0.2000); + --shadow-none: none; + + /* transition easing (--ease-*) */ + --ease-linear: linear; + --ease-in: cubic-bezier(0.55, 0.06, 0.7, 0.2); + --ease-out: cubic-bezier(0.2, 0.6, 0.4, 1); + --ease-inOut: cubic-bezier(0.65, 0.05, 0.35, 1); } diff --git a/tailwind.config.js b/tailwind.config.js deleted file mode 100644 index 5ca81c64..00000000 --- a/tailwind.config.js +++ /dev/null @@ -1,162 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -const generateColor = (color, arr) => { - return arr.reduce((res, value) => { - res[value] = `var(--${color}-${value})`; - return res; - }, {}); -}; -const arr_10_100 = [100, 90, 80, 70, 60, 50, 40, 30, 20, 10]; -// const arr_50_950 = [ 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950 ]; -const arr_0_900 = [0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900]; -const arr_0_900_alpha = [...arr_0_900, 'alpha']; - -export default { - content: ['./src/**/*.{js,ts,html}', './primeng-sass-theme/themes/base/_styles-tailwind.scss'], - theme: { - screens: { - sm: '1px', - md: '768px', - lg: '1200px', - xl: '1280px', - '2xl': '1536px' - }, - extend: { - fontFamily: { - roboto: ['Roboto', 'sans-serif'], - sans: ['Roboto', 'sans-serif'] - }, - colors: { - // Common - current: 'currentColor', - transparent: 'transparent', - // Primary - primary: { - ...generateColor('primary', arr_0_900_alpha), - DEFAULT: 'var(--primary-color)' - }, - // Service - danger: 'var(--red-400)', - warning: 'var(--orange-400)', - success: 'var(--green-400)', - info: 'var(--blue-400)', - help: 'var(--purple-400)', - // Neutrals - white: { - ...generateColor('white', arr_10_100), - DEFAULT: 'var(--white-100)' - }, - black: { - ...generateColor('black', arr_10_100), - DEFAULT: 'var(--black-100)' - }, - //Surface - surface: { - ...generateColor('surface', arr_0_900), - ground: 'var(--surface-ground)', - section: 'var(--surface-section)', - card: 'var(--surface-card)', - overlay: 'var(--surface-overlay)', - border: 'var(--surface-border)', - hover: 'var(--surface-hover)', - transparent: 'transparent' // rgba(255, 255, 255, 0.0001) - в фигме нет transparent, это костыль на нее - }, - // Text - color: 'var(--text-color)', - 'color-secondary': 'var(--text-color-secondary)', - 'color-primary': 'var(--primary-color-text)' - }, - lineHeight: { - DEFAULT: 'normal', - auto: '1.2' - }, - borderRadius: { - kit: 'var(--border-radius)' - }, - borderWidth: { - 1: '1px', - 2: '2px', - 3: '3px' - }, - width: { - 1: '1rem', - 2: '2rem', - 3: '3rem', - 4: '4rem', - 5: '5rem', - 6: '6rem', - 7: '7rem', - 8: '8rem', - 9: '9rem', - 10: '10rem', - 11: '11rem', - 12: '12rem', - 13: '13rem', - 14: '14rem', - 15: '15rem', - 16: '16rem', - 17: '17rem', - 18: '18rem', - 19: '19rem', - 20: '20rem', - 21: '21rem', - 22: '22rem', - 23: '23rem', - 24: '24rem', - 25: '25rem', - 26: '26rem', - 27: '27rem', - 28: '28rem', - 29: '29rem', - 30: '30rem', - 34: '34rem', - 45: '45rem', - 50: '50rem', - 54: '54rem', - 58: '58rem', - 60: '60rem' - }, - height: { - 1: '1rem', - 2: '2rem', - 3: '3rem', - 4: '4rem', - 5: '5rem', - 6: '6rem', - 7: '7rem', - 8: '8rem', - 9: '9rem', - 10: '10rem', - 11: '11rem', - 12: '12rem', - 13: '13rem', - 14: '14rem', - 15: '15rem', - 16: '16rem', - 17: '17rem', - 18: '18rem', - 19: '19rem', - 20: '20rem', - 21: '21rem', - 22: '22rem', - 23: '23rem', - 24: '24rem', - 25: '25rem', - 26: '26rem', - 27: '27rem', - 28: '28rem', - 29: '29rem', - 30: '30rem', - 34: '34rem', - 45: '45rem', - 50: '50rem', - 54: '54rem', - 58: '58rem', - 60: '60rem' - }, - zIndex: { - 1: '1' - } - } - }, - plugins: [require('tailwindcss')] -}; From 5aebc55466ffc2af4b091855de9f333efd00d197 Mon Sep 17 00:00:00 2001 From: "e.viskunov@cdek.ru" Date: Thu, 25 Jun 2026 15:14:06 +0700 Subject: [PATCH 3/3] ~update --- package.json | 4 +- .../popover-rich-content.component.ts | 4 +- src/styles.scss | 3 +- .../copy-to-dist.mjs | 2 +- .../generate.mjs | 106 +++++++++++------- {src/tailwind => tailwind}/theme.css | 59 +++++----- 6 files changed, 108 insertions(+), 70 deletions(-) rename scripts/copy-tailwind-to-dist.mjs => tailwind/copy-to-dist.mjs (98%) rename scripts/generate-tailwind.mjs => tailwind/generate.mjs (70%) rename {src/tailwind => tailwind}/theme.css (88%) diff --git a/package.json b/package.json index 88fdf39a..ead6b20d 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "format:check": "prettier --check \"**/*.{js,ts,d.ts}\"", "build:check": "npm run format:check && npm run security:check", "build:storybook": "ng run angular-ui-kit:build-storybook", - "build:lib": "ng build angular-ui-kit-lib && npm run generate:tailwind && node scripts/copy-tailwind-to-dist.mjs", - "generate:tailwind": "node scripts/generate-tailwind.mjs", + "build:lib": "ng build angular-ui-kit-lib && npm run generate:tailwind && node tailwind/copy-to-dist.mjs", + "generate:tailwind": "node tailwind/generate.mjs", "security:check": "npm audit --production --audit-level high", "copy:dist": "cpx 'src/lib/providers/prime-preset/**/*.{json,ts}' dist/ && cpx 'src-tokens/theme.preset.ts' dist/" }, diff --git a/src/stories/components/popover/examples/popover-rich-content.component.ts b/src/stories/components/popover/examples/popover-rich-content.component.ts index 717c3e7e..63d0dfb4 100644 --- a/src/stories/components/popover/examples/popover-rich-content.component.ts +++ b/src/stories/components/popover/examples/popover-rich-content.component.ts @@ -10,7 +10,7 @@ const template = `
Заголовок -

Дополнительное описание или любой произвольный контент внутри popover.

+

Дополнительное описание или любой произвольный контент внутри popover.

@@ -52,7 +52,7 @@ import { ExtraButtonComponent } from '@cdek-it/angular-ui-kit';
Заголовок -

Дополнительное описание или любой произвольный контент внутри popover.

+

Дополнительное описание или любой произвольный контент внутри popover.

\`, diff --git a/src/styles.scss b/src/styles.scss index 5dfda6dd..75d23e2d 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,7 +1,8 @@ // Tailwind v4 CSS-first. Демо/бин кита «ест свой корм»: тема (цвета/типографика/radius/тени/easing) // берётся из собственного сгенерированного @theme — того же, что кит публикует consumer'ам. @use 'tailwindcss'; -@use '@cdek-it/angular-ui-kit/tailwind'; +// Демо кита «ест свой корм» — подключает собственную сгенерированную тему напрямую из tailwind/theme.css. +@use '../tailwind/theme.css'; @import '@tabler/icons-webfont/dist/tabler-icons.min.css'; diff --git a/scripts/copy-tailwind-to-dist.mjs b/tailwind/copy-to-dist.mjs similarity index 98% rename from scripts/copy-tailwind-to-dist.mjs rename to tailwind/copy-to-dist.mjs index b2750253..9f120622 100644 --- a/scripts/copy-tailwind-to-dist.mjs +++ b/tailwind/copy-to-dist.mjs @@ -12,7 +12,7 @@ import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(__dirname, '..'); -const SRC = resolve(ROOT, 'src/tailwind'); +const SRC = resolve(ROOT, 'tailwind'); const DIST = resolve(ROOT, 'dist'); const DIST_TW = resolve(DIST, 'tailwind'); const DIST_PKG = resolve(DIST, 'package.json'); diff --git a/scripts/generate-tailwind.mjs b/tailwind/generate.mjs similarity index 70% rename from scripts/generate-tailwind.mjs rename to tailwind/generate.mjs index 9007a743..f98f7bdd 100644 --- a/scripts/generate-tailwind.mjs +++ b/tailwind/generate.mjs @@ -25,7 +25,7 @@ import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(__dirname, '..'); const TOKENS_PATH = resolve(ROOT, 'src/lib/providers/prime-preset/tokens/tokens.json'); -const OUT_DIR = resolve(ROOT, 'src/tailwind'); +const OUT_DIR = resolve(ROOT, 'tailwind'); const tokens = JSON.parse(readFileSync(TOKENS_PATH, 'utf8')); const primitive = tokens.primitive; @@ -107,33 +107,55 @@ function resolveInline(value) { }); } -// ── semantic → линк на runtime --p-* + hex-fallback из tokens.json ────────── -// Имена --p-* — стандартные PrimeNG styled-mode (semantic.* => --p-*, camelCase → kebab). -const SEMANTIC_LINKS = [ - // [tailwind var, runtime --p-* name, fallback hex/value] - ['--color-primary', 'var(--p-primary-color)', solidHex('green', '500')], - ['--color-on-primary', 'var(--p-primary-contrast-color)', ALPHA.white[1000]], - ['--color-primary-hover', 'var(--p-primary-hover-color)', solidHex('green', '600')], - ['--color-primary-active', 'var(--p-primary-active-color)', solidHex('green', '700')], - ['--color-surface-ground', 'var(--p-content-background)', ALPHA.white[1000]], - ['--color-surface-section', 'var(--p-content-hover-background)', solidHex('zinc', '100')], - ['--color-surface-card', 'var(--p-content-background)', ALPHA.white[1000]], - ['--color-surface-overlay', 'var(--p-overlay-background)', ALPHA.white[1000]], - ['--color-surface-border', 'var(--p-content-border-color)', solidHex('zinc', '200')], - ['--color-surface-hover', 'var(--p-content-hover-background)', solidHex('zinc', '100')], - ['--color-text', 'var(--p-text-color)', solidHex('zinc', '900')], - ['--color-text-muted', 'var(--p-text-muted-color)', solidHex('zinc', '500')], - ['--color-text-secondary', 'var(--p-text-secondary-color)', solidHex('zinc', '600')], - ['--color-text-disabled', 'var(--p-text-disabled-color)', solidHex('zinc', '300')], - ['--color-form-border', 'var(--p-form-field-border-color)', solidHex('zinc', '300')], - ['--color-form-bg', 'var(--p-form-field-background)', ALPHA.white[1000]], - ['--color-danger', 'var(--p-text-danger-color)', solidHex('red', '600')], - ['--color-success', 'var(--p-text-success-color)', solidHex('green', '700')], - ['--color-warning', 'var(--p-text-warning-color)', solidHex('yellow', '600')], - ['--color-info', 'var(--p-text-info-color)', solidHex('blue', '600')], - ['--color-help', 'var(--p-text-help-color)', solidHex('purple', '600')] +// ── semantic → литералы из tokens.json (статика) ──────────────────────────── +// Тема кита одна (darkModeSelector: false), пресет = definePreset(Aura, tokens), поэтому +// значения semantic-токенов в tokens.json и есть финальные цвета. Резолвим их в литералы, +// без линков на runtime --p-* (их имена у кастомного пресета нестандартны) и без fallback'ов. +// Нейминг чистый: foreground/secondary/muted/disabled (утилиты text-foreground, text-secondary…). +const SEMANTIC_TOKENS = [ + // [tailwind var, путь в semantic.colorScheme.light.*] + ['--color-foreground', 'text.color'], + ['--color-secondary', 'text.secondaryColor'], + ['--color-muted', 'text.mutedColor'], + ['--color-disabled', 'text.disabledColor'], + ['--color-primary', 'primary.color'], + ['--color-on-primary', 'primary.contrastColor'], + ['--color-primary-hover', 'primary.hoverColor'], + ['--color-primary-active', 'primary.activeColor'], + ['--color-surface-ground', 'content.background'], + ['--color-surface-section', 'content.hoverBackground'], + ['--color-surface-card', 'content.background'], + ['--color-surface-overlay', 'overlay.select.background'], + ['--color-surface-border', 'content.borderColor'], + ['--color-surface-hover', 'content.hoverBackground'], + ['--color-form-border', 'form.borderColor'], + ['--color-form-bg', 'form.background'], + ['--color-danger', 'text.dangerColor'], + ['--color-success', 'text.successColor'], + ['--color-warning', 'text.warningColor'], + ['--color-info', 'text.infoColor'], + ['--color-help', 'text.helpColor'] ]; +/** Разрешить semantic-токен по пути (text.color, primary.color, content.background…). */ +function semanticValue(path) { + return resolveToken(`{${path}}`); +} + +/** + * Гард: значение должно разрешиться в конкретную величину. Иначе генератор падает с понятной + * ошибкой вместо того, чтобы молча написать `--x: undefined;` в тему. + */ +function assertResolved(twVar, value, path) { + if (value === undefined || value === null || value === '' || `${value}`.includes('{')) { + throw new Error( + `[generate-tailwind] токен не разрешён: ${twVar} ← semantic.${path} (получено "${value}"). ` + + `Проверьте путь в tokens.json (semantic.colorScheme.light.*).` + ); + } + return value; +} + // ── service colors: семантика кита → какой solid-цвет несёт полный рейнж ───── const SERVICE_TO_SOLID = { danger: 'red', @@ -160,14 +182,21 @@ const HEADER = `/** * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. * Регенерация: \`npm run generate:tailwind\`. * - * Tailwind v4 CSS-first тема кита @cdek-it/angular-ui-kit. + * Tailwind v4 CSS-first тема кита @cdek-it/angular-ui-kit. Единая точка истины — tokens.json + * (тот же источник, что и пресет PrimeNG provideExtraThemes()). + * * Подключение в проекте: * @use "tailwindcss"; * @use "@cdek-it/angular-ui-kit/tailwind"; * - * Semantic-токены ссылаются на runtime-переменные PrimeNG (--p-*) — цвет трекает - * provideExtraThemes(). Primitive-оттенки — статический слепок палитры кита - * (их runtime-имена --p-* нестандартны, поэтому заморожены здесь). + * ВСЕ значения — статические литералы, разрешённые из tokens.json (semantic-токены из + * semantic.colorScheme.light.*, оттенки палитры — из colors.solid/alpha). Ссылок на runtime + * переменные PrimeNG (--p-*) НЕТ: тема кита одна (darkModeSelector: false), поэтому tokens + * совпадают с рантаймом, и статика = рантайм. Поменяли токен → пересобрали кит → у consumer'а + * обновилось (через bump версии). + * + * Покрытие: colors, fonts (--font-*), font-weight, font-size (--text-*), line-height (--leading-*), + * radius (--radius-*), shadow (--shadow-*), easing (--ease-*), spacing (--spacing). */ `; @@ -176,10 +205,10 @@ function buildThemeCss() { const lines = []; lines.push('@theme {'); - // semantic links - lines.push(' /* semantic — линк на runtime тему кита (--p-*) + hex-fallback */'); - for (const [twVar, runtime, fallback] of SEMANTIC_LINKS) { - lines.push(` ${twVar}: ${runtime.replace(')', `, ${fallback})`)};`); + // semantic — литералы из tokens.json (статика, через гард) + lines.push(' /* semantic — литералы из tokens.json (тема кита одна → tokens = рантайм) */'); + for (const [twVar, path] of SEMANTIC_TOKENS) { + lines.push(` ${twVar}: ${assertResolved(twVar, semanticValue(path), path)};`); } // primary = green-палитра (primary кита это green.500). DEFAULT уже задан в semantic-блоке выше. @@ -256,13 +285,14 @@ function buildThemeCss() { // spacing — единственная ручка v4; из неё выводятся p/m/w/h/gap/inset/space/translate. lines.push(''); lines.push(' /* spacing: множитель для p/m/w/h/gap/inset/… (v4: calc(var(--spacing)*N)) */'); - lines.push(` --spacing: ${SPACING_STEP};`); + lines.push(` --spacing: ${assertResolved('--spacing', SPACING_STEP, "spacing['1x']")};`); - // shadows (со ссылками на alpha-цвета раскрываем инлайн) + // shadows (со ссылками на alpha-цвета раскрываем инлайн; гард ловит неразрешённые ref) lines.push(''); lines.push(' /* shadows (box-shadow, {colors.alpha.*} раскрыты) */'); for (const [k, v] of Object.entries(SHADOWS)) { - lines.push(` --shadow-${k}: ${resolveInline(v)};`); + const resolved = resolveInline(v); + lines.push(` --shadow-${k}: ${assertResolved(`--shadow-${k}`, resolved, `shadows.${k}`)};`); } // easing @@ -285,4 +315,4 @@ mkdirSync(OUT_DIR, { recursive: true }); const themeCss = `${HEADER}\n${buildThemeCss()}\n`; writeFileSync(resolve(OUT_DIR, 'theme.css'), themeCss); -console.log('✓ Generated src/tailwind/theme.css'); +console.log('✓ Generated tailwind/theme.css'); diff --git a/src/tailwind/theme.css b/tailwind/theme.css similarity index 88% rename from src/tailwind/theme.css rename to tailwind/theme.css index f15ef3fc..0847d253 100644 --- a/src/tailwind/theme.css +++ b/tailwind/theme.css @@ -2,39 +2,46 @@ * СГЕНЕРИРОВАНО. Не править руками — источник: src/lib/providers/prime-preset/tokens/tokens.json. * Регенерация: `npm run generate:tailwind`. * - * Tailwind v4 CSS-first тема кита @cdek-it/angular-ui-kit. + * Tailwind v4 CSS-first тема кита @cdek-it/angular-ui-kit. Единая точка истины — tokens.json + * (тот же источник, что и пресет PrimeNG provideExtraThemes()). + * * Подключение в проекте: * @use "tailwindcss"; * @use "@cdek-it/angular-ui-kit/tailwind"; * - * Semantic-токены ссылаются на runtime-переменные PrimeNG (--p-*) — цвет трекает - * provideExtraThemes(). Primitive-оттенки — статический слепок палитры кита - * (их runtime-имена --p-* нестандартны, поэтому заморожены здесь). + * ВСЕ значения — статические литералы, разрешённые из tokens.json (semantic-токены из + * semantic.colorScheme.light.*, оттенки палитры — из colors.solid/alpha). Ссылок на runtime + * переменные PrimeNG (--p-*) НЕТ: тема кита одна (darkModeSelector: false), поэтому tokens + * совпадают с рантаймом, и статика = рантайм. Поменяли токен → пересобрали кит → у consumer'а + * обновилось (через bump версии). + * + * Покрытие: colors, fonts (--font-*), font-weight, font-size (--text-*), line-height (--leading-*), + * radius (--radius-*), shadow (--shadow-*), easing (--ease-*), spacing (--spacing). */ @theme { - /* semantic — линк на runtime тему кита (--p-*) + hex-fallback */ - --color-primary: var(--p-primary-color, #44e858); - --color-on-primary: var(--p-primary-contrast-color, #ffffff); - --color-primary-hover: var(--p-primary-hover-color, #1dc831); - --color-primary-active: var(--p-primary-active-color, #168322); - --color-surface-ground: var(--p-content-background, #ffffff); - --color-surface-section: var(--p-content-hover-background, #f0f0f1); - --color-surface-card: var(--p-content-background, #ffffff); - --color-surface-overlay: var(--p-overlay-background, #ffffff); - --color-surface-border: var(--p-content-border-color, #e2e2e4); - --color-surface-hover: var(--p-content-hover-background, #f0f0f1); - --color-text: var(--p-text-color, #2b2e33); - --color-text-muted: var(--p-text-muted-color, #85888e); - --color-text-secondary: var(--p-text-secondary-color, #6d7076); - --color-text-disabled: var(--p-text-disabled-color, #cecfd2); - --color-form-border: var(--p-form-field-border-color, #cecfd2); - --color-form-bg: var(--p-form-field-background, #ffffff); - --color-danger: var(--p-text-danger-color, #db3424); - --color-success: var(--p-text-success-color, #168322); - --color-warning: var(--p-text-warning-color, #dc9710); - --color-info: var(--p-text-info-color, #1e76cd); - --color-help: var(--p-text-help-color, #9333ea); + /* semantic — литералы из tokens.json (тема кита одна → tokens = рантайм) */ + --color-foreground: #2b2e33; + --color-secondary: #6d7076; + --color-muted: #85888e; + --color-disabled: #cecfd2; + --color-primary: #44e858; + --color-on-primary: #ffffff; + --color-primary-hover: #1dc831; + --color-primary-active: #168322; + --color-surface-ground: #ffffff; + --color-surface-section: #f0f0f1; + --color-surface-card: #ffffff; + --color-surface-overlay: #ffffff; + --color-surface-border: #e2e2e4; + --color-surface-hover: #f0f0f1; + --color-form-border: #cecfd2; + --color-form-bg: #ffffff; + --color-danger: #db3424; + --color-success: #168322; + --color-warning: #dc9710; + --color-info: #1e76cd; + --color-help: #9333ea; /* primary — фирменный цвет кита (= green-палитра), оттенки */ --color-primary-50: #fafffb;