@maggioli-design-system/magma-react 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +71 -0
- package/agents/anti-patterns.md +39 -0
- package/agents/assets.md +203 -0
- package/agents/color.md +193 -0
- package/agents/components.md +129 -0
- package/agents/conventions.md +188 -0
- package/agents/install.md +183 -0
- package/agents/theming.md +140 -0
- package/agents/typography.md +32 -0
- package/agents/variants.md +112 -0
- package/dist/mds-button-dropdown.js +1 -1
- package/dist/mds-button-dropdown.server.js +2 -0
- package/dist/mds-button.server.js +2 -0
- package/dist/mds-input-date-range.server.js +2 -1
- package/dist/mds-input-otp.server.js +1 -0
- package/dist/mds-input-upload.server.js +2 -0
- package/dist/types/mds-button-dropdown.d.ts +5 -2
- package/dist/types/mds-button-dropdown.server.d.ts +5 -2
- package/dist/types/mds-input-select.d.ts +2 -2
- package/dist/types/mds-input-select.server.d.ts +2 -2
- package/package.json +2 -2
package/AGENTS.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
GENERATED FILE - do not edit by hand.
|
|
3
|
+
Source of truth: docs/agents/ in the magma monorepo.
|
|
4
|
+
Regenerate with: npm run sync.agent-docs (from the stencil package).
|
|
5
|
+
-->
|
|
6
|
+
# @maggioli-design-system/magma-react - agent install guide
|
|
7
|
+
|
|
8
|
+
> Version 2.1.0. You (the agent) are installing Magma into THIS project. Do not
|
|
9
|
+
> assume the setup - detect it from the project, then ask the user only for what you
|
|
10
|
+
> cannot infer. The detailed steps live in [`agents/install.md`](agents/install.md)
|
|
11
|
+
> (this target) and [`agents/assets.md`](agents/assets.md) (shared styles, fonts,
|
|
12
|
+
> icons). This package targets: **React / Next.js**.
|
|
13
|
+
|
|
14
|
+
## Step 1 - detect (read, do not ask)
|
|
15
|
+
|
|
16
|
+
Inspect the consumer project before asking anything:
|
|
17
|
+
|
|
18
|
+
| What | Where to look |
|
|
19
|
+
| ---- | ------------- |
|
|
20
|
+
| Framework | `package.json` deps: `@angular/core` -> Angular, `react`/`next` -> React, else vanilla |
|
|
21
|
+
| Magma wrapper installed | presence of `magma-angular` / `magma-react` / `magma` in deps |
|
|
22
|
+
| Bundler / static dir | `angular.json` (Angular CLI assets), `vite.config.*`, `next.config.*` (`public/`), webpack |
|
|
23
|
+
| Tailwind + version | `tailwindcss` in deps: v4 -> the CSS imports, v3 -> the JS preset (see agents/assets.md) |
|
|
24
|
+
| SSR | `@angular/ssr` / Angular Universal, or Next App Router |
|
|
25
|
+
| Compatible versions | derive from the installed `@maggioli-design-system/magma` major (see matrix in install.md) |
|
|
26
|
+
|
|
27
|
+
## Step 2 - ask only the gaps
|
|
28
|
+
|
|
29
|
+
Ask the user only what detection left undecided. Typical questions:
|
|
30
|
+
|
|
31
|
+
1. **Icons**: use the prebuilt set (`@maggioli-design-system/svg-icons`) or do you need
|
|
32
|
+
**iconsauce** for tree-shaking / custom icons? Most consumers do NOT need iconsauce -
|
|
33
|
+
Magma already ships resolved SVGs; iconsauce is an internal build dependency. Only
|
|
34
|
+
add `@iconsauce/*` if the user wants their own icon pipeline.
|
|
35
|
+
2. **Static assets path**: where are static files served from? This sets `mdsIconSvgPath`
|
|
36
|
+
and the SVG copy destination.
|
|
37
|
+
3. **Dark mode / preferences**: needed? If yes, wire the preference classes and components.
|
|
38
|
+
4. Confirm the version row if the installed major is ambiguous.
|
|
39
|
+
|
|
40
|
+
## Step 3 - execute
|
|
41
|
+
|
|
42
|
+
1. Install packages and the shared assets - see [`agents/install.md`](agents/install.md).
|
|
43
|
+
2. Wire styles in the exact cascade-layer order - see [`agents/assets.md`](agents/assets.md).
|
|
44
|
+
3. Copy the icon SVGs to the static path and set `mdsIconSvgPath`.
|
|
45
|
+
4. Register components: import the Mds* components from '@maggioli-design-system/magma-react' (no defineCustomElements needed).
|
|
46
|
+
|
|
47
|
+
## Step 4 - verify
|
|
48
|
+
|
|
49
|
+
Build the app and confirm an `mds-*` component renders and at least one icon loads from
|
|
50
|
+
the configured path. Report what was installed, the cascade order used, and the icon path.
|
|
51
|
+
|
|
52
|
+
## Using the components
|
|
53
|
+
|
|
54
|
+
Once installed, do not guess component APIs or rules - read only the file you need:
|
|
55
|
+
|
|
56
|
+
| You need | Read |
|
|
57
|
+
| -------- | ---- |
|
|
58
|
+
| Which component to reach for | [`agents/components.md`](agents/components.md) - the catalogue, one line each |
|
|
59
|
+
| One component's API (props with allowed values, events, methods, slots, parts, CSS vars) | its `AGENTS.md`, linked from the catalogue |
|
|
60
|
+
| Correct usage and mistakes for one component | `pattern.md` / `antipattern.md` beside its `AGENTS.md` |
|
|
61
|
+
| Rules shared by every component: naming, events, slots, compound, icons, a11y, styling from outside | [`agents/conventions.md`](agents/conventions.md) |
|
|
62
|
+
| `variant` and `tone` values | [`agents/variants.md`](agents/variants.md) |
|
|
63
|
+
| Mistakes to avoid with any component | [`agents/anti-patterns.md`](agents/anti-patterns.md) |
|
|
64
|
+
| Coloring your own UI | [`agents/color.md`](agents/color.md) |
|
|
65
|
+
| Typography utilities | [`agents/typography.md`](agents/typography.md) |
|
|
66
|
+
| Dark mode, preferences, named themes, surface levels and elevation, global design decisions, corner geometry | [`agents/theming.md`](agents/theming.md) |
|
|
67
|
+
|
|
68
|
+
Tooling that needs structured data reads `documentation.json`: one per component beside
|
|
69
|
+
its `AGENTS.md`, or `@maggioli-design-system/magma/dist/documentation.json` for all of them
|
|
70
|
+
(over 2 MB - do not load it into context). `dist/types/components.d.ts` drives editor
|
|
71
|
+
IntelliSense.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
GENERATED FILE - do not edit by hand.
|
|
3
|
+
Source of truth: docs/agents/ in the magma monorepo.
|
|
4
|
+
Regenerate with: npm run sync.agent-docs (from the stencil package).
|
|
5
|
+
-->
|
|
6
|
+
# Magma components - system-level anti-patterns
|
|
7
|
+
|
|
8
|
+
> Scope: mistakes that apply to **every** component. Each component's own
|
|
9
|
+
> `antipattern.md` (next to its `AGENTS.md`) covers the component-specific ones; the
|
|
10
|
+
> ones below are universal. The rules they break: [`conventions.md`](conventions.md),
|
|
11
|
+
> [`variants.md`](variants.md), [`color.md`](color.md), [`theming.md`](theming.md).
|
|
12
|
+
|
|
13
|
+
- Replacing a Magma component with a raw HTML element (`<button>`, `<input>`, `<a>` for
|
|
14
|
+
an action) when an `mds-*` equivalent exists.
|
|
15
|
+
- Wrapping an interactive `mds-*` component in another interactive element
|
|
16
|
+
(`<a><mds-button></mds-button></a>` - use the `href` prop instead).
|
|
17
|
+
- Reaching into shadow DOM past the documented API: undocumented `::part()` names,
|
|
18
|
+
internal class names, `>>>`, `/deep/`, or attribute-selector hacks. Use the CSS custom
|
|
19
|
+
properties and, for a deep customisation, the parts listed in the component's
|
|
20
|
+
`AGENTS.md` (see [`conventions.md`](conventions.md)).
|
|
21
|
+
- Setting boolean attributes to the string `"false"` (e.g. `disabled="false"`,
|
|
22
|
+
`await="false"`). Stencil reads `"false"` as `false`, but the attribute stays in the
|
|
23
|
+
DOM on a prop that is not reflected (and until the first render on one that is), so
|
|
24
|
+
`[disabled]` selectors and scripts reading the attribute still see it set. **Remove
|
|
25
|
+
the attribute** to turn it off.
|
|
26
|
+
- Embedding nested HTML in a default slot when the component documents a `label` prop.
|
|
27
|
+
- Using raw Tailwind colour utilities (`bg-white`, `text-gray-700`) on or inside Magma
|
|
28
|
+
components - use the semantic role classes (`bg-surface-default`, `text-fg-muted`),
|
|
29
|
+
see [`color.md`](color.md).
|
|
30
|
+
- Writing `@media (prefers-color-scheme: dark)` overrides - dark mode is handled by the
|
|
31
|
+
palette layer.
|
|
32
|
+
- Hand-rolling focus styles instead of `focus-bounce` / `focus-zoom`.
|
|
33
|
+
- Listening for native DOM events (`change`, `input`) when the component emits a
|
|
34
|
+
documented `mds*` event - they may not bubble out of shadow DOM the way you expect.
|
|
35
|
+
- Applying a `tone`, `variant`, or `size` value to a component without checking its
|
|
36
|
+
typed signature (the Props table of its `AGENTS.md`, or
|
|
37
|
+
`dist/types/components.d.ts`). The same prop name accepts different value sets per
|
|
38
|
+
component - e.g. `<mds-banner tone="outline">` is invalid because `mds-banner.tone` is
|
|
39
|
+
`ToneMinimalBoxVariantType` (`strong | weak | box` only).
|
package/agents/assets.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
GENERATED FILE - do not edit by hand.
|
|
3
|
+
Source of truth: docs/agents/ in the magma monorepo.
|
|
4
|
+
Regenerate with: npm run sync.agent-docs (from the stencil package).
|
|
5
|
+
-->
|
|
6
|
+
# install assets.md
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Canonical setup for the assets every Magma consumer needs, **identical for all three
|
|
11
|
+
targets** (web components, React, Angular): styles, fonts, icons and optional brand
|
|
12
|
+
identity. The per-target tracks ([`install.md`](install.md)) link here instead of repeating
|
|
13
|
+
this. If something about styles/fonts/icons setup is unclear, this file wins.
|
|
14
|
+
|
|
15
|
+
This file is the minimum to get a consumer running. Once it runs: coloring your own UI
|
|
16
|
+
in [`color.md`](color.md), the typography utilities in [`typography.md`](typography.md),
|
|
17
|
+
dark mode, preferences, named themes, the `--magma-*` global decisions and the corner
|
|
18
|
+
geometry in [`theming.md`](theming.md).
|
|
19
|
+
|
|
20
|
+
## 1. Styles
|
|
21
|
+
|
|
22
|
+
### Packages
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i @maggioli-design-system/styles @maggioli-design-system/design-tokens
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Pin both to the row matching your `magma` major (see [`AGENTS.md`](../AGENTS.md) matrix).
|
|
29
|
+
|
|
30
|
+
### Import order (mandatory)
|
|
31
|
+
|
|
32
|
+
Magma styles rely on a fixed cascade-layer order. Import them in exactly this order
|
|
33
|
+
in your global CSS entry point, or specificity conflicts and dark mode will break:
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
@layer reset, vendor, theme, base, components, utilities, overrides;
|
|
37
|
+
/* or @import '@maggioli-design-system/styles/dist/css/layer.css'; */
|
|
38
|
+
|
|
39
|
+
@import 'normalize.css' layer(reset);
|
|
40
|
+
|
|
41
|
+
/* Fonts - see section 2 */
|
|
42
|
+
@import '@fontsource/karla/400.css' layer(vendor);
|
|
43
|
+
@import '@fontsource/karla/700.css' layer(vendor);
|
|
44
|
+
@import '@fontsource/merriweather/300.css' layer(vendor);
|
|
45
|
+
@import '@fontsource/merriweather/400.css' layer(vendor);
|
|
46
|
+
@import '@fontsource/merriweather/700.css' layer(vendor);
|
|
47
|
+
@import '@fontsource/roboto/500.css' layer(vendor);
|
|
48
|
+
@import '@fontsource/roboto/700.css' layer(vendor);
|
|
49
|
+
@import '@fontsource/roboto/900.css' layer(vendor);
|
|
50
|
+
@import '@fontsource/roboto-mono/400.css' layer(vendor);
|
|
51
|
+
|
|
52
|
+
/* Magma styles */
|
|
53
|
+
@import '@maggioli-design-system/styles/dist/css/colors-rgb.css' layer(theme);
|
|
54
|
+
@import '@maggioli-design-system/styles/dist/css/typography.css' layer(theme);
|
|
55
|
+
@import '@maggioli-design-system/styles/dist/css/reset.css' layer(reset);
|
|
56
|
+
@import '@maggioli-design-system/styles/dist/css/hydrated.css' layer(base);
|
|
57
|
+
@import '@maggioli-design-system/styles/dist/css/transitions.css' layer(base);
|
|
58
|
+
@import '@maggioli-design-system/styles/dist/css/animations.css' layer(base);
|
|
59
|
+
@import '@maggioli-design-system/styles/dist/css/globals.css' layer(theme);
|
|
60
|
+
@import '@maggioli-design-system/styles/dist/css/semantic.css' layer(theme);
|
|
61
|
+
@import '@maggioli-design-system/styles/dist/css/themes.css' layer(theme);
|
|
62
|
+
@import '@maggioli-design-system/styles/dist/css/base.css' layer(base);
|
|
63
|
+
|
|
64
|
+
/* your Tailwind entry point, if any */
|
|
65
|
+
@import './tailwind.css';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
What each file provides:
|
|
69
|
+
|
|
70
|
+
| File | Purpose |
|
|
71
|
+
| ---- | ------- |
|
|
72
|
+
| `colors-rgb.css` | RGB color tokens (`--tone-*`, `--status-*`, ...). Required by components and Tailwind. Also redefines tokens for dark / high-contrast |
|
|
73
|
+
| `typography.css` | The non-color tokens as CSS vars: fonts, type sizes, spacing, radius, shadows (`--shadow-md-sharp`, ...). Components carry their own fallbacks; your CSS needs this file for `var(--shadow-*)`, `var(--radius-*)` and the `--magma-radius-*` corner scale |
|
|
74
|
+
| `reset.css` | Opinionated CSS reset |
|
|
75
|
+
| `hydrated.css` | Anti-FOUC for Stencil - hides components until hydrated |
|
|
76
|
+
| `transitions.css`, `animations.css` | Shared motion |
|
|
77
|
+
| `globals.css` | Global `--magma-*` design decisions |
|
|
78
|
+
| `semantic.css` | The semantic color roles (`--magma-surface-*`, `--magma-text-*`, ..., see [`color.md`](color.md)). Required: without it the page `body` has no colour, the Tailwind role utilities paint nothing, and components lose named themes and high contrast |
|
|
79
|
+
| `themes.css` | The named themes (`data-theme-name`): retint the semantic roles. Import it after `semantic.css` |
|
|
80
|
+
| `base.css` | Base element styles (sets `--font-info` body font, etc.) |
|
|
81
|
+
|
|
82
|
+
DO NOT import `colors-hex-*.css` when using components or Tailwind - they cannot be
|
|
83
|
+
used with opacity modifiers and bypass dark mode. Use `colors-rgb.css`.
|
|
84
|
+
|
|
85
|
+
### Tailwind (optional)
|
|
86
|
+
|
|
87
|
+
With Tailwind 4, import Magma's Tailwind layer in your Tailwind entry point (the
|
|
88
|
+
`./tailwind.css` of the block above), after Tailwind's own theme and utilities. Leave out
|
|
89
|
+
`@import 'tailwindcss'`: its preflight would duplicate Magma's reset.
|
|
90
|
+
|
|
91
|
+
```css
|
|
92
|
+
/* tailwind.css */
|
|
93
|
+
@import 'tailwindcss/theme.css' layer(theme);
|
|
94
|
+
@import 'tailwindcss/utilities.css' layer(utilities);
|
|
95
|
+
@import '@maggioli-design-system/styles/dist/tailwind/theme.css';
|
|
96
|
+
@import '@maggioli-design-system/styles/dist/tailwind/typography.css';
|
|
97
|
+
@import '@maggioli-design-system/styles/dist/tailwind/utilities.css';
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`theme.css` brings the palette, the typography tokens and the semantic color utilities
|
|
101
|
+
(`bg-surface-raised`, `text-fg-muted`, ..., see [`color.md`](color.md)), `typography.css`
|
|
102
|
+
the `text-title-*` / `text-info-*` / `text-read-*` / `text-code-*` utilities,
|
|
103
|
+
`utilities.css` the `focus-bounce` / `focus-zoom` helpers.
|
|
104
|
+
|
|
105
|
+
Do not use the JS preset (`presets: [require('@maggioli-design-system/styles')]`) with
|
|
106
|
+
Tailwind 4: it is the Tailwind 3 path (with the layers in
|
|
107
|
+
`@maggioli-design-system/styles/dist/tailwind3/`), its colours are Tailwind 3 colour
|
|
108
|
+
functions, and Tailwind 4 generates none of the Magma utilities from it.
|
|
109
|
+
|
|
110
|
+
## 2. Fonts
|
|
111
|
+
|
|
112
|
+
Magma does NOT bundle webfonts. The typography tokens point to **Roboto** (title),
|
|
113
|
+
**Karla** (info / UI), **Merriweather** (read / editorial) and **Roboto Mono**
|
|
114
|
+
(code), each with a system fallback. The consumer must load the actual fonts, easiest
|
|
115
|
+
via [`@fontsource`](https://fontsource.org/):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm i @fontsource/karla @fontsource/merriweather @fontsource/roboto @fontsource/roboto-mono
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The `@import` lines are already in the section 1 block (under `layer(vendor)`). They
|
|
122
|
+
are the weights the type scale uses: Roboto 500/700/900 (actions, h6, h1-h5), Karla
|
|
123
|
+
400/700, Merriweather 300/400 (reading paragraph and detail, caption) plus 700 for bold in
|
|
124
|
+
reading text, Roboto Mono 400. Add more weights as needed.
|
|
125
|
+
|
|
126
|
+
Self-hosting via `@fontsource` is preferred over a CDN `<link>` so the fonts respect
|
|
127
|
+
the `vendor` cascade layer and ship offline.
|
|
128
|
+
|
|
129
|
+
## 3. Icons
|
|
130
|
+
|
|
131
|
+
Icons are consumed at runtime by `mds-icon`, which fetches each icon as an SVG file from
|
|
132
|
+
a path the host app configures. A slug starts with its icon set (`mi/` Material Icons,
|
|
133
|
+
`mdi/` Material Design Icons, `mgg/` Maggioli) and resolves to
|
|
134
|
+
`<mdsIconSvgPath><slug>.svg`: with the path `/svg/`, `mi/baseline/email` is fetched from
|
|
135
|
+
`/svg/mi/baseline/email.svg`.
|
|
136
|
+
|
|
137
|
+
### Package and asset copy
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm i @maggioli-design-system/svg-icons
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Copy the SVG library to a publicly served path. The package ships the files under
|
|
144
|
+
`@maggioli-design-system/svg-icons/dist/svg/`. Copy them to e.g. `public/svg/` (the
|
|
145
|
+
mechanism depends on the bundler - see each track file).
|
|
146
|
+
|
|
147
|
+
### Tell mds-icon where the icons are
|
|
148
|
+
|
|
149
|
+
The simplest way: set `mdsIconSvgPath` in `sessionStorage` before components hydrate.
|
|
150
|
+
The value is the public URL of the folder you copied the SVGs into:
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
window.sessionStorage.setItem('mdsIconSvgPath', '/svg/');
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Alternatives, documented in
|
|
157
|
+
the mds-icon readme:
|
|
158
|
+
|
|
159
|
+
- `IconsSetService.setSvgPath('/svg/')`, imported from
|
|
160
|
+
`@maggioli-design-system/magma/services`: sets the path in code, without
|
|
161
|
+
`sessionStorage`, and reloads the icons already mounted
|
|
162
|
+
- `mdsIcon.setSvgPath('/svg/')` - instance method on a temporary `mds-icon` node, after
|
|
163
|
+
`defineCustomElements()` has run
|
|
164
|
+
- dispatch `new CustomEvent('mdsIconSvgPathUpdate')` on `window` to force a refresh
|
|
165
|
+
after changing the path
|
|
166
|
+
|
|
167
|
+
Reference an icon by slug, never inline SVG and never import from an icon-set package:
|
|
168
|
+
|
|
169
|
+
```html
|
|
170
|
+
<mds-icon name="mi/baseline/email"></mds-icon>
|
|
171
|
+
<mds-button icon="mi/baseline/send">Send</mds-button>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The mgg-icons webfont (`@maggioli-design-system/icons`) is an alternative output and
|
|
175
|
+
is NOT used by Magma at runtime - prefer the SVG-file strategy above.
|
|
176
|
+
|
|
177
|
+
## 4. Identity / brand (optional)
|
|
178
|
+
|
|
179
|
+
Logos and avatars for Maggioli Group products. Install only if the app renders brand
|
|
180
|
+
assets:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npm i @maggioli-design-system/identity
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Assets live under `@maggioli-design-system/identity/dist/`:
|
|
187
|
+
|
|
188
|
+
- `dist/brand/` - logos per brand (gruppo-maggioli, maggioli-editore, rnd, ...)
|
|
189
|
+
- `dist/avatar/` - avatar illustrations (svg / webp / png / pdf)
|
|
190
|
+
- `dist/illustrations/`, `dist/products/` - additional brand imagery
|
|
191
|
+
|
|
192
|
+
These are static read-only files - serve them like any other asset, do not modify
|
|
193
|
+
them in the consumer project.
|
|
194
|
+
|
|
195
|
+
## Checklist
|
|
196
|
+
|
|
197
|
+
- [ ] `styles` + `design-tokens` installed on the matching version row
|
|
198
|
+
- [ ] Global CSS imports in the exact cascade-layer order above
|
|
199
|
+
- [ ] `@fontsource` fonts installed and imported in the `vendor` layer
|
|
200
|
+
- [ ] `svg-icons` SVGs copied to a public path
|
|
201
|
+
- [ ] `mdsIconSvgPath` set to that public path before hydration
|
|
202
|
+
- [ ] (optional) `identity` installed if brand assets are used
|
|
203
|
+
- [ ] Components registered per your target track
|
package/agents/color.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
GENERATED FILE - do not edit by hand.
|
|
3
|
+
Source of truth: docs/agents/ in the magma monorepo.
|
|
4
|
+
Regenerate with: npm run sync.agent-docs (from the stencil package).
|
|
5
|
+
-->
|
|
6
|
+
# Magma styles - color
|
|
7
|
+
|
|
8
|
+
> Scope: coloring your own UI with Magma's semantic color roles, in Tailwind and in
|
|
9
|
+
> plain CSS. Requires the styles setup in [`assets.md`](assets.md), including
|
|
10
|
+
> `semantic.css`. Dark mode, contrast and named themes: [`theming.md`](theming.md).
|
|
11
|
+
> The `variant` prop of the components: [`variants.md`](variants.md).
|
|
12
|
+
|
|
13
|
+
## Name the role, not the colour
|
|
14
|
+
|
|
15
|
+
Paint your UI with the semantic roles (`--magma-*`), not with a raw palette step and never
|
|
16
|
+
with Tailwind's own palette:
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<!-- correct: roles follow the mode, the named theme and high contrast -->
|
|
20
|
+
<section class="bg-surface-raised text-fg-default border border-border-muted">
|
|
21
|
+
<p class="text-fg-muted">Secondary text</p>
|
|
22
|
+
</section>
|
|
23
|
+
|
|
24
|
+
<!-- incorrect: raw Magma steps only flip with the mode -->
|
|
25
|
+
<section class="bg-tone-neutral-seed text-tone-neutral-01 border-tone-neutral-09">...</section>
|
|
26
|
+
|
|
27
|
+
<!-- incorrect: Tailwind's palette ignores Magma entirely -->
|
|
28
|
+
<section class="bg-white text-gray-700">...</section>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
A role resolves per mode (light / dark), per named theme (`data-theme-name` retints the
|
|
32
|
+
neutral scaffolding and the accent) and per contrast preference (`pref-contrast-more`
|
|
33
|
+
promotes text and borders, and the page). A raw step (`tone-neutral-03`,
|
|
34
|
+
`status-error-05`, `variant-primary-04`) only flips with the mode: it stays grey under a
|
|
35
|
+
tinted theme and gains no contrast when the user asks for more.
|
|
36
|
+
|
|
37
|
+
## One token, two faces
|
|
38
|
+
|
|
39
|
+
Every role is a CSS custom property holding an RGB channel triplet, and a Tailwind color
|
|
40
|
+
of the same role.
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
/* plain CSS: always inside rgb(), alpha with the slash syntax */
|
|
44
|
+
.panel {
|
|
45
|
+
background: rgb(var(--magma-surface-raised));
|
|
46
|
+
color: rgb(var(--magma-text-default));
|
|
47
|
+
border: 1px solid rgb(var(--magma-border-muted));
|
|
48
|
+
box-shadow: 0 2px 8px rgb(var(--magma-shadow-ink) / 0.12);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Tailwind names the TEXT roles `fg-*`, so a utility never reads `text-text-*`:
|
|
53
|
+
`--magma-text-muted` is `text-fg-muted`, `--magma-danger-text-default` is
|
|
54
|
+
`text-danger-fg-default`. Every other role keeps its name: `bg-surface-raised`,
|
|
55
|
+
`border-border-default`, `bg-accent-emphasis`, `bg-danger-wash-base`.
|
|
56
|
+
|
|
57
|
+
Both faces need the setup in [`assets.md`](assets.md): the values come from
|
|
58
|
+
`styles/dist/css/semantic.css` (without it every role paints nothing), the Tailwind
|
|
59
|
+
utilities from `styles/dist/tailwind/theme.css`. A Tailwind modifier works as usual
|
|
60
|
+
(`bg-surface-raised/80`).
|
|
61
|
+
|
|
62
|
+
## The roles
|
|
63
|
+
|
|
64
|
+
### Neutral scaffolding
|
|
65
|
+
|
|
66
|
+
Backgrounds, text and borders of everything that is neither an action nor a state. A
|
|
67
|
+
named theme retints all of it at once.
|
|
68
|
+
|
|
69
|
+
| Token (`--magma-*`) | Tailwind | Use |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `surface-default` | `bg-surface-default` | the page canvas (the `body` already has it) |
|
|
72
|
+
| `surface-raised` | `bg-surface-raised` | cards, panels, sticky headers |
|
|
73
|
+
| `surface-overlay` | `bg-surface-overlay` | modal, dropdown, popover, sheet |
|
|
74
|
+
| `surface-sunken` | `bg-surface-sunken` | wells, insets, code blocks, tracks |
|
|
75
|
+
| `surface-muted` | `bg-surface-muted` | same-plane grouping: zebra rows, a subtle section |
|
|
76
|
+
| `wash-soft` / `wash-base` / `wash-strong` | `bg-wash-*` | a neutral pill or chip, by how marked it is |
|
|
77
|
+
| `surface-inverse` / `surface-inverse-muted` | `bg-surface-inverse*` | the chip that flips with the mode (dark on a light UI) |
|
|
78
|
+
| `on-inverse` | `text-on-inverse` | text and icons on either inverse level |
|
|
79
|
+
| `text-default` | `text-fg-default` | body text, titles, primary data |
|
|
80
|
+
| `text-muted` | `text-fg-muted` | secondary text that is still essential (an address, a phone) |
|
|
81
|
+
| `text-subtle` | `text-fg-subtle` | non-essential text only: captions, units, hints |
|
|
82
|
+
| `text-disabled` | `text-fg-disabled` | disabled labels |
|
|
83
|
+
| `text-on-emphasis` | `text-fg-on-emphasis` | text on a solid fill |
|
|
84
|
+
| `border-muted` | `border-border-muted` | decorative: dividers, table grid |
|
|
85
|
+
| `border-default` | `border-border-default` | functional outlines: inputs, cards |
|
|
86
|
+
| `border-strong` | `border-border-strong` | a border that conveys state (selected) |
|
|
87
|
+
| `border-focus` | `border-border-focus` | focus indication; follows the accent |
|
|
88
|
+
| `neutral-fg` / `neutral-border` | `text-neutral-fg` / `border-neutral-border` | neutral ink and border on a colored context |
|
|
89
|
+
| `shadow-ink` | `shadow-shadow-ink` | the colour of a projected shadow; compose it with your own geometry and alpha |
|
|
90
|
+
|
|
91
|
+
`--magma-on-backdrop` (in `globals.css`) is the ink on the modal scrim, fixed in both modes.
|
|
92
|
+
|
|
93
|
+
How the five surfaces stack, their values in light and dark, why a raised element needs a
|
|
94
|
+
shadow in light, and how themes and high contrast move them: [`theming.md`](theming.md#surfaces-and-elevation).
|
|
95
|
+
|
|
96
|
+
### Accent: actions and selection
|
|
97
|
+
|
|
98
|
+
Two accents with the same nine roles: `accent` (the brand action colour) and `accent-ai`
|
|
99
|
+
(AI-driven features). A named theme can repoint them.
|
|
100
|
+
|
|
101
|
+
| Token | Tailwind | Use |
|
|
102
|
+
| --- | --- | --- |
|
|
103
|
+
| `--magma-accent-emphasis` | `bg-accent-emphasis` | solid fill: the primary action |
|
|
104
|
+
| `--magma-accent-emphasis-hover` / `-emphasis-active` | `hover:bg-accent-emphasis-hover` | the fill hovered / pressed |
|
|
105
|
+
| `--magma-accent-on-emphasis` | `text-accent-on-emphasis` | text and icons on the fill |
|
|
106
|
+
| `--magma-accent-surface` | `bg-accent-surface` | tinted background: a selected row or chip |
|
|
107
|
+
| `--magma-accent-surface-subtle` / `-surface-hover` | `bg-accent-surface-*` | the tinted background, lighter / hovered |
|
|
108
|
+
| `--magma-accent-fg` | `text-accent-fg` | accent text or icon on a neutral surface (a link) |
|
|
109
|
+
| `--magma-accent-border` | `border-accent-border` | tinted border |
|
|
110
|
+
|
|
111
|
+
`accent-ai` is the same set with the infix: `--magma-accent-ai-emphasis`,
|
|
112
|
+
`bg-accent-ai-surface`, `text-accent-ai-fg`.
|
|
113
|
+
|
|
114
|
+
### Status: info, success, warning, danger
|
|
115
|
+
|
|
116
|
+
Each status publishes the same vocabulary. The hue is named `danger` (the palette family
|
|
117
|
+
is `status-error`). A named theme never retints a status.
|
|
118
|
+
|
|
119
|
+
| Token (`<hue>` = `info`, `success`, `warning`, `danger`) | Tailwind | Use |
|
|
120
|
+
| --- | --- | --- |
|
|
121
|
+
| `--magma-<hue>-wash-soft` / `-wash-base` / `-wash-strong` | `bg-<hue>-wash-*` | colored background, by how marked it is |
|
|
122
|
+
| `--magma-<hue>-text-default` / `-muted` / `-subtle` / `-disabled` | `text-<hue>-fg-*` | colored text on that wash |
|
|
123
|
+
| `--magma-<hue>-border-muted` / `-default` / `-strong` | `border-<hue>-border-*` | colored border |
|
|
124
|
+
| `--magma-<hue>-emphasis` (+ `-hover`, `-active`) | `bg-<hue>-emphasis*` | solid fill: a destructive button, a solid badge |
|
|
125
|
+
| `--magma-<hue>-on-emphasis` | `text-<hue>-on-emphasis` | text and icons on the fill |
|
|
126
|
+
|
|
127
|
+
Shortcuts at the default prominence, kept for brevity: `--magma-<hue>-surface` =
|
|
128
|
+
`wash-base`, `--magma-<hue>-fg` = `text-default`, `--magma-<hue>-border` =
|
|
129
|
+
`border-default` (Tailwind `bg-<hue>-surface`, `text-<hue>-fg`, `border-<hue>-border`).
|
|
130
|
+
|
|
131
|
+
## Pairing rules
|
|
132
|
+
|
|
133
|
+
These are the pairs the contrast gate measures in CI; any other combination is not
|
|
134
|
+
measured.
|
|
135
|
+
|
|
136
|
+
- **`-fg` on a neutral surface, `-on-emphasis` on the fill.** `--magma-accent-fg` is ink
|
|
137
|
+
for the page; on `--magma-accent-emphasis` use `--magma-accent-on-emphasis`. Swapping
|
|
138
|
+
them is the quickest way to break contrast.
|
|
139
|
+
- **Text on a wash is bounded.** `wash-soft` carries the whole text ladder, `wash-base`
|
|
140
|
+
carries `text-default` only, `wash-strong` carries icons only (no essential text). Same
|
|
141
|
+
rule for the neutral band and for every status.
|
|
142
|
+
- **Hierarchy without dropping contrast.** `text-muted` is for essential secondary text,
|
|
143
|
+
`text-subtle` only for what the user can skip. For more hierarchy use weight, size and
|
|
144
|
+
spacing, and soften the chrome (`border-muted`, zebra on `surface-muted`) instead of the
|
|
145
|
+
text.
|
|
146
|
+
- **Elevation is a role.** Page `surface-default`, card
|
|
147
|
+
`surface-raised`, floating layer `surface-overlay`, well `surface-sunken`: choose by
|
|
148
|
+
what the element is, not by the shade you want, and give `raised` / `overlay` a shadow
|
|
149
|
+
([`theming.md`](theming.md#surfaces-and-elevation)). A grey that has to look marked in
|
|
150
|
+
both modes (a pill, a chip, a hover) is a wash, not a surface.
|
|
151
|
+
- **No `dark:` variants and no dark-mode media queries.** The roles already flip.
|
|
152
|
+
|
|
153
|
+
## When a raw palette colour is right
|
|
154
|
+
|
|
155
|
+
Only when the colour encodes data rather than an interface role:
|
|
156
|
+
|
|
157
|
+
- `label-*` (`bg-label-sky-09`, `rgb(var(--label-orchid-04))`): a category, a tag, a
|
|
158
|
+
colour the user picked;
|
|
159
|
+
- `brand-*`: Maggioli brand identity;
|
|
160
|
+
- `--tone-neutral-seed` (`#fff` in light, `#000` in dark): the rare pure extreme, a
|
|
161
|
+
knockout; not a page or card background.
|
|
162
|
+
|
|
163
|
+
Never use `--magma-tint-*`: it is the internal pointer a named theme repoints, not a role.
|
|
164
|
+
`tone-porcelain` and `tone-bisque` back the named themes `cool` and `warm`: switch them on
|
|
165
|
+
with `data-theme-name` ([`theming.md`](theming.md)), do not paint them by hand.
|
|
166
|
+
`variant-*` has no role of its own: the accents are `accent` and `accent-ai`.
|
|
167
|
+
|
|
168
|
+
Deprecated: `--magma-neutral-emphasis` / `--magma-neutral-on-emphasis` are aliases of
|
|
169
|
+
`--magma-surface-inverse` / `--magma-on-inverse`.
|
|
170
|
+
|
|
171
|
+
## Migrating Magma 1 colour classes
|
|
172
|
+
|
|
173
|
+
Magma 1 code paints raw steps, often with a hand-tuned `dark:` override. These steps have
|
|
174
|
+
a role with the same light value; switch to the role and delete the `dark:` override:
|
|
175
|
+
|
|
176
|
+
| Magma 1 step | As | Role |
|
|
177
|
+
| --- | --- | --- |
|
|
178
|
+
| `tone-neutral-01` / `-03` / `-04` / `-05` | text | `fg-default` / `fg-muted` / `fg-subtle` / `fg-disabled` |
|
|
179
|
+
| `tone-neutral-10` / `-09` / `-08` | background | `wash-soft` / `wash-base` / `wash-strong` |
|
|
180
|
+
| `tone-neutral-02` / `-03` | background | `surface-inverse` / `surface-inverse-muted` |
|
|
181
|
+
| `tone-neutral-06` | border | `neutral-border` |
|
|
182
|
+
| `tone-neutral` (the bare seed) | background | by context: `surface-default`, `-raised` or `-overlay` |
|
|
183
|
+
| `status-<x>-01` / `-02` / `-03` / `-05` | text | `<hue>-fg-default` / `-muted` / `-subtle` / `-disabled` |
|
|
184
|
+
| `status-<x>-04` / `-03` / `-02` | background | `<hue>-emphasis` / `-emphasis-hover` / `-emphasis-active` |
|
|
185
|
+
| `status-<x>-10` / `-09` / `-08` | background | `<hue>-wash-soft` / `-wash-base` / `-wash-strong` |
|
|
186
|
+
| `variant-primary-04` / `-03` / `-02` | background | `accent-emphasis` / `-emphasis-hover` / `-emphasis-active` |
|
|
187
|
+
| `variant-primary-09` / `-08` / `-10` | background | `accent-surface` / `-surface-hover` / `-surface-subtle` |
|
|
188
|
+
| `variant-primary-03` / `-06` | text / border | `accent-fg` / `accent-border` |
|
|
189
|
+
|
|
190
|
+
`variant-ai-*` maps the same way onto `accent-ai-*`. The codemod
|
|
191
|
+
(`@maggioli-design-system/magma-codemods`, `--accept-semantic=exact`) applies this table
|
|
192
|
+
to markup, `clsx()`, Angular bindings and `@apply`, and reports what a value cannot
|
|
193
|
+
decide.
|