@tenphi/tasty 0.0.0-snapshot.0003ae6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +685 -0
  3. package/dist/babel-rZcEwPLM.d.ts +82 -0
  4. package/dist/chunks/async-storage-CG5HnUT5.js +20 -0
  5. package/dist/chunks/async-storage-CG5HnUT5.js.map +1 -0
  6. package/dist/chunks/build-config-_cm7XDZ0.js +42 -0
  7. package/dist/chunks/build-config-_cm7XDZ0.js.map +1 -0
  8. package/dist/chunks/collector-DZh0frqA.js +208 -0
  9. package/dist/chunks/collector-DZh0frqA.js.map +1 -0
  10. package/dist/chunks/config-engine-B9arIU78.js +272 -0
  11. package/dist/chunks/config-engine-B9arIU78.js.map +1 -0
  12. package/dist/chunks/css-definitions-LxHlQWqa.js +876 -0
  13. package/dist/chunks/css-definitions-LxHlQWqa.js.map +1 -0
  14. package/dist/chunks/css-resources-P7IBUUZs.js +142 -0
  15. package/dist/chunks/css-resources-P7IBUUZs.js.map +1 -0
  16. package/dist/chunks/debug-Cp6kyH_o.js +502 -0
  17. package/dist/chunks/debug-Cp6kyH_o.js.map +1 -0
  18. package/dist/chunks/dsl-MW8TZusz.js +1377 -0
  19. package/dist/chunks/dsl-MW8TZusz.js.map +1 -0
  20. package/dist/chunks/hydration-TRcz5vnk.js +41 -0
  21. package/dist/chunks/hydration-TRcz5vnk.js.map +1 -0
  22. package/dist/chunks/react-runtime-DFK-u-KU.js +562 -0
  23. package/dist/chunks/react-runtime-DFK-u-KU.js.map +1 -0
  24. package/dist/chunks/runtime-engine-BNE2KUiS.js +2412 -0
  25. package/dist/chunks/runtime-engine-BNE2KUiS.js.map +1 -0
  26. package/dist/chunks/runtime-state-BsBWQeBn.js +127 -0
  27. package/dist/chunks/runtime-state-BsBWQeBn.js.map +1 -0
  28. package/dist/chunks/shared-utils-CGMsLq--.js +148 -0
  29. package/dist/chunks/shared-utils-CGMsLq--.js.map +1 -0
  30. package/dist/chunks/style-engine-BuW7q07d.js +5260 -0
  31. package/dist/chunks/style-engine-BuW7q07d.js.map +1 -0
  32. package/dist/chunks/zero-engine-DzsBXgfk.js +275 -0
  33. package/dist/chunks/zero-engine-DzsBXgfk.js.map +1 -0
  34. package/dist/collector-w4mBj5gd.d.ts +164 -0
  35. package/dist/config-CZWCzBr6.d.ts +1349 -0
  36. package/dist/core/index.d.ts +5 -0
  37. package/dist/core/index.js +9 -0
  38. package/dist/index-G9JuwM9p.d.ts +1920 -0
  39. package/dist/index.d.ts +5 -0
  40. package/dist/index.js +11 -0
  41. package/dist/merge-styles-VXwJ0Frr.d.ts +6 -0
  42. package/dist/ssr/astro-client.d.ts +1 -0
  43. package/dist/ssr/astro-client.js +6 -0
  44. package/dist/ssr/astro-client.js.map +1 -0
  45. package/dist/ssr/astro-middleware-extract-static.d.ts +10 -0
  46. package/dist/ssr/astro-middleware-extract-static.js +9 -0
  47. package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
  48. package/dist/ssr/astro-middleware-extract.d.ts +10 -0
  49. package/dist/ssr/astro-middleware-extract.js +9 -0
  50. package/dist/ssr/astro-middleware-extract.js.map +1 -0
  51. package/dist/ssr/astro-middleware-static.d.ts +17 -0
  52. package/dist/ssr/astro-middleware-static.js +7 -0
  53. package/dist/ssr/astro-middleware-static.js.map +1 -0
  54. package/dist/ssr/astro-middleware.d.ts +18 -0
  55. package/dist/ssr/astro-middleware.js +7 -0
  56. package/dist/ssr/astro-middleware.js.map +1 -0
  57. package/dist/ssr/astro.d.ts +127 -0
  58. package/dist/ssr/astro.js +221 -0
  59. package/dist/ssr/astro.js.map +1 -0
  60. package/dist/ssr/index.d.ts +36 -0
  61. package/dist/ssr/index.js +10 -0
  62. package/dist/ssr/index.js.map +1 -0
  63. package/dist/ssr/next-config.d.ts +64 -0
  64. package/dist/ssr/next-config.js +128 -0
  65. package/dist/ssr/next-config.js.map +1 -0
  66. package/dist/ssr/next.d.ts +46 -0
  67. package/dist/ssr/next.js +60 -0
  68. package/dist/ssr/next.js.map +1 -0
  69. package/dist/static/index.d.ts +90 -0
  70. package/dist/static/index.js +32 -0
  71. package/dist/static/index.js.map +1 -0
  72. package/dist/static/inject.d.ts +4 -0
  73. package/dist/static/inject.js +17 -0
  74. package/dist/static/inject.js.map +1 -0
  75. package/dist/types-JEY8PVYP.d.ts +1567 -0
  76. package/dist/zero/babel.d.ts +2 -0
  77. package/dist/zero/babel.js +412 -0
  78. package/dist/zero/babel.js.map +1 -0
  79. package/dist/zero/index.d.ts +80 -0
  80. package/dist/zero/index.js +2 -0
  81. package/dist/zero/next.d.ts +84 -0
  82. package/dist/zero/next.js +112 -0
  83. package/dist/zero/next.js.map +1 -0
  84. package/docs/README.md +39 -0
  85. package/docs/adoption.md +323 -0
  86. package/docs/ai-agents.md +250 -0
  87. package/docs/comparison.md +448 -0
  88. package/docs/configuration.md +839 -0
  89. package/docs/debug.md +332 -0
  90. package/docs/design-system.md +455 -0
  91. package/docs/dsl.md +1065 -0
  92. package/docs/getting-started.md +240 -0
  93. package/docs/injector.md +634 -0
  94. package/docs/methodology.md +648 -0
  95. package/docs/migration-v3.md +285 -0
  96. package/docs/pipeline.md +765 -0
  97. package/docs/plugins.md +353 -0
  98. package/docs/react-api.md +683 -0
  99. package/docs/runtime-benchmarks.md +388 -0
  100. package/docs/ssr.md +610 -0
  101. package/docs/styles.md +715 -0
  102. package/docs/tasty-static.md +582 -0
  103. package/package.json +314 -0
  104. package/tasty.config.ts +20 -0
@@ -0,0 +1,84 @@
1
+ import { r as TastyZeroConfig } from "../babel-rZcEwPLM.js";
2
+ //#region src/zero/next.d.ts
3
+ interface WebpackConfigContext {
4
+ isServer: boolean;
5
+ dev: boolean;
6
+ buildId: string;
7
+ dir: string;
8
+ }
9
+ interface TurbopackLoaderItem {
10
+ loader: string;
11
+ options?: Record<string, unknown>;
12
+ }
13
+ interface TurbopackRuleConfig {
14
+ loaders: (string | TurbopackLoaderItem)[];
15
+ as?: string;
16
+ condition?: unknown;
17
+ }
18
+ interface TurbopackConfig {
19
+ rules?: Record<string, TurbopackRuleConfig | TurbopackRuleConfig[]>;
20
+ [key: string]: unknown;
21
+ }
22
+ interface NextConfig {
23
+ webpack?: (config: any, context: WebpackConfigContext) => any;
24
+ turbopack?: TurbopackConfig;
25
+ [key: string]: unknown;
26
+ }
27
+ export interface TastyZeroNextOptions {
28
+ /**
29
+ * Output path for CSS relative to project root.
30
+ * @default 'public/tasty.css'
31
+ */
32
+ output?: string;
33
+ /**
34
+ * Whether to enable the plugin.
35
+ * @default true
36
+ */
37
+ enabled?: boolean;
38
+ /**
39
+ * Tasty configuration for build-time processing.
40
+ * For static configs that don't change during dev.
41
+ *
42
+ * For configs that depend on theme files, use `configFile` instead.
43
+ */
44
+ config?: TastyZeroConfig;
45
+ /**
46
+ * Path to a TypeScript/JavaScript module that exports the tasty zero config
47
+ * as its default export. The module is re-evaluated on each
48
+ * compilation, enabling hot reload when the file (or its imports) change.
49
+ *
50
+ * @example './app/tasty-zero.config.ts'
51
+ */
52
+ configFile?: string;
53
+ /**
54
+ * Extra file paths (relative to project root) that the config depends on.
55
+ * When any of these files change, the Babel cache is invalidated and
56
+ * the config is re-evaluated.
57
+ *
58
+ * The `configFile` itself is always tracked automatically.
59
+ * Use this for transitive dependencies that aren't directly imported
60
+ * by the config file, or when using `config` instead of `configFile`.
61
+ *
62
+ * @example ['./app/theme.ts']
63
+ */
64
+ configDeps?: string[];
65
+ /**
66
+ * Output mode for extracted CSS.
67
+ *
68
+ * - `'file'` (default): CSS is written to a single output file.
69
+ * - `'inject'`: CSS is embedded inline in JS and injected at runtime.
70
+ * No CSS file is written. Best for reusable components and extensions.
71
+ *
72
+ * When `mode` is `'inject'`, `output` is ignored.
73
+ *
74
+ * @default 'file'
75
+ */
76
+ mode?: 'file' | 'inject';
77
+ }
78
+ /**
79
+ * Next.js configuration wrapper for tasty-zero.
80
+ * Configures both webpack and Turbopack bundlers automatically.
81
+ */
82
+ export declare function withTastyZero(options?: TastyZeroNextOptions): (nextConfig?: NextConfig) => NextConfig;
83
+ //#endregion
84
+ //# sourceMappingURL=next.d.ts.map
@@ -0,0 +1,112 @@
1
+ import * as path from "path";
2
+ import { createJiti } from "jiti";
3
+ import { createRequire } from "module";
4
+ import { fileURLToPath } from "url";
5
+ //#region src/zero/next.ts
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ function withTastyZero(options = {}) {
9
+ const { output = "public/tasty.css", enabled = true, config: tastyConfig, configFile, configDeps = [], mode } = options;
10
+ return (nextConfig = {}) => {
11
+ if (!enabled) return nextConfig;
12
+ const projectDir = process.cwd();
13
+ const absoluteOutput = path.resolve(projectDir, output);
14
+ const babelPluginPath = path.resolve(__dirname, "babel.js");
15
+ const absoluteConfigFile = configFile ? path.resolve(projectDir, configFile) : void 0;
16
+ const allDeps = [...absoluteConfigFile ? [absoluteConfigFile] : [], ...configDeps.map((dep) => path.resolve(projectDir, dep))];
17
+ const turbopackBabelOptions = {
18
+ babelrc: false,
19
+ configFile: false,
20
+ parserOpts: { plugins: [
21
+ "typescript",
22
+ "jsx",
23
+ "decorators-legacy"
24
+ ] },
25
+ plugins: [[babelPluginPath, {
26
+ output: absoluteOutput,
27
+ injectImport: true,
28
+ ...mode ? { mode } : {},
29
+ ...absoluteConfigFile ? { configFile: absoluteConfigFile } : tastyConfig ? { config: tastyConfig } : {},
30
+ ...allDeps.length > 0 ? { configDeps: allDeps } : {}
31
+ }]]
32
+ };
33
+ const existingTurbopack = nextConfig.turbopack || {};
34
+ const existingRules = existingTurbopack.rules || {};
35
+ const existingExperimental = nextConfig.experimental || {};
36
+ return {
37
+ ...nextConfig,
38
+ experimental: {
39
+ ...existingExperimental,
40
+ turbopackUseBuiltinBabel: true
41
+ },
42
+ turbopack: {
43
+ ...existingTurbopack,
44
+ rules: {
45
+ ...existingRules,
46
+ "*.{ts,tsx,js,jsx}": {
47
+ condition: { not: "foreign" },
48
+ loaders: [{
49
+ loader: "babel-loader",
50
+ options: turbopackBabelOptions
51
+ }]
52
+ }
53
+ }
54
+ },
55
+ webpack(config, context) {
56
+ const { dir } = context;
57
+ const wpProjectDir = dir || projectDir;
58
+ const wpAbsoluteOutput = path.resolve(wpProjectDir, output);
59
+ const projectRequire = createRequire(path.resolve(wpProjectDir, "package.json"));
60
+ const wpAbsoluteConfigFile = configFile ? path.resolve(wpProjectDir, configFile) : void 0;
61
+ const wpAllDeps = [...wpAbsoluteConfigFile ? [wpAbsoluteConfigFile] : [], ...configDeps.map((dep) => path.resolve(wpProjectDir, dep))];
62
+ const babelPluginOptions = {
63
+ output: wpAbsoluteOutput,
64
+ injectImport: true,
65
+ ...mode ? { mode } : {}
66
+ };
67
+ if (wpAbsoluteConfigFile) {
68
+ const jiti = createJiti(wpProjectDir, { moduleCache: false });
69
+ babelPluginOptions.config = () => {
70
+ return jiti(wpAbsoluteConfigFile);
71
+ };
72
+ } else if (tastyConfig) babelPluginOptions.config = tastyConfig;
73
+ if (wpAllDeps.length > 0) babelPluginOptions.configDeps = wpAllDeps;
74
+ const babelPluginConfig = [babelPluginPath, babelPluginOptions];
75
+ const existingRule = config.module?.rules?.find((rule) => rule.use?.loader === "babel-loader" || rule.use?.some?.((u) => u.loader === "babel-loader"));
76
+ if (existingRule) {
77
+ const babelUse = Array.isArray(existingRule.use) ? existingRule.use.find((u) => u.loader === "babel-loader") : existingRule.use;
78
+ if (babelUse?.options) {
79
+ babelUse.options.plugins = babelUse.options.plugins || [];
80
+ babelUse.options.plugins.push(babelPluginConfig);
81
+ }
82
+ } else {
83
+ config.module = config.module || {};
84
+ config.module.rules = config.module.rules || [];
85
+ config.module.rules.push({
86
+ test: /\.(tsx?|jsx?)$/,
87
+ exclude: /node_modules/,
88
+ use: [{
89
+ loader: projectRequire.resolve("babel-loader"),
90
+ options: {
91
+ babelrc: false,
92
+ configFile: false,
93
+ parserOpts: { plugins: [
94
+ "typescript",
95
+ "jsx",
96
+ "decorators-legacy"
97
+ ] },
98
+ plugins: [babelPluginConfig]
99
+ }
100
+ }]
101
+ });
102
+ }
103
+ if (typeof nextConfig.webpack === "function") return nextConfig.webpack(config, context);
104
+ return config;
105
+ }
106
+ };
107
+ };
108
+ }
109
+ //#endregion
110
+ export { withTastyZero };
111
+
112
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","names":[],"sources":["../../src/zero/next.ts"],"sourcesContent":["/**\n * Next.js configuration wrapper for tasty-zero.\n *\n * Supports both webpack and Turbopack bundlers:\n * - **webpack**: Injects a babel-loader rule with the tasty-zero Babel plugin\n * via `webpack()` config hook. Config is passed as a jiti factory function.\n * - **Turbopack**: Adds a `turbopack.rules` entry with babel-loader and\n * JSON-serializable options (`configFile` path instead of a function).\n * The Babel plugin loads the config internally via jiti.\n *\n * The generated CSS is injected automatically — `@tenphi/tasty/static`\n * imports are replaced with an import of the output CSS file at build time.\n * No manual CSS import in layout files is needed.\n *\n * @example\n * ```javascript\n * // next.config.js\n * const { withTastyZero } = require('@tenphi/tasty/zero/next');\n *\n * module.exports = withTastyZero({\n * output: 'public/tasty.css',\n * configFile: './app/tasty-zero.config.ts',\n * })({\n * // your Next.js config\n * });\n * ```\n */\n\nimport { createRequire } from 'module';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { createJiti } from 'jiti';\n\nimport type { TastyZeroBabelOptions, TastyZeroConfig } from './babel';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Next.js types (inline to avoid requiring next as a dependency)\ninterface WebpackConfigContext {\n isServer: boolean;\n dev: boolean;\n buildId: string;\n dir: string;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any -- webpack/Next.js config types are complex */\ninterface TurbopackLoaderItem {\n loader: string;\n options?: Record<string, unknown>;\n}\n\ninterface TurbopackRuleConfig {\n loaders: (string | TurbopackLoaderItem)[];\n as?: string;\n condition?: unknown;\n}\n\ninterface TurbopackConfig {\n rules?: Record<string, TurbopackRuleConfig | TurbopackRuleConfig[]>;\n [key: string]: unknown;\n}\n\ninterface NextConfig {\n webpack?: (config: any, context: WebpackConfigContext) => any;\n turbopack?: TurbopackConfig;\n [key: string]: unknown;\n}\n\nexport interface TastyZeroNextOptions {\n /**\n * Output path for CSS relative to project root.\n * @default 'public/tasty.css'\n */\n output?: string;\n\n /**\n * Whether to enable the plugin.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Tasty configuration for build-time processing.\n * For static configs that don't change during dev.\n *\n * For configs that depend on theme files, use `configFile` instead.\n */\n config?: TastyZeroConfig;\n\n /**\n * Path to a TypeScript/JavaScript module that exports the tasty zero config\n * as its default export. The module is re-evaluated on each\n * compilation, enabling hot reload when the file (or its imports) change.\n *\n * @example './app/tasty-zero.config.ts'\n */\n configFile?: string;\n\n /**\n * Extra file paths (relative to project root) that the config depends on.\n * When any of these files change, the Babel cache is invalidated and\n * the config is re-evaluated.\n *\n * The `configFile` itself is always tracked automatically.\n * Use this for transitive dependencies that aren't directly imported\n * by the config file, or when using `config` instead of `configFile`.\n *\n * @example ['./app/theme.ts']\n */\n configDeps?: string[];\n\n /**\n * Output mode for extracted CSS.\n *\n * - `'file'` (default): CSS is written to a single output file.\n * - `'inject'`: CSS is embedded inline in JS and injected at runtime.\n * No CSS file is written. Best for reusable components and extensions.\n *\n * When `mode` is `'inject'`, `output` is ignored.\n *\n * @default 'file'\n */\n mode?: 'file' | 'inject';\n}\n\n/**\n * Next.js configuration wrapper for tasty-zero.\n * Configures both webpack and Turbopack bundlers automatically.\n */\nexport function withTastyZero(options: TastyZeroNextOptions = {}) {\n const {\n output = 'public/tasty.css',\n enabled = true,\n config: tastyConfig,\n configFile,\n configDeps = [],\n mode,\n } = options;\n\n return (nextConfig: NextConfig = {}): NextConfig => {\n if (!enabled) {\n return nextConfig;\n }\n\n const projectDir = process.cwd();\n const absoluteOutput = path.resolve(projectDir, output);\n const babelPluginPath = path.resolve(__dirname, 'babel.js');\n\n const absoluteConfigFile = configFile\n ? path.resolve(projectDir, configFile)\n : undefined;\n\n const allDeps = [\n ...(absoluteConfigFile ? [absoluteConfigFile] : []),\n ...configDeps.map((dep) => path.resolve(projectDir, dep)),\n ];\n\n // --- Turbopack configuration ---\n // Turbopack loader options must be JSON-serializable (no functions).\n // The Babel plugin loads config internally via `configFile` path + jiti.\n const turbopackBabelOptions: Record<string, unknown> = {\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: ['typescript', 'jsx', 'decorators-legacy'],\n },\n plugins: [\n [\n babelPluginPath,\n {\n output: absoluteOutput,\n injectImport: true,\n ...(mode ? { mode } : {}),\n ...(absoluteConfigFile\n ? { configFile: absoluteConfigFile }\n : tastyConfig\n ? { config: tastyConfig }\n : {}),\n ...(allDeps.length > 0 ? { configDeps: allDeps } : {}),\n },\n ],\n ],\n };\n\n const existingTurbopack = nextConfig.turbopack || {};\n const existingRules = existingTurbopack.rules || {};\n\n const existingExperimental =\n (nextConfig.experimental as Record<string, unknown>) || {};\n\n return {\n ...nextConfig,\n\n experimental: {\n ...existingExperimental,\n turbopackUseBuiltinBabel: true,\n },\n\n turbopack: {\n ...existingTurbopack,\n rules: {\n ...existingRules,\n '*.{ts,tsx,js,jsx}': {\n condition: { not: 'foreign' },\n loaders: [\n {\n loader: 'babel-loader',\n options: turbopackBabelOptions,\n },\n ],\n },\n },\n },\n\n webpack(config: any, context: WebpackConfigContext) {\n const { dir } = context;\n\n const wpProjectDir = dir || projectDir;\n const wpAbsoluteOutput = path.resolve(wpProjectDir, output);\n const projectRequire = createRequire(\n path.resolve(wpProjectDir, 'package.json'),\n );\n\n const wpAbsoluteConfigFile = configFile\n ? path.resolve(wpProjectDir, configFile)\n : undefined;\n\n const wpAllDeps = [\n ...(wpAbsoluteConfigFile ? [wpAbsoluteConfigFile] : []),\n ...configDeps.map((dep) => path.resolve(wpProjectDir, dep)),\n ];\n\n const babelPluginOptions: TastyZeroBabelOptions = {\n output: wpAbsoluteOutput,\n injectImport: true,\n ...(mode ? { mode } : {}),\n };\n\n if (wpAbsoluteConfigFile) {\n const jiti = createJiti(wpProjectDir, {\n moduleCache: false,\n });\n\n babelPluginOptions.config = () => {\n return jiti(wpAbsoluteConfigFile) as TastyZeroConfig;\n };\n } else if (tastyConfig) {\n babelPluginOptions.config = tastyConfig;\n }\n\n if (wpAllDeps.length > 0) {\n babelPluginOptions.configDeps = wpAllDeps;\n }\n\n const babelPluginConfig = [babelPluginPath, babelPluginOptions];\n\n const existingRule = config.module?.rules?.find(\n (rule: any) =>\n rule.use?.loader === 'babel-loader' ||\n rule.use?.some?.((u: any) => u.loader === 'babel-loader'),\n );\n\n if (existingRule) {\n const babelUse = Array.isArray(existingRule.use)\n ? existingRule.use.find((u: any) => u.loader === 'babel-loader')\n : existingRule.use;\n\n if (babelUse?.options) {\n babelUse.options.plugins = babelUse.options.plugins || [];\n babelUse.options.plugins.push(babelPluginConfig);\n }\n } else {\n config.module = config.module || {};\n config.module.rules = config.module.rules || [];\n config.module.rules.push({\n test: /\\.(tsx?|jsx?)$/,\n exclude: /node_modules/,\n use: [\n {\n loader: projectRequire.resolve('babel-loader'),\n options: {\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: ['typescript', 'jsx', 'decorators-legacy'],\n },\n plugins: [babelPluginConfig],\n },\n },\n ],\n });\n }\n\n if (typeof nextConfig.webpack === 'function') {\n return nextConfig.webpack(config, context);\n }\n\n return config;\n },\n };\n };\n}\n"],"mappings":"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"}
package/docs/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Tasty Docs
2
+
3
+ Tasty is CSS-in-JS for React design systems. You describe hover, disabled, variants, themes, responsive behavior, and other conditions as state maps; Tasty compiles them so one branch wins without specificity fights or source-order surprises.
4
+
5
+ Use this hub to move from the core idea to a working component, then into design-system patterns or API reference as needed.
6
+
7
+ ## Start Here
8
+
9
+ - **Understand why**: [Introduction](../README.md) for the problem, the state-map model, and the product overview.
10
+ - **Try it**: [Getting Started](getting-started.md) to build a stateful component, add shared configuration, and choose a rendering mode.
11
+ - **Build a component system**: [Methodology](methodology.md) for root + sub-elements, typed public APIs, tokens, and extension patterns; then [Building a Design System](design-system.md).
12
+ - **Evaluate or adopt it**: [Comparison](comparison.md) for tool-selection context and [Adoption Guide](adoption.md) for an incremental rollout.
13
+ - **Understand the compiler**: [Style rendering pipeline](pipeline.md) for how state maps become mutually exclusive selectors.
14
+
15
+ ## By Role
16
+
17
+ - **Application developer using an existing design system**: [Getting Started](getting-started.md), then [React API](react-api.md).
18
+ - **Design-system author**: [Methodology](methodology.md), [Building a Design System](design-system.md), [Configuration](configuration.md), and [Adoption Guide](adoption.md).
19
+ - **Platform or tooling engineer**: [Configuration](configuration.md), [Build-Time Extraction (`tastyStatic`)](tasty-static.md), [Server-Side Rendering](ssr.md), and [Debug Utilities](debug.md).
20
+
21
+ ## By Styling Approach
22
+
23
+ - **React components**: [React API](react-api.md)
24
+ - **Zero-client-runtime React with `tasty()`**: [Server-Side Rendering](ssr.md), especially the static Astro integration
25
+ - **Build-time extraction with `tastyStatic()`**: [Build-Time Extraction](tasty-static.md)
26
+ - **Hydrated `tasty()` with server collection**: [Server-Side Rendering](ssr.md)
27
+ - **Upgrading from v2**: [Migration Guide (v2 → v3)](migration-v3.md)
28
+
29
+ ## By Task
30
+
31
+ - **Learn the style language**: [Style DSL](dsl.md)
32
+ - **Brief an AI agent (or yourself) on writing correct styles**: [Style Rules for AI Agents](ai-agents.md)
33
+ - **Look up a property handler**: [Style Properties](styles.md)
34
+ - **Define tokens, units, recipes, keyframes, properties, functions, or polyfills globally**: [Configuration](configuration.md)
35
+ - **Extend Tasty with a plugin, custom handler, or custom prop**: [Plugins & Extension Points](plugins.md)
36
+ - **Debug generated CSS or cache behavior**: [Debug Utilities](debug.md)
37
+ - **Understand how selector generation works internally**: [Style rendering pipeline](pipeline.md)
38
+ - **Understand runtime injection internals**: [Style Injector](injector.md)
39
+ - **Reproduce and interpret performance measurements**: [Runtime Benchmarks](runtime-benchmarks.md)
@@ -0,0 +1,323 @@
1
+ # Adoption Guide
2
+
3
+ Tasty is most useful where reusable component styling has become a state-resolution problem: hover intersects with disabled, variants intersect with themes, and every extension makes selector behavior harder to predict.
4
+
5
+ It normally sits underneath a design system’s existing components. You can preserve their public React APIs while moving their style logic into state maps that produce one declared winner. Adoption should start with a small, state-heavy component—not an all-at-once rewrite.
6
+
7
+ This guide is for design-system maintainers and platform engineers evaluating Tasty or introducing it into an existing codebase. Use it for rollout strategy and adoption sequencing; use the [Comparison guide](comparison.md) when the open question is whether Tasty is the right tool.
8
+
9
+ ---
10
+
11
+ ## Where Tasty sits in the stack
12
+
13
+ Tasty is not the surface your product engineers interact with directly. It sits one layer below:
14
+
15
+ ```
16
+ Product code
17
+ └─ DS components (Button, Card, Layout, ...)
18
+ └─ Tasty engine (tasty(), configure(), style functions)
19
+ └─ CSS (mutually exclusive selectors, tokens, custom properties)
20
+ ```
21
+
22
+ **What Tasty owns:**
23
+
24
+ - The DSL and value parser (tokens, custom units, auto-calc, color opacity)
25
+ - State compilation (mutually exclusive selectors from state maps)
26
+ - Style injection and deduplication (runtime or build-time)
27
+ - The `tasty()` component factory and hooks API
28
+
29
+ **What the DS team owns:**
30
+
31
+ - Token names and values (colors, spacing, typography)
32
+ - Custom units and their semantics
33
+ - State aliases (`@mobile`, `@dark`, `@compact`)
34
+ - Recipes (reusable style bundles)
35
+ - Which style props each component exposes
36
+ - Sub-element structure for compound components
37
+ - The override and extension rules product teams follow
38
+
39
+ Two teams using Tasty can end up with very different authoring models. That is by design.
40
+
41
+ ---
42
+
43
+ ## Who should adopt Tasty
44
+
45
+ **Strong fit:**
46
+
47
+ - A design-system or platform team that owns shared component APIs
48
+ - Components with complex, intersecting states (hover + disabled + theme + breakpoint)
49
+ - Teams that need deterministic style resolution without cascade/specificity bugs
50
+ - Organizations that want tokens, states, and extension rules to stay consistent across products
51
+
52
+ **Not the right fit:**
53
+
54
+ - Solo developers building a one-off app with minimal UI structure
55
+ - Teams that want a shared utility vocabulary and direct markup authoring (Tailwind is better here)
56
+ - Projects where low ceremony matters more than central governance
57
+ - Codebases where intersecting state complexity is low
58
+
59
+ For a detailed comparison with Tailwind, Panda CSS, vanilla-extract, StyleX, Stitches, and Emotion, see the [Comparison guide](comparison.md).
60
+
61
+ ---
62
+
63
+ ## What you are expected to define
64
+
65
+ Tasty provides the engine. The DS team defines the language that runs on it. Here is what that typically involves:
66
+
67
+ | Layer | What you define | Where |
68
+ | ------------------ | ---------------------------------------------------------- | ------------------------------------------ |
69
+ | **Tokens** | Color names, spacing scale, border widths, radii | `configure({ tokens })` |
70
+ | **Units** | Custom multiplier units (`x`, `r`, `bw`, or your own) | `configure({ units })` |
71
+ | **State aliases** | Responsive breakpoints, theme modes, feature flags | `configure({ states })` |
72
+ | **Recipes** | Reusable style bundles (card, elevated, input-reset) | `configure({ recipes })` |
73
+ | **Typography** | Preset definitions (h1-h6, t1-t4, etc.) | `configure({ presets: { ... } })` |
74
+ | **Style props** | Which CSS properties each component exposes as React props | `styleProps` in each component |
75
+ | **Sub-elements** | Inner parts of compound components (Title, Icon, Content) | `elements` + capitalized keys in `styles` |
76
+ | **Override rules** | How product engineers extend or constrain components | Styled wrappers via `tasty(Base, { ... })` |
77
+
78
+ The same engine can power a minimal design system with a handful of tokens:
79
+
80
+ ```tsx
81
+ configure({
82
+ tokens: { '#bg': '#white', '#text': '#111' },
83
+ states: { '@dark': '@root(schema=dark)' },
84
+ });
85
+ ```
86
+
87
+ ...or an enterprise-scale system with dozens of tokens, multiple state aliases, typography presets, recipes, and custom units. The scope is yours to decide.
88
+
89
+ Here is how the layers connect end-to-end. The DS team configures the engine, defines components, and product engineers consume them:
90
+
91
+ ```tsx
92
+ // ds/config.ts — DS team defines the language
93
+ configure({
94
+ tokens: {
95
+ '#primary': 'oklch(55% 0.25 265)',
96
+ '#surface': '#fff',
97
+ '#text': '#111',
98
+ },
99
+ states: { '@mobile': '@media(w < 768px)', '@dark': '@root(schema=dark)' },
100
+ recipes: {
101
+ card: { padding: '4x', fill: '#surface', radius: '1r', border: true },
102
+ },
103
+ });
104
+
105
+ // ds/components/Card.tsx — DS team builds components on top
106
+ const Card = tasty({
107
+ styles: {
108
+ recipe: 'card',
109
+ Title: { preset: 'h3', color: '#primary' },
110
+ Body: { preset: 't2', color: '#text' },
111
+ },
112
+ elements: { Title: 'h2', Body: 'div' },
113
+ styleProps: ['padding', 'fill'],
114
+ });
115
+
116
+ // app/Dashboard.tsx — product engineer uses the component
117
+ <Card padding={{ '': '4x', '@mobile': '2x' }}>
118
+ <Card.Title>Monthly Revenue</Card.Title>
119
+ <Card.Body>$1.2M — up 12% from last month</Card.Body>
120
+ </Card>;
121
+ ```
122
+
123
+ See [Configuration](configuration.md) for the full `configure()` API.
124
+
125
+ ---
126
+
127
+ ## Incremental adoption
128
+
129
+ You do not need to adopt everything at once. Tasty is designed to be introduced layer by layer.
130
+
131
+ A practical first slice is one component that already suffers from intersecting state and variant logic: a button, input, menu item, disclosure, or interactive card. Keep its public API unchanged, move one or two properties into Tasty state maps, and verify that the declared priority matches the behavior your team expects.
132
+
133
+ This proves the differentiator before you invest in a complete token vocabulary or migrate an entire component library.
134
+
135
+ ### Phase 1 -- Pilot one state-heavy component
136
+
137
+ Choose a component with a known hover/disabled, focus/error, or variant/theme interaction. Preserve its external props and visual behavior. The pilot should answer three questions:
138
+
139
+ 1. Is the state map easier to review than the existing selectors or conditional class logic?
140
+ 2. Does extending the component keep the intended state priority?
141
+ 3. Can your current tokens and component API move over without product-code churn?
142
+
143
+ If the answer is yes, establish the shared design-system vocabulary around the successful slice.
144
+
145
+ ### Phase 2 -- Tokens and units
146
+
147
+ Start by defining your design tokens and custom units. This is the lowest-risk step: it only configures the parser and does not require rewriting any components.
148
+
149
+ ```tsx
150
+ import { configure } from '@tenphi/tasty';
151
+
152
+ configure({
153
+ tokens: {
154
+ '#primary': 'oklch(55% 0.25 265)',
155
+ '#surface': '#white',
156
+ '#text': '#111',
157
+ '$card-padding': '4x',
158
+ },
159
+ // Common units (x, r, bw, ow, cr) are built-in.
160
+ // A DS typically redefines them to use CSS custom properties
161
+ // so that the actual scale is controlled via CSS, not JS:
162
+ units: {
163
+ x: 'var(--gap)', // 2x → calc(var(--gap) * 2)
164
+ r: 'var(--radius)',
165
+ bw: 'var(--border-width)',
166
+ },
167
+ });
168
+ ```
169
+
170
+ ### Phase 3 -- State aliases and recipes
171
+
172
+ Define the state vocabulary your components will share. This is where you start encoding your team's conventions.
173
+
174
+ ```tsx
175
+ configure({
176
+ states: {
177
+ '@mobile': '@media(w < 768px)',
178
+ '@tablet': '@media(w < 1024px)',
179
+ '@dark':
180
+ '@root(schema=dark) | (!@root(schema) & @media(prefers-color-scheme: dark))',
181
+ },
182
+ recipes: {
183
+ card: { padding: '4x', fill: '#surface', radius: '1r', border: true },
184
+ elevated: { shadow: '0 2x 4x #shadow' },
185
+ },
186
+ });
187
+ ```
188
+
189
+ ### Phase 4 -- Migrate a few primitives
190
+
191
+ Pick 2-3 widely used primitives (Box, Text, Button) and rewrite them with `tasty()`. Keep the public API identical so product code does not need to change.
192
+
193
+ ```tsx
194
+ const Box = tasty({
195
+ as: 'div',
196
+ styles: {
197
+ display: 'flex',
198
+ flow: 'column',
199
+ gap: '1x',
200
+ },
201
+ styleProps: ['gap', 'flow', 'padding', 'fill'],
202
+ });
203
+ ```
204
+
205
+ At this point you can validate the DSL, token workflow, and component authoring experience before expanding the rollout.
206
+
207
+ ### Phase 5 -- Expand state resolution
208
+
209
+ Move the components with the most painful intersecting states (buttons with hover + disabled + theme variants, inputs with focus + error + readonly) to Tasty's state map syntax. This is where mutually exclusive selectors start paying off.
210
+
211
+ ```tsx
212
+ const Button = tasty({
213
+ as: 'button',
214
+ styles: {
215
+ fill: {
216
+ '': '#primary',
217
+ ':hover': '#primary-hover',
218
+ ':active': '#primary-pressed',
219
+ // `disabled` is a data-attribute modifier → [data-disabled].
220
+ // Tasty auto-applies it from the native `disabled` attribute.
221
+ // `[disabled]` (attribute selector) also works here.
222
+ disabled: '#surface',
223
+ },
224
+ color: {
225
+ '': '#on-primary',
226
+ disabled: '#text.40',
227
+ },
228
+ cursor: {
229
+ '': 'pointer',
230
+ disabled: 'not-allowed',
231
+ },
232
+ transition: 'theme',
233
+ },
234
+ });
235
+ ```
236
+
237
+ ### Phase 6 -- Standardize style props and sub-elements
238
+
239
+ Define which style props each component category exposes. Layout components get flow/gap/padding. Interactive components get positioning. Compound components declare sub-elements.
240
+
241
+ ```tsx
242
+ const Card = tasty({
243
+ styles: {
244
+ recipe: 'card elevated',
245
+ Title: { preset: 'h3', color: '#primary' },
246
+ Content: { color: '#text', preset: 't2' },
247
+ },
248
+ elements: { Title: 'h2', Content: 'div' },
249
+ styleProps: ['padding', 'fill', 'radius'],
250
+ });
251
+ ```
252
+
253
+ ### Phase 7 -- Expand to full DS coverage
254
+
255
+ Migrate the remaining components, add the [ESLint plugin](https://github.com/tenphi/eslint-plugin-tasty) to enforce style conventions at lint time, and choose between [server-only `tasty()`](ssr.md) and [`tastyStatic()` build-time extraction](tasty-static.md) when a page should ship no Tasty styling runtime.
256
+
257
+ ---
258
+
259
+ ## What changes for product engineers
260
+
261
+ When a DS is powered by Tasty, product engineers typically interact with **components, not Tasty itself**. Here is what changes from their perspective:
262
+
263
+ **They do not write CSS directly.** Styling decisions are embedded in the components the DS provides. Product code consumes components, tokens, and style props.
264
+
265
+ **Overrides use styled wrappers.** Instead of passing one-off `className` or `style` props, product engineers extend components:
266
+
267
+ ```tsx
268
+ import { tasty } from '@tenphi/tasty';
269
+ import { Button } from 'my-ds';
270
+
271
+ // Replace mode: providing '' (default) key replaces the parent's fill entirely
272
+ const DangerButton = tasty(Button, {
273
+ styles: {
274
+ fill: { '': '#danger', ':hover': '#danger-hover' },
275
+ },
276
+ });
277
+
278
+ // Extend mode: omitting '' key preserves parent states and adds/overrides
279
+ const LoadingButton = tasty(Button, {
280
+ styles: {
281
+ fill: {
282
+ loading: '#yellow', // new state appended
283
+ disabled: '#gray.20', // existing state overridden in place
284
+ },
285
+ },
286
+ });
287
+ ```
288
+
289
+ **Style props replace raw CSS.** Layout, spacing, and positioning are controlled through typed props on the components that expose them:
290
+
291
+ ```tsx
292
+ <Space flow="row" gap="2x" placeItems="center">
293
+ <Title>Dashboard</Title>
294
+ <Button placeSelf="end">Add Item</Button>
295
+ </Space>
296
+ ```
297
+
298
+ **Components are server components by default.** All `tasty()` components and style functions are hook-free, so they work as React Server Components without `'use client'`. In server-only contexts they ship no Tasty styling runtime. Astro without `client:*` directives ships no client JavaScript; server-only Next.js RSC follows the same Tasty architecture, while final output depends on the application deployment. Product engineers only add `'use client'` when their component needs actual React interactivity (state, effects, event handlers), never because of styling.
299
+
300
+ **No cascade/specificity concerns.** Tasty's mutually exclusive selectors mean extending a component cannot accidentally break another. Import order, class name collisions, and specificity arithmetic are non-issues.
301
+
302
+ ---
303
+
304
+ ## Migration and Interop Notes
305
+
306
+ - **From Tailwind**: keep utility-authored product surfaces as-is at first, and use Tasty to build or replace the design-system primitives underneath them instead of forcing an all-at-once markup rewrite.
307
+ - **From CSS-in-JS libraries**: start with shared primitives such as `Box`, `Text`, and `Button`, preserve the external component API, and move state logic into Tasty state maps so behavior changes without product-code churn.
308
+ - **From CSS Modules or plain CSS**: migrate token definitions and repeated patterns first, then wrap existing DOM structure with `tasty()` components gradually rather than converting every stylesheet at once.
309
+
310
+ ---
311
+
312
+ ## Learn more
313
+
314
+ - [README](../README.md) -- overview, quick start, and feature highlights
315
+ - [Getting Started](getting-started.md) -- installation, first component, tooling setup
316
+ - [Methodology](methodology.md) -- the recommended patterns for structuring Tasty components
317
+ - [Building a Design System](design-system.md) -- practical guide to building a DS layer with Tasty
318
+ - [Style DSL](dsl.md) -- state maps, tokens, units, extending semantics, keyframes, @property
319
+ - [React API](react-api.md) -- `tasty()` factory, component props, variants, sub-elements, style functions
320
+ - [Configuration](configuration.md) -- tokens, recipes, custom units, style handlers, and TypeScript extensions
321
+ - [Style Properties](styles.md) -- complete reference for all enhanced style properties
322
+ - [Comparison](comparison.md) -- positioning and trade-offs vs. other styling systems
323
+ - [Build-Time Extraction (`tastyStatic`)](tasty-static.md) -- static styling with the Babel plugin