@revikornmann/muka-ui 0.18.0 → 0.20.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 (195) hide show
  1. package/README.md +81 -60
  2. package/cli/bin/muka-ui.js +12 -5
  3. package/cli/commands/brand.js +33 -14
  4. package/cli/commands/init.js +21 -17
  5. package/cli/commands/install-skill.js +84 -26
  6. package/cli/templates/AGENTS.md +128 -0
  7. package/cli/templates/CLAUDE.md +8 -88
  8. package/cli/templates/muka-ui-guidelines.md +50 -14
  9. package/dist/cjs/components/ActionSheet/ActionSheet.css +4 -4
  10. package/dist/cjs/components/BottomBar/BottomBar.css +0 -3
  11. package/dist/cjs/components/Breadcrumb/Breadcrumb.css +26 -2
  12. package/dist/cjs/components/Combobox/Combobox.css +116 -132
  13. package/dist/cjs/components/Combobox/Combobox.js +175 -52
  14. package/dist/cjs/components/Combobox/Combobox.js.map +1 -1
  15. package/dist/cjs/components/Combobox/index.js.map +1 -1
  16. package/dist/cjs/components/ContextSelect/ContextSelect.css +4 -4
  17. package/dist/cjs/components/DocumentViewer/DocumentViewer.css +2 -2
  18. package/dist/cjs/components/DropdownSelect/DropdownSelect.css +225 -0
  19. package/dist/cjs/components/DropdownSelect/DropdownSelect.js +106 -0
  20. package/dist/cjs/components/DropdownSelect/DropdownSelect.js.map +1 -0
  21. package/dist/cjs/components/DropdownSelect/index.js +6 -0
  22. package/dist/cjs/components/DropdownSelect/index.js.map +1 -0
  23. package/dist/cjs/components/EmptyState/EmptyState.css +8 -8
  24. package/dist/cjs/components/FAB/FAB.css +1 -1
  25. package/dist/cjs/components/FileUpload/FileUpload.css +10 -10
  26. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js +11 -0
  27. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  28. package/dist/cjs/components/Icon/iconRegistry.js +14 -1
  29. package/dist/cjs/components/Icon/iconRegistry.js.map +1 -1
  30. package/dist/cjs/components/Input/Input.css +47 -10
  31. package/dist/cjs/components/Input/Input.js +14 -3
  32. package/dist/cjs/components/Input/Input.js.map +1 -1
  33. package/dist/cjs/components/Label/Label.css +1 -1
  34. package/dist/cjs/components/LicensePlateInput/LicensePlateInput.css +1 -1
  35. package/dist/cjs/components/Menu/Menu.css +124 -38
  36. package/dist/cjs/components/Menu/Menu.js +283 -25
  37. package/dist/cjs/components/Menu/Menu.js.map +1 -1
  38. package/dist/cjs/components/Pagination/Pagination.css +15 -15
  39. package/dist/cjs/components/PhotoUploader/PhotoUploader.css +4 -4
  40. package/dist/cjs/components/ProgressAccordeon/ProgressAccordeon.css +10 -6
  41. package/dist/cjs/components/ProgressAccordeon/ProgressAccordeon.js +27 -16
  42. package/dist/cjs/components/ProgressAccordeon/ProgressAccordeon.js.map +1 -1
  43. package/dist/cjs/components/ProgressTracker/ProgressTracker.css +273 -22
  44. package/dist/cjs/components/ProgressTracker/ProgressTracker.js +109 -9
  45. package/dist/cjs/components/ProgressTracker/ProgressTracker.js.map +1 -1
  46. package/dist/cjs/components/Scrollbar/Scrollbar.css +7 -6
  47. package/dist/cjs/components/SearchInput/SearchInput.css +4 -4
  48. package/dist/cjs/components/Select/Select.css +2 -2
  49. package/dist/cjs/components/SmsOtpField/SmsOtpField.css +2 -2
  50. package/dist/cjs/components/SpecList/SpecList.css +8 -8
  51. package/dist/cjs/components/Spinner/Spinner.css +1 -1
  52. package/dist/cjs/components/SwipeActions/SwipeActions.css +6 -6
  53. package/dist/cjs/components/Table/Table.css +3 -3
  54. package/dist/cjs/components/Table/TablePagination.css +1 -1
  55. package/dist/cjs/components/Tabs/Tabs.css +6 -6
  56. package/dist/cjs/components/Textarea/Textarea.css +2 -2
  57. package/dist/cjs/components/Waveform/Waveform.css +1 -1
  58. package/dist/cjs/components/index.js +5 -3
  59. package/dist/cjs/components/index.js.map +1 -1
  60. package/dist/esm/components/ActionSheet/ActionSheet.css +4 -4
  61. package/dist/esm/components/BottomBar/BottomBar.css +0 -3
  62. package/dist/esm/components/Breadcrumb/Breadcrumb.css +26 -2
  63. package/dist/esm/components/Combobox/Combobox.css +116 -132
  64. package/dist/esm/components/Combobox/Combobox.js +177 -54
  65. package/dist/esm/components/Combobox/Combobox.js.map +1 -1
  66. package/dist/esm/components/Combobox/index.js +1 -1
  67. package/dist/esm/components/Combobox/index.js.map +1 -1
  68. package/dist/esm/components/ContextSelect/ContextSelect.css +4 -4
  69. package/dist/esm/components/DocumentViewer/DocumentViewer.css +2 -2
  70. package/dist/esm/components/DropdownSelect/DropdownSelect.css +225 -0
  71. package/dist/esm/components/DropdownSelect/DropdownSelect.js +102 -0
  72. package/dist/esm/components/DropdownSelect/DropdownSelect.js.map +1 -0
  73. package/dist/esm/components/DropdownSelect/index.js +2 -0
  74. package/dist/esm/components/DropdownSelect/index.js.map +1 -0
  75. package/dist/esm/components/EmptyState/EmptyState.css +8 -8
  76. package/dist/esm/components/FAB/FAB.css +1 -1
  77. package/dist/esm/components/FileUpload/FileUpload.css +10 -10
  78. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js +7 -0
  79. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  80. package/dist/esm/components/Icon/iconRegistry.js +14 -1
  81. package/dist/esm/components/Icon/iconRegistry.js.map +1 -1
  82. package/dist/esm/components/Input/Input.css +47 -10
  83. package/dist/esm/components/Input/Input.js +14 -3
  84. package/dist/esm/components/Input/Input.js.map +1 -1
  85. package/dist/esm/components/Label/Label.css +1 -1
  86. package/dist/esm/components/LicensePlateInput/LicensePlateInput.css +1 -1
  87. package/dist/esm/components/Menu/Menu.css +124 -38
  88. package/dist/esm/components/Menu/Menu.js +284 -26
  89. package/dist/esm/components/Menu/Menu.js.map +1 -1
  90. package/dist/esm/components/Pagination/Pagination.css +15 -15
  91. package/dist/esm/components/PhotoUploader/PhotoUploader.css +4 -4
  92. package/dist/esm/components/ProgressAccordeon/ProgressAccordeon.css +10 -6
  93. package/dist/esm/components/ProgressAccordeon/ProgressAccordeon.js +27 -16
  94. package/dist/esm/components/ProgressAccordeon/ProgressAccordeon.js.map +1 -1
  95. package/dist/esm/components/ProgressTracker/ProgressTracker.css +273 -22
  96. package/dist/esm/components/ProgressTracker/ProgressTracker.js +110 -10
  97. package/dist/esm/components/ProgressTracker/ProgressTracker.js.map +1 -1
  98. package/dist/esm/components/Scrollbar/Scrollbar.css +7 -6
  99. package/dist/esm/components/SearchInput/SearchInput.css +4 -4
  100. package/dist/esm/components/Select/Select.css +2 -2
  101. package/dist/esm/components/SmsOtpField/SmsOtpField.css +2 -2
  102. package/dist/esm/components/SpecList/SpecList.css +8 -8
  103. package/dist/esm/components/Spinner/Spinner.css +1 -1
  104. package/dist/esm/components/SwipeActions/SwipeActions.css +6 -6
  105. package/dist/esm/components/Table/Table.css +3 -3
  106. package/dist/esm/components/Table/TablePagination.css +1 -1
  107. package/dist/esm/components/Tabs/Tabs.css +6 -6
  108. package/dist/esm/components/Textarea/Textarea.css +2 -2
  109. package/dist/esm/components/Waveform/Waveform.css +1 -1
  110. package/dist/esm/components/index.js +1 -0
  111. package/dist/esm/components/index.js.map +1 -1
  112. package/dist/styles/components/ActionSheet.css +4 -4
  113. package/dist/styles/components/BottomBar.css +0 -3
  114. package/dist/styles/components/Breadcrumb.css +26 -2
  115. package/dist/styles/components/Combobox.css +116 -132
  116. package/dist/styles/components/ContextSelect.css +4 -4
  117. package/dist/styles/components/DocumentViewer.css +2 -2
  118. package/dist/styles/components/DropdownSelect.css +225 -0
  119. package/dist/styles/components/EmptyState.css +8 -8
  120. package/dist/styles/components/FAB.css +1 -1
  121. package/dist/styles/components/FileUpload.css +10 -10
  122. package/dist/styles/components/Input.css +47 -10
  123. package/dist/styles/components/Label.css +1 -1
  124. package/dist/styles/components/LicensePlateInput.css +1 -1
  125. package/dist/styles/components/Menu.css +124 -38
  126. package/dist/styles/components/Pagination.css +15 -15
  127. package/dist/styles/components/PhotoUploader.css +4 -4
  128. package/dist/styles/components/ProgressAccordeon.css +10 -6
  129. package/dist/styles/components/ProgressTracker.css +273 -22
  130. package/dist/styles/components/Scrollbar.css +7 -6
  131. package/dist/styles/components/SearchInput.css +4 -4
  132. package/dist/styles/components/Select.css +2 -2
  133. package/dist/styles/components/SmsOtpField.css +2 -2
  134. package/dist/styles/components/SpecList.css +8 -8
  135. package/dist/styles/components/Spinner.css +1 -1
  136. package/dist/styles/components/SwipeActions.css +6 -6
  137. package/dist/styles/components/Table.css +3 -3
  138. package/dist/styles/components/Tabs.css +6 -6
  139. package/dist/styles/components/Textarea.css +2 -2
  140. package/dist/styles/components/Typography.css +89 -0
  141. package/dist/styles/components/Waveform.css +1 -1
  142. package/dist/styles/index.css +1167 -462
  143. package/dist/styles/muka-dark.css +1167 -462
  144. package/dist/styles/muka-light.css +1167 -462
  145. package/dist/styles/tokens-bouwplan-dark.css +5 -4
  146. package/dist/styles/tokens-bouwplan-light.css +5 -4
  147. package/dist/styles/tokens-fscl-dark.css +25 -24
  148. package/dist/styles/tokens-fscl-light.css +25 -24
  149. package/dist/styles/tokens-grip-dark.css +4 -3
  150. package/dist/styles/tokens-grip-light.css +4 -3
  151. package/dist/styles/tokens-muka-dark.css +4 -3
  152. package/dist/styles/tokens-muka-light.css +4 -3
  153. package/dist/styles/tokens-wireframe-dark.css +49 -48
  154. package/dist/styles/tokens-wireframe-light.css +49 -48
  155. package/dist/styles/wireframe-dark.css +1212 -507
  156. package/dist/styles/wireframe-light.css +1212 -507
  157. package/dist/types/components/Combobox/Combobox.d.ts +38 -38
  158. package/dist/types/components/Combobox/Combobox.d.ts.map +1 -1
  159. package/dist/types/components/Combobox/index.d.ts +1 -1
  160. package/dist/types/components/Combobox/index.d.ts.map +1 -1
  161. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts +71 -0
  162. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts.map +1 -0
  163. package/dist/types/components/DropdownSelect/index.d.ts +2 -0
  164. package/dist/types/components/DropdownSelect/index.d.ts.map +1 -0
  165. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts +9 -0
  166. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts.map +1 -0
  167. package/dist/types/components/Icon/iconRegistry.d.ts.map +1 -1
  168. package/dist/types/components/Input/Input.d.ts +5 -0
  169. package/dist/types/components/Input/Input.d.ts.map +1 -1
  170. package/dist/types/components/Menu/Menu.d.ts +42 -2
  171. package/dist/types/components/Menu/Menu.d.ts.map +1 -1
  172. package/dist/types/components/ProgressAccordeon/ProgressAccordeon.d.ts +17 -12
  173. package/dist/types/components/ProgressAccordeon/ProgressAccordeon.d.ts.map +1 -1
  174. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts +29 -8
  175. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts.map +1 -1
  176. package/dist/types/components/index.d.ts +1 -0
  177. package/dist/types/components/index.d.ts.map +1 -1
  178. package/docs/consumers/README.md +116 -37
  179. package/docs/consumers/brand.md +261 -0
  180. package/docs/consumers/figma-console-mcp.md +116 -0
  181. package/docs/consumers/setup-instructions.md +98 -12
  182. package/docs/consumers/skills.md +79 -0
  183. package/package.json +5 -6
  184. package/scripts/postinstall-nudge.js +8 -4
  185. package/skills/add-brand/SKILL.md +204 -0
  186. package/skills/add-brand/reference.md +160 -0
  187. package/skills/figma-to-code/SKILL.md +127 -0
  188. package/skills/pull-from-figma/SKILL.md +123 -0
  189. package/skills/push-to-figma/SKILL.md +172 -0
  190. package/skills/setup-muka/SKILL.md +73 -13
  191. package/tokens/README.md +39 -17
  192. package/tokens/t2-alias/brand/bouwplan/fonts.json +1 -1
  193. package/tokens/t2-alias/brand/fscl/fonts.json +3 -3
  194. package/tokens/t2-alias/brand/wireframe/fonts.json +2 -2
  195. package/tokens/t4-components/menu.json +8 -3
@@ -9,6 +9,9 @@ version.
9
9
  Muka UI is a **public npm package** — installing it needs no `.npmrc`, registry
10
10
  configuration, or auth token.
11
11
 
12
+ For the wider picture — brands, Figma, the skills — start at
13
+ [`README.md`](README.md).
14
+
12
15
  ## 1. Install
13
16
 
14
17
  ```bash
@@ -22,29 +25,80 @@ import '@revikornmann/muka-ui/styles'; // default muka-light — muka fonts incl
22
25
  import { Button } from '@revikornmann/muka-ui';
23
26
  ```
24
27
 
25
- The default `/styles` bundle — and the pre-bundled `/styles/muka-dark.css` and
26
- `/styles/wireframe-{light,dark}.css` files — already include that brand's self-hosted
27
- fonts, so on those themes you need no separate fonts import. Other brands are loaded
28
- via their raw `tokens-<brand>-<mode>.css` (below), which carries no fonts, so those
29
- also import `fonts-<brand>.css`.
28
+ ## 2. Pick a brand and theme
29
+
30
+ Muka ships five brands — `muka`, `wireframe`, `grip`, `fscl`, `bouwplan` — each in
31
+ light and dark, for **ten themes**. How you load one depends on the brand.
32
+
33
+ **Pre-bundled (muka and wireframe).** `/styles` is `muka-light`; three
34
+ alternatives are drop-in replacements for it. Each is self-contained: base
35
+ styles, tokens, every component's CSS, and that brand's self-hosted fonts.
36
+
37
+ ```ts
38
+ import '@revikornmann/muka-ui/styles'; // muka-light
39
+ import '@revikornmann/muka-ui/styles/muka-dark.css';
40
+ import '@revikornmann/muka-ui/styles/wireframe-light.css';
41
+ import '@revikornmann/muka-ui/styles/wireframe-dark.css';
42
+ ```
30
43
 
31
- For a brand theme, also load the brand CSS **and the brand's fonts** and set the
32
- data attributes (replace `bouwplan` with your brand):
44
+ **Composed (grip, fscl, bouwplan).** No pre-bundled file, so combine three
45
+ imports — base styles, the brand's raw token CSS, and the brand's fonts. The raw
46
+ token CSS carries no `@font-face`, which is why the fonts import is separate:
33
47
 
34
48
  ```ts
49
+ import '@revikornmann/muka-ui/styles/base.css';
35
50
  import '@revikornmann/muka-ui/styles/tokens-bouwplan-light.css';
36
51
  import '@revikornmann/muka-ui/styles/fonts-bouwplan.css';
37
52
  ```
38
53
 
54
+ None of the five fitting? Build your own brand — see [`brand.md`](brand.md).
55
+
56
+ ### How theme selection actually works
57
+
58
+ Every token stylesheet declares its variables on `:root`. There are **no
59
+ `[data-brand]` or `[data-theme]` selectors in Muka's CSS**, so you select a theme
60
+ by **choosing which stylesheet loads**, and importing two means the last one
61
+ wins. Setting `data-brand` / `data-theme` attributes has no effect.
62
+
63
+ For a runtime light/dark toggle, swap a `<link>` instead of importing both:
64
+
65
+ ```html
66
+ <link id="muka-theme" rel="stylesheet" href="/styles/tokens-muka-light.css" />
67
+ ```
68
+
69
+ ```ts
70
+ document.getElementById('muka-theme').href =
71
+ `/styles/tokens-${brand}-${mode}.css`;
72
+ ```
73
+
74
+ Copy the token CSS you need into your static/public directory (or let your
75
+ bundler emit it at a stable URL) so those hrefs resolve. Muka's own Storybook
76
+ switches between all ten themes exactly this way — see
77
+ `.storybook/ThemeDecorator.ts` in the repo.
78
+
79
+ ### `data-layout`: the one attribute that does do something
80
+
81
+ Brand and theme are not attributes, but **layout density is**. Section padding
82
+ and container gaps respond to viewport width through `@media` blocks, and
83
+ `data-layout` forces one of those steps regardless of viewport:
84
+
39
85
  ```html
40
- <html data-brand="bouwplan" data-theme="light">
86
+ <div data-layout="desktop">…</div>
41
87
  ```
42
88
 
89
+ Accepted values are `tablet`, `desktop`, and `widescreen`; omit the attribute to
90
+ let the media queries decide. Use it when a region should keep desktop spacing
91
+ inside a narrow container (or the reverse) — it only overrides
92
+ `--section-padding-*` and `--container-gap-*`, never colours or type.
93
+
94
+ If your app only ever needs one theme, a plain import is simpler and this does
95
+ not apply.
96
+
43
97
  ### Fonts come from Muka — do not load them yourself
44
98
 
45
99
  Muka self-hosts every brand's fonts and ships them as `@font-face` in
46
- `styles/fonts-<brand>.css` (backed by bundled WOFF2, so they work offline with no
47
- CDN). Importing that one file is all the wiring you need:
100
+ `styles/fonts-<brand>.css`, backed by bundled WOFF2, so they work offline with no
101
+ CDN. Importing that one file is all the wiring you need:
48
102
 
49
103
  - **Do not** load these fonts via `next/font`, a Google Fonts `<link>`, or any
50
104
  other loader — you'd ship the bytes twice and risk a name mismatch.
@@ -52,7 +106,7 @@ CDN). Importing that one file is all the wiring you need:
52
106
  font-family names in Muka's tokens are the exact `@font-face` family names, so
53
107
  overriding them only breaks the resolution.
54
108
 
55
- ## 2. Add the auto-update workflow
109
+ ## 3. Add the auto-update workflow
56
110
 
57
111
  Copy the shipped template into your repo so it stays current with Muka releases:
58
112
 
@@ -77,7 +131,10 @@ The workflow auto-detects your package manager from the lockfile
77
131
  > rejecting a just-published version). Match the value to the pnpm/yarn version
78
132
  > you use locally (e.g. `lockfileVersion: 9.0` → pnpm 9).
79
133
 
80
- ## 3. Register as a consumer
134
+ Muka is under active development, so a bump can change component behaviour or
135
+ appearance. Keep CI checks on the update PR rather than trusting it blindly.
136
+
137
+ ## 4. Register as a consumer
81
138
 
82
139
  Add `owner/repo` to Muka's [`.github/consumers.txt`](../../.github/consumers.txt)
83
140
  so the release pipeline dispatches updates here. The `/setup-muka` skill opens
@@ -85,3 +142,32 @@ this PR automatically; merge it to enable automatic updates.
85
142
 
86
143
  The Muka `CONSUMER_DISPATCH_TOKEN` PAT must have **write** access to this repo
87
144
  for the `repository_dispatch` to succeed.
145
+
146
+ ## 5. Give your agents the house rules
147
+
148
+ ```bash
149
+ npx muka-ui init
150
+ ```
151
+
152
+ Writes `AGENTS.md`, `CLAUDE.md`, and `docs/muka-ui-guidelines.md` into your repo
153
+ (prompting before overwriting any of them), so agents working here compose Muka
154
+ components and use token custom properties instead of inventing markup and
155
+ hardcoding values. It also warns about styling libraries that conflict with Muka.
156
+
157
+ `AGENTS.md` holds the rules, because that filename is the vendor-neutral
158
+ convention most agents read. `CLAUDE.md` is a few lines pointing at it, so Claude
159
+ Code finds them too without a second copy that can drift.
160
+
161
+ ## Verify
162
+
163
+ - `npm ls @revikornmann/muka-ui` shows a semver version resolved from npmjs.
164
+ - The app builds and Muka components render with brand tokens.
165
+ - A component's computed `background-color` resolves to a real colour rather than
166
+ falling back — that is the check that the token CSS actually loaded.
167
+ - `.github/workflows/update-muka.yml` exists and is valid YAML.
168
+
169
+ ## Next
170
+
171
+ - [`brand.md`](brand.md) — build your own brand
172
+ - [`skills.md`](skills.md) — every shipped agent skill
173
+ - <https://muka.kornmann.com> — component APIs, Playgrounds, token docs
@@ -0,0 +1,79 @@
1
+ # Agent skills shipped with Muka UI
2
+
3
+ `@revikornmann/muka-ui` ships agent skills inside the package. They turn the
4
+ multi-step jobs around a design system — installing it, branding it, translating
5
+ a design into code, syncing tokens with Figma — into one command each.
6
+
7
+ ## Installing them
8
+
9
+ Agents discover skills under `.claude/skills/`, never inside `node_modules/`, so
10
+ the package ships them and the CLI copies them in:
11
+
12
+ ```bash
13
+ npx muka-ui install-skill # install all of them
14
+ npx muka-ui install-skill --list # see what's available first
15
+ npx muka-ui install-skill add-brand figma-to-code # install specific ones
16
+ ```
17
+
18
+ Restart your agent afterwards so it picks up the new slash commands. Re-run the
19
+ same command after a Muka upgrade to refresh them; it skips anything already
20
+ identical and prompts before overwriting local edits.
21
+
22
+ ## Which agents can use them
23
+
24
+ The directory name is Claude's, but the contents are not: a skill is a plain
25
+ markdown file with YAML frontmatter, and `.claude/skills/` is scanned by **Claude
26
+ Code and Cursor** alike. For an agent that reads neither, the skills still work
27
+ as documentation — point it at `.claude/skills/<name>/SKILL.md` and it has the
28
+ same instructions, just without a slash command to trigger them.
29
+
30
+ Nothing else Muka ships is agent-specific. The tokens are CSS custom properties,
31
+ the components are React, and these consumer docs are prose — none of that cares
32
+ what is editing your repo. `npx muka-ui init` writes the house rules to
33
+ `AGENTS.md`, the vendor-neutral convention, and leaves a short `CLAUDE.md`
34
+ pointing at it.
35
+
36
+ ## The skills
37
+
38
+ | Skill | What it does | Needs |
39
+ |---|---|---|
40
+ | `/setup-muka` | Installs the package, wires up styles and fonts, adds the release auto-update workflow, and registers your repo as a consumer. Start here. | — |
41
+ | `/add-brand` | Creates a custom brand in **your** repo that overrides Muka's brand layer, so every Muka component takes your colours and typography. Scaffolds the token files, explains the palette choices, and builds the CSS. | `/setup-muka` |
42
+ | `/figma-to-code` | Turns a Figma link into a working screen composed from Muka components and token custom properties — rather than a pixel-matched rebuild that ignores your brand. | A Figma MCP server |
43
+ | `/push-to-figma` | Publishes your brand's tokens into Figma as variables, so designers can design in your brand. Code → Figma. | `/add-brand` + Figma Console MCP |
44
+ | `/pull-from-figma` | Brings brand colour and font changes a designer made in Figma back into your token files. Figma → Code. | `/push-to-figma` + Figma Console MCP |
45
+
46
+ `/setup-muka` and `/add-brand` are the two most people need. The Figma pair
47
+ matters once designers and engineers are both editing the brand.
48
+
49
+ ## The Figma Console MCP dependency
50
+
51
+ `/push-to-figma` and `/pull-from-figma` read and write Figma **variables**, which
52
+ the Figma REST API cannot do for local variables. They therefore drive
53
+ [**Figma Console MCP**](https://github.com/southleft/figma-console-mcp), an
54
+ open-source (MIT) MCP server by **[Southleft](https://southleft.com)** published
55
+ as [`figma-console-mcp`](https://www.npmjs.com/package/figma-console-mcp). It
56
+ relays commands to a Desktop Bridge plugin inside Figma Desktop.
57
+
58
+ It is a third-party project. Muka ships only the skills that drive it; report
59
+ server problems [upstream](https://github.com/southleft/figma-console-mcp/issues).
60
+
61
+ One-time setup — token, `.mcp.json`, Desktop Bridge plugin, verification — is in
62
+ [`figma-console-mcp.md`](figma-console-mcp.md). Without it, those two skills
63
+ cannot run; the other three are unaffected.
64
+
65
+ `/figma-to-code` is different: it reads designs through **Figma's own official
66
+ MCP server**, not Figma Console MCP, and needs no Desktop Bridge.
67
+
68
+ ## Maintainer skills are not shipped
69
+
70
+ The Muka repo has its own skills for working **on** the design system —
71
+ `/component-rules`, `/token-system`, `/new-component`, `/release`, and a
72
+ repo-scoped `/add-brand` that adds a brand to Muka itself for every consumer.
73
+ Those live in
74
+ [`.claude/skills/`](https://github.com/revikornmann/muka/tree/main/.claude/skills)
75
+ and are deliberately excluded from the package, because they edit files that
76
+ exist only in the Muka repo.
77
+
78
+ If you are contributing to Muka rather than consuming it, clone the repo and use
79
+ those directly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revikornmann/muka-ui",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "Muka Design System - Multi-brand design tokens and React components",
5
5
  "main": "dist/cjs/components/index.js",
6
6
  "module": "dist/esm/components/index.js",
@@ -62,6 +62,7 @@
62
62
  "figma:connect:publish": "figma-code-connect --publish",
63
63
  "typecheck": "tsc --project tsconfig.typecheck.json",
64
64
  "check:docs": "node scripts/check-doc-sync.js",
65
+ "check:tokens-used": "node scripts/check-tokens-used.js",
65
66
  "lint": "eslint .",
66
67
  "lint:rsc": "eslint --config eslint.rsc.mjs \"components/**/*.{ts,tsx}\"",
67
68
  "validate:tokens": "node scripts/validate-tokens.js",
@@ -69,8 +70,6 @@
69
70
  "disable:automation": "node scripts/disable-automation.js",
70
71
  "enable:automation": "node scripts/enable-automation.js",
71
72
  "check:automation": "node scripts/check-automation-status.js",
72
- "sync:skills": "node scripts/sync-shipped-skills.js",
73
- "prepack": "node scripts/sync-shipped-skills.js",
74
73
  "prepublishOnly": "npm run build",
75
74
  "postinstall": "node scripts/postinstall-nudge.js",
76
75
  "prepare": "husky || true"
@@ -108,15 +107,14 @@
108
107
  "@fontsource-variable/ibm-plex-sans": "^5.2.8",
109
108
  "@fontsource-variable/lora": "^5.2.8",
110
109
  "@fontsource-variable/quicksand": "^5.2.10",
111
- "@fontsource-variable/red-hat-display": "^5.2.8",
112
- "@fontsource-variable/red-hat-text": "^5.2.8",
110
+ "@fontsource-variable/red-hat-display": "^5.3.0",
111
+ "@fontsource-variable/red-hat-text": "^5.3.0",
113
112
  "@fontsource/yesteryear": "^5.2.8",
114
113
  "@playwright/test": "^1.56.1",
115
114
  "@storybook/addon-a11y": "^10.3.4",
116
115
  "@storybook/addon-designs": "^11.1.3",
117
116
  "@storybook/addon-docs": "^10.3.4",
118
117
  "@storybook/addon-mcp": "^0.5.0",
119
- "@storybook/addon-onboarding": "^10.3.4",
120
118
  "@storybook/addon-vitest": "^10.3.4",
121
119
  "@storybook/react-vite": "^10.3.4",
122
120
  "@testing-library/dom": "^10.4.1",
@@ -139,6 +137,7 @@
139
137
  "playwright": "^1.56.1",
140
138
  "react": "^18.0.0",
141
139
  "react-dom": "^18.0.0",
140
+ "remark-gfm": "^4.0.1",
142
141
  "storybook": "^10.3.4",
143
142
  "typescript": "^5.0.0",
144
143
  "typescript-eslint": "^8.59.2",
@@ -18,9 +18,13 @@ if (!__dirname.includes(`${require('path').sep}node_modules${require('path').sep
18
18
  console.log(`
19
19
  🎨 Muka UI installed.
20
20
 
21
- Finish setup in Claude Code:
22
- 1. npx muka-ui install-skill # makes /setup-muka available
23
- 2. /setup-muka [brand] # installs styles + auto-update workflow
21
+ Finish setup in your agent:
22
+ 1. npx muka-ui install-skill # makes the Muka skills available
23
+ 2. /setup-muka [brand] # styles, fonts, auto-update workflow
24
24
 
25
- Docs: node_modules/@revikornmann/muka-ui/docs/consumers/setup-instructions.md
25
+ Then, when you want your own brand:
26
+ /add-brand <name> # overrides Muka's brand layer in this repo
27
+
28
+ See every shipped skill: npx muka-ui install-skill --list
29
+ Docs: node_modules/@revikornmann/muka-ui/docs/consumers/README.md
26
30
  `);
@@ -0,0 +1,204 @@
1
+ ---
2
+ name: add-brand
3
+ description: Create a custom brand in this repo that overrides Muka UI's brand layer, so every Muka component picks up your colours and typography.
4
+ disable-model-invocation: true
5
+ argument-hint: "[brand-name]"
6
+ ---
7
+
8
+ # Add your own brand
9
+
10
+ Give this repo its own brand without forking Muka UI. You author **only the T2
11
+ brand layer**; primitives, semantics, and all component tokens keep coming from
12
+ the installed package, so every Muka component restyles itself with no component
13
+ code changes.
14
+
15
+ `$ARGUMENTS` is the brand name — lowercase, starting with a letter, letters,
16
+ numbers and hyphens only (e.g. `acme`, `northwind`, `blue-harbour`).
17
+
18
+ **Prerequisite:** `@revikornmann/muka-ui` is installed. If not, run
19
+ `/setup-muka` first.
20
+
21
+ See [`reference.md`](reference.md) for the full token map, the available
22
+ primitive palettes, and the colour-scale conventions.
23
+
24
+ ## How the override works
25
+
26
+ ```
27
+ T1 Primitives (package) raw ramps: color.indigo.9, spacing.4, size.md
28
+ T2 Alias base (package) brand-agnostic defaults
29
+ T2 Alias brand ← YOU brand/light.json, brand/dark.json, brand/fonts.json
30
+ T3 Semantics (package) color.surface.level1, color.action.default
31
+ T4 Components (package) button.color.primary.background.default
32
+ ```
33
+
34
+ Your three files replace the brand slice of T2. Everything above resolves
35
+ through them, which is why one file of colour references repaints the whole
36
+ library.
37
+
38
+ ## Step 1: Scaffold the brand
39
+
40
+ ```bash
41
+ npx muka-ui brand init $ARGUMENTS
42
+ ```
43
+
44
+ This creates, prompting before overwriting anything that exists:
45
+
46
+ | Path | Contents |
47
+ |---|---|
48
+ | `brand/fonts.json` | Font families and weights for the `brand`, `plain`, `mono`, `script` roles |
49
+ | `brand/light.json` | Light-mode colour aliases (78 tokens) |
50
+ | `brand/dark.json` | Dark-mode colour aliases |
51
+ | `brand/muka.brand.json` | Build manifest — your brand files plus package token globs |
52
+ | `brand/build.js` | Build entry using `TokenBuilder` from the package |
53
+
54
+ It also adds a `build:tokens` script to `package.json` if one is not there.
55
+
56
+ The scaffolded files are copies of Muka's `wireframe` brand, so they are a
57
+ complete, valid, buildable starting point rather than empty stubs. Confirm the
58
+ build works before editing anything:
59
+
60
+ ```bash
61
+ npm run build:tokens
62
+ ```
63
+
64
+ That must print `All theme combinations built successfully!` and produce
65
+ `styles/tokens-$ARGUMENTS-light.css` and `styles/tokens-$ARGUMENTS-dark.css`.
66
+ Fix any failure here before moving on — it is much easier to debug against
67
+ known-good token values.
68
+
69
+ ## Step 2: Decide the brand identity
70
+
71
+ Before editing, settle these and write them down in the conversation:
72
+
73
+ | Decision | Feeds |
74
+ |---|---|
75
+ | Neutral ramp | `alias.color.neutral.*` — every surface, border, and text colour |
76
+ | Accent colour | `alias.color.accent.*` — buttons, links, focus rings, selection |
77
+ | Primary / secondary brand colours | `alias.color.brand.*` — logos, marketing accents |
78
+ | State colours | `alias.color.state.{success,warning,error,info}` |
79
+ | Brand and body typefaces | `alias.font.brand.family`, `alias.font.plain.family` |
80
+
81
+ Pick a **hue-matched pair** of primitive ramps for light and dark: light mode
82
+ uses `{color.<name>.N}`, dark mode uses `{color.<name>dark.N}`. Ask the user for
83
+ the brand's colours if they have not supplied them; do not invent a palette.
84
+
85
+ ## Step 3: Edit the colour aliases
86
+
87
+ Edit `brand/light.json`. Every value is a **reference to a T1 primitive**, never
88
+ a raw hex — that is what keeps the ramp coherent and lets dark mode mirror it:
89
+
90
+ ```json
91
+ "neutral": {
92
+ "1": { "$type": "color", "$value": "{color.slate.1}" },
93
+ "12": { "$type": "color", "$value": "{color.slate.12}" }
94
+ },
95
+ "accent": {
96
+ "default": { "$type": "color", "$value": "{color.violet.9}" },
97
+ "hover": { "$type": "color", "$value": "{color.violet.10}" },
98
+ "pressed": { "$type": "color", "$value": "{color.violet.11}" },
99
+ "contrast": { "$type": "color", "$value": "{color.violet.12}" },
100
+ "muted": { "$type": "color", "$value": "{color.violet.8}" }
101
+ }
102
+ ```
103
+
104
+ Then mirror it in `brand/dark.json` using the `Dark` ramps —
105
+ `{color.slateDark.1}`, `{color.violetDark.9}`. The suffix is **camelCase
106
+ `Dark`**, and references are case-sensitive: `{color.slatedark.1}` resolves to
107
+ nothing. Keep the **same step numbers** in both files; the ramps are designed so
108
+ equal steps read as equal emphasis in either mode.
109
+
110
+ Rules that matter:
111
+
112
+ - **Reference primitives, never hex.** A raw hex silently opts that token out of
113
+ the system and will not have a dark-mode counterpart.
114
+ - **Keep every key.** Deleting a token leaves the semantic layer resolving to
115
+ the base alias value, which is rarely what you want. Repoint it instead.
116
+ - **Do not edit anything above T2.** Semantics and component tokens come from
117
+ the package and are overwritten on every upgrade.
118
+ - Only `alias.*` belongs in these files.
119
+
120
+ Available palettes and the meaning of each step are in
121
+ [`reference.md`](reference.md).
122
+
123
+ ## Step 4: Set the typography
124
+
125
+ Edit `brand/fonts.json`. The `family` values must be the **exact `@font-face`
126
+ family name** that will be loaded, because the generated CSS passes the literal
127
+ through to `font-family`.
128
+
129
+ - **Reusing a font Muka already bundles** (Funnel Display, Funnel Sans, Red Hat
130
+ Display, Red Hat Text, Quicksand, IBM Plex Sans, Lora, Yesteryear) — import
131
+ that brand's fonts file and you are done:
132
+ ```ts
133
+ import '@revikornmann/muka-ui/styles/fonts-muka.css';
134
+ ```
135
+ - **Using a system font** (Helvetica, Arial, Menlo, Georgia, …) — nothing to
136
+ load.
137
+ - **Bringing your own font** — self-host it with your own `@font-face` under the
138
+ exact family name you put in `fonts.json`. Do not use a Google Fonts `<link>`:
139
+ it breaks offline and air-gapped installs and adds a render-blocking request.
140
+ Muka's own font pipeline is not available to consumer brands, so this
141
+ `@font-face` block is yours to own.
142
+
143
+ ## Step 5: Build and wire up the CSS
144
+
145
+ ```bash
146
+ npm run build:tokens
147
+ ```
148
+
149
+ Import your brand CSS **after** Muka's base and component styles so your `:root`
150
+ block wins the cascade:
151
+
152
+ ```ts
153
+ import '@revikornmann/muka-ui/styles/base.css';
154
+ import './styles/tokens-acme-light.css';
155
+ import '@revikornmann/muka-ui/styles/fonts-muka.css'; // or your own @font-face
156
+ ```
157
+
158
+ Do **not** import `@revikornmann/muka-ui/styles` as well — that bundle contains
159
+ the full muka-light token set and, depending on import order, will fight your
160
+ brand. Use `base.css` instead, which is the component and reset layer only.
161
+
162
+ There are no `[data-brand]` / `[data-theme]` selectors; to toggle light/dark at
163
+ runtime, swap the stylesheet rather than importing both:
164
+
165
+ ```ts
166
+ link.href = `/styles/tokens-acme-${mode}.css`;
167
+ ```
168
+
169
+ ## Step 6: Rebuild on every Muka upgrade
170
+
171
+ Your brand CSS is generated against the package's primitives, semantics, and
172
+ component tokens, so it goes stale when Muka publishes new ones. Add the build
173
+ to the existing pipeline so it cannot be forgotten:
174
+
175
+ ```json
176
+ "scripts": {
177
+ "build": "npm run build:tokens && <your existing build>",
178
+ "postinstall": "npm run build:tokens"
179
+ }
180
+ ```
181
+
182
+ Commit `brand/**`. Generated CSS under `styles/tokens-*.css` can be committed or
183
+ gitignored — commit it if your host does not run a build step.
184
+
185
+ ## Verify
186
+
187
+ - `styles/tokens-$ARGUMENTS-light.css` and `-dark.css` exist and were rebuilt
188
+ after your last edit.
189
+ - Neither file contains `undefined` — that means an unresolved `{reference}`,
190
+ usually a typo'd primitive name.
191
+ - Your accent colour appears as a real value:
192
+ ```bash
193
+ grep -- '--alias-color-accent-default' styles/tokens-$ARGUMENTS-light.css
194
+ ```
195
+ - A primary `<Button>` renders in your accent colour and body text in your
196
+ typeface, in both light and dark.
197
+ - Toggling to dark mode changes surfaces without leaving light-mode text
198
+ unreadable.
199
+
200
+ ## Next
201
+
202
+ - `/push-to-figma` — publish this brand to Figma as variables, so designers can
203
+ design in your brand.
204
+ - `/figma-to-code` — turn a Figma link into a screen built from Muka components.
@@ -0,0 +1,160 @@
1
+ # Brand token reference
2
+
3
+ Everything you need while editing `brand/light.json`, `brand/dark.json`, and
4
+ `brand/fonts.json`. The authoritative values live in
5
+ `node_modules/@revikornmann/muka-ui/tokens/t1-primitives/color.json`.
6
+
7
+ ## Available primitive palettes
8
+
9
+ Each palette is a 12-step ramp. Light-mode references use the base name; dark
10
+ mode appends **camelCase `Dark`** (`{color.violet.9}` → `{color.violetDark.9}`).
11
+ References are case-sensitive.
12
+
13
+ **Neutrals** — `gray`, `mauve`, `slate`, `sage`, `olive`, `sand`
14
+
15
+ **Colours** — `tomato`, `red`, `ruby`, `crimson`, `pink`, `plum`, `purple`,
16
+ `violet`, `iris`, `indigo`, `blue`, `cyan`, `teal`, `jade`, `green`, `grass`,
17
+ `bronze`, `gold`, `brown`, `orange`, `amber`, `yellow`, `lime`, `mint`, `sky`
18
+
19
+ **Absolutes** — `white`, `black`, and the transparency ramps `black-alpha`,
20
+ `white-alpha`
21
+
22
+ **Hued neutral alphas** — `mauveA`, `grayA`, `sandA`, `sageA` (and
23
+ `mauveDarkA`, `grayDarkA`, `sandDarkA`, `sageDarkA`) back
24
+ `alias.color.neutral.alphaHued.*`, which is used for overlays and scrims that
25
+ must tint rather than cover. Match these to whichever neutral ramp you chose.
26
+
27
+ Every palette has a dark counterpart except `white`, `black`, and the alpha
28
+ ramps, which are mode-independent.
29
+
30
+ ## What each step in a 12-step ramp is for
31
+
32
+ | Steps | Use |
33
+ |---|---|
34
+ | 1–2 | App and component backgrounds |
35
+ | 3–5 | Subtle backgrounds: hover, selected, muted fills |
36
+ | 6–8 | Borders and separators (8 is the strongest border / focus ring) |
37
+ | 9–10 | Solid fills — 9 is the palette's most saturated step, 10 is its hover |
38
+ | 11 | Low-contrast text, and text on light backgrounds |
39
+ | 12 | High-contrast text and headings |
40
+
41
+ Pick `accent.default` at step **9**, `hover` at **10**, `pressed` at **11**, and
42
+ `contrast` at **12** unless you have a reason not to. This pattern is what every
43
+ shipped brand uses.
44
+
45
+ ## Token groups in `light.json` / `dark.json`
46
+
47
+ 78 tokens across five groups. All are `$type: "color"`.
48
+
49
+ ### `alias.color.neutral`
50
+
51
+ - `1`–`12` — the neutral ramp. Drives every surface level, border, and text
52
+ colour in the semantic layer, so this choice has the widest visual effect of
53
+ anything in the file.
54
+ - `alphaHued.1`–`12` — translucent neutrals for overlays and scrims.
55
+
56
+ ### `alias.color.brand`
57
+
58
+ - `primary.{regular,contrast,muted}`
59
+ - `secondary.{regular,contrast,muted}`
60
+
61
+ Brand identity colours. Used for marketing surfaces and accents rather than
62
+ ordinary controls — controls read from `accent`.
63
+
64
+ ### `alias.color.accent`
65
+
66
+ - `{default,hover,pressed,contrast,muted}`
67
+ - `inverse.{default,hover,pressed,contrast,muted}`
68
+
69
+ The interactive colour: primary buttons, links, focus rings, selection,
70
+ active navigation. `inverse` is the same role on top of an accent-filled
71
+ surface, so it usually runs from step 1 up to `white`.
72
+
73
+ If you only change one thing, change this.
74
+
75
+ ### `alias.color.state`
76
+
77
+ For each of `success`, `warning`, `error`, `info`:
78
+
79
+ - `{contrast,default,muted}`
80
+ - `surface.{level0,level1,level2,level3}`
81
+
82
+ Keep the hues conventional — green for success, red for error, amber for
83
+ warning. `default` is the solid step 9, `contrast` the readable step 11, `muted`
84
+ a step 3 fill, and the `surface` levels are the elevation ramp for banners and
85
+ alerts.
86
+
87
+ ### `alias.color.conversation`
88
+
89
+ For each of `own`, `peer`, `agent`:
90
+
91
+ - `surface.{default,raised}`
92
+ - `border`
93
+
94
+ Plus `meta` for timestamps and read receipts. These back the chat components. If
95
+ your app has no chat surface, leave them as scaffolded — they still need to
96
+ resolve.
97
+
98
+ ## `fonts.json` roles
99
+
100
+ | Role | Used for |
101
+ |---|---|
102
+ | `brand` | Headings, buttons, labels — the expressive typeface |
103
+ | `plain` | Body copy and UI text — the readable typeface |
104
+ | `mono` | Code, numeric tables, anything needing fixed advance |
105
+ | `script` | Decorative accents only |
106
+
107
+ Each role has `family` plus a `weight` map. `brand` and `plain` carry
108
+ `regular` / `medium` / `semibold` / `bold`; `mono` carries `regular` / `bold`;
109
+ `script` is `family` only.
110
+
111
+ Weights are CSS numerics as strings (`"400"`, `"600"`). Only list weights the
112
+ font actually provides — naming a weight the file lacks makes the browser
113
+ synthesise it, which looks wrong at large sizes.
114
+
115
+ Pointing `brand` and `plain` at the same family is normal and is what the
116
+ `wireframe` and `fscl` brands do.
117
+
118
+ ## Fonts Muka already bundles
119
+
120
+ Reference any of these and you get a real self-hosted face by importing the
121
+ matching `fonts-<brand>.css`:
122
+
123
+ | Family | Import this brand's fonts file |
124
+ |---|---|
125
+ | `Funnel Display`, `Funnel Sans` | `fonts-muka.css` |
126
+ | `Quicksand` | `fonts-grip.css` |
127
+ | `IBM Plex Sans`, `Lora` | `fonts-fscl.css` |
128
+ | `Red Hat Display`, `Red Hat Text` | `fonts-bouwplan.css` |
129
+ | `Yesteryear` (script role) | `fonts-muka.css`, `fonts-grip.css`, or `fonts-bouwplan.css` |
130
+
131
+ `fonts-wireframe.css` is empty — that brand is system fonts only.
132
+
133
+ System families need no loading: `Helvetica`, `Arial`, `Menlo`,
134
+ `Lucida Console`, `Times New Roman`, `Courier New`, `Georgia`, `Verdana`,
135
+ `Tahoma`, `Trebuchet MS`, `system-ui`, `ui-sans-serif`, `ui-serif`,
136
+ `ui-monospace`, and the generic `sans-serif` / `serif` / `monospace`.
137
+
138
+ ## Generated CSS names
139
+
140
+ Token paths become custom properties by flattening on `-`:
141
+
142
+ | Token | Custom property |
143
+ |---|---|
144
+ | `alias.color.accent.default` | `--alias-color-accent-default` |
145
+ | `alias.color.neutral.3` | `--alias-color-neutral-3` |
146
+ | `alias.font.brand.family` | `--alias-font-brand-family` |
147
+
148
+ You will rarely reference these directly — components read T3/T4 properties like
149
+ `--color-action-default` and `--button-color-primary-background-default`, which
150
+ resolve through your aliases. Grep for `--alias-` only when debugging.
151
+
152
+ ## Debugging
153
+
154
+ | Symptom | Cause |
155
+ |---|---|
156
+ | `undefined` in the generated CSS | An unresolved `{reference}` — usually a typo'd palette name or a missing `Dark` suffix |
157
+ | Dark mode looks identical to light | `dark.json` still references light ramps |
158
+ | Text unreadable on accent fills | `accent.contrast` is too close to `accent.default`; move it to step 12 or `white` |
159
+ | Fonts fall back to a system face | No `@font-face` is loaded for that family name, or the name does not match byte-for-byte |
160
+ | Colours unchanged after a rebuild | The brand CSS is imported before Muka's token bundle, so the bundle wins. Import `base.css` instead of `styles`, and your brand CSS last |