@yahoo/uds 3.113.0 → 3.114.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automated-config/dist/mapTextVariantFixtureToValue.cjs +12 -1
- package/dist/automated-config/dist/mapTextVariantFixtureToValue.js +12 -1
- package/dist/automated-config/dist/properties.cjs +1 -1
- package/dist/automated-config/dist/properties.js +1 -1
- package/dist/automated-config/dist/utils/getConfigVariantProperties.d.cts +2 -2
- package/dist/automated-config/dist/utils/getConfigVariantProperties.d.ts +2 -2
- package/dist/cli/commands/sync.cjs +1 -3
- package/dist/cli/commands/sync.d.cts +1 -1
- package/dist/cli/commands/sync.d.ts +1 -1
- package/dist/cli/commands/sync.js +1 -3
- package/dist/cli/commands/version.cjs +0 -2
- package/dist/cli/commands/version.d.cts +1 -1
- package/dist/cli/commands/version.d.ts +1 -1
- package/dist/cli/commands/version.js +0 -2
- package/dist/cli/dist/cli.cjs +1 -1
- package/dist/cli/dist/cli.js +1 -1
- package/dist/cli/dist/commands/editor-rules.cjs +2 -2
- package/dist/cli/dist/commands/editor-rules.js +2 -2
- package/dist/cli/dist/lib/logger.cjs +66 -0
- package/dist/cli/dist/lib/logger.js +66 -0
- package/dist/cli/dist/utils/rules/config.cjs +1 -1
- package/dist/cli/dist/utils/rules/config.js +1 -1
- package/dist/cli/runner.cjs +11 -2
- package/dist/cli/runner.js +11 -2
- package/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +1 -1
- package/dist/components/client/Menu/Menu.ItemCheckbox.d.ts +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/styles/styler.d.cts +41 -41
- package/dist/styles/styler.d.ts +41 -41
- package/dist/styles/variants.cjs +278 -278
- package/dist/styles/variants.js +278 -278
- package/dist/tailwind/dist/commands/css.cjs +79 -0
- package/dist/tailwind/dist/commands/css.d.ts +3 -0
- package/dist/tailwind/dist/commands/css.helpers.cjs +32 -0
- package/dist/tailwind/dist/commands/css.helpers.js +28 -0
- package/dist/tailwind/dist/commands/css.js +79 -0
- package/dist/tailwind/dist/commands/generateComponentData.cjs +33 -31
- package/dist/tailwind/dist/commands/generateComponentData.d.ts +1 -1
- package/dist/tailwind/dist/commands/generateComponentData.js +33 -31
- package/dist/tailwind/dist/commands/generatePurgeCSSData.d.ts +1 -1
- package/dist/tailwind/dist/commands/purge.cjs +3 -4
- package/dist/tailwind/dist/commands/purge.d.ts +1 -1
- package/dist/tailwind/dist/commands/purge.js +3 -4
- package/dist/tailwind/dist/css/generate.cjs +120 -0
- package/dist/tailwind/dist/css/generate.d.cts +30 -0
- package/dist/tailwind/dist/css/generate.d.ts +31 -0
- package/dist/tailwind/dist/css/generate.helpers.cjs +112 -0
- package/dist/tailwind/dist/css/generate.helpers.js +100 -0
- package/dist/tailwind/dist/css/generate.js +115 -0
- package/dist/tailwind/dist/css/postcss.cjs +35 -0
- package/dist/tailwind/dist/css/postcss.helpers.cjs +27 -0
- package/dist/tailwind/dist/css/postcss.helpers.js +26 -0
- package/dist/tailwind/dist/css/postcss.js +35 -0
- package/dist/tailwind/dist/css/runner.cjs +278 -0
- package/dist/tailwind/dist/css/runner.helpers.cjs +26 -0
- package/dist/tailwind/dist/css/runner.helpers.js +23 -0
- package/dist/tailwind/dist/css/runner.js +275 -0
- package/dist/tailwind/dist/css/theme.cjs +12 -0
- package/dist/tailwind/dist/css/theme.d.cts +66 -0
- package/dist/tailwind/dist/css/theme.d.ts +66 -0
- package/dist/tailwind/dist/css/theme.js +11 -0
- package/dist/tailwind/dist/css/utils.cjs +234 -0
- package/dist/tailwind/dist/css/utils.js +223 -0
- package/dist/tailwind/dist/index.d.cts +1 -0
- package/dist/tailwind/dist/index.d.ts +5 -3
- package/dist/tailwind/dist/purger/legacy/purgeCSS.cjs +4 -3
- package/dist/tailwind/dist/purger/legacy/purgeCSS.js +4 -3
- package/dist/tailwind/dist/purger/optimized/ast/expressions.cjs +122 -125
- package/dist/tailwind/dist/purger/optimized/ast/expressions.js +122 -125
- package/dist/tailwind/dist/purger/optimized/ast/jsx.cjs +1 -8
- package/dist/tailwind/dist/purger/optimized/ast/jsx.js +1 -8
- package/dist/tailwind/dist/purger/optimized/purge.cjs +11 -10
- package/dist/tailwind/dist/purger/optimized/purge.js +10 -9
- package/dist/tailwind/dist/purger/optimized/purgeFromCode.cjs +232 -127
- package/dist/tailwind/dist/purger/optimized/purgeFromCode.js +232 -127
- package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.cjs +330 -262
- package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.js +329 -262
- package/dist/tailwind/dist/purger/optimized/utils/files.cjs +4 -3
- package/dist/tailwind/dist/purger/optimized/utils/files.js +4 -3
- package/dist/tailwind/dist/purger/optimized/utils/safelist.cjs +13 -21
- package/dist/tailwind/dist/purger/optimized/utils/safelist.js +13 -21
- package/dist/tailwind/dist/tailwind/plugins/typography.cjs +41 -13
- package/dist/tailwind/dist/tailwind/plugins/typography.js +41 -13
- package/dist/tailwind/dist/tailwind/utils/composeTailwindPlugins.cjs +4 -2
- package/dist/tailwind/dist/tailwind/utils/composeTailwindPlugins.d.cts +10 -1
- package/dist/tailwind/dist/tailwind/utils/composeTailwindPlugins.d.ts +10 -1
- package/dist/tailwind/dist/tailwind/utils/composeTailwindPlugins.js +4 -2
- package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.cts +1 -1
- package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.ts +1 -1
- package/dist/tailwind/dist/utils/optimizeCSS.cjs +405 -0
- package/dist/tailwind/dist/utils/optimizeCSS.js +403 -0
- package/dist/tailwind/dist/utils/postcssPreserveVars.cjs +67 -0
- package/dist/tailwind/dist/utils/postcssPreserveVars.js +65 -0
- package/dist/tailwind/dist/utils/tsMorph.cjs +1 -1
- package/dist/uds/generated/componentData.cjs +943 -928
- package/dist/uds/generated/componentData.js +943 -928
- package/dist/uds/package.cjs +10 -4
- package/dist/uds/package.js +10 -4
- package/generated/componentData.json +2397 -0
- package/generated/tailwindPurge.ts +4560 -0
- package/package.json +7 -4
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
|
|
2
|
+
import { UDSCSSOptions } from "./generate.js";
|
|
3
|
+
|
|
4
|
+
//#region ../tailwind/dist/css/theme.d.ts
|
|
5
|
+
//#region src/css/theme.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Context passed to theme config function
|
|
8
|
+
*/
|
|
9
|
+
interface UDSThemeContext {
|
|
10
|
+
/** Current working directory */
|
|
11
|
+
cwd: string;
|
|
12
|
+
/** Whether the CLI is running in watch mode */
|
|
13
|
+
watch?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* CSS optimization options for uds.theme.ts
|
|
17
|
+
*/
|
|
18
|
+
interface UDSCSSOptimizationOptions {
|
|
19
|
+
/** Enable all CSS optimizations (default: true) */
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
/** Remove @font-face declarations for fonts not used in the CSS (default: false) */
|
|
22
|
+
removeUnusedFonts?: boolean;
|
|
23
|
+
/** Remove empty CSS rules (default: true) */
|
|
24
|
+
removeEmptyRules?: boolean;
|
|
25
|
+
/** Aggregate duplicate selectors (default: true) */
|
|
26
|
+
aggregateDuplicateSelectors?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Remove duplicate content from scoped CSS that already exists in main CSS (default: true)
|
|
29
|
+
* Currently deduplicates @font-face declarations. Reduces bundle size when scoped packages
|
|
30
|
+
* share fonts with the main app.
|
|
31
|
+
*/
|
|
32
|
+
deduplicateScopedCss?: boolean;
|
|
33
|
+
/** Prune unused CSS variables (default: true) */
|
|
34
|
+
pruneVars?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Theme configuration structure for uds.theme.ts
|
|
38
|
+
*/
|
|
39
|
+
interface UDSThemeConfig {
|
|
40
|
+
/** Path to app's uds.config (relative to project root) */
|
|
41
|
+
config?: string;
|
|
42
|
+
/** Entry directory for app code scanning (default: '/src/') */
|
|
43
|
+
entry?: string;
|
|
44
|
+
/** Suppress log output during generation (default: false) */
|
|
45
|
+
silent?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Packages that inherit the app's theme configuration.
|
|
48
|
+
* These packages' styles are merged into the main uds.css file.
|
|
49
|
+
*/
|
|
50
|
+
inherit?: string[];
|
|
51
|
+
/** Color modes to include (default: ['dark']) - light mode is always in :root */
|
|
52
|
+
colorModes?: ('dark' | 'light')[];
|
|
53
|
+
/** CSS generation options */
|
|
54
|
+
css?: UDSCSSOptions;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Theme config can be an object or a function that receives context
|
|
58
|
+
*/
|
|
59
|
+
type UDSThemeConfigInput = UDSThemeConfig | ((ctx: UDSThemeContext) => UDSThemeConfig | Promise<UDSThemeConfig>);
|
|
60
|
+
/**
|
|
61
|
+
* Helper function to define theme configuration with full type support.
|
|
62
|
+
* Supports both static config objects and dynamic functions.
|
|
63
|
+
*/
|
|
64
|
+
declare const defineTheme: (config: UDSThemeConfigInput) => UDSThemeConfigInput; //#endregion
|
|
65
|
+
//#endregion
|
|
66
|
+
export { type UDSCSSOptimizationOptions, defineTheme };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
|
|
2
|
+
//#region ../tailwind/dist/css/theme.js
|
|
3
|
+
/*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
|
|
4
|
+
/**
|
|
5
|
+
* Helper function to define theme configuration with full type support.
|
|
6
|
+
* Supports both static config objects and dynamic functions.
|
|
7
|
+
*/
|
|
8
|
+
const defineTheme = (config) => config;
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { defineTheme };
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
|
|
2
|
+
const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_properties = require('../../../automated-config/dist/properties.cjs');
|
|
4
|
+
const require_purgeFromCode = require('../purger/optimized/purgeFromCode.cjs');
|
|
5
|
+
const require_colors = require('../../../cli/dist/lib/colors.cjs');
|
|
6
|
+
const require_print = require('../../../cli/dist/lib/print.cjs');
|
|
7
|
+
let node_fs = require("node:fs");
|
|
8
|
+
node_fs = require_runtime.__toESM(node_fs);
|
|
9
|
+
let node_path = require("node:path");
|
|
10
|
+
node_path = require_runtime.__toESM(node_path);
|
|
11
|
+
let fast_glob = require("fast-glob");
|
|
12
|
+
fast_glob = require_runtime.__toESM(fast_glob);
|
|
13
|
+
let node_module = require("node:module");
|
|
14
|
+
|
|
15
|
+
//#region ../tailwind/dist/css/utils.js
|
|
16
|
+
/*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
|
|
17
|
+
/**
|
|
18
|
+
* Load a TypeScript/JavaScript config file dynamically
|
|
19
|
+
*/
|
|
20
|
+
const loadConfigFile = async (configPath) => {
|
|
21
|
+
const absolutePath = node_path.default.isAbsolute(configPath) ? configPath : node_path.default.join(process.cwd(), configPath);
|
|
22
|
+
if (!node_fs.default.existsSync(absolutePath)) return null;
|
|
23
|
+
try {
|
|
24
|
+
const module = await import(absolutePath);
|
|
25
|
+
return module.default ?? module.config ?? module;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
throw new Error(`Failed to load config file: ${absolutePath}\n${error instanceof Error ? error.message : "Unknown error"}`);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Extract variant defaults from a UniversalTokensConfig.
|
|
32
|
+
* Converts from config structure to a simpler lookup format.
|
|
33
|
+
* e.g., { button: { defaults: { size: 'md' } } } -> { Button: { size: 'md' } }
|
|
34
|
+
*/
|
|
35
|
+
const extractVariantDefaults = (config) => {
|
|
36
|
+
const componentNameMap = {
|
|
37
|
+
avatar: "Avatar",
|
|
38
|
+
badge: "Badge",
|
|
39
|
+
button: "Button",
|
|
40
|
+
checkbox: "Checkbox",
|
|
41
|
+
chip: "Chip",
|
|
42
|
+
divider: "Divider",
|
|
43
|
+
iconButton: "IconButton",
|
|
44
|
+
input: "Input",
|
|
45
|
+
link: "Link",
|
|
46
|
+
menu: "Menu",
|
|
47
|
+
radio: "Radio",
|
|
48
|
+
switch: "Switch"
|
|
49
|
+
};
|
|
50
|
+
return Object.entries(config).reduce((acc, [configKey, componentConfig]) => {
|
|
51
|
+
const pascalName = componentNameMap[configKey];
|
|
52
|
+
if (!pascalName || !componentConfig || typeof componentConfig !== "object") return acc;
|
|
53
|
+
const configWithDefaults = componentConfig;
|
|
54
|
+
return configWithDefaults.defaults ? {
|
|
55
|
+
...acc,
|
|
56
|
+
[pascalName]: configWithDefaults.defaults
|
|
57
|
+
} : acc;
|
|
58
|
+
}, {});
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Scan directory for JSX/TSX files and extract safelist
|
|
62
|
+
*/
|
|
63
|
+
const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants, componentData, variantDefaults, includeAllClassNamePrimitives = false) => {
|
|
64
|
+
const files = await (0, fast_glob.default)("**/*.{js,jsx,ts,tsx}", {
|
|
65
|
+
cwd: dir,
|
|
66
|
+
absolute: true,
|
|
67
|
+
ignore: ["**/node_modules/**"]
|
|
68
|
+
});
|
|
69
|
+
const results = await Promise.all(files.map(async (filePath) => {
|
|
70
|
+
return require_purgeFromCode.purgeFromCodeOptimized(node_fs.default.readFileSync(filePath, "utf-8"), {
|
|
71
|
+
colorModes,
|
|
72
|
+
variantDefaults,
|
|
73
|
+
variants,
|
|
74
|
+
autoVariants,
|
|
75
|
+
componentData,
|
|
76
|
+
includeAllClassNamePrimitives
|
|
77
|
+
});
|
|
78
|
+
}));
|
|
79
|
+
return {
|
|
80
|
+
safelist: results.flatMap((result) => result.safelist),
|
|
81
|
+
components: [...new Set(results.flatMap((result) => result.components))],
|
|
82
|
+
filesScanned: files.length
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Find a package's source directory in node_modules
|
|
87
|
+
*/
|
|
88
|
+
const findMonorepoRoot = (startDir) => {
|
|
89
|
+
const findUp = (currentDir) => {
|
|
90
|
+
if (node_fs.default.existsSync(node_path.default.join(currentDir, "packages"))) return currentDir;
|
|
91
|
+
const parentDir = node_path.default.dirname(currentDir);
|
|
92
|
+
return parentDir === currentDir ? null : findUp(parentDir);
|
|
93
|
+
};
|
|
94
|
+
return findUp(startDir);
|
|
95
|
+
};
|
|
96
|
+
const resolvePackageRoot = (workspaceDir, packageName) => {
|
|
97
|
+
const require = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
98
|
+
try {
|
|
99
|
+
const resolvedPackageJson = require.resolve(node_path.default.join(packageName, "package.json"), { paths: [workspaceDir] });
|
|
100
|
+
return node_path.default.dirname(resolvedPackageJson);
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
|
|
106
|
+
const matchingPath = fast_glob.default.sync("packages/**/package.json", {
|
|
107
|
+
cwd: monorepoRoot,
|
|
108
|
+
absolute: true,
|
|
109
|
+
ignore: ["**/node_modules/**", "**/dist/**"]
|
|
110
|
+
}).find((pkgJsonPath) => {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(node_fs.default.readFileSync(pkgJsonPath, "utf8")).name === packageName;
|
|
113
|
+
} catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return matchingPath ? node_path.default.dirname(matchingPath) : null;
|
|
118
|
+
};
|
|
119
|
+
const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) => {
|
|
120
|
+
return [
|
|
121
|
+
packageRoot ? node_path.default.join(packageRoot, "src") : null,
|
|
122
|
+
packageRoot ? node_path.default.join(packageRoot, "lib") : null,
|
|
123
|
+
packageRoot ? node_path.default.join(packageRoot, "dist") : null,
|
|
124
|
+
packageRoot,
|
|
125
|
+
node_path.default.join(workspaceDir, "node_modules", packageName, "src"),
|
|
126
|
+
node_path.default.join(workspaceDir, "node_modules", packageName, "lib"),
|
|
127
|
+
node_path.default.join(workspaceDir, "node_modules", packageName, "dist"),
|
|
128
|
+
node_path.default.join(workspaceDir, "node_modules", packageName)
|
|
129
|
+
].filter(Boolean);
|
|
130
|
+
};
|
|
131
|
+
const getFirstExistingPath = (candidates) => candidates.find((candidate) => node_fs.default.existsSync(candidate)) ?? null;
|
|
132
|
+
const findPackageSourceDir = (packageName) => {
|
|
133
|
+
const workspaceDir = process.cwd();
|
|
134
|
+
const monorepoRoot = findMonorepoRoot(workspaceDir);
|
|
135
|
+
let packageRoot = resolvePackageRoot(workspaceDir, packageName);
|
|
136
|
+
if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
|
|
137
|
+
return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Format bytes to human readable string
|
|
141
|
+
*/
|
|
142
|
+
const formatBytes = (bytes) => {
|
|
143
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
144
|
+
const kb = bytes / 1024;
|
|
145
|
+
if (kb < 1024) return `${kb.toFixed(1)} KB`;
|
|
146
|
+
return `${(kb / 1024).toFixed(2)} MB`;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Generate a uds.theme.ts scaffold file
|
|
150
|
+
*/
|
|
151
|
+
const scaffoldThemeConfig = async (options) => {
|
|
152
|
+
const workspaceDir = process.cwd();
|
|
153
|
+
const outputPath = options.outputPath ?? "uds.theme.ts";
|
|
154
|
+
const absoluteOutputPath = node_path.default.isAbsolute(outputPath) ? outputPath : node_path.default.join(workspaceDir, outputPath);
|
|
155
|
+
if (node_fs.default.existsSync(absoluteOutputPath) && !options.force) {
|
|
156
|
+
require_print.print(require_colors.red(`Error: ${outputPath} already exists. Use --force to overwrite.`));
|
|
157
|
+
process.exitCode = 1;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const template = `import { defineTheme } from '@yahoo/uds';
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* UDS Theme Configuration
|
|
164
|
+
*
|
|
165
|
+
* This file configures CSS generation for your app and shared packages.
|
|
166
|
+
* Run \`uds css\` to generate optimized CSS.
|
|
167
|
+
*/
|
|
168
|
+
export default defineTheme({
|
|
169
|
+
// Path to your uds.config.ts file
|
|
170
|
+
config: '${options.configPath ?? "./uds.config.ts"}',
|
|
171
|
+
|
|
172
|
+
// Entry directory for scanning your app code
|
|
173
|
+
entry: '${options.entry ?? "./src"}',
|
|
174
|
+
|
|
175
|
+
// Color modes to include (light mode is always in :root)
|
|
176
|
+
colorModes: ['dark'],
|
|
177
|
+
|
|
178
|
+
// Packages that inherit your app's theme (merged into main uds.css)
|
|
179
|
+
// inherit: ['@your-org/shared-ui'],
|
|
180
|
+
|
|
181
|
+
// CSS generation options (all optional)
|
|
182
|
+
// css: {
|
|
183
|
+
// safelist: [],
|
|
184
|
+
// preflight: true,
|
|
185
|
+
// fontFaceDeclarations: true,
|
|
186
|
+
// optimization: {
|
|
187
|
+
// removeUnusedFonts: false,
|
|
188
|
+
// removeEmptyRules: true,
|
|
189
|
+
// deduplicateScopedCss: true
|
|
190
|
+
// }
|
|
191
|
+
// }
|
|
192
|
+
});
|
|
193
|
+
`;
|
|
194
|
+
node_fs.default.writeFileSync(absoluteOutputPath, template);
|
|
195
|
+
require_print.print("");
|
|
196
|
+
require_print.print(require_colors.green("✅ Created uds.theme.ts"));
|
|
197
|
+
require_print.print("");
|
|
198
|
+
require_print.print(`${require_colors.magenta("Next steps:")}`);
|
|
199
|
+
require_print.print(` 1. Review and customize ${require_colors.cyan(outputPath)}`);
|
|
200
|
+
require_print.print(` 2. Run ${require_colors.cyan("uds css")} to generate CSS`);
|
|
201
|
+
require_print.print("");
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Get motion CSS variable prefixes needed by a set of components.
|
|
205
|
+
* Looks up motionVarPrefixes from componentData.json for each component.
|
|
206
|
+
*/
|
|
207
|
+
const getMotionVarPrefixes = (componentData, components) => {
|
|
208
|
+
const prefixes = components.flatMap((componentName) => {
|
|
209
|
+
return componentData[componentName]?.motionVarPrefixes ?? [];
|
|
210
|
+
});
|
|
211
|
+
return [...new Set(prefixes)];
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Collect css variable names exposed by configurable properties.
|
|
215
|
+
*/
|
|
216
|
+
const getConfigurableCssVariables = () => {
|
|
217
|
+
const udsVarPrefix = "--uds";
|
|
218
|
+
const cssVars = Object.values(require_properties.configurableProperties).flatMap(({ cssProperties }) => {
|
|
219
|
+
if (typeof cssProperties === "string") return cssProperties.startsWith(udsVarPrefix) ? [cssProperties] : [];
|
|
220
|
+
if (Array.isArray(cssProperties)) return cssProperties.filter((cssProperty) => typeof cssProperty === "string" && cssProperty.startsWith(udsVarPrefix));
|
|
221
|
+
return [];
|
|
222
|
+
});
|
|
223
|
+
return [...new Set(["--uds-button-gap", ...cssVars])];
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
//#endregion
|
|
227
|
+
exports.extractVariantDefaults = extractVariantDefaults;
|
|
228
|
+
exports.findPackageSourceDir = findPackageSourceDir;
|
|
229
|
+
exports.formatBytes = formatBytes;
|
|
230
|
+
exports.getConfigurableCssVariables = getConfigurableCssVariables;
|
|
231
|
+
exports.getMotionVarPrefixes = getMotionVarPrefixes;
|
|
232
|
+
exports.loadConfigFile = loadConfigFile;
|
|
233
|
+
exports.scaffoldThemeConfig = scaffoldThemeConfig;
|
|
234
|
+
exports.scanDirectoryForSafelist = scanDirectoryForSafelist;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
|
|
2
|
+
import { configurableProperties } from "../../../automated-config/dist/properties.js";
|
|
3
|
+
import { purgeFromCodeOptimized } from "../purger/optimized/purgeFromCode.js";
|
|
4
|
+
import { cyan, green, magenta, red } from "../../../cli/dist/lib/colors.js";
|
|
5
|
+
import { print } from "../../../cli/dist/lib/print.js";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import fg from "fast-glob";
|
|
9
|
+
import { createRequire } from "node:module";
|
|
10
|
+
|
|
11
|
+
//#region ../tailwind/dist/css/utils.js
|
|
12
|
+
/*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
|
|
13
|
+
/**
|
|
14
|
+
* Load a TypeScript/JavaScript config file dynamically
|
|
15
|
+
*/
|
|
16
|
+
const loadConfigFile = async (configPath) => {
|
|
17
|
+
const absolutePath = path.isAbsolute(configPath) ? configPath : path.join(process.cwd(), configPath);
|
|
18
|
+
if (!fs.existsSync(absolutePath)) return null;
|
|
19
|
+
try {
|
|
20
|
+
const module = await import(absolutePath);
|
|
21
|
+
return module.default ?? module.config ?? module;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw new Error(`Failed to load config file: ${absolutePath}\n${error instanceof Error ? error.message : "Unknown error"}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Extract variant defaults from a UniversalTokensConfig.
|
|
28
|
+
* Converts from config structure to a simpler lookup format.
|
|
29
|
+
* e.g., { button: { defaults: { size: 'md' } } } -> { Button: { size: 'md' } }
|
|
30
|
+
*/
|
|
31
|
+
const extractVariantDefaults = (config) => {
|
|
32
|
+
const componentNameMap = {
|
|
33
|
+
avatar: "Avatar",
|
|
34
|
+
badge: "Badge",
|
|
35
|
+
button: "Button",
|
|
36
|
+
checkbox: "Checkbox",
|
|
37
|
+
chip: "Chip",
|
|
38
|
+
divider: "Divider",
|
|
39
|
+
iconButton: "IconButton",
|
|
40
|
+
input: "Input",
|
|
41
|
+
link: "Link",
|
|
42
|
+
menu: "Menu",
|
|
43
|
+
radio: "Radio",
|
|
44
|
+
switch: "Switch"
|
|
45
|
+
};
|
|
46
|
+
return Object.entries(config).reduce((acc, [configKey, componentConfig]) => {
|
|
47
|
+
const pascalName = componentNameMap[configKey];
|
|
48
|
+
if (!pascalName || !componentConfig || typeof componentConfig !== "object") return acc;
|
|
49
|
+
const configWithDefaults = componentConfig;
|
|
50
|
+
return configWithDefaults.defaults ? {
|
|
51
|
+
...acc,
|
|
52
|
+
[pascalName]: configWithDefaults.defaults
|
|
53
|
+
} : acc;
|
|
54
|
+
}, {});
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Scan directory for JSX/TSX files and extract safelist
|
|
58
|
+
*/
|
|
59
|
+
const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants, componentData, variantDefaults, includeAllClassNamePrimitives = false) => {
|
|
60
|
+
const files = await fg("**/*.{js,jsx,ts,tsx}", {
|
|
61
|
+
cwd: dir,
|
|
62
|
+
absolute: true,
|
|
63
|
+
ignore: ["**/node_modules/**"]
|
|
64
|
+
});
|
|
65
|
+
const results = await Promise.all(files.map(async (filePath) => {
|
|
66
|
+
return purgeFromCodeOptimized(fs.readFileSync(filePath, "utf-8"), {
|
|
67
|
+
colorModes,
|
|
68
|
+
variantDefaults,
|
|
69
|
+
variants,
|
|
70
|
+
autoVariants,
|
|
71
|
+
componentData,
|
|
72
|
+
includeAllClassNamePrimitives
|
|
73
|
+
});
|
|
74
|
+
}));
|
|
75
|
+
return {
|
|
76
|
+
safelist: results.flatMap((result) => result.safelist),
|
|
77
|
+
components: [...new Set(results.flatMap((result) => result.components))],
|
|
78
|
+
filesScanned: files.length
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Find a package's source directory in node_modules
|
|
83
|
+
*/
|
|
84
|
+
const findMonorepoRoot = (startDir) => {
|
|
85
|
+
const findUp = (currentDir) => {
|
|
86
|
+
if (fs.existsSync(path.join(currentDir, "packages"))) return currentDir;
|
|
87
|
+
const parentDir = path.dirname(currentDir);
|
|
88
|
+
return parentDir === currentDir ? null : findUp(parentDir);
|
|
89
|
+
};
|
|
90
|
+
return findUp(startDir);
|
|
91
|
+
};
|
|
92
|
+
const resolvePackageRoot = (workspaceDir, packageName) => {
|
|
93
|
+
const require = createRequire(import.meta.url);
|
|
94
|
+
try {
|
|
95
|
+
const resolvedPackageJson = require.resolve(path.join(packageName, "package.json"), { paths: [workspaceDir] });
|
|
96
|
+
return path.dirname(resolvedPackageJson);
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
|
|
102
|
+
const matchingPath = fg.sync("packages/**/package.json", {
|
|
103
|
+
cwd: monorepoRoot,
|
|
104
|
+
absolute: true,
|
|
105
|
+
ignore: ["**/node_modules/**", "**/dist/**"]
|
|
106
|
+
}).find((pkgJsonPath) => {
|
|
107
|
+
try {
|
|
108
|
+
return JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")).name === packageName;
|
|
109
|
+
} catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return matchingPath ? path.dirname(matchingPath) : null;
|
|
114
|
+
};
|
|
115
|
+
const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) => {
|
|
116
|
+
return [
|
|
117
|
+
packageRoot ? path.join(packageRoot, "src") : null,
|
|
118
|
+
packageRoot ? path.join(packageRoot, "lib") : null,
|
|
119
|
+
packageRoot ? path.join(packageRoot, "dist") : null,
|
|
120
|
+
packageRoot,
|
|
121
|
+
path.join(workspaceDir, "node_modules", packageName, "src"),
|
|
122
|
+
path.join(workspaceDir, "node_modules", packageName, "lib"),
|
|
123
|
+
path.join(workspaceDir, "node_modules", packageName, "dist"),
|
|
124
|
+
path.join(workspaceDir, "node_modules", packageName)
|
|
125
|
+
].filter(Boolean);
|
|
126
|
+
};
|
|
127
|
+
const getFirstExistingPath = (candidates) => candidates.find((candidate) => fs.existsSync(candidate)) ?? null;
|
|
128
|
+
const findPackageSourceDir = (packageName) => {
|
|
129
|
+
const workspaceDir = process.cwd();
|
|
130
|
+
const monorepoRoot = findMonorepoRoot(workspaceDir);
|
|
131
|
+
let packageRoot = resolvePackageRoot(workspaceDir, packageName);
|
|
132
|
+
if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
|
|
133
|
+
return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Format bytes to human readable string
|
|
137
|
+
*/
|
|
138
|
+
const formatBytes = (bytes) => {
|
|
139
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
140
|
+
const kb = bytes / 1024;
|
|
141
|
+
if (kb < 1024) return `${kb.toFixed(1)} KB`;
|
|
142
|
+
return `${(kb / 1024).toFixed(2)} MB`;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Generate a uds.theme.ts scaffold file
|
|
146
|
+
*/
|
|
147
|
+
const scaffoldThemeConfig = async (options) => {
|
|
148
|
+
const workspaceDir = process.cwd();
|
|
149
|
+
const outputPath = options.outputPath ?? "uds.theme.ts";
|
|
150
|
+
const absoluteOutputPath = path.isAbsolute(outputPath) ? outputPath : path.join(workspaceDir, outputPath);
|
|
151
|
+
if (fs.existsSync(absoluteOutputPath) && !options.force) {
|
|
152
|
+
print(red(`Error: ${outputPath} already exists. Use --force to overwrite.`));
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const template = `import { defineTheme } from '@yahoo/uds';
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* UDS Theme Configuration
|
|
160
|
+
*
|
|
161
|
+
* This file configures CSS generation for your app and shared packages.
|
|
162
|
+
* Run \`uds css\` to generate optimized CSS.
|
|
163
|
+
*/
|
|
164
|
+
export default defineTheme({
|
|
165
|
+
// Path to your uds.config.ts file
|
|
166
|
+
config: '${options.configPath ?? "./uds.config.ts"}',
|
|
167
|
+
|
|
168
|
+
// Entry directory for scanning your app code
|
|
169
|
+
entry: '${options.entry ?? "./src"}',
|
|
170
|
+
|
|
171
|
+
// Color modes to include (light mode is always in :root)
|
|
172
|
+
colorModes: ['dark'],
|
|
173
|
+
|
|
174
|
+
// Packages that inherit your app's theme (merged into main uds.css)
|
|
175
|
+
// inherit: ['@your-org/shared-ui'],
|
|
176
|
+
|
|
177
|
+
// CSS generation options (all optional)
|
|
178
|
+
// css: {
|
|
179
|
+
// safelist: [],
|
|
180
|
+
// preflight: true,
|
|
181
|
+
// fontFaceDeclarations: true,
|
|
182
|
+
// optimization: {
|
|
183
|
+
// removeUnusedFonts: false,
|
|
184
|
+
// removeEmptyRules: true,
|
|
185
|
+
// deduplicateScopedCss: true
|
|
186
|
+
// }
|
|
187
|
+
// }
|
|
188
|
+
});
|
|
189
|
+
`;
|
|
190
|
+
fs.writeFileSync(absoluteOutputPath, template);
|
|
191
|
+
print("");
|
|
192
|
+
print(green("✅ Created uds.theme.ts"));
|
|
193
|
+
print("");
|
|
194
|
+
print(`${magenta("Next steps:")}`);
|
|
195
|
+
print(` 1. Review and customize ${cyan(outputPath)}`);
|
|
196
|
+
print(` 2. Run ${cyan("uds css")} to generate CSS`);
|
|
197
|
+
print("");
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* Get motion CSS variable prefixes needed by a set of components.
|
|
201
|
+
* Looks up motionVarPrefixes from componentData.json for each component.
|
|
202
|
+
*/
|
|
203
|
+
const getMotionVarPrefixes = (componentData, components) => {
|
|
204
|
+
const prefixes = components.flatMap((componentName) => {
|
|
205
|
+
return componentData[componentName]?.motionVarPrefixes ?? [];
|
|
206
|
+
});
|
|
207
|
+
return [...new Set(prefixes)];
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Collect css variable names exposed by configurable properties.
|
|
211
|
+
*/
|
|
212
|
+
const getConfigurableCssVariables = () => {
|
|
213
|
+
const udsVarPrefix = "--uds";
|
|
214
|
+
const cssVars = Object.values(configurableProperties).flatMap(({ cssProperties }) => {
|
|
215
|
+
if (typeof cssProperties === "string") return cssProperties.startsWith(udsVarPrefix) ? [cssProperties] : [];
|
|
216
|
+
if (Array.isArray(cssProperties)) return cssProperties.filter((cssProperty) => typeof cssProperty === "string" && cssProperty.startsWith(udsVarPrefix));
|
|
217
|
+
return [];
|
|
218
|
+
});
|
|
219
|
+
return [...new Set(["--uds-button-gap", ...cssVars])];
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
//#endregion
|
|
223
|
+
export { extractVariantDefaults, findPackageSourceDir, formatBytes, getConfigurableCssVariables, getMotionVarPrefixes, loadConfigFile, scaffoldThemeConfig, scanDirectoryForSafelist };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import "./tailwind/components/getResponsiveTextStyles.js";
|
|
3
|
-
import { WebTokens, parseTokens } from "./utils/parseTokens.js";
|
|
4
2
|
import "./commands/generateComponentData.js";
|
|
3
|
+
import "./commands/css.js";
|
|
5
4
|
import "./commands/generatePurgeCSSData.js";
|
|
6
|
-
import "./commands/purge.js";
|
|
5
|
+
import "./commands/purge.js";
|
|
6
|
+
import { defineTheme } from "./css/theme.js";
|
|
7
|
+
import "./tailwind/components/getResponsiveTextStyles.js";
|
|
8
|
+
import { WebTokens, parseTokens } from "./utils/parseTokens.js";
|
|
@@ -4,10 +4,10 @@ const require_index = require('../../../../css-tokens/dist/index.cjs');
|
|
|
4
4
|
const require_print = require('../../../../cli/dist/lib/print.cjs');
|
|
5
5
|
const require_spinner = require('../../../../cli/dist/lib/spinner.cjs');
|
|
6
6
|
const require_tsMorph = require('../../utils/tsMorph.cjs');
|
|
7
|
+
let ts_morph = require("ts-morph");
|
|
8
|
+
let node_fs = require("node:fs");
|
|
7
9
|
let node_path = require("node:path");
|
|
8
10
|
node_path = require_runtime.__toESM(node_path);
|
|
9
|
-
let node_fs = require("node:fs");
|
|
10
|
-
let ts_morph = require("ts-morph");
|
|
11
11
|
let fast_glob = require("fast-glob");
|
|
12
12
|
fast_glob = require_runtime.__toESM(fast_glob);
|
|
13
13
|
|
|
@@ -32,7 +32,8 @@ const getFiles = async (entry) => {
|
|
|
32
32
|
if (!workspaceDir) throw new Error("Workspace directory not found.");
|
|
33
33
|
return await (0, fast_glob.default)(["**/*.jsx", "**/*.tsx"], {
|
|
34
34
|
cwd: node_path.default.join(workspaceDir, entry),
|
|
35
|
-
absolute: true
|
|
35
|
+
absolute: true,
|
|
36
|
+
ignore: ["**/node_modules/**"]
|
|
36
37
|
});
|
|
37
38
|
} catch {
|
|
38
39
|
throw new Error(`Couldn't find the entry directory: ${entry}. Please make sure it exists.`);
|
|
@@ -3,9 +3,9 @@ import { DARK_COLOR_MODE_CLASSNAME, LARGE_SCALE_MODE_CLASSNAME, LIGHT_COLOR_MODE
|
|
|
3
3
|
import { print } from "../../../../cli/dist/lib/print.js";
|
|
4
4
|
import { spinStart, spinStop } from "../../../../cli/dist/lib/spinner.js";
|
|
5
5
|
import { findReferencesAsJsxElements, getUsedPropsInReference } from "../../utils/tsMorph.js";
|
|
6
|
-
import path from "node:path";
|
|
7
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
8
6
|
import { Node, Project, SyntaxKind, ts } from "ts-morph";
|
|
7
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
9
|
import fg from "fast-glob";
|
|
10
10
|
|
|
11
11
|
//#region ../tailwind/dist/purger/legacy/purgeCSS.js
|
|
@@ -29,7 +29,8 @@ const getFiles = async (entry) => {
|
|
|
29
29
|
if (!workspaceDir) throw new Error("Workspace directory not found.");
|
|
30
30
|
return await fg(["**/*.jsx", "**/*.tsx"], {
|
|
31
31
|
cwd: path.join(workspaceDir, entry),
|
|
32
|
-
absolute: true
|
|
32
|
+
absolute: true,
|
|
33
|
+
ignore: ["**/node_modules/**"]
|
|
33
34
|
});
|
|
34
35
|
} catch {
|
|
35
36
|
throw new Error(`Couldn't find the entry directory: ${entry}. Please make sure it exists.`);
|