@revikornmann/muka-ui 0.17.0 → 0.19.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/README.md +81 -60
- package/cli/bin/muka-ui.js +12 -5
- package/cli/commands/brand.js +33 -14
- package/cli/commands/init.js +21 -17
- package/cli/commands/install-skill.js +84 -26
- package/cli/templates/AGENTS.md +128 -0
- package/cli/templates/CLAUDE.md +8 -88
- package/cli/templates/muka-ui-guidelines.md +50 -14
- package/dist/cjs/components/ActionSheet/ActionSheet.js +1 -1
- package/dist/cjs/components/Breadcrumb/Breadcrumb.css +11 -3
- package/dist/cjs/components/Breadcrumb/Breadcrumb.js +19 -1
- package/dist/cjs/components/Breadcrumb/Breadcrumb.js.map +1 -1
- package/dist/cjs/components/Combobox/Combobox.css +116 -132
- package/dist/cjs/components/Combobox/Combobox.js +175 -52
- package/dist/cjs/components/Combobox/Combobox.js.map +1 -1
- package/dist/cjs/components/Combobox/index.js.map +1 -1
- package/dist/cjs/components/ContextSelect/ContextSelect.css +117 -0
- package/dist/cjs/components/ContextSelect/ContextSelect.js +49 -0
- package/dist/cjs/components/ContextSelect/ContextSelect.js.map +1 -0
- package/dist/cjs/components/ContextSelect/index.js +11 -0
- package/dist/cjs/components/ContextSelect/index.js.map +1 -0
- package/dist/cjs/components/DropdownSelect/DropdownSelect.css +225 -0
- package/dist/cjs/components/DropdownSelect/DropdownSelect.js +106 -0
- package/dist/cjs/components/DropdownSelect/DropdownSelect.js.map +1 -0
- package/dist/cjs/components/DropdownSelect/index.js +6 -0
- package/dist/cjs/components/DropdownSelect/index.js.map +1 -0
- package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js +11 -0
- package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
- package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js +11 -0
- package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
- package/dist/cjs/components/Icon/iconRegistry.js +11 -0
- package/dist/cjs/components/Icon/iconRegistry.js.map +1 -1
- package/dist/cjs/components/Input/Input.css +45 -8
- package/dist/cjs/components/Input/Input.js +14 -3
- package/dist/cjs/components/Input/Input.js.map +1 -1
- package/dist/cjs/components/Menu/Menu.css +213 -17
- package/dist/cjs/components/Menu/Menu.js +429 -39
- package/dist/cjs/components/Menu/Menu.js.map +1 -1
- package/dist/cjs/components/Menu/index.js +5 -1
- package/dist/cjs/components/Menu/index.js.map +1 -1
- package/dist/cjs/components/ProgressTracker/ProgressTracker.css +273 -22
- package/dist/cjs/components/ProgressTracker/ProgressTracker.js +109 -9
- package/dist/cjs/components/ProgressTracker/ProgressTracker.js.map +1 -1
- package/dist/cjs/components/Scrollbar/Scrollbar.css +124 -0
- package/dist/cjs/components/Scrollbar/Scrollbar.js +118 -0
- package/dist/cjs/components/Scrollbar/Scrollbar.js.map +1 -0
- package/dist/cjs/components/Scrollbar/index.js +11 -0
- package/dist/cjs/components/Scrollbar/index.js.map +1 -0
- package/dist/cjs/components/index.js +13 -16
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/esm/components/ActionSheet/ActionSheet.js +1 -1
- package/dist/esm/components/Breadcrumb/Breadcrumb.css +11 -3
- package/dist/esm/components/Breadcrumb/Breadcrumb.js +19 -1
- package/dist/esm/components/Breadcrumb/Breadcrumb.js.map +1 -1
- package/dist/esm/components/Combobox/Combobox.css +116 -132
- package/dist/esm/components/Combobox/Combobox.js +177 -54
- package/dist/esm/components/Combobox/Combobox.js.map +1 -1
- package/dist/esm/components/Combobox/index.js +1 -1
- package/dist/esm/components/Combobox/index.js.map +1 -1
- package/dist/esm/components/ContextSelect/ContextSelect.css +117 -0
- package/dist/esm/components/ContextSelect/ContextSelect.js +45 -0
- package/dist/esm/components/ContextSelect/ContextSelect.js.map +1 -0
- package/dist/esm/components/ContextSelect/index.js +3 -0
- package/dist/esm/components/ContextSelect/index.js.map +1 -0
- package/dist/esm/components/DropdownSelect/DropdownSelect.css +225 -0
- package/dist/esm/components/DropdownSelect/DropdownSelect.js +102 -0
- package/dist/esm/components/DropdownSelect/DropdownSelect.js.map +1 -0
- package/dist/esm/components/DropdownSelect/index.js +2 -0
- package/dist/esm/components/DropdownSelect/index.js.map +1 -0
- package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js +7 -0
- package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
- package/dist/esm/components/Icon/custom/ArrowReturnIcon.js +7 -0
- package/dist/esm/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
- package/dist/esm/components/Icon/iconRegistry.js +11 -0
- package/dist/esm/components/Icon/iconRegistry.js.map +1 -1
- package/dist/esm/components/Input/Input.css +45 -8
- package/dist/esm/components/Input/Input.js +14 -3
- package/dist/esm/components/Input/Input.js.map +1 -1
- package/dist/esm/components/Menu/Menu.css +213 -17
- package/dist/esm/components/Menu/Menu.js +428 -40
- package/dist/esm/components/Menu/Menu.js.map +1 -1
- package/dist/esm/components/Menu/index.js +1 -1
- package/dist/esm/components/Menu/index.js.map +1 -1
- package/dist/esm/components/ProgressTracker/ProgressTracker.css +273 -22
- package/dist/esm/components/ProgressTracker/ProgressTracker.js +110 -10
- package/dist/esm/components/ProgressTracker/ProgressTracker.js.map +1 -1
- package/dist/esm/components/Scrollbar/Scrollbar.css +124 -0
- package/dist/esm/components/Scrollbar/Scrollbar.js +114 -0
- package/dist/esm/components/Scrollbar/Scrollbar.js.map +1 -0
- package/dist/esm/components/Scrollbar/index.js +3 -0
- package/dist/esm/components/Scrollbar/index.js.map +1 -0
- package/dist/esm/components/index.js +4 -2
- package/dist/esm/components/index.js.map +1 -1
- package/dist/styles/components/Breadcrumb.css +11 -3
- package/dist/styles/components/Combobox.css +116 -132
- package/dist/styles/components/ContextSelect.css +117 -0
- package/dist/styles/components/DropdownSelect.css +225 -0
- package/dist/styles/components/Input.css +45 -8
- package/dist/styles/components/Menu.css +213 -17
- package/dist/styles/components/ProgressTracker.css +273 -22
- package/dist/styles/components/Scrollbar.css +124 -0
- package/dist/styles/components/Typography.css +89 -0
- package/dist/styles/index.css +1526 -480
- package/dist/styles/muka-dark.css +1526 -480
- package/dist/styles/muka-light.css +1526 -480
- package/dist/styles/tokens-bouwplan-dark.css +9 -6
- package/dist/styles/tokens-bouwplan-light.css +9 -6
- package/dist/styles/tokens-fscl-dark.css +29 -26
- package/dist/styles/tokens-fscl-light.css +29 -26
- package/dist/styles/tokens-grip-dark.css +8 -5
- package/dist/styles/tokens-grip-light.css +8 -5
- package/dist/styles/tokens-muka-dark.css +8 -5
- package/dist/styles/tokens-muka-light.css +8 -5
- package/dist/styles/tokens-wireframe-dark.css +53 -50
- package/dist/styles/tokens-wireframe-light.css +53 -50
- package/dist/styles/wireframe-dark.css +1571 -525
- package/dist/styles/wireframe-light.css +1571 -525
- package/dist/types/components/ActionSheet/ActionSheet.d.ts +1 -1
- package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +27 -3
- package/dist/types/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/dist/types/components/Combobox/Combobox.d.ts +38 -38
- package/dist/types/components/Combobox/Combobox.d.ts.map +1 -1
- package/dist/types/components/Combobox/index.d.ts +1 -1
- package/dist/types/components/Combobox/index.d.ts.map +1 -1
- package/dist/types/components/ContextSelect/ContextSelect.d.ts +62 -0
- package/dist/types/components/ContextSelect/ContextSelect.d.ts.map +1 -0
- package/dist/types/components/ContextSelect/index.d.ts +3 -0
- package/dist/types/components/ContextSelect/index.d.ts.map +1 -0
- package/dist/types/components/DataTable/DataTable.d.ts +1 -1
- package/dist/types/components/DropdownSelect/DropdownSelect.d.ts +71 -0
- package/dist/types/components/DropdownSelect/DropdownSelect.d.ts.map +1 -0
- package/dist/types/components/DropdownSelect/index.d.ts +2 -0
- package/dist/types/components/DropdownSelect/index.d.ts.map +1 -0
- package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts +9 -0
- package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts.map +1 -0
- package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts +9 -0
- package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts.map +1 -0
- package/dist/types/components/Icon/iconRegistry.d.ts.map +1 -1
- package/dist/types/components/Input/Input.d.ts +5 -0
- package/dist/types/components/Input/Input.d.ts.map +1 -1
- package/dist/types/components/Menu/Menu.d.ts +99 -29
- package/dist/types/components/Menu/Menu.d.ts.map +1 -1
- package/dist/types/components/Menu/index.d.ts +2 -2
- package/dist/types/components/Menu/index.d.ts.map +1 -1
- package/dist/types/components/ProgressTracker/ProgressTracker.d.ts +29 -8
- package/dist/types/components/ProgressTracker/ProgressTracker.d.ts.map +1 -1
- package/dist/types/components/Scrollbar/Scrollbar.d.ts +19 -0
- package/dist/types/components/Scrollbar/Scrollbar.d.ts.map +1 -0
- package/dist/types/components/Scrollbar/index.d.ts +3 -0
- package/dist/types/components/Scrollbar/index.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +5 -4
- package/dist/types/components/index.d.ts.map +1 -1
- package/docs/consumers/README.md +116 -37
- package/docs/consumers/brand.md +261 -0
- package/docs/consumers/figma-console-mcp.md +116 -0
- package/docs/consumers/setup-instructions.md +98 -12
- package/docs/consumers/skills.md +79 -0
- package/package.json +4 -6
- package/scripts/postinstall-nudge.js +8 -4
- package/skills/add-brand/SKILL.md +204 -0
- package/skills/add-brand/reference.md +160 -0
- package/skills/figma-to-code/SKILL.md +127 -0
- package/skills/pull-from-figma/SKILL.md +123 -0
- package/skills/push-to-figma/SKILL.md +172 -0
- package/skills/setup-muka/SKILL.md +73 -13
- package/tokens/README.md +40 -18
- package/tokens/t2-alias/brand/bouwplan/fonts.json +1 -1
- package/tokens/t2-alias/brand/fscl/fonts.json +3 -3
- package/tokens/t2-alias/brand/wireframe/fonts.json +2 -2
- package/tokens/t4-components/menu.json +20 -5
- package/dist/cjs/components/ContextMenu/ContextMenu.js +0 -186
- package/dist/cjs/components/ContextMenu/ContextMenu.js.map +0 -1
- package/dist/cjs/components/ContextMenu/index.js +0 -17
- package/dist/cjs/components/ContextMenu/index.js.map +0 -1
- package/dist/esm/components/ContextMenu/ContextMenu.js +0 -145
- package/dist/esm/components/ContextMenu/ContextMenu.js.map +0 -1
- package/dist/esm/components/ContextMenu/index.js +0 -2
- package/dist/esm/components/ContextMenu/index.js.map +0 -1
- package/dist/types/components/ContextMenu/ContextMenu.d.ts +0 -188
- package/dist/types/components/ContextMenu/ContextMenu.d.ts.map +0 -1
- package/dist/types/components/ContextMenu/index.d.ts +0 -3
- package/dist/types/components/ContextMenu/index.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,91 +1,112 @@
|
|
|
1
|
-
|
|
1
|
+
<img src=".storybook/public/logo-on-light.svg" alt="Muka UI" height="40" />
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Muka UI
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A multi-brand, multi-theme React design system for mobile-first web apps, built
|
|
6
|
+
so that coding agents can consume it accurately. Five brands × light and dark =
|
|
7
|
+
**ten themes**, one component library, no per-brand component code.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
- **Storybook:** <https://muka.kornmann.com> — component APIs, Playgrounds, token docs
|
|
10
|
+
- **npm:** [`@revikornmann/muka-ui`](https://www.npmjs.com/package/@revikornmann/muka-ui)
|
|
11
|
+
(public — no registry config or auth token)
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
> **Under active development.** Releases can bring breaking changes — visual
|
|
14
|
+
> shifts, changed component APIs, altered token values. Pin a version and
|
|
15
|
+
> re-test your app when you upgrade.
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
- **Component Library**: Reusable UI components built with design tokens
|
|
13
|
-
- **Theme Support**: Light and dark mode support with brand-specific variations
|
|
14
|
-
- **Responsive Design**: Built-in support for mobile, tablet, and desktop layouts
|
|
17
|
+
## Use it in your app
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- [Design Tokens](./tokens/README.md): Comprehensive documentation of our design token system
|
|
19
|
-
- Components: Coming soon
|
|
20
|
-
- Guidelines: Coming soon
|
|
21
|
-
|
|
22
|
-
## Installation
|
|
23
|
-
|
|
24
|
-
Muka is a **public npm package** published under the scoped name
|
|
25
|
-
`@revikornmann/muka-ui` (the bare `muka-ui` name is taken on npm by an unrelated
|
|
26
|
-
package). No registry config or auth token is needed.
|
|
19
|
+
Five steps from an empty repo to a branded, designed, working app. Each one is a
|
|
20
|
+
skill or a single command.
|
|
27
21
|
|
|
28
22
|
```bash
|
|
29
23
|
npm install @revikornmann/muka-ui
|
|
24
|
+
npx muka-ui install-skill # make the Muka skills discoverable
|
|
30
25
|
```
|
|
31
26
|
|
|
32
|
-
|
|
27
|
+
Then, in Claude Code or Cursor:
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
| # | Step | How |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| 1 | Create your repo | Any React app with a bundler that imports CSS |
|
|
32
|
+
| 2 | Install and wire up Muka UI | `/setup-muka [brand]` |
|
|
33
|
+
| 3 | Add your own brand, overriding Muka's brand layer | `/add-brand acme` |
|
|
34
|
+
| 4 | Design against the Muka UI Figma Library | `/push-to-figma` to publish your brand to Figma |
|
|
35
|
+
| 5 | Hand the Figma link to your agent | `/figma-to-code <figma-url>` |
|
|
36
|
+
|
|
37
|
+
And voilà — a branded app built from a component library you didn't write, that
|
|
38
|
+
follows brand changes centrally and updates itself on each release.
|
|
39
|
+
|
|
40
|
+
**Full guide: [`docs/consumers/README.md`](docs/consumers/README.md).**
|
|
41
|
+
|
|
42
|
+
### Skills shipped in the package
|
|
43
|
+
|
|
44
|
+
| Skill | What it does |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `/setup-muka` | Install the package, wire up styles and fonts, add the auto-update workflow, register as a consumer |
|
|
47
|
+
| `/add-brand` | Create a custom brand in your repo that overrides Muka's brand layer |
|
|
48
|
+
| `/figma-to-code` | Turn a Figma link into a screen composed from Muka components and tokens |
|
|
49
|
+
| `/push-to-figma` | Publish your brand tokens to Figma as variables, so designers design in your brand |
|
|
50
|
+
| `/pull-from-figma` | Bring a designer's brand edits in Figma back into your token files |
|
|
51
|
+
|
|
52
|
+
`npx muka-ui install-skill --list` prints these from the installed version.
|
|
53
|
+
|
|
54
|
+
`/push-to-figma` and `/pull-from-figma` read and write Figma **variables**, which
|
|
55
|
+
the REST API cannot do, so they drive
|
|
56
|
+
[**Figma Console MCP**](https://github.com/southleft/figma-console-mcp) — an
|
|
57
|
+
open-source (MIT) MCP server by **[Southleft](https://southleft.com)**. It needs
|
|
58
|
+
a one-time setup: [`docs/consumers/figma-console-mcp.md`](docs/consumers/figma-console-mcp.md).
|
|
59
|
+
The other three skills don't require it.
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
|
|
61
|
+
Reference: [`docs/consumers/skills.md`](docs/consumers/skills.md).
|
|
62
|
+
|
|
63
|
+
### Installing by hand
|
|
41
64
|
|
|
42
65
|
```ts
|
|
43
|
-
import '@revikornmann/muka-ui/styles
|
|
66
|
+
import '@revikornmann/muka-ui/styles'; // muka-light, fonts included
|
|
67
|
+
import { Button, Card, Input } from '@revikornmann/muka-ui';
|
|
44
68
|
```
|
|
45
69
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
70
|
+
Other brands load a different stylesheet — `muka-dark`, `wireframe-light`, and
|
|
71
|
+
`wireframe-dark` are pre-bundled; `grip`, `fscl`, and `bouwplan` compose from
|
|
72
|
+
`base.css` + `tokens-<brand>-<mode>.css` + `fonts-<brand>.css`. Brand and theme
|
|
73
|
+
are selected by **which stylesheet loads**, not by data attributes. See
|
|
74
|
+
[`docs/consumers/setup-instructions.md`](docs/consumers/setup-instructions.md).
|
|
49
75
|
|
|
50
|
-
|
|
76
|
+
## How the token system works
|
|
51
77
|
|
|
52
|
-
|
|
53
|
-
styles, the auto-update workflow, and consumer registration:
|
|
78
|
+
Four layers, each resolving through the one below:
|
|
54
79
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
| Layer | Purpose | Example |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| **T1 Primitives** | Raw ramps, never used directly | `color.indigo.9`, `spacing.4` |
|
|
83
|
+
| **T2 Alias** | Brand-specific references — **the layer a brand swaps** | `alias.color.accent.default` |
|
|
84
|
+
| **T3 Semantics** | Design intent | `color.surface.level1`, `color.action.default` |
|
|
85
|
+
| **T4 Components** | Component-specific | `button.color.primary.background.default` |
|
|
86
|
+
|
|
87
|
+
Components read T3 and T4 only. Swapping T2 cascades a whole new visual identity
|
|
88
|
+
through the library, which is what makes both the five shipped brands and your
|
|
89
|
+
own brand possible without touching component code.
|
|
60
90
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
the full consumer flow and the release-gated auto-update mechanism.
|
|
91
|
+
Details: [`tokens/README.md`](tokens/README.md) and the Design Tokens section of
|
|
92
|
+
the Storybook.
|
|
64
93
|
|
|
65
|
-
##
|
|
94
|
+
## Contribute to Muka itself
|
|
66
95
|
|
|
67
96
|
```bash
|
|
68
|
-
# Install dependencies
|
|
69
97
|
npm install
|
|
70
|
-
|
|
71
|
-
#
|
|
72
|
-
npm run dev
|
|
98
|
+
npm run build:tokens # required before Storybook — postinstall does not do it
|
|
99
|
+
npm run dev # Storybook on port 6006
|
|
73
100
|
```
|
|
74
101
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
muka/
|
|
79
|
-
├── tokens/ # Design tokens
|
|
80
|
-
├── components/ # UI components
|
|
81
|
-
├── styles/ # Global styles
|
|
82
|
-
└── docs/ # Documentation
|
|
83
|
-
```
|
|
102
|
+
[`DEVELOPMENT.md`](DEVELOPMENT.md) is the maintainer guide: commands, token
|
|
103
|
+
layers, component structure, CI, and releases. Maintainer skills live in
|
|
104
|
+
[`.claude/skills/`](.claude/skills) and are not shipped to consumers.
|
|
84
105
|
|
|
85
|
-
##
|
|
106
|
+
## License
|
|
86
107
|
|
|
87
|
-
|
|
108
|
+
MIT.
|
|
88
109
|
|
|
89
|
-
|
|
110
|
+
---
|
|
90
111
|
|
|
91
|
-
|
|
112
|
+
Created by **Revi Körnmann** · [LinkedIn](https://linkedin.com/in/revikornmann) · [kornmann.com](https://kornmann.com)
|
package/cli/bin/muka-ui.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Commands:
|
|
7
7
|
* init - Set up a project to use Muka UI
|
|
8
|
-
* install-skill - Copy shipped skills into .claude/skills
|
|
8
|
+
* install-skill - Copy shipped skills into .claude/skills
|
|
9
9
|
* brand init <name> - Scaffold a custom brand override
|
|
10
10
|
* link [path] - Set up npm link for local development
|
|
11
11
|
* components - List available components
|
|
@@ -24,8 +24,8 @@ Usage:
|
|
|
24
24
|
muka-ui <command> [options]
|
|
25
25
|
|
|
26
26
|
Commands:
|
|
27
|
-
init Set up project for Muka UI (creates
|
|
28
|
-
install-skill Copy shipped skills into .claude/skills
|
|
27
|
+
init Set up project for Muka UI (creates AGENTS.md, guidelines)
|
|
28
|
+
install-skill Copy shipped skills into .claude/skills
|
|
29
29
|
brand init <name> Scaffold a custom brand (T2 tokens, manifest, build script)
|
|
30
30
|
link [path] Set up npm link for local muka-ui development
|
|
31
31
|
components List available Muka UI components
|
|
@@ -35,11 +35,18 @@ Options:
|
|
|
35
35
|
--version, -v Show version
|
|
36
36
|
|
|
37
37
|
Examples:
|
|
38
|
+
npx muka-ui install-skill --list # what skills ship with the package
|
|
39
|
+
npx muka-ui install-skill # install them, then run /setup-muka
|
|
38
40
|
npx muka-ui init
|
|
39
|
-
npx muka-ui
|
|
40
|
-
npx muka-ui brand init fscl
|
|
41
|
+
npx muka-ui brand init acme
|
|
41
42
|
npx muka-ui link /path/to/muka
|
|
42
43
|
npx muka-ui components
|
|
44
|
+
|
|
45
|
+
Typical flow:
|
|
46
|
+
npm install @revikornmann/muka-ui
|
|
47
|
+
npx muka-ui install-skill
|
|
48
|
+
/setup-muka # in your agent
|
|
49
|
+
/add-brand acme # optional: your own brand
|
|
43
50
|
`;
|
|
44
51
|
|
|
45
52
|
// Version from package.json
|
package/cli/commands/brand.js
CHANGED
|
@@ -19,24 +19,36 @@ const {
|
|
|
19
19
|
readPackageJson
|
|
20
20
|
} = require('../lib/fs-utils');
|
|
21
21
|
|
|
22
|
+
// The published package name, read from the package's own manifest so the paths
|
|
23
|
+
// written into a consumer repo stay correct if the package is ever renamed.
|
|
24
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
|
|
25
|
+
const PACKAGE_NAME = JSON.parse(
|
|
26
|
+
fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')
|
|
27
|
+
).name;
|
|
28
|
+
|
|
22
29
|
/**
|
|
23
30
|
* Read a wireframe brand file as a template
|
|
24
31
|
*/
|
|
25
32
|
function readBrandTemplate(filename) {
|
|
26
|
-
const templatePath = path.join(
|
|
33
|
+
const templatePath = path.join(PACKAGE_ROOT, 'tokens/t2-alias/brand/wireframe', filename);
|
|
27
34
|
return JSON.parse(fs.readFileSync(templatePath, 'utf8'));
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
/**
|
|
31
|
-
* Generate the brand manifest for a consumer repo
|
|
38
|
+
* Generate the brand manifest for a consumer repo.
|
|
39
|
+
*
|
|
40
|
+
* Every layer except the brand's own T2 files is read straight out of
|
|
41
|
+
* node_modules, so the consumer only owns the brand layer and inherits
|
|
42
|
+
* primitives, semantics, and component tokens from the installed package.
|
|
32
43
|
*/
|
|
33
44
|
function generateManifest(brandName) {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
45
|
+
const pkgTokens = `node_modules/${PACKAGE_NAME}/tokens`;
|
|
46
|
+
const t1 = `${pkgTokens}/t1-primitives/**/*.json`;
|
|
47
|
+
const base = `${pkgTokens}/t2-alias/base.json`;
|
|
36
48
|
const fonts = `brand/fonts.json`;
|
|
37
|
-
const layout =
|
|
38
|
-
const semantics =
|
|
39
|
-
const components =
|
|
49
|
+
const layout = `${pkgTokens}/t2-alias/layout/mobile.json`;
|
|
50
|
+
const semantics = `${pkgTokens}/t3-semantics/ui.json`;
|
|
51
|
+
const components = `${pkgTokens}/t4-components/**/*.json`;
|
|
40
52
|
|
|
41
53
|
return {
|
|
42
54
|
themes: {
|
|
@@ -50,8 +62,9 @@ function generateManifest(brandName) {
|
|
|
50
62
|
]
|
|
51
63
|
},
|
|
52
64
|
breakpoints: {
|
|
53
|
-
md:
|
|
54
|
-
lg:
|
|
65
|
+
md: `${pkgTokens}/t2-alias/layout/tablet.json`,
|
|
66
|
+
lg: `${pkgTokens}/t2-alias/layout/desktop.json`,
|
|
67
|
+
xl: `${pkgTokens}/t2-alias/layout/wide.json`
|
|
55
68
|
}
|
|
56
69
|
};
|
|
57
70
|
}
|
|
@@ -61,7 +74,7 @@ function generateManifest(brandName) {
|
|
|
61
74
|
*/
|
|
62
75
|
function generateBuildScript() {
|
|
63
76
|
return `const path = require('path');
|
|
64
|
-
const TokenBuilder = require('
|
|
77
|
+
const TokenBuilder = require('${PACKAGE_NAME}/build');
|
|
65
78
|
const manifest = require('./muka.brand.json');
|
|
66
79
|
|
|
67
80
|
const builder = new TokenBuilder({ rootDir: path.resolve(__dirname, '..') });
|
|
@@ -183,13 +196,18 @@ async function brand(args) {
|
|
|
183
196
|
console.log('');
|
|
184
197
|
console.log('2. Build your brand CSS:');
|
|
185
198
|
console.log(' npm run build:tokens');
|
|
199
|
+
console.log(` → styles/tokens-${brandName}-light.css and -dark.css`);
|
|
186
200
|
console.log('');
|
|
187
|
-
console.log(
|
|
188
|
-
console.log(
|
|
201
|
+
console.log('3. Import your brand CSS AFTER the Muka base styles, so your brand');
|
|
202
|
+
console.log(' layer wins the cascade:');
|
|
203
|
+
console.log(` import '${PACKAGE_NAME}/styles/base.css';`);
|
|
204
|
+
console.log(` import './styles/tokens-${brandName}-light.css';`);
|
|
205
|
+
console.log(' Both files target :root, so the one imported last is the active');
|
|
206
|
+
console.log(' theme. To switch brand or mode at runtime, swap the stylesheet.');
|
|
189
207
|
console.log('');
|
|
190
208
|
console.log('4. Fonts: the family names in brand/fonts.json must be loaded somewhere.');
|
|
191
209
|
console.log(' - Reusing a font Muka already ships? Import its fonts file, e.g.');
|
|
192
|
-
console.log(
|
|
210
|
+
console.log(` import '${PACKAGE_NAME}/styles/fonts-muka.css';`);
|
|
193
211
|
console.log(' - Introducing your own font? Self-host it with your own @font-face');
|
|
194
212
|
console.log(' under the exact family name you put in fonts.json (do NOT use a');
|
|
195
213
|
console.log(' Google Fonts <link> in production — it breaks offline installs).');
|
|
@@ -198,7 +216,8 @@ async function brand(args) {
|
|
|
198
216
|
console.log(' Colors use T1 primitives like {color.gray.9}, {color.indigo.11}');
|
|
199
217
|
console.log(' Available palettes: gray, mauve, sand, indigo, iris, mint, jade,');
|
|
200
218
|
console.log(' tomato, red, amber, green, blue, and more.');
|
|
201
|
-
console.log(
|
|
219
|
+
console.log(` See node_modules/${PACKAGE_NAME}/tokens/t1-primitives/color.json`);
|
|
220
|
+
console.log(' for all values.');
|
|
202
221
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
|
203
222
|
}
|
|
204
223
|
|
package/cli/commands/init.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* `muka-ui init` command
|
|
3
3
|
*
|
|
4
4
|
* Sets up a project for Muka UI usage:
|
|
5
|
-
* - Creates
|
|
5
|
+
* - Creates AGENTS.md with the development guidelines every agent reads
|
|
6
|
+
* - Creates CLAUDE.md pointing at AGENTS.md, for Claude Code
|
|
6
7
|
* - Creates docs/muka-ui-guidelines.md with usage documentation
|
|
7
8
|
* - Checks for conflicting dependencies and warns
|
|
8
9
|
*/
|
|
@@ -95,21 +96,24 @@ async function init(args) {
|
|
|
95
96
|
// Get template replacements
|
|
96
97
|
const replacements = getReplacements();
|
|
97
98
|
|
|
98
|
-
// ---
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
99
|
+
// --- Agent briefs ---
|
|
100
|
+
// AGENTS.md holds the rules and is read by most agents; CLAUDE.md is a
|
|
101
|
+
// pointer to it so Claude Code finds them without a second copy to maintain.
|
|
102
|
+
for (const name of ['AGENTS.md', 'CLAUDE.md']) {
|
|
103
|
+
const target = path.join(projectRoot, name);
|
|
104
|
+
let write = true;
|
|
105
|
+
|
|
106
|
+
if (fileExists(target)) {
|
|
107
|
+
console.log(`${name} already exists.`);
|
|
108
|
+
write = await confirm('Overwrite with Muka UI template?');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (write) {
|
|
112
|
+
writeFile(target, loadTemplate(name, replacements));
|
|
113
|
+
console.log(`✓ Created ${name}\n`);
|
|
114
|
+
} else {
|
|
115
|
+
console.log(`⏭ Skipped ${name}\n`);
|
|
116
|
+
}
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
// --- docs/muka-ui-guidelines.md ---
|
|
@@ -163,7 +167,7 @@ async function init(args) {
|
|
|
163
167
|
console.log(`3. Browse components: ${manifest.storybook_url}`);
|
|
164
168
|
console.log('');
|
|
165
169
|
console.log('4. Stay current: run `npx muka-ui install-skill` then `/setup-muka`');
|
|
166
|
-
console.log(' in
|
|
170
|
+
console.log(' in your agent — it adds the auto-update workflow and registers');
|
|
167
171
|
console.log(' this repo as a consumer. (Or copy templates/update-muka.yml into');
|
|
168
172
|
console.log(' .github/workflows/ by hand.)');
|
|
169
173
|
console.log(` See node_modules/${manifest.package_name}/docs/consumers/setup-instructions.md`);
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
* `muka-ui install-skill` command
|
|
3
3
|
*
|
|
4
4
|
* Copies the consumer-facing skills shipped inside the package (under
|
|
5
|
-
* `skills/`) into the consuming repo's `.claude/skills
|
|
6
|
-
*
|
|
5
|
+
* `skills/`) into the consuming repo's `.claude/skills/`, the directory Claude
|
|
6
|
+
* Code and Cursor both scan for skills.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Agents discover skills under `.claude/skills/`, never inside `node_modules/`,
|
|
9
|
+
* so a skill shipped in the package is present but not discoverable until it is
|
|
10
|
+
* copied in. This command is that bridge.
|
|
11
11
|
*
|
|
12
12
|
* npx muka-ui install-skill # install all shipped skills
|
|
13
|
-
* npx muka-ui install-skill setup-muka # install
|
|
13
|
+
* npx muka-ui install-skill setup-muka # install specific skills
|
|
14
|
+
* npx muka-ui install-skill --list # show what is available
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
const path = require('path');
|
|
@@ -39,28 +40,63 @@ function listShippedSkills() {
|
|
|
39
40
|
return fs
|
|
40
41
|
.readdirSync(SHIPPED_SKILLS_DIR, { withFileTypes: true })
|
|
41
42
|
.filter((d) => d.isDirectory() && fileExists(path.join(SHIPPED_SKILLS_DIR, d.name, 'SKILL.md')))
|
|
42
|
-
.map((d) => d.name)
|
|
43
|
+
.map((d) => d.name)
|
|
44
|
+
.sort();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Pull the `description:` line out of a skill's YAML frontmatter so `--list`
|
|
49
|
+
* can explain what each skill does without the caller opening the files.
|
|
50
|
+
*/
|
|
51
|
+
function describeSkill(skillName) {
|
|
52
|
+
const content = readFile(path.join(SHIPPED_SKILLS_DIR, skillName, 'SKILL.md'));
|
|
53
|
+
const match = content.match(/^description:\s*(.+)$/m);
|
|
54
|
+
return match ? match[1].trim() : '';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Every file in a skill directory, as paths relative to that directory. Skills
|
|
59
|
+
* may ship reference files alongside SKILL.md, and dropping them would leave
|
|
60
|
+
* the skill pointing at documentation that never arrived.
|
|
61
|
+
*/
|
|
62
|
+
function skillFiles(skillDir, prefix = '') {
|
|
63
|
+
const files = [];
|
|
64
|
+
for (const entry of fs.readdirSync(path.join(skillDir, prefix), { withFileTypes: true })) {
|
|
65
|
+
const relative = path.join(prefix, entry.name);
|
|
66
|
+
if (entry.isDirectory()) {
|
|
67
|
+
files.push(...skillFiles(skillDir, relative));
|
|
68
|
+
} else if (entry.isFile()) {
|
|
69
|
+
files.push(relative);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return files;
|
|
43
73
|
}
|
|
44
74
|
|
|
45
75
|
/**
|
|
46
76
|
* Copy one shipped skill into the project's .claude/skills directory.
|
|
47
|
-
* Returns true if written, false if skipped.
|
|
77
|
+
* Returns true if anything was written, false if skipped.
|
|
48
78
|
*/
|
|
49
79
|
async function installOne(skillName, projectRoot) {
|
|
50
|
-
const
|
|
51
|
-
if (!fileExists(
|
|
80
|
+
const srcDir = path.join(SHIPPED_SKILLS_DIR, skillName);
|
|
81
|
+
if (!fileExists(path.join(srcDir, 'SKILL.md'))) {
|
|
52
82
|
console.log(`⚠️ No shipped skill named "${skillName}".`);
|
|
53
83
|
return false;
|
|
54
84
|
}
|
|
55
85
|
|
|
56
86
|
const destDir = path.join(projectRoot, '.claude', 'skills', skillName);
|
|
57
|
-
const
|
|
87
|
+
const files = skillFiles(srcDir);
|
|
58
88
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
89
|
+
const identical = files.every((file) => {
|
|
90
|
+
const dest = path.join(destDir, file);
|
|
91
|
+
return fileExists(dest) && readFile(dest) === readFile(path.join(srcDir, file));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (identical) {
|
|
95
|
+
console.log(`✓ /${skillName} already up to date`);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (dirExists(destDir)) {
|
|
64
100
|
const overwrite = await confirm(`/${skillName} already exists. Overwrite?`);
|
|
65
101
|
if (!overwrite) {
|
|
66
102
|
console.log(`⏭ Skipped /${skillName}`);
|
|
@@ -68,20 +104,20 @@ async function installOne(skillName, projectRoot) {
|
|
|
68
104
|
}
|
|
69
105
|
}
|
|
70
106
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
const dest = path.join(destDir, file);
|
|
109
|
+
ensureDir(path.dirname(dest));
|
|
110
|
+
writeFile(dest, readFile(path.join(srcDir, file)));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const extra = files.length > 1 ? ` (+${files.length - 1} reference file(s))` : '';
|
|
114
|
+
console.log(`✓ Installed /${skillName} → .claude/skills/${skillName}/${extra}`);
|
|
74
115
|
return true;
|
|
75
116
|
}
|
|
76
117
|
|
|
77
118
|
async function installSkill(args) {
|
|
78
119
|
console.log('\n🎨 Muka UI — install skills\n');
|
|
79
120
|
|
|
80
|
-
const projectRoot = findProjectRoot();
|
|
81
|
-
if (!projectRoot) {
|
|
82
|
-
throw new Error('Could not find package.json. Are you in a Node.js project?');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
121
|
const available = listShippedSkills();
|
|
86
122
|
if (available.length === 0) {
|
|
87
123
|
throw new Error(
|
|
@@ -90,8 +126,26 @@ async function installSkill(args) {
|
|
|
90
126
|
);
|
|
91
127
|
}
|
|
92
128
|
|
|
129
|
+
if (args && (args.includes('--list') || args.includes('-l'))) {
|
|
130
|
+
console.log('Shipped skills:\n');
|
|
131
|
+
for (const name of available) {
|
|
132
|
+
console.log(` /${name}`);
|
|
133
|
+
const description = describeSkill(name);
|
|
134
|
+
if (description) console.log(` ${description}`);
|
|
135
|
+
}
|
|
136
|
+
console.log('\nInstall all of them with: npx muka-ui install-skill');
|
|
137
|
+
console.log('Or just some: npx muka-ui install-skill setup-muka add-brand\n');
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const projectRoot = findProjectRoot();
|
|
142
|
+
if (!projectRoot) {
|
|
143
|
+
throw new Error('Could not find package.json. Are you in a Node.js project?');
|
|
144
|
+
}
|
|
145
|
+
|
|
93
146
|
const requested = args && args.length > 0 ? args : available;
|
|
94
147
|
let installed = 0;
|
|
148
|
+
const present = [];
|
|
95
149
|
for (const name of requested) {
|
|
96
150
|
if (!available.includes(name)) {
|
|
97
151
|
console.log(`⚠️ "${name}" is not a shipped skill (available: ${available.join(', ')})`);
|
|
@@ -100,12 +154,16 @@ async function installSkill(args) {
|
|
|
100
154
|
if (await installOne(name, projectRoot)) {
|
|
101
155
|
installed += 1;
|
|
102
156
|
}
|
|
157
|
+
present.push(name);
|
|
103
158
|
}
|
|
104
159
|
|
|
105
160
|
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
106
161
|
if (installed > 0) {
|
|
107
|
-
|
|
108
|
-
|
|
162
|
+
// Suggest a skill that is actually there — a partial install may not
|
|
163
|
+
// include /setup-muka.
|
|
164
|
+
const next = present.includes('setup-muka') ? '/setup-muka [brand]' : `/${present[0]}`;
|
|
165
|
+
console.log('Done. Restart your agent if it is open, then run:');
|
|
166
|
+
console.log(` ${next}`);
|
|
109
167
|
} else {
|
|
110
168
|
console.log('Nothing to install — skills already present.');
|
|
111
169
|
}
|