@kong/design-tokens 2.0.1 → 2.0.2-pr.666.012f8f0.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.
Files changed (44) hide show
  1. package/README.md +253 -31
  2. package/TOKENS.md +7568 -1503
  3. package/dist/themes/classic-day.cjs +349 -0
  4. package/dist/themes/classic-day.css +349 -0
  5. package/dist/themes/classic-day.d.cts +5 -0
  6. package/dist/themes/classic-day.d.ts +5 -0
  7. package/dist/themes/classic-day.mjs +347 -0
  8. package/dist/themes/classic-night.cjs +349 -0
  9. package/dist/themes/classic-night.css +349 -0
  10. package/dist/themes/classic-night.d.cts +5 -0
  11. package/dist/themes/classic-night.d.ts +5 -0
  12. package/dist/themes/classic-night.mjs +347 -0
  13. package/dist/themes/electric-lime-day.cjs +928 -0
  14. package/dist/themes/electric-lime-day.css +928 -0
  15. package/dist/themes/electric-lime-day.d.cts +5 -0
  16. package/dist/themes/electric-lime-day.d.ts +5 -0
  17. package/dist/themes/electric-lime-day.mjs +926 -0
  18. package/dist/themes/electric-lime-night.cjs +928 -0
  19. package/dist/themes/electric-lime-night.css +928 -0
  20. package/dist/themes/electric-lime-night.d.cts +5 -0
  21. package/dist/themes/electric-lime-night.d.ts +5 -0
  22. package/dist/themes/electric-lime-night.mjs +926 -0
  23. package/dist/themes/index.cjs +11 -0
  24. package/dist/themes/index.d.cts +8 -0
  25. package/dist/themes/index.d.ts +8 -0
  26. package/dist/themes/index.mjs +8 -0
  27. package/dist/tokens/README.md +7568 -1503
  28. package/dist/tokens/css/custom-properties-list.css +163 -155
  29. package/dist/tokens/css/custom-properties.css +100 -96
  30. package/dist/tokens/js/cjs/index.d.ts +92 -86
  31. package/dist/tokens/js/cjs/index.js +100 -96
  32. package/dist/tokens/js/cjs/package.json +3 -0
  33. package/dist/tokens/js/index.d.ts +154 -146
  34. package/dist/tokens/js/index.mjs +101 -97
  35. package/dist/tokens/js/tokens.json +100 -96
  36. package/dist/tokens/scss/_map.scss +101 -97
  37. package/dist/tokens/scss/_mixins.scss +64 -60
  38. package/dist/tokens/scss/_variables.scss +100 -96
  39. package/dist/tokens/themeable-tokens/index.cjs +5528 -0
  40. package/dist/tokens/themeable-tokens/index.d.cts +5536 -0
  41. package/dist/tokens/themeable-tokens/index.d.ts +5536 -0
  42. package/dist/tokens/themeable-tokens/index.mjs +5530 -0
  43. package/package.json +54 -20
  44. package/dist/tokens/less/variables.less +0 -345
package/README.md CHANGED
@@ -2,18 +2,26 @@
2
2
 
3
3
  Kong Design Tokens for Konnect, via [Style Dictionary](https://github.com/amzn/style-dictionary).
4
4
 
5
+ - [Token Tiers](#token-tiers)
6
+ - [Semantic tokens](#semantic-tokens)
7
+ - [Component tokens — names only, value-less](#component-tokens--names-only-value-less)
8
+ - [Themeable token list](#themeable-token-list)
9
+ - [Themes](#themes)
5
10
  - [Tokens](#tokens)
6
11
  - [Token Formats](#token-formats)
7
12
  - [SCSS](#scss)
8
- - [LESS](#less)
9
13
  - [CSS Custom Properties](#css-custom-properties)
10
14
  - [JavaScript](#javascript)
11
15
  - [Usage](#usage)
12
16
  - [Installation](#installation)
13
17
  - [Standalone components](#standalone-components)
14
18
  - [Host applications](#host-applications)
19
+ - [Kongponents](#kongponents)
15
20
  - [Updating Tokens & Local Development](#updating-tokens--local-development)
21
+ - [Directory structure](#directory-structure)
16
22
  - [Token Requirements](#token-requirements)
23
+ - [Creating a new theme](#creating-a-new-theme)
24
+ - [Theme `$description` authoring rules](#theme-description-authoring-rules)
17
25
  - [Development Sandbox](#development-sandbox)
18
26
  - [Lint and fix](#lint-and-fix)
19
27
  - [Build for production](#build-for-production)
@@ -22,9 +30,96 @@ Kong Design Tokens for Konnect, via [Style Dictionary](https://github.com/amzn/s
22
30
  - [Approvals](#approvals)
23
31
  - [Package Publishing](#package-publishing)
24
32
 
25
- ## Tokens
33
+ ## Token Tiers
34
+
35
+ The `@kong/design-tokens` package uses a two-tier exported token taxonomy.
36
+
37
+ | Tier | Source directory | Examples | Exported as |
38
+ |------|-----------------|----------|-------------|
39
+ | **Semantic** | `tokens/source/**` | `--kui-color-background-primary`, `--kui-space-40`, `--kui-border-radius-30`, `--kui-method-color-background-get` | CSS custom properties, SCSS variables, JS constants |
40
+ | **Component** | `tokens/components/**` | `--kui-button-border-radius-medium`, `--kui-button-color-background-primary`, `--kui-button-shadow-focus` | Included in `KUI_THEMEABLE_TOKENS` — **no CSS value** |
41
+
42
+ > **Alias tokens** (`themes/<name>/<name>.alias.color.json`, one per theme) form a third internal
43
+ > category. They hold the raw palette values (hex colors) that semantic and component tokens
44
+ > reference. They are **never exported** — they exist only so Style Dictionary can resolve
45
+ > `{color.alias.blue.100}` references at build time.
46
+
47
+ ### Semantic tokens
48
+
49
+ Everything in `tokens/source/` is a semantic token — it has a concrete value and is exported to all formats (CSS, SCSS, JS). This includes:
50
+
51
+ - **Scale tokens** — `--kui-color-*`, `--kui-space-*`, `--kui-border-radius-*`, `--kui-shadow-*`, `--kui-font-*`, etc. Named after the design dimension they represent.
52
+ - **Concept tokens** — `--kui-method-*`, `--kui-status-*`, `--kui-navigation-*`, `--kui-icon-*`. Named after a cross-cutting UI concept (HTTP methods, status codes, navigation chrome, icons) rather than a design dimension. Each family lives in its own folder under `tokens/source/` (`method/`, `status/`, `navigation/`, `icon/`), following the same pattern as the scale folders. They are plain semantic tokens, valued and exported exactly like scale tokens. **These are not component tokens** even though they're used inside components.
53
+
54
+ > **IMPORTANT — `primary` and `accent` colors must be overridden in the Dev Portal**
55
+ >
56
+ > The `primary` tokens (`--kui-color-background-primary`, `--kui-color-text-primary`, `--kui-color-border-primary`) and the `accent` tokens (`--kui-color-background-accent`, `--kui-color-text-accent`, `--kui-color-border-accent`) — plus any future brand-derived color used the same way — ship a **Kong-branded default value**. The Kong Konnect **Dev Portal** (`kong-konnect/portal`) renders **customer-branded** UIs, where each customer configures their own brand/theme color.
57
+ >
58
+ > Because these tokens carry a default, that default will **leak Kong's brand color into the customer's portal** unless the portal overrides it. Therefore, whenever a `primary`- or `accent`-like brand color token is **added, renamed, or its default value changes**, the `kong-konnect/portal` customization plugin **must** be updated to override the token with the portal's configured theme color variants so the design-tokens default never reaches the rendered Dev Portal.
59
+
60
+ ### Component tokens — names only, value-less
61
+
62
+ Component tokens (`--kui-button-*`, `--kui-card-*`, `--kui-input-*`, `--kui-badge-*`, …) live in `tokens/components/` and are **declared without any CSS value** — they are purely override slots. Every Kongponents component uses them in a `var()` fallback chain:
63
+
64
+ ```scss
65
+ border-radius: var(--kui-button-border-radius-medium, var(--kui-border-radius-30, $kui-border-radius-30));
66
+ // ↑ component token (empty by default) ↑ semantic fallback ↑ SCSS literal
67
+ ```
68
+
69
+ When a theme writes `--kui-button-border-radius-medium: 999px`, only buttons go pill-shaped. Inputs and other components keep their semantic default. When no theme writes the token, `var()` falls through to the semantic default — **byte-identical to the un-themed render**.
70
+
71
+ ### Themeable token list
72
+
73
+ The `./tokens/themeable-tokens` subpath exports `KUI_THEMEABLE_TOKENS` — a typed `readonly` tuple of every `--kui-*` custom property name that a theme may meaningfully override. It combines both semantic tokens and value-less component tokens.
74
+
75
+ ```ts
76
+ import { KUI_THEMEABLE_TOKENS } from '@kong/design-tokens/tokens/themeable-tokens'
77
+
78
+ // Each entry is a `{ name, description, category, value }` record.
79
+ // Derive a union type of all valid theme keys from their `name`s:
80
+ type ThemeToken = typeof KUI_THEMEABLE_TOKENS[number]['name']
81
+ ```
82
+
83
+ ## Themes
26
84
 
27
- All design tokens **must** be placed inside of the `packages/design-tokens/tokens/` directory in one of two sub-directories.
85
+ Pre-built theme CSS files activate a complete set of token overrides via a `data-kui-theme` attribute on any element. Load a theme CSS file and then set the attribute on the root element (or any subtree element):
86
+
87
+ ```html
88
+ <!-- In your HTML template or equivalent -->
89
+ <html data-kui-theme="electric-lime-day">
90
+ ```
91
+
92
+ ```ts
93
+ // Load the theme CSS — webpack/Vite will bundle it
94
+ import '@kong/design-tokens/themes/electric-lime-day.css'
95
+
96
+ // Switch the active theme at runtime
97
+ document.documentElement.setAttribute('data-kui-theme', 'electric-lime-night')
98
+ ```
99
+
100
+ Available themes: `classic-day`, `classic-night`, `electric-lime-day`, `electric-lime-night`.
101
+ `classic-day` is the default look (identical to the unthemed `:root` exports); `classic-night` is its dark counterpart.
102
+
103
+ Each theme CSS file uses `@layer kui.theme { [data-kui-theme="name"] { ... } }`. This means customer `:root {}` overrides (which are **unlayered**) beat the theme automatically — no `!important` or special selectors needed.
104
+
105
+ To respond to the system dark-mode preference, listen to the `prefers-color-scheme` media query in JS:
106
+
107
+ ```ts
108
+ const mq = window.matchMedia('(prefers-color-scheme: dark)')
109
+ const applyColorScheme = (dark: boolean) =>
110
+ document.documentElement.setAttribute('data-kui-theme', dark ? 'electric-lime-night' : 'electric-lime-day')
111
+
112
+ applyColorScheme(mq.matches)
113
+ mq.addEventListener('change', e => applyColorScheme(e.matches))
114
+ ```
115
+
116
+ You can also import the theme objects as JavaScript for runtime composition or for use with Kongponents' `applyTheme` / `defineKongponentsTheme`:
117
+
118
+ ```ts
119
+ import { electricLimeDay, electricLimeNight, classicDay, classicNight } from '@kong/design-tokens/themes'
120
+ ```
121
+
122
+ ## Tokens
28
123
 
29
124
  [View the lists of available tokens here](TOKENS.md), or keep reading for more information.
30
125
 
@@ -33,7 +128,6 @@ All design tokens **must** be placed inside of the `packages/design-tokens/token
33
128
  The `@kong/design-tokens` package exports tokens in multiple formats:
34
129
 
35
130
  - [SCSS](#scss)
36
- - [LESS](#less)
37
131
  - [CSS Custom Properties](#css-custom-properties)
38
132
  - [JavaScript](#javascript) (ESM, CJS, and JSON), along with corresponding TypeScript types
39
133
 
@@ -89,14 +183,6 @@ $tokens-map: (
89
183
  );
90
184
  ```
91
185
 
92
- ### LESS
93
-
94
- #### LESS Variables
95
-
96
- LESS variables can be utilized in your project's LESS files or in-component style blocks (this assumes your app is already configured to compile LESS).
97
-
98
- To use the LESS variables, you need to import them into your component or app stylesheet so they are available throughout your project via the export from `@kong/design-tokens/tokens/less/variables.less`.
99
-
100
186
  ### CSS Custom Properties
101
187
 
102
188
  You may scope your CSS variable overrides inside the `:root` selector as shown here, or inside any other valid CSS selector.
@@ -249,6 +335,55 @@ Typically, a host application should only utilize the SCSS and/or JavaScript var
249
335
  </style>
250
336
  ```
251
337
 
338
+ #### Kongponents
339
+
340
+ [Kongponents](https://kongponents.konghq.com) ships its own `defineKongponentsTheme` helper that validates a theme object against the full typed token surface at authoring time. To use a pre-built design-tokens theme in Kongponents, wrap it with `defineKongponentsTheme`:
341
+
342
+ ```ts
343
+ // my-app-theme.ts
344
+ import { electricLimeDay } from '@kong/design-tokens/themes'
345
+ import { defineKongponentsTheme } from '@kong/kongponents'
346
+
347
+ export const myTheme = defineKongponentsTheme({
348
+ ...electricLimeDay, // spread the base theme
349
+ '--kui-button-border-radius-medium': '999px', // then override specific tokens
350
+ })
351
+ ```
352
+
353
+ Register the theme at app startup via the Kongponents plugin:
354
+
355
+ ```ts
356
+ // main.ts
357
+ import { createApp } from 'vue'
358
+ import Kongponents from '@kong/kongponents'
359
+ import { myTheme } from './my-app-theme'
360
+ import App from './App.vue'
361
+
362
+ createApp(App)
363
+ .use(Kongponents, { theme: myTheme })
364
+ .mount('#app')
365
+ ```
366
+
367
+ Or apply a theme to a specific subtree at runtime using `KThemeProvider`:
368
+
369
+ ```vue
370
+ <template>
371
+ <KThemeProvider :theme="myTheme">
372
+ <!-- everything here renders with myTheme active -->
373
+ </KThemeProvider>
374
+ </template>
375
+ ```
376
+
377
+ For per-tenant runtime composition (e.g. theme values fetched from an API), use `applyTheme` from `@kong/kongponents`:
378
+
379
+ ```ts
380
+ import { applyTheme } from '@kong/kongponents'
381
+ import { electricLimeDay } from '@kong/design-tokens/themes'
382
+
383
+ // Merge the base theme with tenant-specific overrides, then apply to :root
384
+ applyTheme({ ...electricLimeDay, ...tenantOverrides })
385
+ ```
386
+
252
387
  #### Server-Side Rendering (SSR)
253
388
 
254
389
  If your host application utilizes SSR, you may need to resolve aliases to the package exports.
@@ -276,22 +411,25 @@ To get started, install the package dependencies from the repo root:
276
411
  pnpm install
277
412
  ```
278
413
 
279
- ### Token Requirements
414
+ ### Directory structure
280
415
 
281
- - Tokens **must** be defined in the corresponding JSON files within the `packages/design-tokens/tokens/` directory in one of two sub-directories:
416
+ The package is organized around three top-level source directories:
282
417
 
283
- Directory | Description
284
- ---------|----------
285
- `/tokens/alias` | The `alias` directory **must** only contain alias values that point directly to a raw CSS value. Any tokens defined within the `alias` directory **will not** be exposed in the package exports. Tokens defined in the `/tokens/alias/` directory can be utilized/referenced within the `/tokens/source/` files; however, these tokens will **NOT** be exported in the build files.
286
- `/tokens/source` | The `source` directory contains all tokens that **will be** available for consumption from the package exports.
418
+ | Directory | Purpose |
419
+ |-----------|---------|
420
+ | `tokens/source/` | **Semantic tokens** exported to `custom-properties.css`, SCSS, and JS. Each token family is its own subdirectory: `color/`, `space/`, `shadow/`, `font/`, `border/`, `animation/`, `breakpoint/`, `letter-spacing/`, `line-height/`, plus the concept-named families `method/`, `status/`, `navigation/`, and `icon/` (HTTP methods, status codes, navigation chrome, icons). |
421
+ | `tokens/components/` | **Component tokens** — name-only override slots for Kongponents components (`button/`, `card/`, `input/`, `badge/`, …). All `$value` fields must be `""`. Included in `KUI_THEMEABLE_TOKENS` no CSS, no SCSS/JS values emitted. |
422
+ | `themes/` | **Named theme override sets**, one directory per theme (`themes/<name>/`), each holding two co-located files: `<name>.theme.json` (the token values that activate for `[data-kui-theme="<name>"]`) and `<name>.alias.color.json` (that theme's color palette — the **internal alias tokens**, never exported, that `<name>.theme.json`'s `{color.alias.*}` references resolve against). Both filenames are required and enforced by the build and tests. `themes/_manifest.alias.color.json` is the names-only contract every palette must match. |
423
+
424
+ ### Token Requirements
287
425
 
288
426
  - Token keys **must** be lowercase, snake_case, and defined in normal alphabetical order (rules enforced by the eslint config)
289
- - The `category` of each token should be its own directory (e.g. `tokens/color/`)
290
- - Each `type` of token should be a file in the `category` directory, named `{type}.json` (e.g. `tokens/color/background.json`)
291
- - If there is only a single `type` of token within a `category`, you **should** name the file `index.json` (e.g. `tokens/line-height/index.json`)
292
- - Component tokens **must** be defined within the `/tokens/source/components/` directory. All tokens for a component should be defined in a single JSON file, `{component-name}.json`, with the name of the component as the top-level property in the file.
293
- - Token aliases (e.g. color aliases) **must not** be exposed/exported from the package exports
427
+ - The `category` of each token should be its own directory (e.g. `tokens/source/color/`)
428
+ - Each `type` of token should be a file in the `category` directory, named `{type}.json` (e.g. `tokens/source/color/background.json`)
429
+ - If there is only a single `type` of token within a `category`, you **should** name the file `index.json` (e.g. `tokens/source/line-height/index.json`)
430
+ - Alias tokens (`themes/<name>/<name>.alias.color.json`) **must not** be exposed/exported from the package exports
294
431
  - Tokens at the "root" of their structure **must** be defined with a key of `"_"` to allow for nested child tokens.
432
+ - Component tokens in `tokens/components/` **must always have `$value: ""`** — they are name-only slots with no CSS value. A non-empty `$value` is a build violation caught by the test suite.
295
433
 
296
434
  <details>
297
435
 
@@ -302,17 +440,17 @@ pnpm install
302
440
  "color": {
303
441
  "text": {
304
442
  "_": {
305
- "comment": "blue-100",
306
- "value": "{color.alias.blue.100}"
443
+ "$description": "Default text color.",
444
+ "$value": "{color.alias.blue.100}"
307
445
  },
308
446
  "neutral": {
309
447
  "_": {
310
- "comment": "gray-100",
311
- "value": "{color.alias.gray.60}"
448
+ "$description": "Neutral text color.",
449
+ "$value": "{color.alias.gray.60}"
312
450
  },
313
451
  "strong": {
314
- "comment": "gray-70",
315
- "value": "{color.alias.gray.70}"
452
+ "$description": "Strong neutral text color.",
453
+ "$value": "{color.alias.gray.70}"
316
454
  }
317
455
  }
318
456
  }
@@ -329,6 +467,90 @@ pnpm install
329
467
 
330
468
  </details>
331
469
 
470
+ ### Creating a new theme
471
+
472
+ A new theme is scaffolded **directly from the canonical token tree** — not copied from an existing
473
+ theme. `pnpm theme:scaffold <name>` generates `themes/<name>/<name>.theme.json` and
474
+ `themes/<name>/<name>.alias.color.json`:
475
+
476
+ - Every **semantic** token (`tokens/source/**`) is seeded with its real default `{color.alias.*}`
477
+ mapping — a safe, sensible starting point.
478
+ - Every **component** token (`tokens/components/**`) is seeded as an **empty slot** (`$value: ""`)
479
+ for you to fill deliberately — a component token's value is a genuine design decision (e.g. an
480
+ alert's danger background is a light tint, not the strong semantic danger color) and can't be
481
+ safely defaulted.
482
+ - The **palette** is seeded from `classic-day`'s real neutral values, so the theme builds and
483
+ renders immediately, rather than from a placeholder.
484
+
485
+ The result is **exhaustive by construction** — it contains exactly `KUI_THEMEABLE_TOKENS`, with no
486
+ comparison against any other theme required. (For a **semantic-only** theme instead — every
487
+ semantic token, **zero** component tokens, like `classic-day`/`classic-night` — scaffold normally,
488
+ then delete the component-token entries and add the theme's name to `SEMANTIC_ONLY_THEMES` in
489
+ `platforms/themes.mjs`.)
490
+
491
+ ```sh
492
+ pnpm theme:scaffold my-brand
493
+ # Fill in real palette values (themes/my-brand/my-brand.alias.color.json) and component
494
+ # tokens (themes/my-brand/my-brand.theme.json) to taste.
495
+ pnpm themes:unfilled my-brand # reports empty component slots and palette families still
496
+ # unchanged from the classic-day seed
497
+ pnpm build:tokens && pnpm test # the drift and off-source guards confirm completeness
498
+ ```
499
+
500
+ The build auto-discovers any `themes/<name>/<name>.theme.json` — no code change needed. A theme
501
+ directory whose `<name>.theme.json` is missing is a hard build error (and fails `pnpm test`), as is
502
+ an alias-referencing theme with no matching `<name>.alias.color.json` palette (no silent fallback).
503
+ See [`ALIAS-COLOR-MAPPING-GUIDE.md`](./docs/ALIAS-COLOR-MAPPING-GUIDE.md) §6, "Adding a future theme".
504
+
505
+ **Keeping every theme in sync as the token set grows.** Adding a token to `tokens/source/**` or
506
+ `tokens/components/**` doesn't require hand-editing every theme file — run `pnpm themes:sync` to
507
+ add the new token to every theme (semantic tokens get their source default; component tokens get
508
+ an empty slot to fill), or `pnpm themes:unfilled <name>` to check what any one theme still needs.
509
+
510
+ > **Note — theme-creation skill dependency.** The `theme-creation` skill in
511
+ > `packages/skills/theme-creation/` automates this flow end-to-end (scaffolding, matching a
512
+ > source's look, previewing against Kongponents). It calls this package's `theme:scaffold` /
513
+ > `themes:sync` / `themes:unfilled` commands directly rather than duplicating their logic, so
514
+ > renaming or restructuring those commands (`scripts/theme-scaffold.mjs`, `scripts/themes-sync.mjs`,
515
+ > `scripts/themes-unfilled.mjs`) only needs updating in one place — the skill won't silently drift
516
+ > out of sync with them.
517
+
518
+ ### Theme `$description` authoring rules
519
+
520
+ Every token entry in a theme JSON file may carry an optional `$description` field. When present, it must follow these rules:
521
+
522
+ - **Match the semantic token's description** — copy the text from the corresponding token in `tokens/source/`. Do not invent a different description for the same concept.
523
+ - **Never reference a CSS value** — descriptions must be value-agnostic. The description explains *what* the token controls, not *what value* it currently holds.
524
+
525
+ | ❌ Avoid | ✅ Use instead |
526
+ |---|---|
527
+ | `"2px border radius."` | _(omit — scale tokens are self-documenting by name)_ |
528
+ | `"Background color for containers (white)."` | `"Default background color for containers."` |
529
+ | `"Border color for danger actions or messages (red.60)."` | `"Border color for danger actions or messages."` |
530
+ | `"0px 0px 0px 1px blue.60 inset"` | `"Primary state inset border shadow."` |
531
+
532
+ **When to omit `$description` entirely:** pure scale tokens (`--kui-space-*`, `--kui-border-radius-0` through `-50`, `--kui-border-width-*`, `--kui-icon-size-*`, `--kui-line-height-*`, `--kui-letter-spacing-*`) are self-documenting — their token names carry all the meaning. Leave `$description` off these entries.
533
+
534
+ **Component tokens may appear in theme files with `$description`.** A theme may set any component token (`--kui-button-*`, `--kui-card-*`, etc.) to provide per-component customization that diverges from the semantic fallback. Use the same description as the component token's source definition in `tokens/components/`.
535
+
536
+ ```json
537
+ // ✅ Correct — description matches source definition
538
+ "kui-button-border-radius-medium": {
539
+ "$description": "Medium button border radius.",
540
+ "$value": "999px"
541
+ }
542
+ ```
543
+
544
+ **A theme file must define its full token set, not just the tokens it changes.** An exhaustive
545
+ theme must contain exactly `KUI_THEMEABLE_TOKENS` (every semantic *and* component token); a
546
+ semantic-only theme (`SEMANTIC_ONLY_THEMES`) must contain every semantic token and zero component
547
+ tokens — nothing may be missing, even if its value is identical to another theme's. The
548
+ `[data-kui-theme]` CSS cascade / `var()` fallback behavior governs runtime behavior for *component*
549
+ tokens that are legitimately absent from a semantic-only theme (they fall through to the semantic
550
+ layer) — it does not mean a theme file itself may omit tokens whose value happens not to differ.
551
+ `pnpm theme:scaffold` and `pnpm themes:sync` handle this for you: every scaffolded or synced theme
552
+ already contains its full required set.
553
+
332
554
  ### Development Sandbox
333
555
 
334
556
  This package includes a Vue sandbox (see the `sandbox/` directory) to allow you to experiment with consuming tokens.
@@ -345,7 +567,7 @@ Or from within this package directory:
345
567
  pnpm sandbox
346
568
  ```
347
569
 
348
- This command will simultaneously start the Vite dev server and initialize a watcher on the `tokens/` directory. If any files in the `tokens/` directory are modified, the sandbox will automatically run the build command to update the tokens and then restart the Vite dev server (simulating hot module reload).
570
+ This command simultaneously starts the Vite dev server and watches both the `tokens/` and `themes/` directories. Changes to either trigger a rebuild and restart the Vite dev server.
349
571
 
350
572
  Updating any files within the sandbox itself will also trigger hot module reload as expected.
351
573
 
@@ -399,7 +621,7 @@ For example, if I want to add a new `my-feature` folder, I'd update the `exports
399
621
 
400
622
  1. Ensure you are on the `main` branch, then pull down the latest code by running `git checkout main && git pull origin main`
401
623
  2. Checkout a new branch for your changes with `git checkout -b {type}/{jira-ticket}-{description}` — as an example, `git checkout feat/khcp-1234-add-color-tokens`
402
- 3. Add/edit the tokens in the `packages/design-tokens/tokens/` directory as needed, ensuring to adhere to the [Token Requirements](#token-requirements)
624
+ 3. Add/edit the tokens in the `tokens/` or `themes/` directory as needed, ensuring to adhere to the [Token Requirements](#token-requirements)
403
625
  4. Before committing your changes, locally run `pnpm lint` to ensure you do not have any linting errors. If you have errors, you can try running `pnpm lint:fix` to resolve
404
626
  5. Commit your changes, adhering to [Conventional Commits](#committing-changes). To make this easier, you're encouraged to run `pnpm commit` from the repo root to help build your commit message
405
627
  6. Push your branch up to the remote with `git push origin {branch-name}`