@wordpress/theme 0.1.0
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/LICENSE.md +788 -0
- package/README.md +67 -0
- package/bin/build-tokens.js +83 -0
- package/bin/generate-primitive-tokens/index.ts +115 -0
- package/bin/terrazzo-plugin-ds-tokens-docs/index.ts +103 -0
- package/bin/terrazzo-plugin-figma-ds-token-manager/index.ts +210 -0
- package/bin/terrazzo-plugin-figma-ds-token-manager/lib.ts +1 -0
- package/bin/terrazzo-plugin-known-wpds-css-variables/index.ts +72 -0
- package/build/color-ramps/index.js +132 -0
- package/build/color-ramps/index.js.map +7 -0
- package/build/color-ramps/lib/cache-utils.js +57 -0
- package/build/color-ramps/lib/cache-utils.js.map +7 -0
- package/build/color-ramps/lib/constants.js +105 -0
- package/build/color-ramps/lib/constants.js.map +7 -0
- package/build/color-ramps/lib/find-color-with-constraints.js +141 -0
- package/build/color-ramps/lib/find-color-with-constraints.js.map +7 -0
- package/build/color-ramps/lib/index.js +264 -0
- package/build/color-ramps/lib/index.js.map +7 -0
- package/build/color-ramps/lib/ramp-configs.js +315 -0
- package/build/color-ramps/lib/ramp-configs.js.map +7 -0
- package/build/color-ramps/lib/taper-chroma.js +159 -0
- package/build/color-ramps/lib/taper-chroma.js.map +7 -0
- package/build/color-ramps/lib/types.js +17 -0
- package/build/color-ramps/lib/types.js.map +7 -0
- package/build/color-ramps/lib/utils.js +106 -0
- package/build/color-ramps/lib/utils.js.map +7 -0
- package/build/context.js +34 -0
- package/build/context.js.map +7 -0
- package/build/index.js +29 -0
- package/build/index.js.map +7 -0
- package/build/lock-unlock.js +35 -0
- package/build/lock-unlock.js.map +7 -0
- package/build/prebuilt/js/design-tokens.js +135 -0
- package/build/prebuilt/js/design-tokens.js.map +7 -0
- package/build/prebuilt/json/figma.json +1317 -0
- package/build/prebuilt/ts/design-tokens.js +354 -0
- package/build/prebuilt/ts/design-tokens.js.map +7 -0
- package/build/private-apis.js +36 -0
- package/build/private-apis.js.map +7 -0
- package/build/style.module.css.js +2 -0
- package/build/theme-provider.js +92 -0
- package/build/theme-provider.js.map +7 -0
- package/build/types/css-modules.d.js +2 -0
- package/build/types/css-modules.d.js.map +7 -0
- package/build/types.js +17 -0
- package/build/types.js.map +7 -0
- package/build/use-theme-provider-styles.js +230 -0
- package/build/use-theme-provider-styles.js.map +7 -0
- package/build-module/color-ramps/index.js +95 -0
- package/build-module/color-ramps/index.js.map +7 -0
- package/build-module/color-ramps/lib/cache-utils.js +31 -0
- package/build-module/color-ramps/lib/cache-utils.js.map +7 -0
- package/build-module/color-ramps/lib/constants.js +63 -0
- package/build-module/color-ramps/lib/constants.js.map +7 -0
- package/build-module/color-ramps/lib/find-color-with-constraints.js +112 -0
- package/build-module/color-ramps/lib/find-color-with-constraints.js.map +7 -0
- package/build-module/color-ramps/lib/index.js +235 -0
- package/build-module/color-ramps/lib/index.js.map +7 -0
- package/build-module/color-ramps/lib/ramp-configs.js +290 -0
- package/build-module/color-ramps/lib/ramp-configs.js.map +7 -0
- package/build-module/color-ramps/lib/taper-chroma.js +125 -0
- package/build-module/color-ramps/lib/taper-chroma.js.map +7 -0
- package/build-module/color-ramps/lib/types.js +1 -0
- package/build-module/color-ramps/lib/types.js.map +7 -0
- package/build-module/color-ramps/lib/utils.js +84 -0
- package/build-module/color-ramps/lib/utils.js.map +7 -0
- package/build-module/context.js +10 -0
- package/build-module/context.js.map +7 -0
- package/build-module/index.js +5 -0
- package/build-module/index.js.map +7 -0
- package/build-module/lock-unlock.js +10 -0
- package/build-module/lock-unlock.js.map +7 -0
- package/build-module/prebuilt/js/design-tokens.js +115 -0
- package/build-module/prebuilt/js/design-tokens.js.map +7 -0
- package/build-module/prebuilt/json/figma.json +1317 -0
- package/build-module/prebuilt/ts/design-tokens.js +334 -0
- package/build-module/prebuilt/ts/design-tokens.js.map +7 -0
- package/build-module/private-apis.js +12 -0
- package/build-module/private-apis.js.map +7 -0
- package/build-module/style.module.css.js +1 -0
- package/build-module/theme-provider.js +58 -0
- package/build-module/theme-provider.js.map +7 -0
- package/build-module/types/css-modules.d.js +1 -0
- package/build-module/types/css-modules.d.js.map +7 -0
- package/build-module/types.js +1 -0
- package/build-module/types.js.map +7 -0
- package/build-module/use-theme-provider-styles.js +200 -0
- package/build-module/use-theme-provider-styles.js.map +7 -0
- package/build-style/style.css +3 -0
- package/build-types/color-ramps/index.d.ts +44 -0
- package/build-types/color-ramps/index.d.ts.map +1 -0
- package/build-types/color-ramps/lib/cache-utils.d.ts +22 -0
- package/build-types/color-ramps/lib/cache-utils.d.ts.map +1 -0
- package/build-types/color-ramps/lib/constants.d.ts +38 -0
- package/build-types/color-ramps/lib/constants.d.ts.map +1 -0
- package/build-types/color-ramps/lib/find-color-with-constraints.d.ts +37 -0
- package/build-types/color-ramps/lib/find-color-with-constraints.d.ts.map +1 -0
- package/build-types/color-ramps/lib/index.d.ts +11 -0
- package/build-types/color-ramps/lib/index.d.ts.map +1 -0
- package/build-types/color-ramps/lib/ramp-configs.d.ts +7 -0
- package/build-types/color-ramps/lib/ramp-configs.d.ts.map +1 -0
- package/build-types/color-ramps/lib/taper-chroma.d.ts +32 -0
- package/build-types/color-ramps/lib/taper-chroma.d.ts.map +1 -0
- package/build-types/color-ramps/lib/types.d.ts +78 -0
- package/build-types/color-ramps/lib/types.d.ts.map +1 -0
- package/build-types/color-ramps/lib/utils.d.ts +38 -0
- package/build-types/color-ramps/lib/utils.d.ts.map +1 -0
- package/build-types/color-ramps/stories/index.story.d.ts +14 -0
- package/build-types/color-ramps/stories/index.story.d.ts.map +1 -0
- package/build-types/color-ramps/stories/ramp-table.d.ts +19 -0
- package/build-types/color-ramps/stories/ramp-table.d.ts.map +1 -0
- package/build-types/context.d.ts +10 -0
- package/build-types/context.d.ts.map +1 -0
- package/build-types/index.d.ts +2 -0
- package/build-types/index.d.ts.map +1 -0
- package/build-types/lock-unlock.d.ts +2 -0
- package/build-types/lock-unlock.d.ts.map +1 -0
- package/build-types/prebuilt/js/design-tokens.d.ts +3 -0
- package/build-types/prebuilt/js/design-tokens.d.ts.map +1 -0
- package/build-types/prebuilt/ts/design-tokens.d.ts +7 -0
- package/build-types/prebuilt/ts/design-tokens.d.ts.map +1 -0
- package/build-types/private-apis.d.ts +2 -0
- package/build-types/private-apis.d.ts.map +1 -0
- package/build-types/stories/index.story.d.ts +15 -0
- package/build-types/stories/index.story.d.ts.map +1 -0
- package/build-types/theme-provider.d.ts +3 -0
- package/build-types/theme-provider.d.ts.map +1 -0
- package/build-types/types.d.ts +42 -0
- package/build-types/types.d.ts.map +1 -0
- package/build-types/use-theme-provider-styles.d.ts +17 -0
- package/build-types/use-theme-provider-styles.d.ts.map +1 -0
- package/docs/ds-tokens.md +283 -0
- package/package.json +58 -0
- package/src/color-ramps/index.ts +155 -0
- package/src/color-ramps/lib/cache-utils.ts +56 -0
- package/src/color-ramps/lib/constants.ts +85 -0
- package/src/color-ramps/lib/find-color-with-constraints.ts +190 -0
- package/src/color-ramps/lib/index.ts +369 -0
- package/src/color-ramps/lib/ramp-configs.ts +309 -0
- package/src/color-ramps/lib/taper-chroma.ts +226 -0
- package/src/color-ramps/lib/types.ts +90 -0
- package/src/color-ramps/lib/utils.ts +161 -0
- package/src/color-ramps/stories/index.story.tsx +264 -0
- package/src/color-ramps/stories/ramp-table.tsx +212 -0
- package/src/color-ramps/test/__snapshots__/index.test.ts.snap +1280 -0
- package/src/color-ramps/test/index.test.ts +94 -0
- package/src/context.ts +19 -0
- package/src/index.ts +2 -0
- package/src/lock-unlock.ts +10 -0
- package/src/prebuilt/css/design-tokens.css +401 -0
- package/src/prebuilt/js/design-tokens.js +116 -0
- package/src/prebuilt/json/figma.json +1317 -0
- package/src/prebuilt/ts/design-tokens.ts +335 -0
- package/src/private-apis.ts +12 -0
- package/src/stories/index.story.tsx +426 -0
- package/src/style.module.css +3 -0
- package/src/theme-provider.tsx +87 -0
- package/src/types/css-modules.d.ts +4 -0
- package/src/types.ts +44 -0
- package/src/use-theme-provider-styles.ts +247 -0
- package/terrazzo.config.ts +102 -0
- package/tokens/border.json +34 -0
- package/tokens/color.json +877 -0
- package/tokens/elevation.json +201 -0
- package/tokens/spacing.json +45 -0
- package/tokens/typography.json +93 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# (Experimental) Theme
|
|
2
|
+
|
|
3
|
+
A theming package that's part of the WordPress Design System. It has two parts:
|
|
4
|
+
|
|
5
|
+
- **Design Tokens**: A comprehensive system of design tokens for colors, spacing, typography, and more
|
|
6
|
+
- **Theme System**: A flexible theming provider for consistent theming across applications
|
|
7
|
+
|
|
8
|
+
## Design Tokens
|
|
9
|
+
|
|
10
|
+
In the **[Design Tokens Reference](docs/ds-tokens.md)** document there is a complete reference of all available design tokens including colors, spacing, typography, and more.
|
|
11
|
+
|
|
12
|
+
## Theme Provider
|
|
13
|
+
|
|
14
|
+
The `ThemeProvider` is a React component that should wrap your application to provide design tokens and theme context to the child UI components.
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { ThemeProvider } from '@wordpress/theme';
|
|
18
|
+
|
|
19
|
+
function App() {
|
|
20
|
+
return (
|
|
21
|
+
<ThemeProvider color={ { scheme: 'light', accent: 'blue' } }>
|
|
22
|
+
{ /* Your app content */ }
|
|
23
|
+
</ThemeProvider>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The provider can be used recursively to override or modify the theme for a specific subtree.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<ThemeProvider>
|
|
32
|
+
{ /* system-themed UI components */ }
|
|
33
|
+
<ThemeProvider color={ { scheme: 'dark' } }>
|
|
34
|
+
{ /* dark-themed UI components */ }
|
|
35
|
+
<ThemeProvider color={ { scheme: 'light' } }>
|
|
36
|
+
{ /* light-themed UI components */ }
|
|
37
|
+
</ThemeProvider>
|
|
38
|
+
{ /* dark-themed UI components */ }
|
|
39
|
+
</ThemeProvider>
|
|
40
|
+
{ /* system-themed UI components */ }
|
|
41
|
+
</ThemeProvider>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The `ThemeProvider` redefines some of the design system tokens. Components consuming semantic design system tokens will automatically follow the chosen theme. Note that the tokens are defined and inherited using the CSS cascade, and therefore the DOM tree, not the React tree. This is very important when using React portals.
|
|
45
|
+
|
|
46
|
+
### Building
|
|
47
|
+
|
|
48
|
+
This package is built in two steps. When `npm run build` is run at the root of the repo, it will first run the "prebuild" step of this package, which is defined in the `build` script of this package's package.json.
|
|
49
|
+
|
|
50
|
+
This step will:
|
|
51
|
+
|
|
52
|
+
1. Generate primitive tokens.
|
|
53
|
+
2. Build CSS and JavaScript token files.
|
|
54
|
+
3. Update the design tokens documentation.
|
|
55
|
+
4. Format all generated files.
|
|
56
|
+
|
|
57
|
+
The files generated in this step will all be committed to the repo.
|
|
58
|
+
|
|
59
|
+
After the prebuild step, the package will be built into its final form via the repo's standard package build script.
|
|
60
|
+
|
|
61
|
+
## Contributing to this package
|
|
62
|
+
|
|
63
|
+
This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
|
|
64
|
+
|
|
65
|
+
To find out more about contributing to this package or Gutenberg as a whole, please read the project's main [contributor guide](https://github.com/WordPress/gutenberg/tree/HEAD/CONTRIBUTING.md).
|
|
66
|
+
|
|
67
|
+
<br /><br /><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
const { execSync } = require( 'child_process' );
|
|
5
|
+
const fs = require( 'fs' );
|
|
6
|
+
const path = require( 'path' );
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Build script for design tokens.
|
|
10
|
+
*
|
|
11
|
+
* This script:
|
|
12
|
+
* 1. Compiles and runs the primitive token generator
|
|
13
|
+
* 2. Compiles the terrazzo config and runs the Terrazzo build
|
|
14
|
+
* 3. Cleans up temporary files
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const TEMP_FILES = [
|
|
18
|
+
'bin/generate-primitive-tokens/index.mjs',
|
|
19
|
+
'terrazzo.config.mjs',
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
function cleanup() {
|
|
23
|
+
TEMP_FILES.forEach( ( file ) => {
|
|
24
|
+
const filePath = path.join( process.cwd(), file );
|
|
25
|
+
if ( fs.existsSync( filePath ) ) {
|
|
26
|
+
fs.unlinkSync( filePath );
|
|
27
|
+
}
|
|
28
|
+
} );
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Ensure cleanup happens even if the process exits unexpectedly
|
|
32
|
+
process.on( 'exit', cleanup );
|
|
33
|
+
process.on( 'SIGINT', () => {
|
|
34
|
+
cleanup();
|
|
35
|
+
process.exit( 130 );
|
|
36
|
+
} );
|
|
37
|
+
process.on( 'SIGTERM', () => {
|
|
38
|
+
cleanup();
|
|
39
|
+
process.exit( 143 );
|
|
40
|
+
} );
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
// Step 1: Compile the primitive token generator
|
|
44
|
+
console.log( '🔨 Compiling primitive token generator...' );
|
|
45
|
+
execSync(
|
|
46
|
+
'npx esbuild bin/generate-primitive-tokens/index.ts --bundle --platform=node --format=esm --packages=external --outfile=bin/generate-primitive-tokens/index.mjs',
|
|
47
|
+
{
|
|
48
|
+
stdio: 'inherit',
|
|
49
|
+
cwd: process.cwd(),
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Step 2: Run the primitive token generator
|
|
54
|
+
console.log( '🎨 Generating primitive tokens...' );
|
|
55
|
+
execSync( 'node bin/generate-primitive-tokens/index.mjs', {
|
|
56
|
+
stdio: 'inherit',
|
|
57
|
+
cwd: process.cwd(),
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
// Step 3: Compile the terrazzo config
|
|
61
|
+
console.log( '🔨 Compiling terrazzo config...' );
|
|
62
|
+
execSync(
|
|
63
|
+
'npx esbuild terrazzo.config.ts --bundle --platform=node --format=esm --packages=external --outfile=terrazzo.config.mjs',
|
|
64
|
+
{
|
|
65
|
+
stdio: 'inherit',
|
|
66
|
+
cwd: process.cwd(),
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Step 4: Run terrazzo build
|
|
71
|
+
console.log( '🏗️ Running terrazzo build...' );
|
|
72
|
+
execSync( 'npx tz build --config terrazzo.config.mjs', {
|
|
73
|
+
stdio: 'inherit',
|
|
74
|
+
cwd: process.cwd(),
|
|
75
|
+
} );
|
|
76
|
+
|
|
77
|
+
console.log( '✅ Token build complete!' );
|
|
78
|
+
} catch ( error ) {
|
|
79
|
+
console.error( '❌ Build failed:', error.message );
|
|
80
|
+
process.exit( 1 );
|
|
81
|
+
} finally {
|
|
82
|
+
cleanup();
|
|
83
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import Color from 'colorjs.io';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_SEED_COLORS,
|
|
14
|
+
buildBgRamp,
|
|
15
|
+
buildAccentRamp,
|
|
16
|
+
} from '../../src/color-ramps/index';
|
|
17
|
+
|
|
18
|
+
const __filename = fileURLToPath( import.meta.url );
|
|
19
|
+
const __dirname = path.dirname( __filename );
|
|
20
|
+
|
|
21
|
+
// Path to the color.json file
|
|
22
|
+
const colorJsonPath = path.join( __dirname, '../../tokens/color.json' );
|
|
23
|
+
|
|
24
|
+
const transformColorStringToDTCGValue = ( color: string ) => {
|
|
25
|
+
if ( /oklch|p3/.test( color ) ) {
|
|
26
|
+
let parsed: Color;
|
|
27
|
+
try {
|
|
28
|
+
parsed = new Color( color ).to( 'oklch' );
|
|
29
|
+
} catch {
|
|
30
|
+
return color;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const coords = parsed.coords;
|
|
34
|
+
return {
|
|
35
|
+
colorSpace: 'oklch',
|
|
36
|
+
components: [
|
|
37
|
+
Math.floor( 10000 * coords[ 0 ] ) / 10000, // l
|
|
38
|
+
coords[ 1 ], // c
|
|
39
|
+
isNaN( coords[ 2 ] ) ? 0 : coords[ 2 ], // h
|
|
40
|
+
],
|
|
41
|
+
...( parsed.alpha < 1 ? { alpha: parsed.alpha } : undefined ),
|
|
42
|
+
hex: parsed.to( 'srgb' ).toString( { format: 'hex' } ),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return color;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Main function
|
|
50
|
+
function generatePrimitiveColorTokens() {
|
|
51
|
+
const startTime = performance.now();
|
|
52
|
+
console.log( '🎨 Starting primitive color tokens generation...' );
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
// Read the color.json file
|
|
56
|
+
const colorJson = JSON.parse(
|
|
57
|
+
fs.readFileSync( colorJsonPath, 'utf8' )
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Build the ramps
|
|
61
|
+
const bgRamp = buildBgRamp( { seed: DEFAULT_SEED_COLORS.bg } );
|
|
62
|
+
const accentRamps = [ ...Object.entries( DEFAULT_SEED_COLORS ) ]
|
|
63
|
+
.filter( ( [ scaleName ] ) => scaleName !== 'bg' )
|
|
64
|
+
.map( ( [ scaleName, seed ] ) => ( {
|
|
65
|
+
scaleName,
|
|
66
|
+
ramp: buildAccentRamp( {
|
|
67
|
+
seed,
|
|
68
|
+
bgRamp,
|
|
69
|
+
} ),
|
|
70
|
+
} ) );
|
|
71
|
+
|
|
72
|
+
// Convert the ramp values in a DTCG compatible format
|
|
73
|
+
[
|
|
74
|
+
{
|
|
75
|
+
scaleName: 'bg',
|
|
76
|
+
ramp: bgRamp,
|
|
77
|
+
},
|
|
78
|
+
...accentRamps,
|
|
79
|
+
].forEach( ( { scaleName, ramp } ) => {
|
|
80
|
+
colorJson.color.primitive[ scaleName ] = {};
|
|
81
|
+
for ( const [ tokenName, tokenValue ] of Object.entries(
|
|
82
|
+
ramp.ramp
|
|
83
|
+
) ) {
|
|
84
|
+
colorJson.color.primitive[ scaleName ][ tokenName ] = {
|
|
85
|
+
$value: transformColorStringToDTCGValue( tokenValue.color ),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
} );
|
|
89
|
+
|
|
90
|
+
// Write the updated JSON back to the file with proper formatting
|
|
91
|
+
fs.writeFileSync(
|
|
92
|
+
colorJsonPath,
|
|
93
|
+
JSON.stringify( colorJson, null, '\t' )
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const endTime = performance.now();
|
|
97
|
+
const duration = endTime - startTime;
|
|
98
|
+
console.log(
|
|
99
|
+
`✅ Successfully updated color.json (${ duration.toFixed( 2 ) }ms)`
|
|
100
|
+
);
|
|
101
|
+
} catch ( error ) {
|
|
102
|
+
const endTime = performance.now();
|
|
103
|
+
const duration = endTime - startTime;
|
|
104
|
+
console.error(
|
|
105
|
+
`❌ Error updating color tokens after ${ duration.toFixed(
|
|
106
|
+
2
|
|
107
|
+
) }ms:`,
|
|
108
|
+
error
|
|
109
|
+
);
|
|
110
|
+
process.exit( 1 );
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Run the script
|
|
115
|
+
generatePrimitiveColorTokens();
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { FORMAT_ID } from '@terrazzo/plugin-css';
|
|
5
|
+
import type { Plugin } from '@terrazzo/parser';
|
|
6
|
+
|
|
7
|
+
function isPrivateToken( token: string ) {
|
|
8
|
+
return /-private-/i.test( token );
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function titleCase( str: string ) {
|
|
12
|
+
return str[ 0 ].toUpperCase() + str.slice( 1 );
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type TokensMap = Record< string, Record< string, string > >;
|
|
16
|
+
|
|
17
|
+
export default function pluginDsTokenDocs( {
|
|
18
|
+
filename = 'design-tokens.md',
|
|
19
|
+
} = {} ): Plugin {
|
|
20
|
+
return {
|
|
21
|
+
name: '@terrazzo/terrazzo-plugin-ds-tokens-docs',
|
|
22
|
+
async build( { getTransforms, outputFile } ) {
|
|
23
|
+
if ( ! filename ) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const primitiveTokens: TokensMap = {};
|
|
28
|
+
const semanticTokens: TokensMap = {};
|
|
29
|
+
// Re-use transformed tokens from the CSS plugin
|
|
30
|
+
for ( const token of getTransforms( {
|
|
31
|
+
format: FORMAT_ID,
|
|
32
|
+
id: '*',
|
|
33
|
+
mode: '.',
|
|
34
|
+
} ) ) {
|
|
35
|
+
if ( token.localID === undefined ) {
|
|
36
|
+
console.warn(
|
|
37
|
+
'Unexpected — Missing local ID when building token list for eslint plugin'
|
|
38
|
+
);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Use the tokens filename (without .json) as the group name
|
|
43
|
+
const group =
|
|
44
|
+
token.token.source.loc
|
|
45
|
+
?.split( '/' )
|
|
46
|
+
.at( -1 )
|
|
47
|
+
?.split( '.json' )[ 0 ] ?? 'Miscellaneous';
|
|
48
|
+
|
|
49
|
+
// Organize tokens in semantic/private, and group by category.
|
|
50
|
+
const tokensObject = isPrivateToken( token.localID )
|
|
51
|
+
? primitiveTokens
|
|
52
|
+
: semanticTokens;
|
|
53
|
+
tokensObject[ group ] ??= {};
|
|
54
|
+
tokensObject[ group ][ token.localID ] =
|
|
55
|
+
token.token.$description ?? 'N/A';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function tokensToMdTable(
|
|
59
|
+
tokens: TokensMap,
|
|
60
|
+
isPrivate: boolean = false
|
|
61
|
+
) {
|
|
62
|
+
return Object.entries( tokens )
|
|
63
|
+
.map( ( [ group, tokensInGroup ] ) => [
|
|
64
|
+
`### ${ titleCase( group ) }${
|
|
65
|
+
isPrivate ? ' (private)' : ''
|
|
66
|
+
}`,
|
|
67
|
+
'',
|
|
68
|
+
'| Variable name | Description |',
|
|
69
|
+
'|---|---|',
|
|
70
|
+
...Object.entries( tokensInGroup ).map(
|
|
71
|
+
( [ name, description ] ) =>
|
|
72
|
+
`| \`${ name }\` | ${ description } |`
|
|
73
|
+
),
|
|
74
|
+
'',
|
|
75
|
+
] )
|
|
76
|
+
.flat( 2 );
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
outputFile(
|
|
80
|
+
filename,
|
|
81
|
+
[
|
|
82
|
+
'<!--',
|
|
83
|
+
'This file is generated by @terrazzo/terrazzo-plugin-ds-tokens-docs.',
|
|
84
|
+
'Do not edit directly.',
|
|
85
|
+
'-->',
|
|
86
|
+
'',
|
|
87
|
+
'# DS Tokens reference',
|
|
88
|
+
'',
|
|
89
|
+
'## Semantic tokens',
|
|
90
|
+
'',
|
|
91
|
+
...tokensToMdTable( semanticTokens ),
|
|
92
|
+
'',
|
|
93
|
+
'## Primitive tokens',
|
|
94
|
+
'',
|
|
95
|
+
'**🚨 Note: These tokens are only private implementation details of the Theme, and should never be referenced / consumed directly in the code.**',
|
|
96
|
+
'',
|
|
97
|
+
...tokensToMdTable( primitiveTokens, true ),
|
|
98
|
+
'', // final empty line
|
|
99
|
+
].join( '\n' )
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type { Plugin, TokenNormalized } from '@terrazzo/parser';
|
|
5
|
+
import { transformCSSValue } from '@terrazzo/token-tools/css';
|
|
6
|
+
import Color from 'colorjs.io';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import { FORMAT_JSON_ID } from './lib';
|
|
12
|
+
|
|
13
|
+
function titleCase( str: string ) {
|
|
14
|
+
return str[ 0 ].toUpperCase() + str.slice( 1 );
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function kebabToCamel( str: string ) {
|
|
18
|
+
return str.replace( /-([a-z])/g, ( _, letter ) => letter.toUpperCase() );
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function transformTokenName( { id }: { id: string } ) {
|
|
22
|
+
return (
|
|
23
|
+
id
|
|
24
|
+
// Capitalize first segment
|
|
25
|
+
.replace( /^(\w+)\./g, ( _, g1 ) => `${ titleCase( g1 ) }/` )
|
|
26
|
+
// Capitalize
|
|
27
|
+
.replace( /primitive\./g, '_Primitives/' )
|
|
28
|
+
.replace( /semantic\./g, 'Semantic/' )
|
|
29
|
+
.replace(
|
|
30
|
+
/(color\/_Primitives)\/(\w+)\.(.*)/gi,
|
|
31
|
+
( _, prefix, tone, rampStep ) => {
|
|
32
|
+
return `${ prefix }/${ titleCase( tone ) }/${ rampStep }`;
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
// Color-specific transformation for semantic tokens:
|
|
36
|
+
// - add extra folder (Background, Foreground, Stroke)
|
|
37
|
+
// - swap "tone" folder order, capitalize
|
|
38
|
+
// - limit bg-* to 6 characters
|
|
39
|
+
// - keep last part of the token name with dots (eg no folders)
|
|
40
|
+
.replace(
|
|
41
|
+
/(color\/Semantic)\/([\w,\-]+)\.(\w+)\.(.*)/gi,
|
|
42
|
+
( _, prefix, element, tone, emphasisAndState ) => {
|
|
43
|
+
let extraFolder = '';
|
|
44
|
+
let elementName = element;
|
|
45
|
+
if ( /bg/.test( element ) ) {
|
|
46
|
+
extraFolder = 'Background/';
|
|
47
|
+
elementName = element.slice( 0, 6 );
|
|
48
|
+
} else if ( /fg/.test( element ) ) {
|
|
49
|
+
extraFolder = 'Foreground/';
|
|
50
|
+
elementName = element.slice( 0, 6 );
|
|
51
|
+
} else if ( /stroke/.test( element ) ) {
|
|
52
|
+
extraFolder = 'Stroke/';
|
|
53
|
+
elementName = element.slice( 0, 10 );
|
|
54
|
+
}
|
|
55
|
+
return `${ prefix }/${ extraFolder }${ titleCase(
|
|
56
|
+
tone
|
|
57
|
+
) }/${ kebabToCamel(
|
|
58
|
+
elementName
|
|
59
|
+
) }.${ tone }.${ emphasisAndState }`;
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
// Remove default emphasis and state variants from variable name
|
|
63
|
+
.replace( /normal\./g, '' )
|
|
64
|
+
.replace( /resting/g, '' )
|
|
65
|
+
// Remove double dots
|
|
66
|
+
.replace( /\.{2,}/g, '.' )
|
|
67
|
+
// Remove trailing dot
|
|
68
|
+
.replace( /\.$/g, '' )
|
|
69
|
+
// Replace remaining dots with dashes
|
|
70
|
+
.replace( /\./g, '-' )
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function transformColorToken(
|
|
75
|
+
token: TokenNormalized,
|
|
76
|
+
mode: string,
|
|
77
|
+
tokens: Record< string, TokenNormalized >
|
|
78
|
+
) {
|
|
79
|
+
if (
|
|
80
|
+
token.mode[ mode ]?.aliasChain &&
|
|
81
|
+
token.mode[ mode ].aliasChain.length > 0
|
|
82
|
+
) {
|
|
83
|
+
// Keep aliases
|
|
84
|
+
return `{${ transformTokenName( {
|
|
85
|
+
id: token.mode[ mode ].aliasChain[ 0 ],
|
|
86
|
+
} ) }}`;
|
|
87
|
+
}
|
|
88
|
+
// Start by letting terrazzo do the heavy lifting.
|
|
89
|
+
const baselineCSSValue = transformCSSValue( token, {
|
|
90
|
+
mode,
|
|
91
|
+
tokensSet: tokens,
|
|
92
|
+
transformAlias: transformTokenName,
|
|
93
|
+
} );
|
|
94
|
+
|
|
95
|
+
if ( baselineCSSValue === undefined ) {
|
|
96
|
+
console.warn( 'Unexpected: could not tranform color token value' );
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let cssColorValue: string;
|
|
101
|
+
|
|
102
|
+
if ( typeof baselineCSSValue === 'object' ) {
|
|
103
|
+
if ( 'srgb' in baselineCSSValue ) {
|
|
104
|
+
// Pick SRGB gamut (safer compared to p3 or rec2020)
|
|
105
|
+
cssColorValue = baselineCSSValue.srgb;
|
|
106
|
+
} else {
|
|
107
|
+
console.log( 'UNSUPPORTED USE CASE' );
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
cssColorValue = baselineCSSValue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Always convert to hex
|
|
115
|
+
// (easier to convert to Figma RGB, and includes clamping)
|
|
116
|
+
let convertedColor: Color;
|
|
117
|
+
try {
|
|
118
|
+
convertedColor = new Color( cssColorValue );
|
|
119
|
+
} catch {
|
|
120
|
+
console.warn( 'Unexpected: could not convert token value to Color' );
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return convertedColor.to( 'srgb' ).toString( { format: 'hex' } );
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default function pluginFigmaDsTokenManager( {
|
|
128
|
+
filename = 'figma-ds-tokens.json',
|
|
129
|
+
} = {} ): Plugin {
|
|
130
|
+
return {
|
|
131
|
+
name: '@terrazzo/plugin-figma-ds-token-manager',
|
|
132
|
+
async transform( { tokens, getTransforms, setTransform } ) {
|
|
133
|
+
// skip work if another .json plugin has already run
|
|
134
|
+
const jsonTokens = getTransforms( {
|
|
135
|
+
format: FORMAT_JSON_ID,
|
|
136
|
+
id: '*',
|
|
137
|
+
mode: '.',
|
|
138
|
+
} );
|
|
139
|
+
if ( jsonTokens.length ) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for ( const [ id, token ] of Object.entries( tokens ) ) {
|
|
144
|
+
for ( const mode of Object.keys( token.mode ) ) {
|
|
145
|
+
const localID = transformTokenName( token );
|
|
146
|
+
|
|
147
|
+
let transformedValue;
|
|
148
|
+
|
|
149
|
+
if ( token.$type === 'color' ) {
|
|
150
|
+
transformedValue = transformColorToken(
|
|
151
|
+
token,
|
|
152
|
+
mode,
|
|
153
|
+
tokens
|
|
154
|
+
);
|
|
155
|
+
} else if (
|
|
156
|
+
token.mode[ mode ]?.aliasChain &&
|
|
157
|
+
token.mode[ mode ].aliasChain.length > 0
|
|
158
|
+
) {
|
|
159
|
+
// Keep aliases
|
|
160
|
+
transformedValue = `{${ transformTokenName( {
|
|
161
|
+
id: token.mode[ mode ].aliasChain[ 0 ],
|
|
162
|
+
} ) }}`;
|
|
163
|
+
} else {
|
|
164
|
+
// Fallback to terrazzo
|
|
165
|
+
transformedValue = transformCSSValue( token, {
|
|
166
|
+
mode,
|
|
167
|
+
tokensSet: tokens,
|
|
168
|
+
transformAlias: transformTokenName,
|
|
169
|
+
} );
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if ( transformedValue !== undefined ) {
|
|
173
|
+
setTransform( id, {
|
|
174
|
+
format: FORMAT_JSON_ID,
|
|
175
|
+
localID,
|
|
176
|
+
value: transformedValue,
|
|
177
|
+
mode,
|
|
178
|
+
} );
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
async build( { getTransforms, outputFile } ) {
|
|
184
|
+
const tokenVals: Record<
|
|
185
|
+
string,
|
|
186
|
+
{
|
|
187
|
+
value: Record< string, string | Record< string, string > >;
|
|
188
|
+
description?: string;
|
|
189
|
+
}
|
|
190
|
+
> = {};
|
|
191
|
+
|
|
192
|
+
for ( const token of getTransforms( {
|
|
193
|
+
format: FORMAT_JSON_ID,
|
|
194
|
+
id: '*',
|
|
195
|
+
} ) ) {
|
|
196
|
+
if ( ! token.localID ) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
tokenVals[ token.localID ] ??= { value: {}, description: '' };
|
|
201
|
+
|
|
202
|
+
tokenVals[ token.localID ].value[ token.mode ] = token.value;
|
|
203
|
+
tokenVals[ token.localID ].description =
|
|
204
|
+
token.token.$description;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
outputFile( filename, JSON.stringify( tokenVals, null, 2 ) );
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const FORMAT_JSON_ID = 'json';
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { FORMAT_ID } from '@terrazzo/plugin-css';
|
|
5
|
+
import type { Plugin } from '@terrazzo/parser';
|
|
6
|
+
|
|
7
|
+
function isPrivateToken( token: string ) {
|
|
8
|
+
return /-private-/i.test( token );
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function pluginKnownWpdsCssVariables( {
|
|
12
|
+
exports = [ { filename: 'design-tokens.js', modes: false } ],
|
|
13
|
+
} = {} ): Plugin {
|
|
14
|
+
return {
|
|
15
|
+
name: '@terrazzo/plugin-known-wpds-css-variables',
|
|
16
|
+
async build( { getTransforms, outputFile } ) {
|
|
17
|
+
// Either a string (modes=false) or an object (modes=true)
|
|
18
|
+
const tokensToExport: Record<
|
|
19
|
+
string,
|
|
20
|
+
Record< string, string | Record< string, string > >
|
|
21
|
+
> = {};
|
|
22
|
+
|
|
23
|
+
for ( const token of getTransforms( {
|
|
24
|
+
format: FORMAT_ID,
|
|
25
|
+
id: '*',
|
|
26
|
+
} ) ) {
|
|
27
|
+
if ( ! token.localID ) {
|
|
28
|
+
console.warn(
|
|
29
|
+
'Unexpected — Missing local ID when building token list for eslint plugin'
|
|
30
|
+
);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if ( ! isPrivateToken( token.localID ) ) {
|
|
35
|
+
tokensToExport[ token.localID ] ??= {};
|
|
36
|
+
|
|
37
|
+
tokensToExport[ token.localID ][ token.mode ] = token.value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const exportsAsArray = ! Array.isArray( exports )
|
|
42
|
+
? [ exports ]
|
|
43
|
+
: exports;
|
|
44
|
+
for ( const { filename, modes } of exportsAsArray ) {
|
|
45
|
+
outputFile(
|
|
46
|
+
filename,
|
|
47
|
+
[
|
|
48
|
+
'/**',
|
|
49
|
+
' * This file is generated by the @terrazzo/plugin-known-wpds-css-variables plugin.',
|
|
50
|
+
' * Do not edit this file directly.',
|
|
51
|
+
' */',
|
|
52
|
+
'',
|
|
53
|
+
`export default ${ JSON.stringify(
|
|
54
|
+
modes === false
|
|
55
|
+
? Array.from(
|
|
56
|
+
new Set( Object.keys( tokensToExport ) )
|
|
57
|
+
)
|
|
58
|
+
: tokensToExport,
|
|
59
|
+
null,
|
|
60
|
+
2
|
|
61
|
+
) }${
|
|
62
|
+
filename.endsWith( '.ts' ) && modes
|
|
63
|
+
? ' as Record< string, Record< string, string > >'
|
|
64
|
+
: ''
|
|
65
|
+
}`,
|
|
66
|
+
'', // final empty line
|
|
67
|
+
].join( '\n' )
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|