unholy-design-tokens 1.0.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/.github/workflows/lint-format-build.yml +35 -0
- package/.github/workflows/publish_release.yml +18 -0
- package/.prettierrc +9 -0
- package/ANALOGY_HOUSE.md +139 -0
- package/ANALOGY_I18NEXT.md +160 -0
- package/LICENSE +201 -0
- package/README.md +90 -0
- package/WHY_THIS_EXISTS.md +74 -0
- package/bin/build-tokens.ts +34 -0
- package/build/css/bg/bg.css +60 -0
- package/build/css/border/border.css +51 -0
- package/build/css/colors.css +204 -0
- package/build/css/conditional.css +8 -0
- package/build/css/cube/cube.block.css +18 -0
- package/build/css/cube/cube.composition.css +16 -0
- package/build/css/cube/cube.utility.css +185 -0
- package/build/css/font/font.css +24 -0
- package/build/css/space.css +20 -0
- package/build/css/text/text.css +48 -0
- package/build/css/themes/private-theme.css +228 -0
- package/build/css/themes/public-theme.css +228 -0
- package/build/css/variant/variant.css +42 -0
- package/build/css/variants.css +167 -0
- package/build/types/theme.d.ts +932 -0
- package/build/types/tokens.ts +653 -0
- package/dist/bin/build-tokens.js +27 -0
- package/dist/scripts/build-style-dictionary.js +32 -0
- package/dist/scripts/generate-typography-tokens.js +125 -0
- package/dist/src/colors/color.config.js +45 -0
- package/dist/src/colors/color.filter.js +19 -0
- package/dist/src/colors/color.formatter.js +25 -0
- package/dist/src/colors/index.js +2 -0
- package/dist/src/cube-css/cube.config.js +42 -0
- package/dist/src/cube-css/cube.formatter.js +89 -0
- package/dist/src/style-dictionary.config.js +143 -0
- package/dist/src/type-declarations/type-declarations.config.js +29 -0
- package/dist/src/type-declarations/type-declarations.formatter.js +111 -0
- package/dist/src/utils/helpers.js +9 -0
- package/dist/src/utils/index.js +4 -0
- package/dist/src/utils/template.js +83 -0
- package/dist/src/utils/tokens.js +80 -0
- package/dist/src/utils/utopia.js +19 -0
- package/eslint.config.js +67 -0
- package/package.json +60 -0
- package/scripts/build-style-dictionary.ts +44 -0
- package/scripts/generate-typography-tokens.ts +138 -0
- package/src/LICENSE +201 -0
- package/src/README.md +88 -0
- package/src/colors/color.config.ts +48 -0
- package/src/colors/color.filter.ts +28 -0
- package/src/colors/color.formatter.ts +43 -0
- package/src/colors/index.ts +6 -0
- package/src/cube-css/cube.config.ts +50 -0
- package/src/cube-css/cube.formatter.ts +104 -0
- package/src/formatters/spacing.js +95 -0
- package/src/style-dictionary.config.ts +151 -0
- package/src/theme/README.md +256 -0
- package/src/theme/cube-theme-addon.js +44 -0
- package/src/theme/helper.js +38 -0
- package/src/theme/index.js +6 -0
- package/src/theme/theme.config.js +42 -0
- package/src/theme/theme.filter.js +42 -0
- package/src/theme/theme.formatter.js +71 -0
- package/src/tokens/1 - primitives/README.md +58 -0
- package/src/tokens/1 - primitives/border.json +54 -0
- package/src/tokens/1 - primitives/breakpoint.json +10 -0
- package/src/tokens/1 - primitives/color-pool.json +266 -0
- package/src/tokens/1 - primitives/color.json +266 -0
- package/src/tokens/1 - primitives/font-scale.json +27 -0
- package/src/tokens/1 - primitives/font.json +23 -0
- package/src/tokens/1 - primitives/shadow.json +26 -0
- package/src/tokens/1 - primitives/space.json +27 -0
- package/src/tokens/2 - semantic/README.md +49 -0
- package/src/tokens/2 - semantic/border.json +27 -0
- package/src/tokens/2 - semantic/color.json +263 -0
- package/src/tokens/2 - semantic/details.md +1 -0
- package/src/tokens/2 - semantic/layout.json +52 -0
- package/src/tokens/2 - semantic/radius.json +13 -0
- package/src/tokens/2 - semantic/shadow.json +19 -0
- package/src/tokens/2 - semantic/spacing.json +25 -0
- package/src/tokens/3 - intent/README.md +43 -0
- package/src/tokens/3 - intent/background.json +135 -0
- package/src/tokens/3 - intent/color.json +265 -0
- package/src/tokens/3 - intent/font.json +61 -0
- package/src/tokens/3 - intent/text +67 -0
- package/src/tokens/README.md +176 -0
- package/src/tokens/color/brand.json +316 -0
- package/src/tokens/component/theming.json +69 -0
- package/src/tokens/conditional.json +40 -0
- package/src/tokens/custom/4 - (OPTIONAL) cube css/README.md +38 -0
- package/src/tokens/custom/4 - (OPTIONAL) cube css/block.json +24 -0
- package/src/tokens/custom/4 - (OPTIONAL) cube css/composition.json +26 -0
- package/src/tokens/custom/4 - (OPTIONAL) cube css/global.json +15 -0
- package/src/tokens/custom/4 - (OPTIONAL) cube css/utility.json +224 -0
- package/src/tokens/custom/OKlch/color.json +61 -0
- package/src/tokens/custom/OKlch/state.json +107 -0
- package/src/tokens/custom/OKlch/theme-color.json +34 -0
- package/src/tokens/custom/OKlch/variant.json +67 -0
- package/src/tokens/custom/components/highlighted.json +16 -0
- package/src/tokens/state.js +29 -0
- package/src/tokens/theme-color.json +34 -0
- package/src/type-declarations/type-declarations.config.ts +34 -0
- package/src/type-declarations/type-declarations.formatter.ts +122 -0
- package/src/utils/helpers.ts +11 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/template.ts +110 -0
- package/src/utils/tokens.ts +95 -0
- package/src/utils/utopia.ts +36 -0
- package/tailwind.md +720 -0
- package/tsconfig.json +19 -0
- package/turbowatch.ts +14 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import StyleDictionary, { Token } from 'style-dictionary'
|
|
2
|
+
import { formats, transformGroups } from 'style-dictionary/enums'
|
|
3
|
+
// @ts-expect-error - JS module without type declarations
|
|
4
|
+
import { themeConfig } from './theme/index.js'
|
|
5
|
+
import typeDeclarationsConfig from './type-declarations/type-declarations.config.js'
|
|
6
|
+
// import { cubeCssVariablesLayerFormatter } from './cube-css/formatters/cube-css.js';
|
|
7
|
+
import cubeConfig from './cube-css/cube.config.js'
|
|
8
|
+
// @ts-expect-error - JS module without type declarations
|
|
9
|
+
import { spacingFluid } from './formatters/spacing.js'
|
|
10
|
+
// import "./theme/formatters/theme.format.js"; // your file shown above (theme formats)
|
|
11
|
+
|
|
12
|
+
import colorConfig from './colors/color.config.js'
|
|
13
|
+
// import themeConfig from './theme/theme.config.js';
|
|
14
|
+
|
|
15
|
+
StyleDictionary.registerFormat(spacingFluid)
|
|
16
|
+
|
|
17
|
+
function generateThemeFiles(directories: string[]) {
|
|
18
|
+
const genericAttributes = {
|
|
19
|
+
format: formats.cssVariables,
|
|
20
|
+
options: {
|
|
21
|
+
// outputReferences: true,
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
return directories.map((dir) => {
|
|
25
|
+
return {
|
|
26
|
+
...genericAttributes,
|
|
27
|
+
// output the dironent tokens in the right folder and file e.g. dironents/button/button-vars.css
|
|
28
|
+
destination: `${dir}/${dir}.css`,
|
|
29
|
+
format: formats.cssVariables,
|
|
30
|
+
// only include the tokens that are inside this dironent token group
|
|
31
|
+
filter: (token: Token) => {
|
|
32
|
+
return token.path[0] === dir || token.attributes?.type === dir
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
StyleDictionary.registerFormat({
|
|
39
|
+
name: 'conditional-css',
|
|
40
|
+
format: function ({ dictionary }) {
|
|
41
|
+
let output = `:root {\n`
|
|
42
|
+
output += dictionary.allTokens
|
|
43
|
+
.map((token) => {
|
|
44
|
+
const { type } = token.attributes || {}
|
|
45
|
+
return ` --${type}: ${token.value};`
|
|
46
|
+
})
|
|
47
|
+
.join('\n')
|
|
48
|
+
output += `\n}\n`
|
|
49
|
+
return output
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
export default {
|
|
54
|
+
// parser: 'initial-theme-parser',
|
|
55
|
+
source: ['src/tokens/**/*.json'],
|
|
56
|
+
// action: ['generate-utopia-typography'],
|
|
57
|
+
platforms: {
|
|
58
|
+
css: {
|
|
59
|
+
transformGroup: transformGroups.css,
|
|
60
|
+
transforms: [
|
|
61
|
+
'attribute/cti', // pick up category/type/item
|
|
62
|
+
],
|
|
63
|
+
buildPath: 'css/',
|
|
64
|
+
clearBuildPath: true,
|
|
65
|
+
outputReferences: true,
|
|
66
|
+
|
|
67
|
+
files: [
|
|
68
|
+
{
|
|
69
|
+
destination: 'tokens.css',
|
|
70
|
+
format: 'css/variables',
|
|
71
|
+
filter: (token: Token) => {
|
|
72
|
+
return token.attributes?.category === 'typography'
|
|
73
|
+
},
|
|
74
|
+
actions: ['generate-utopia-typography'], // <- here
|
|
75
|
+
options: {
|
|
76
|
+
outputReferences: true,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
destination: 'conditional.css',
|
|
81
|
+
filter: (token: Token) => token.attributes?.category === 'conditional',
|
|
82
|
+
format: 'conditional-css',
|
|
83
|
+
transformGroup: 'css',
|
|
84
|
+
options: {
|
|
85
|
+
outputReferences: true,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
...themeConfig,
|
|
89
|
+
{
|
|
90
|
+
destination: 'space.css',
|
|
91
|
+
// format: "css/spacing-fluid",
|
|
92
|
+
format: formats.cssVariables,
|
|
93
|
+
filter: (token: Token) => {
|
|
94
|
+
return token.attributes?.category === 'space' || token.attributes?.type === 'space'
|
|
95
|
+
},
|
|
96
|
+
options: {
|
|
97
|
+
outputReferences: true,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
// -------------------------------------------------------
|
|
101
|
+
/**
|
|
102
|
+
* OKlch tokens
|
|
103
|
+
*/
|
|
104
|
+
// {
|
|
105
|
+
// destination: 'primitives.css',
|
|
106
|
+
// format: formats.cssVariables,
|
|
107
|
+
// filter: (token) => {
|
|
108
|
+
// return token.attributes?.type === 'primitive'
|
|
109
|
+
// },
|
|
110
|
+
// },
|
|
111
|
+
// {
|
|
112
|
+
// destination: 'variant.css',
|
|
113
|
+
// format: formats.cssVariables,
|
|
114
|
+
// filter: (token) => {
|
|
115
|
+
// return token.attributes?.category === 'variant'
|
|
116
|
+
// },
|
|
117
|
+
// options: {
|
|
118
|
+
// fileHeader: (defaultMessage: string[]) => {
|
|
119
|
+
// return [...defaultMessage, 'Variant tokens']
|
|
120
|
+
// },
|
|
121
|
+
// },
|
|
122
|
+
// },
|
|
123
|
+
{
|
|
124
|
+
destination: 'variants.css',
|
|
125
|
+
format: formats.cssVariables,
|
|
126
|
+
filter: (token: Token) => {
|
|
127
|
+
const variants = ['variant', 'state', 'color']
|
|
128
|
+
const category: string | undefined = token.attributes?.category as string
|
|
129
|
+
return (
|
|
130
|
+
variants.includes(category) &&
|
|
131
|
+
token.attributes?.tokenTier !== 'intent' &&
|
|
132
|
+
token.attributes?.tokenTier !== 'semantic' &&
|
|
133
|
+
token.attributes?.tokenTier !== 'primitive'
|
|
134
|
+
)
|
|
135
|
+
},
|
|
136
|
+
options: {
|
|
137
|
+
fileHeader: (defaultMessage: string[]) => {
|
|
138
|
+
return [...defaultMessage, 'Variant tokens']
|
|
139
|
+
},
|
|
140
|
+
outputReferences: true,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
...colorConfig,
|
|
144
|
+
...cubeConfig,
|
|
145
|
+
...generateThemeFiles(['components', 'font', 'bg', 'border', 'text', 'variant']),
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
// Type declarations
|
|
149
|
+
...typeDeclarationsConfig,
|
|
150
|
+
},
|
|
151
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# 🎚️ **Theme Tokens: Public vs Private Variables**
|
|
2
|
+
|
|
3
|
+
This repo generates **two versions** of theme variables:
|
|
4
|
+
|
|
5
|
+
- **Public Theme Tokens** → meant for _outside consumers_
|
|
6
|
+
- **Private Theme Tokens** → meant for _internal component use_
|
|
7
|
+
|
|
8
|
+
Understanding the difference keeps your design system:
|
|
9
|
+
|
|
10
|
+
✔ safe
|
|
11
|
+
|
|
12
|
+
✔ overridable
|
|
13
|
+
|
|
14
|
+
✔ stable
|
|
15
|
+
|
|
16
|
+
✔ predictable
|
|
17
|
+
|
|
18
|
+
Let’s break it down.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🟣 **1. Public Theme Tokens (`-token`)**
|
|
23
|
+
|
|
24
|
+
These are the **official, documented** variables that consumers _are allowed_ to override.
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
|
|
28
|
+
```css
|
|
29
|
+
:root {
|
|
30
|
+
--space-md: 1rem;
|
|
31
|
+
--color-bg-default: #ffffff;
|
|
32
|
+
--text-body-size: 1rem;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### ✔ Purpose
|
|
37
|
+
|
|
38
|
+
- Provide a **stable API** for theming
|
|
39
|
+
- Let applications or customer brands override design tokens
|
|
40
|
+
- Expose “slot” variables, not internal details
|
|
41
|
+
|
|
42
|
+
### ✔ Consumers can override:
|
|
43
|
+
|
|
44
|
+
```css
|
|
45
|
+
:root {
|
|
46
|
+
--color-bg-default: #fef7ff; /* custom brand color */
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 🛑 Consumers _should not_ override:
|
|
51
|
+
|
|
52
|
+
- component-specific tokens
|
|
53
|
+
- conditional tokens
|
|
54
|
+
- computed variables
|
|
55
|
+
- values derived from multiple dependencies
|
|
56
|
+
|
|
57
|
+
Public tokens are your **surface area**.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🔵 **2. Private Theme Tokens (`-_token`)**
|
|
62
|
+
|
|
63
|
+
These exist **only inside the design system**.
|
|
64
|
+
|
|
65
|
+
Generated like this:
|
|
66
|
+
|
|
67
|
+
```css
|
|
68
|
+
--_space-md: var(--space-md, 1rem);
|
|
69
|
+
--_color-bg-default: var(--color-bg-default, #ffffff);
|
|
70
|
+
--_text-body-size: var(--text-body-size, clamp(...));
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This structure follows Lea Verou’s pattern:
|
|
74
|
+
|
|
75
|
+
https://lea.verou.me/blog/2021/10/custom-properties-with-defaults/
|
|
76
|
+
|
|
77
|
+
### ✔ Private variables are _always safe_
|
|
78
|
+
|
|
79
|
+
Even if a consumer overrides a public variable incorrectly, components still resolve safely.
|
|
80
|
+
|
|
81
|
+
Example:
|
|
82
|
+
|
|
83
|
+
```css
|
|
84
|
+
background: var(--_color-bg-default);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### ✔ Developers should **ONLY** use private tokens inside components
|
|
88
|
+
|
|
89
|
+
Never use:
|
|
90
|
+
|
|
91
|
+
```css
|
|
92
|
+
background: var(--color-bg-default); /* ❌ no */
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Always use:
|
|
96
|
+
|
|
97
|
+
```css
|
|
98
|
+
background: var(--_color-bg-default); /* ✔ correct */
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### ✔ Why?
|
|
102
|
+
|
|
103
|
+
Because private variables:
|
|
104
|
+
|
|
105
|
+
- lock in fallback values
|
|
106
|
+
- isolate component behavior from breaking changes
|
|
107
|
+
- prevent invalid overrides from crashing styling
|
|
108
|
+
- are stable even if public tokens change
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 🌀 **How Public → Private Works**
|
|
113
|
+
|
|
114
|
+
Each public token:
|
|
115
|
+
|
|
116
|
+
```css
|
|
117
|
+
--text-body-size: 1rem;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Produces a private counterpart:
|
|
121
|
+
|
|
122
|
+
```css
|
|
123
|
+
--_text-body-size: var(--text-body-size, 1rem);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This means:
|
|
127
|
+
|
|
128
|
+
- if a theme provides a custom `-text-body-size`, it’s used
|
|
129
|
+
- otherwise, fallback = design system default
|
|
130
|
+
|
|
131
|
+
Exactly what you want.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 🧠 **Why Not Use Public Tokens Inside Components?**
|
|
136
|
+
|
|
137
|
+
Because public tokens are:
|
|
138
|
+
|
|
139
|
+
- overrideable
|
|
140
|
+
- unstable
|
|
141
|
+
- potentially missing
|
|
142
|
+
- brand-controlled
|
|
143
|
+
|
|
144
|
+
Private tokens are:
|
|
145
|
+
|
|
146
|
+
- resolved
|
|
147
|
+
- safe
|
|
148
|
+
- internal
|
|
149
|
+
- consistent
|
|
150
|
+
|
|
151
|
+
### Components use internal safety
|
|
152
|
+
|
|
153
|
+
### Apps override external knobs
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 🧩 **Example: Button Token Flow**
|
|
158
|
+
|
|
159
|
+
**Public:**
|
|
160
|
+
|
|
161
|
+
```css
|
|
162
|
+
--button-primary-bg: var(--color-brand-primary);
|
|
163
|
+
--button-primary-radius: 6px;
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Private:**
|
|
167
|
+
|
|
168
|
+
```css
|
|
169
|
+
--_button-primary-bg: var(--button-primary-bg, var(--_color-brand-primary));
|
|
170
|
+
--_button-primary-radius: var(--button-primary-radius, 6px);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Component:**
|
|
174
|
+
|
|
175
|
+
```css
|
|
176
|
+
button.primary {
|
|
177
|
+
background: var(--_button-primary-bg);
|
|
178
|
+
border-radius: var(--_button-primary-radius);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### If a consumer overrides:
|
|
183
|
+
|
|
184
|
+
```css
|
|
185
|
+
:root {
|
|
186
|
+
--button-primary-bg: hotpink;
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
→ component updates correctly
|
|
191
|
+
|
|
192
|
+
→ fallback is preserved
|
|
193
|
+
|
|
194
|
+
→ nothing breaks
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 🧩 **Why Two Levels Are Necessary**
|
|
199
|
+
|
|
200
|
+
| Layer | Who uses it | Purpose |
|
|
201
|
+
| ------------------------ | ------------ | --------------------------- |
|
|
202
|
+
| **Public (`--token`)** | consumers | override, theme, brand |
|
|
203
|
+
| **Private (`--_token`)** | components | stable internal contract |
|
|
204
|
+
| **Component tokens** | DS devs | button/card/input internals |
|
|
205
|
+
| **Semantic tokens** | DS designers | meaning-based mapping |
|
|
206
|
+
| **Primitives** | DS designers | raw values |
|
|
207
|
+
|
|
208
|
+
This hierarchy ensures:
|
|
209
|
+
|
|
210
|
+
- **external flexibility**
|
|
211
|
+
- **internal stability**
|
|
212
|
+
|
|
213
|
+
Exactly what a scalable design system needs.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 🛠 Your Custom Formatters
|
|
218
|
+
|
|
219
|
+
Your Style Dictionary setup generates:
|
|
220
|
+
|
|
221
|
+
### **public-theme.css**
|
|
222
|
+
|
|
223
|
+
```css
|
|
224
|
+
:root {
|
|
225
|
+
--space-md: 1rem;
|
|
226
|
+
--text-body-size: 1rem;
|
|
227
|
+
--color-bg-default: #fff;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### **private-theme.css**
|
|
232
|
+
|
|
233
|
+
```css
|
|
234
|
+
:root {
|
|
235
|
+
--_space-md: var(--space-md, 1rem);
|
|
236
|
+
--_text-body-size: var(--text-body-size, 1rem);
|
|
237
|
+
--_color-bg-default: var(--color-bg-default, #fff);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Nothing else in your build system needs to know how public & private vars relate.
|
|
242
|
+
|
|
243
|
+
Components only consume **private** vars.
|
|
244
|
+
|
|
245
|
+
Component libraries only expose **public** vars.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 🧪 TL;DR Cheat Sheet
|
|
250
|
+
|
|
251
|
+
| Thing | Use Public? | Use Private? | Notes |
|
|
252
|
+
| ---------------- | ----------- | ------------ | --------------------------------- |
|
|
253
|
+
| Apps / Consumers | ✔ yes | ❌ no | override `--token` |
|
|
254
|
+
| DS Components | ❌ no | ✔ yes | use `--_token` |
|
|
255
|
+
| Themes | ✔ yes | ❌ no | theme overrides go to public vars |
|
|
256
|
+
| Fallbacks | automatic | automatic | thanks to var(--token, fallback) |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// // cube-theme-addon.js
|
|
2
|
+
// import { generateThemeCubeCSSVariables } from "../cube-css/formatters/cube-css.js";
|
|
3
|
+
// import {
|
|
4
|
+
// shouldOutputReferences,
|
|
5
|
+
// rewriteOriginalRefs,
|
|
6
|
+
// } from "./formatters/theme-core.js";
|
|
7
|
+
|
|
8
|
+
// export function cubeThemeAddon({ dictionary, options, scope }) {
|
|
9
|
+
// const privateVar = scope === "private";
|
|
10
|
+
|
|
11
|
+
// return dictionary.allTokens
|
|
12
|
+
// .filter((t) => t.attributes?.category === "cube")
|
|
13
|
+
// .map((t) => {
|
|
14
|
+
// // start from your existing cube name rules
|
|
15
|
+
// const entry = generateThemeCubeCSSVariables(t);
|
|
16
|
+
// console.log(
|
|
17
|
+
// "📟 - shouldOutputReferences(t, options, dictionary) → ",
|
|
18
|
+
// shouldOutputReferences(t, options, dictionary),
|
|
19
|
+
// );
|
|
20
|
+
// console.log(
|
|
21
|
+
// "📟 - rewriteOriginalRefs(originalValue, dictionary.tokens, privateVar",
|
|
22
|
+
// rewriteOriginalRefs(t.original?.value, dictionary.tokens, privateVar),
|
|
23
|
+
// );
|
|
24
|
+
// // add refs (optional)
|
|
25
|
+
// const originalValue = t.original?.value;
|
|
26
|
+
// const original = shouldOutputReferences(t, options, dictionary)
|
|
27
|
+
// ? rewriteOriginalRefs(originalValue, dictionary.tokens, privateVar)
|
|
28
|
+
// : null;
|
|
29
|
+
|
|
30
|
+
// return {
|
|
31
|
+
// ...entry,
|
|
32
|
+
// original, // lets generateThemeContent prefer original.value
|
|
33
|
+
// };
|
|
34
|
+
// });
|
|
35
|
+
// }
|
|
36
|
+
|
|
37
|
+
// // cube-theme-addon.js
|
|
38
|
+
import { generateThemeCubeCSSVariables } from "../cube-css/formatters/cube-css.js";
|
|
39
|
+
|
|
40
|
+
export function cubeThemeAddon({ dictionary }) {
|
|
41
|
+
return dictionary.allTokens
|
|
42
|
+
.filter((t) => t.attributes?.category === "cube")
|
|
43
|
+
.map((t) => generateThemeCubeCSSVariables(t));
|
|
44
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// helper.js
|
|
2
|
+
import { generateHeader, generateSubheader } from '../utils/template.js'
|
|
3
|
+
export { generateThemeContent }
|
|
4
|
+
|
|
5
|
+
function generateThemeContent(tokens, scope = 'public') {
|
|
6
|
+
let content = ''
|
|
7
|
+
|
|
8
|
+
let currentCategory = null
|
|
9
|
+
let usedSubsections = new Set() // resets per category
|
|
10
|
+
|
|
11
|
+
for (const t of tokens) {
|
|
12
|
+
const category = t?.category ?? null
|
|
13
|
+
|
|
14
|
+
// New category → print header and reset subsection tracking
|
|
15
|
+
if (category && category !== currentCategory) {
|
|
16
|
+
currentCategory = category
|
|
17
|
+
usedSubsections = new Set()
|
|
18
|
+
content += generateHeader(category)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Optional subsection (opt-in per token)
|
|
22
|
+
const subsection = t?.subsection
|
|
23
|
+
if (subsection && !usedSubsections.has(subsection)) {
|
|
24
|
+
usedSubsections.add(subsection)
|
|
25
|
+
content += generateSubheader(subsection)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const rawValue = t.value
|
|
29
|
+
|
|
30
|
+
if (scope === 'public') {
|
|
31
|
+
content += ` ${t.publicName}: ${rawValue};\n`
|
|
32
|
+
} else {
|
|
33
|
+
content += ` ${t.privateName}: var(${t.publicName}, ${rawValue});\n`
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return content
|
|
38
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// theme.files.js
|
|
2
|
+
import { filterThemeTokens } from "./theme.filter.js";
|
|
3
|
+
|
|
4
|
+
export default [
|
|
5
|
+
// Base theme (no cube)
|
|
6
|
+
{
|
|
7
|
+
destination: "themes/private-theme.css",
|
|
8
|
+
format: "private-theme",
|
|
9
|
+
filter: filterThemeTokens,
|
|
10
|
+
options: {
|
|
11
|
+
// outputReferences: true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
destination: "themes/public-theme.css",
|
|
16
|
+
format: "public-theme",
|
|
17
|
+
filter: filterThemeTokens,
|
|
18
|
+
options: {
|
|
19
|
+
// outputReferences: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// // Optional theme + cube (appended)
|
|
24
|
+
// {
|
|
25
|
+
// destination: "themes/private-theme+cube.css",
|
|
26
|
+
// format: "private-theme+cube",
|
|
27
|
+
// filter: (token) =>
|
|
28
|
+
// filterThemeTokens(token) || token.attributes?.category === "cube",
|
|
29
|
+
// options: {
|
|
30
|
+
// outputReferences: true,
|
|
31
|
+
// },
|
|
32
|
+
// },
|
|
33
|
+
// {
|
|
34
|
+
// destination: "themes/public-theme+cube.css",
|
|
35
|
+
// format: "public-theme+cube",
|
|
36
|
+
// filter: (token) =>
|
|
37
|
+
// filterThemeTokens(token) || token.attributes?.category === "cube",
|
|
38
|
+
// options: {
|
|
39
|
+
// outputReferences: true,
|
|
40
|
+
// },
|
|
41
|
+
// },
|
|
42
|
+
];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const themeCategories = [
|
|
2
|
+
'space',
|
|
3
|
+
'spacing',
|
|
4
|
+
'border',
|
|
5
|
+
'radius',
|
|
6
|
+
'shadow',
|
|
7
|
+
'breakpoint',
|
|
8
|
+
'font',
|
|
9
|
+
'text',
|
|
10
|
+
'component',
|
|
11
|
+
'cube',
|
|
12
|
+
'body',
|
|
13
|
+
'heading',
|
|
14
|
+
'layout',
|
|
15
|
+
|
|
16
|
+
// Components
|
|
17
|
+
'components',
|
|
18
|
+
'highlighted-text',
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const excludeTypes = [
|
|
22
|
+
'utility',
|
|
23
|
+
'variants',
|
|
24
|
+
// add more types to exclude from theme if needed
|
|
25
|
+
]
|
|
26
|
+
/**
|
|
27
|
+
* List of categories part of the generated private and public theme
|
|
28
|
+
* See category: https://styledictionary.com/info/tokens/#category--type--item
|
|
29
|
+
*
|
|
30
|
+
* @param {*} token
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
33
|
+
export function isPartOfTheme(token) {
|
|
34
|
+
return themeCategories.includes(token.attributes?.category) &&
|
|
35
|
+
!excludeTypes.includes(token.attributes?.type)
|
|
36
|
+
? true
|
|
37
|
+
: false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function filterThemeTokens(token) {
|
|
41
|
+
return isPartOfTheme(token)
|
|
42
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// theme.js
|
|
2
|
+
import StyleDictionary from 'style-dictionary'
|
|
3
|
+
import { generateThemeCubeCSS } from '../cube-css/cube.formatter.js'
|
|
4
|
+
import { toKebab } from '../utils/helpers.js'
|
|
5
|
+
import { resolveTokenReferences, tokenName } from '../utils/tokens.js'
|
|
6
|
+
import { generateThemeContent } from './helper.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Takes a token and format it to be rendered in the theme files.
|
|
10
|
+
*
|
|
11
|
+
* Will return:
|
|
12
|
+
* - public name for build/css/themes/public-theme.css
|
|
13
|
+
* - private name for build/css/themes/private-theme.css
|
|
14
|
+
* - resolved value (with references rewritten) or raw value
|
|
15
|
+
* - category for sectioning (heading sections)
|
|
16
|
+
* - subsection for subheading sections
|
|
17
|
+
*
|
|
18
|
+
*
|
|
19
|
+
* @param {*} tokens
|
|
20
|
+
* @param {*} options
|
|
21
|
+
* @param {*} dictionary
|
|
22
|
+
* @param {*} scope
|
|
23
|
+
* @returns {{}}
|
|
24
|
+
*/
|
|
25
|
+
function formatToThemeToken(token, options, dictionary, scope) {
|
|
26
|
+
const privateVar = scope === 'private'
|
|
27
|
+
|
|
28
|
+
// const normal = tokens.map((t) => {
|
|
29
|
+
// const originalValue = t.original?.value;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
publicName: `--${toKebab(tokenName(token))}`,
|
|
33
|
+
privateName: `--_${toKebab(tokenName(token))}`,
|
|
34
|
+
value: resolveTokenReferences(token, options, dictionary, privateVar),
|
|
35
|
+
category: token.attributes?.category,
|
|
36
|
+
subsection: token.attributes?.subsection,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildTheme({ dictionary, options }, scope) {
|
|
41
|
+
const header =
|
|
42
|
+
scope === 'public'
|
|
43
|
+
? `/**
|
|
44
|
+
* Theme Overrides
|
|
45
|
+
* List of CSS variables that can be used to override the default theme
|
|
46
|
+
* Simply uncomment the variables you want to use
|
|
47
|
+
*/`
|
|
48
|
+
: `/**
|
|
49
|
+
* Internal default theme variables
|
|
50
|
+
* Using CSS pseudo-private custom properties
|
|
51
|
+
* https://lea.verou.me/blog/2021/10/custom-properties-with-defaults/
|
|
52
|
+
*/`
|
|
53
|
+
|
|
54
|
+
// We exclude cube tokens from the main theme output
|
|
55
|
+
const themeTokens = dictionary.allTokens.filter((t) => t.attributes?.category !== 'cube')
|
|
56
|
+
let toks = themeTokens.map((token) => formatToThemeToken(token, options, dictionary, scope))
|
|
57
|
+
|
|
58
|
+
toks = [...toks, ...generateThemeCubeCSS(dictionary.allTokens)]
|
|
59
|
+
|
|
60
|
+
return `${header}\n:root {${generateThemeContent(toks, scope)}\n}\n`
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
StyleDictionary.registerFormat({
|
|
64
|
+
name: 'public-theme',
|
|
65
|
+
format: (args) => buildTheme(args, 'public'),
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
StyleDictionary.registerFormat({
|
|
69
|
+
name: 'private-theme',
|
|
70
|
+
format: (args) => buildTheme(args, 'private'),
|
|
71
|
+
})
|