@maggioli-design-system/magma-react 2.2.0 → 2.4.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.
@@ -19,10 +19,13 @@
19
19
  properties and, for a deep customisation, the parts listed in the component's
20
20
  `AGENTS.md` (see [`conventions.md`](conventions.md)).
21
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.
22
+ `await="false"`). On a form-associated component (`mds-button`, `mds-button-dropdown`
23
+ and the form inputs, listed in [`conventions.md`](conventions.md)) it turns the prop
24
+ **on**, as on a native control. On the others Stencil reads `"false"` as `false`, but
25
+ the attribute stays in the DOM on a prop that is not reflected (and until the first
26
+ render on one that is), so `[disabled]` selectors and scripts reading the attribute
27
+ still see it set. **Remove the attribute** to turn it off; from React or Angular, pass
28
+ `false` to the property, as [`conventions.md`](conventions.md) shows.
26
29
  - Embedding nested HTML in a default slot when the component documents a `label` prop.
27
30
  - Using raw Tailwind colour utilities (`bg-white`, `text-gray-700`) on or inside Magma
28
31
  components - use the semantic role classes (`bg-surface-default`, `text-fg-muted`),
package/agents/assets.md CHANGED
@@ -8,8 +8,8 @@
8
8
  ## Purpose
9
9
 
10
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
11
+ targets** (web components, React, Angular): styles, fonts, icons, optional brand
12
+ identity and editor autocomplete. The per-target tracks ([`install.md`](install.md)) link here instead of repeating
13
13
  this. If something about styles/fonts/icons setup is unclear, this file wins.
14
14
 
15
15
  This file is the minimum to get a consumer running. Once it runs: coloring your own UI
@@ -72,10 +72,10 @@ What each file provides:
72
72
  | `colors-rgb.css` | RGB color tokens (`--tone-*`, `--status-*`, ...). Required by components and Tailwind. Also redefines tokens for dark / high-contrast |
73
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
74
  | `reset.css` | Opinionated CSS reset |
75
- | `hydrated.css` | Anti-FOUC for Stencil - hides components until hydrated |
75
+ | `hydrated.css` | Anti-FOUC for Stencil - hides components until hydrated, then keeps the margin, padding and border they give themselves against a page reset such as Tailwind's preflight. Import it into `base`, as above |
76
76
  | `transitions.css`, `animations.css` | Shared motion |
77
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 |
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 are stuck on their light default (the fallback that gives editors a swatch), and components lose dark mode, named themes and high contrast |
79
79
  | `themes.css` | The named themes (`data-theme-name`): retint the semantic roles. Import it after `semantic.css` |
80
80
  | `base.css` | Base element styles (sets `--font-info` body font, etc.) |
81
81
 
@@ -129,40 +129,173 @@ the `vendor` cascade layer and ship offline.
129
129
  ## 3. Icons
130
130
 
131
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`.
132
+ a path the host app configures. The components' own icons are inlined, so what needs
133
+ serving is the icons the app names.
136
134
 
137
- ### Package and asset copy
135
+ ### The contract
136
+
137
+ Every slug the app uses must be served at `<mdsIconSvgPath><slug>.svg`: with the path
138
+ `/svg/`, `mi/baseline/email` is fetched from `/svg/mi/baseline/email.svg`. A slug starts
139
+ with its icon set, and each set comes from its own package, with its own layout:
140
+
141
+ | Slug | Set | Package | File in the package |
142
+ | ---- | --- | ------- | ------------------- |
143
+ | `mi/<variant>/<name>` | Material Icons | `@material-icons/svg` | `svg/<name>/<variant>.svg` |
144
+ | `mdi/<name>` | Material Design Icons | `@mdi/svg` | `svg/<name>.svg` |
145
+ | `mgg/<name>` | Maggioli | `@maggioli-design-system/svg-icons` | `dist/svg/<name>.svg` |
146
+
147
+ Magma ships only the `mgg/` set, and none of these packages is a dependency of `magma`,
148
+ `magma-react` or `magma-angular`: the route you pick installs what it needs. Copying the
149
+ `svg-icons` folder as it is does NOT follow the contract: its files sit directly in
150
+ `dist/svg/`, while `mds-icon` asks for them under `mgg/`.
151
+
152
+ `mds-usage` still fetches `mi/baseline/info` for its header: serve it too if the app
153
+ uses that component.
154
+
155
+ Any setup that follows the contract works. Two tested routes, both run before every dev
156
+ start and build, with the output folder kept out of git:
157
+
158
+ ### Route 1: iconsauce (what Magma uses)
159
+
160
+ iconsauce reads the sources the way Tailwind reads class names and writes only the icons
161
+ they use, one SVG file per slug, in the folders `mds-icon` expects. Its plugins know the
162
+ three sets and bring their packages along.
138
163
 
139
164
  ```bash
140
- npm i @maggioli-design-system/svg-icons
165
+ npm i -D @iconsauce/core @iconsauce/material-icons @iconsauce/mdi-svg @iconsauce/mgg-icons
141
166
  ```
142
167
 
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).
168
+ ```js
169
+ // iconsauce.config.mjs
170
+ import mi from '@iconsauce/material-icons';
171
+ import mdi from '@iconsauce/mdi-svg';
172
+ import mgg from '@iconsauce/mgg-icons';
146
173
 
147
- ### Tell mds-icon where the icons are
174
+ export default {
175
+ content: ['./index.html', './src/**/*.{html,js,jsx,ts,tsx}'], // every file where icon slugs are written
176
+ plugin: [mi, mdi, mgg],
177
+ };
178
+ ```
148
179
 
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:
180
+ ```json
181
+ "scripts": {
182
+ "icons": "iconsauce --config ./iconsauce.config.mjs --output-svg ./public/svg",
183
+ "predev": "npm run icons",
184
+ "prebuild": "npm run icons"
185
+ }
186
+ ```
151
187
 
152
- ```javascript
153
- window.sessionStorage.setItem('mdsIconSvgPath', '/svg/');
188
+ A slug built at runtime (`'mi/baseline/' + name`) is invisible to iconsauce: write slugs
189
+ in full, or list the computed ones in a file that `content` reads.
190
+
191
+ ### Route 2: serve the files yourself
192
+
193
+ One renaming step: `@material-icons/svg` stores `<name>/<variant>.svg`, while the slug
194
+ wants `mi/<variant>/<name>`. `mdi/` and `mgg/` are plain folder copies. This script covers
195
+ the three sets with Node built-ins only, so it fits any bundler:
196
+
197
+ ```bash
198
+ npm i -D @maggioli-design-system/svg-icons @material-icons/svg @mdi/svg
154
199
  ```
155
200
 
156
- Alternatives, documented in
157
- the mds-icon readme:
201
+ ```js
202
+ // scripts/copy-icons.mjs
203
+ // Copies Magma's icon sets where mds-icon fetches them: <OUT>/<slug>.svg.
204
+ // node scripts/copy-icons.mjs icons.json only the slugs listed in icons.json
205
+ // node scripts/copy-icons.mjs every icon of the three sets (18,720 files, 73 MB)
206
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
207
+ import { createRequire } from 'node:module';
208
+ import { dirname, join } from 'node:path';
209
+
210
+ const OUT = 'public/svg'; // served at /svg/ by Vite, Next.js and the Angular CLI
211
+ const require = createRequire(import.meta.url);
212
+ const root = (pkg) => dirname(require.resolve(`${pkg}/package.json`));
213
+ const MI = join(root('@material-icons/svg'), 'svg'); // <name>/<variant>.svg
214
+ const MDI = join(root('@mdi/svg'), 'svg'); // <name>.svg
215
+ const MGG = join(root('@maggioli-design-system/svg-icons'), 'dist/svg'); // <name>.svg
216
+
217
+ // Source file of a slug: mi/<variant>/<name>, mdi/<name>, mgg/<name>.
218
+ function source(slug) {
219
+ const [set, ...rest] = slug.split('/');
220
+ if (set === 'mi' && rest.length === 2) return join(MI, rest[1], `${rest[0]}.svg`);
221
+ if (set === 'mdi' && rest.length === 1) return join(MDI, `${rest[0]}.svg`);
222
+ if (set === 'mgg' && rest.length === 1) return join(MGG, `${rest[0]}.svg`);
223
+ throw new Error(`Not a Magma icon slug: ${slug}`);
224
+ }
225
+
226
+ function allSlugs() {
227
+ const names = (dir) => readdirSync(dir).map((file) => file.replace(/\.svg$/, ''));
228
+ return [
229
+ ...readdirSync(MI).flatMap((name) => names(join(MI, name)).map((variant) => `mi/${variant}/${name}`)),
230
+ ...names(MDI).map((name) => `mdi/${name}`),
231
+ ...names(MGG).map((name) => `mgg/${name}`),
232
+ ];
233
+ }
234
+
235
+ const slugs = process.argv[2] ? JSON.parse(readFileSync(process.argv[2], 'utf8')) : allSlugs();
236
+ for (const slug of slugs) {
237
+ const file = source(slug);
238
+ if (!existsSync(file)) throw new Error(`No such icon: ${slug} (${file})`);
239
+ const target = join(OUT, `${slug}.svg`);
240
+ mkdirSync(dirname(target), { recursive: true });
241
+ copyFileSync(file, target);
242
+ }
243
+ console.log(`${slugs.length} icons in ${OUT}/`);
244
+ ```
245
+
246
+ `icons.json` lists the slugs the app uses:
247
+
248
+ ```json
249
+ ["mi/baseline/email", "mi/baseline/send", "mdi/github", "mgg/abitazione-principale"]
250
+ ```
251
+
252
+ ```json
253
+ "scripts": {
254
+ "icons": "node scripts/copy-icons.mjs icons.json",
255
+ "predev": "npm run icons",
256
+ "prebuild": "npm run icons"
257
+ }
258
+ ```
259
+
260
+ A slug that does not exist stops the script with an error. A slug used in the code but
261
+ missing from `icons.json` gives a 404 at runtime: iconsauce avoids that by reading the
262
+ sources. Without `icons.json` the script copies every icon of the three sets, all of
263
+ them deployed: 18,720 files and 73 MB (`mi` 43 MB in five variants, `mdi` 29 MB, `mgg`
264
+ 1.3 MB).
265
+
266
+ ### Only the `mgg/` set
267
+
268
+ An app that uses only Maggioli icons can copy the `svg-icons` folder, into `mgg/` under
269
+ the served path: `@maggioli-design-system/svg-icons/dist/svg/` to `public/svg/mgg/`. With
270
+ the Angular CLI that is an `assets` entry in `angular.json`:
271
+
272
+ ```json
273
+ { "glob": "**/*.svg", "input": "node_modules/@maggioli-design-system/svg-icons/dist/svg", "output": "/svg/mgg" }
274
+ ```
275
+
276
+ ### Tell mds-icon where the icons are
277
+
278
+ Set the public URL of the folder the icons are served from, before the first `mds-icon`
279
+ renders. Two ways:
158
280
 
159
281
  - `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
282
+ `@maggioli-design-system/magma/services` (recommended): sets the path in code, without
283
+ `sessionStorage`, and reloads the icons already mounted.
284
+ - the `mdsIconSvgPath` key in `sessionStorage`, a one-liner the install tracks use. Some
285
+ browsers block storage (private windows, sandboxed iframes, storage partitioning): there
286
+ only `IconsSetService` works.
287
+
288
+ ```javascript
289
+ import { IconsSetService } from '@maggioli-design-system/magma/services';
290
+
291
+ IconsSetService.setSvgPath('/svg/');
292
+ // or: window.sessionStorage.setItem('mdsIconSvgPath', '/svg/');
293
+ ```
294
+
295
+ Icons mounted before a path set through `sessionStorage` reload on
296
+ `window.dispatchEvent(new CustomEvent('mdsIconSvgPathUpdate'))`. Every option, with its
297
+ snippet, is in the
298
+ [`mds-icon` pattern](../../magma/dist/collection/components/mds-icon/pattern.md).
166
299
 
167
300
  Reference an icon by slug, never inline SVG and never import from an icon-set package:
168
301
 
@@ -190,14 +323,84 @@ Assets live under `@maggioli-design-system/identity/dist/`:
190
323
  - `dist/illustrations/`, `dist/products/` - additional brand imagery
191
324
 
192
325
  These are static read-only files - serve them like any other asset, do not modify
193
- them in the consumer project.
326
+ them in the consumer project. `dist/identity.json` describes them: one entry per family of
327
+ artworks, with its name as the artwork writes it, its owner and kind, and every variant with
328
+ its path, form, colour, the background it is drawn for and its size. Read names and alt texts
329
+ from it instead of from the file names, which lose accents and punctuation.
330
+
331
+ ## 5. Editor autocomplete
332
+
333
+ Two halves, one extension each. Set them up in VS Code; for another editor, point its CSS
334
+ custom property completion at the same `tokens.editor.css` and leave the rest to the user.
335
+
336
+ | Completes | Extension | Fed by |
337
+ | --------- | --------- | ------ |
338
+ | Magma tokens inside `var(--...)`, in scale order, with a swatch on colors | CSS Var Complete (`phoenisx.cssvar`) | `@maggioli-design-system/styles/dist/css/tokens.editor.css`, every public token once |
339
+ | Tailwind classes (`bg-surface-default`, `p-600`), with their value | Tailwind CSS IntelliSense (`bradlc.vscode-tailwindcss`), only if the app uses Tailwind | the CSS entry that imports Tailwind and Magma's theme (section 1) |
340
+
341
+ MERGE these keys into `.vscode/settings.json` and `.vscode/extensions.json`: never overwrite
342
+ a file that exists, the user's own settings stay.
343
+
344
+ ```json
345
+ {
346
+ "cssvar.files": ["node_modules/@maggioli-design-system/styles/dist/css/tokens.editor.css"],
347
+ "cssvar.ignore": [],
348
+ "cssvar.disableSort": true
349
+ }
350
+ ```
351
+
352
+ ```json
353
+ {
354
+ "recommendations": ["phoenisx.cssvar", "bradlc.vscode-tailwindcss"],
355
+ "unwantedRecommendations": ["vunguyentuan.vscode-css-variables"]
356
+ }
357
+ ```
358
+
359
+ Leave `bradlc.vscode-tailwindcss` out of `recommendations` when the app has no Tailwind.
360
+
361
+ The traps, all measured:
362
+
363
+ - `cssvar.ignore` must be `[]`: its default, `["**/node_modules/**"]`, is applied over
364
+ `cssvar.files`, so the path above is dropped and nothing completes.
365
+ - `cssvar.disableSort: true` keeps the order of the file (a scale from its smallest step
366
+ up); without it the list is alphabetical.
367
+ - `vunguyentuan.vscode-css-variables` goes in `unwantedRecommendations`: it sorts
368
+ alphabetically, never opens the list by itself and duplicates every entry next to CSS
369
+ Var Complete.
370
+ - Never import `tokens.editor.css` in the app: it is for editors only, and holds light
371
+ defaults that would freeze theming (it is wrapped in a query that never matches, so an
372
+ import does nothing at best).
373
+
374
+ Tailwind IntelliSense finds the CSS entry on its own, the split imports of section 1
375
+ included. Only if hovering a class shows nothing, add
376
+ `"tailwindCSS.experimental.configFile": "<path of that CSS file>"`. If the app builds class
377
+ names through functions (`clsx`, `cva`, `cn`), list the ones it uses in
378
+ `"tailwindCSS.classFunctions"`, so the classes inside their calls complete too.
379
+
380
+ Verify, after reloading the window:
381
+
382
+ - in a CSS file, `var(--magma-surface` lists the surface roles, in order, with swatches;
383
+ - with Tailwind, in markup: hovering `p-600` shows `1.5rem = 24px`, and `bg-surface-default`
384
+ shows a swatch in the completion list. No swatch on the semantic classes means an older
385
+ `@maggioli-design-system/styles`: update it.
386
+
387
+ Known limits, nothing to configure:
388
+
389
+ - Tailwind IntelliSense lists the utilities alphabetically, whatever the order of the
390
+ theme: `bg-surface-bisque-*` comes before `bg-surface-default`. Type the role name.
391
+ - The class list offers Tailwind's stock spacing steps (`p-1` ... `p-96`), not Magma's:
392
+ with Magma's theme `p-1` is 0.04px. Write the Magma steps in full (`p-600`, `gap-400`):
393
+ they work and hover with their value, they are just not suggested.
194
394
 
195
395
  ## Checklist
196
396
 
197
397
  - [ ] `styles` + `design-tokens` installed on the matching version row
198
398
  - [ ] Global CSS imports in the exact cascade-layer order above
199
399
  - [ ] `@fontsource` fonts installed and imported in the `vendor` layer
200
- - [ ] `svg-icons` SVGs copied to a public path
400
+ - [ ] Every icon slug the app uses served at `<mdsIconSvgPath><slug>.svg` (iconsauce or
401
+ the copy script, run before dev and build, output folder out of git)
201
402
  - [ ] `mdsIconSvgPath` set to that public path before hydration
202
403
  - [ ] (optional) `identity` installed if brand assets are used
203
404
  - [ ] Components registered per your target track
405
+ - [ ] (VS Code) the editor keys merged into `.vscode/settings.json` and `extensions.json`;
406
+ `var(--magma-` completes, and with Tailwind `bg-surface-default` shows a swatch
package/agents/color.md CHANGED
@@ -55,9 +55,11 @@ Tailwind names the TEXT roles `fg-*`, so a utility never reads `text-text-*`:
55
55
  `border-border-default`, `bg-accent-emphasis`, `bg-danger-wash-base`.
56
56
 
57
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`).
58
+ `styles/dist/css/semantic.css`, the Tailwind utilities from `styles/dist/tailwind/theme.css`.
59
+ Without `semantic.css` a `var(--magma-*)` paints nothing, and a Tailwind utility paints the
60
+ light default of its role, the fallback its bridge carries so editors can show a swatch: in
61
+ dark mode, with a named theme or with more contrast it stays wrong, so the file is still
62
+ required. A Tailwind modifier works as usual (`bg-surface-raised/80`).
61
63
 
62
64
  ## The roles
63
65
 
@@ -70,10 +72,10 @@ named theme retints all of it at once.
70
72
  | --- | --- | --- |
71
73
  | `surface-default` | `bg-surface-default` | the page canvas (the `body` already has it) |
72
74
  | `surface-raised` | `bg-surface-raised` | cards, panels, sticky headers |
73
- | `surface-overlay` | `bg-surface-overlay` | modal, dropdown, popover, sheet |
75
+ | `surface-overlay` | `bg-surface-overlay` | modal, dropdown, popover, sheet, and anything lifted with a shadow |
74
76
  | `surface-sunken` | `bg-surface-sunken` | wells, insets, code blocks, tracks |
75
77
  | `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 |
78
+ | `wash-soft` / `wash-base` / `wash-strong` | `bg-wash-*` | a flat neutral pill or chip (no shadow), by how marked it is |
77
79
  | `surface-inverse` / `surface-inverse-muted` | `bg-surface-inverse*` | the chip that flips with the mode (dark on a light UI) |
78
80
  | `on-inverse` | `text-on-inverse` | text and icons on either inverse level |
79
81
  | `text-default` | `text-fg-default` | body text, titles, primary data |
@@ -3,7 +3,7 @@
3
3
  Source of truth: docs/agents/ in the magma monorepo.
4
4
  Regenerate with: npm run sync.agent-docs (from the stencil package).
5
5
  -->
6
- # Magma components catalogue (114 components)
6
+ # Magma components catalogue (115 components)
7
7
 
8
8
  > Generated from each component's usage description. Each tag links the component's
9
9
  > own `AGENTS.md` (its API, with `pattern.md` and `antipattern.md` beside it) in
@@ -83,10 +83,10 @@
83
83
  | [`mds-pref-animation`](../../magma/dist/collection/components/mds-pref-animation/AGENTS.md) | The `<mds-pref-animation>` web component is a preference control that lets users choose how animations are presented (reduced, system-driven, or fully enabled) |
84
84
  | [`mds-pref-consumption`](../../magma/dist/collection/components/mds-pref-consumption/AGENTS.md) | The `<mds-pref-consumption>` web component is a preference control of the Magma Design System that lets the user pick an energy-consumption mode (`low`, `medium`, `high`); it is usually a child of `<mds-pref>` and renders as a tab group with one option per mode, so it has no native HTML primitive equivalent. |
85
85
  | [`mds-pref-contrast`](../../magma/dist/collection/components/mds-pref-contrast/AGENTS.md) | The `<mds-pref-contrast>` web component is a preference control that lets users switch the application's contrast mode (`more`, `system`, or `no-preference`) |
86
- | [`mds-pref-language`](../../magma/dist/collection/components/mds-pref-language/AGENTS.md) | The `<mds-pref-language>` web component is the language-preference control of the Magma Design System, designed to be slotted inside `<mds-pref>` alongside the other preference children |
86
+ | [`mds-pref-language`](../../magma/dist/collection/components/mds-pref-language/AGENTS.md) | The `<mds-pref-language>` web component is the language-preference control of the Magma Design System, usually slotted inside the `<mds-pref>` panel alongside the other preference children |
87
87
  | [`mds-pref-language-item`](../../magma/dist/collection/components/mds-pref-language-item/AGENTS.md) | The `<mds-pref-language-item>` web component represents a single selectable language option inside the language-preference picker `<mds-pref-language>` |
88
- | [`mds-pref-mode`](../../magma/dist/collection/components/mds-pref-mode/AGENTS.md) | The `<mds-pref-mode>` web component is the mode preference control of the Magma Design System, designed to live as a direct child of `<mds-pref>` |
89
- | [`mds-pref-theme`](../../magma/dist/collection/components/mds-pref-theme/AGENTS.md) | The `<mds-pref-theme>` web component is the theme-switcher segment of the Magma accessibility preferences panel, designed to live as a direct child of `<mds-pref>` |
88
+ | [`mds-pref-mode`](../../magma/dist/collection/components/mds-pref-mode/AGENTS.md) | The `<mds-pref-mode>` web component is the mode preference control of the Magma Design System, usually a direct child of the `<mds-pref>` panel |
89
+ | [`mds-pref-theme`](../../magma/dist/collection/components/mds-pref-theme/AGENTS.md) | The `<mds-pref-theme>` web component is the theme-switcher segment of the Magma accessibility preferences panel, usually a direct child of `<mds-pref>` |
90
90
  | [`mds-pref-theme-item`](../../magma/dist/collection/components/mds-pref-theme-item/AGENTS.md) | The `<mds-pref-theme-item>` web component is a single selectable theme entry inside the `<mds-pref-theme>` preference picker |
91
91
  | [`mds-price-table`](../../magma/dist/collection/components/mds-price-table/AGENTS.md) | The `<mds-price-table>` web component is the layout container of the Magma Design System pricing-table family |
92
92
  | [`mds-price-table-features`](../../magma/dist/collection/components/mds-price-table-features/AGENTS.md) | The `<mds-price-table-features>` web component is the feature-matrix block of the Magma Design System pricing-table family |
@@ -120,6 +120,7 @@
120
120
  | [`mds-table-row`](../../magma/dist/collection/components/mds-table-row/AGENTS.md) | The `<mds-table-row>` web component represents a single data row inside a `<mds-table>` (slotted through `mds-table-body`; `mds-table-header` and `mds-table-footer` are rows themselves) |
121
121
  | [`mds-text`](../../magma/dist/collection/components/mds-text/AGENTS.md) | The `<mds-text>` web component is the foundational typography primitive of the Magma Design System |
122
122
  | [`mds-toast`](../../magma/dist/collection/components/mds-toast/AGENTS.md) | The `<mds-toast>` web component is the transient notification surface of the Magma Design System, used to surface brief, non-blocking feedback messages that appear over the viewport and auto-dismiss after a timeout |
123
+ | [`mds-toast-region`](../../magma/dist/collection/components/mds-toast-region/AGENTS.md) | The `<mds-toast-region>` web component is the place where an application shows its toasts: placed once in the application shell, at an edge of the viewport, it lines up the `<mds-toast>` elements visible at the same time, each one readable, and announces them to assistive technologies |
123
124
  | [`mds-tooltip`](../../magma/dist/collection/components/mds-tooltip/AGENTS.md) | The `<mds-tooltip>` web component is the floating contextual hint of the Magma Design System |
124
125
  | [`mds-tree`](../../magma/dist/collection/components/mds-tree/AGENTS.md) | The `<mds-tree>` web component is the root container of the Magma Design System tree view, organizing a hierarchy of slotted `<mds-tree-item>` nodes into an expandable/collapsible structure |
125
126
  | [`mds-tree-item`](../../magma/dist/collection/components/mds-tree-item/AGENTS.md) | The `<mds-tree-item>` web component is the node primitive of the Magma Design System tree view: it represents a single labeled, expandable/collapsible entry inside an `<mds-tree>` and is also the recursive container for its own descendants |
@@ -28,11 +28,27 @@
28
28
 
29
29
  - Boolean props default to `false`/`undefined`. Prefer removing the attribute over
30
30
  setting it to `false`.
31
+ - A boolean attribute turns its prop on by being present. On the form-associated
32
+ components (`mds-button`, `mds-button-dropdown`, `mds-input`, `mds-input-date`,
33
+ `mds-input-date-range`, `mds-input-field`, `mds-input-otp`, `mds-input-range`,
34
+ `mds-input-select`, `mds-input-switch`, `mds-input-upload`) any value turns it on,
35
+ `"false"` included, as on a native control.
31
36
  - Disabled: `<mds-button disabled>`. Never `disabled="false"` - remove it instead. Set
32
37
  `disabled` on the component, not on a wrapper: disabled components are removed from
33
38
  the tab order automatically.
34
39
  - Async: `<mds-button await>` shows a spinner and blocks interaction; remove `await`
35
40
  (set `undefined`) when done.
41
+ - From a framework, pass a real boolean to the property, not a string to the attribute:
42
+ - React with `magma-react`: `<MdsButton disabled={isDisabled} />` sets the property,
43
+ so `false` turns the prop off; the `.server` variants leave a `false` out of the
44
+ markup. A bare `mds-*` tag in React 18 JSX is different: React 18 writes
45
+ `disabled={false}` as the attribute `"false"`, which turns a form-associated component
46
+ on, so pass `undefined` there. React 19 sets the property and turns it off.
47
+ - Angular with `magma-angular`: bind the input, `[disabled]="isDisabled"`. The proxy
48
+ sets the property, so `false` turns the prop off. A static `disabled="false"` or an
49
+ attribute binding (`[attr.disabled]="false"`) writes the attribute instead, and turns
50
+ a form-associated component on; `[attr.disabled]="null"` removes it. Reactive Forms
51
+ `disable()` / `enable()` set the property through the value accessor.
36
52
 
37
53
  ## Sizing
38
54
 
package/agents/install.md CHANGED
@@ -24,7 +24,7 @@ npm i @maggioli-design-system/magma-react @maggioli-design-system/magma
24
24
  matrix). Then install the assets from [`assets.md`](assets.md):
25
25
 
26
26
  ```bash
27
- npm i @maggioli-design-system/styles @maggioli-design-system/design-tokens @maggioli-design-system/svg-icons
27
+ npm i @maggioli-design-system/styles @maggioli-design-system/design-tokens
28
28
  npm i @fontsource/karla @fontsource/merriweather @fontsource/roboto @fontsource/roboto-mono
29
29
  ```
30
30
 
@@ -116,9 +116,10 @@ export default function RootLayout({
116
116
 
117
117
  ## 4. Serve the icon SVGs and styles
118
118
 
119
- - Copy `@maggioli-design-system/svg-icons/dist/svg/` into the static folder served at
120
- `/svg/` (Vite/CRA: `public/svg/`; Next.js: `public/svg/`). Match the path you pass
121
- to `mdsIconSvgPath`.
119
+ - Write the icons into the static folder served at `/svg/` (Vite and Next.js:
120
+ `public/svg/`) with one of the routes of [`assets.md`](assets.md) section 3
121
+ (iconsauce or the copy script, run from `predev` and `prebuild`). Match the path you
122
+ pass to `mdsIconSvgPath`.
122
123
  - Import the global CSS block from [`assets.md`](assets.md) in your global stylesheet
123
124
  (`app/globals.css`, `src/index.css`, ...) so the cascade-layer order is preserved.
124
125
 
@@ -164,7 +165,7 @@ SSR notes:
164
165
  - Icons render empty server-side (the box is reserved, no layout shift) and the
165
166
  default theme is rendered - see the SSR section in
166
167
  [`install.md`](install.md).
167
- - The hydrate module (`magma/hydrate`) bundles all 114 components (~3 MB,
168
+ - The hydrate module (`magma/hydrate`) bundles all 115 components (~3 MB,
168
169
  server-only). It is imported lazily behind a `typeof window` check and must
169
170
  never end up in a client bundle.
170
171
 
@@ -208,6 +209,11 @@ With React Router the handler is `(href) => navigate(href)` from `useNavigate()`
208
209
  on the client - use the `.server` variants (section 5) to get real SSR markup.
209
210
  - Keep `magma` and `magma-react` on the exact same version; the wrapper is generated
210
211
  against a specific `magma` build.
212
+ - Pass booleans as booleans: `<MdsButton disabled={false} />` sets the property and turns
213
+ the prop off, and the `.server` variants leave a `false` out of the markup. Render the
214
+ wrapper, not the bare `mds-*` tag: in React 18 JSX `<mds-button disabled={false}>`
215
+ writes the attribute `"false"`, which turns a form-associated component on (see
216
+ [`conventions.md`](conventions.md)).
211
217
 
212
218
  ## See also
213
219
 
@@ -56,8 +56,11 @@ gh label list --repo magma-design-system/magma --search prd-
56
56
 
57
57
  Match it against this project's repository name (the `origin` remote, or the `name` in
58
58
  `package.json`). If none matches, do not create one: the Magma maintainers manage the
59
- labels of their repository. Open the issue without it and say in the body which project
60
- and repository it comes from, so they can add the label.
59
+ labels of their repository, and a label missing from their configuration is deleted by
60
+ the next sync. Open the issue without it, and propose its name in the body, so the
61
+ maintainers add it as it is: `prd-` and the project's short name, lowercase, in
62
+ kebab-case (`prd-mindy` for `mindy-webapp`, `prd-docs` for the docs site). Leave out
63
+ generic words such as `app`, `webapp`, `frontend` or the organization's name.
61
64
 
62
65
  GitHub sets labels on a new issue only for users with write access to the repository,
63
66
  and drops them for everyone else, often without an error. After creating the issue,
@@ -98,6 +101,12 @@ What the project does meanwhile, if anything.
98
101
  Found in <project> (<repository>): <where in the app>.
99
102
  ```
100
103
 
104
+ When step 4 found no origin label, end the body with the one you propose:
105
+
106
+ ```markdown
107
+ No origin label for this project yet: proposed `prd-<name>`.
108
+ ```
109
+
101
110
  Read the installed versions from the lockfile or `npm ls`, not from the ranges in
102
111
  `package.json`.
103
112
 
package/agents/theming.md CHANGED
@@ -138,3 +138,18 @@ by itself changes the shape WITHOUT the scale.
138
138
  In your own CSS take radii from the `--magma-radius-*` scale (`none`, `3xs` ... `5xl`,
139
139
  `full`), which follows the axis: `border-radius: var(--magma-radius-lg)`. A raw
140
140
  `--radius-*` token or a pixel value stays the same under every shape.
141
+
142
+ A browser without `corner-shape` (Firefox, Safari) gets round corners and the round
143
+ scale on its own. A control of your own whose radius is past half its height
144
+ (Chromium clamps it to half the height) needs one more step to keep its look there:
145
+ cap the radius at a part of its height, as Magma's buttons and fields do.
146
+
147
+ ```css
148
+ .my-control {
149
+ --my-control-height: 2.25rem;
150
+
151
+ border-radius: min(var(--magma-radius-2xl), var(--magma-corner-cap) * var(--my-control-height));
152
+ corner-shape: var(--magma-corner-shape);
153
+ min-height: var(--my-control-height);
154
+ }
155
+ ```
@@ -109,6 +109,7 @@ export { MdsTableHeader } from "./mds-table-header.js";
109
109
  export { MdsTableRow } from "./mds-table-row.js";
110
110
  export { MdsTable } from "./mds-table.js";
111
111
  export { MdsText } from "./mds-text.js";
112
+ export { MdsToastRegion } from "./mds-toast-region.js";
112
113
  export { MdsToast } from "./mds-toast.js";
113
114
  export { MdsTooltip } from "./mds-tooltip.js";
114
115
  export { MdsTreeItem } from "./mds-tree-item.js";
@@ -109,6 +109,7 @@ export { MdsTableHeader } from "./mds-table-header.server.js";
109
109
  export { MdsTableRow } from "./mds-table-row.server.js";
110
110
  export { MdsTable } from "./mds-table.server.js";
111
111
  export { MdsText } from "./mds-text.server.js";
112
+ export { MdsToastRegion } from "./mds-toast-region.server.js";
112
113
  export { MdsToast } from "./mds-toast.server.js";
113
114
  export { MdsTooltip } from "./mds-tooltip.server.js";
114
115
  export { MdsTreeItem } from "./mds-tree-item.server.js";
@@ -12,6 +12,7 @@ export const MdsInputDateRange = /*@__PURE__*/ createComponent({
12
12
  min: 'min',
13
13
  max: 'max',
14
14
  delay: 'delay',
15
+ size: 'size',
15
16
  hideToday: 'hide-today',
16
17
  dualCalendar: 'dual-calendar',
17
18
  name: 'name',
@@ -13,6 +13,7 @@ export const MdsInputDate = /*@__PURE__*/ createComponent({
13
13
  min: 'min',
14
14
  max: 'max',
15
15
  delay: 'delay',
16
+ size: 'size',
16
17
  hideToday: 'hide-today',
17
18
  disabled: 'disabled',
18
19
  readonly: 'readonly',
@@ -14,6 +14,7 @@ export const MdsInputSelect = /*@__PURE__*/ createComponent({
14
14
  disabled: 'disabled',
15
15
  required: 'required',
16
16
  multiple: 'multiple',
17
+ rows: 'rows',
17
18
  size: 'size',
18
19
  value: 'value',
19
20
  defaultValue: 'default-value',
@@ -26,6 +26,7 @@ export const MdsInput = /*@__PURE__*/ createComponent({
26
26
  required: 'required',
27
27
  variant: 'variant',
28
28
  tip: 'tip',
29
+ size: 'size',
29
30
  step: 'step',
30
31
  type: 'type',
31
32
  typography: 'typography',
@@ -5,7 +5,7 @@ import * as clientComponents from "@maggioli-design-system/magma-react";
5
5
  export const serializeShadowRoot = "declarative-shadow-dom";
6
6
  export const MdsTableFooter = /*@__PURE__*/ createComponent({
7
7
  tagName: 'mds-table-footer',
8
- properties: {},
8
+ properties: { selectable: 'selectable' },
9
9
  hydrateModule: typeof window === 'undefined' ? import('@maggioli-design-system/magma/hydrate') : undefined,
10
10
  clientModule: clientComponents.MdsTableFooter,
11
11
  serializeShadowRoot
@@ -7,6 +7,6 @@ export const MdsTableHeaderCell = /*@__PURE__*/ createComponent({
7
7
  elementClass: MdsTableHeaderCellElement,
8
8
  // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
9
9
  react: React,
10
- events: {},
10
+ events: { onMdsTableHeaderCellSort: 'mdsTableHeaderCellSort' },
11
11
  defineCustomElement: defineMdsTableHeaderCell
12
12
  });
@@ -8,6 +8,7 @@ export const MdsTableHeaderCell = /*@__PURE__*/ createComponent({
8
8
  properties: {
9
9
  sortable: 'sortable',
10
10
  label: 'label',
11
+ sortKey: 'sort-key',
11
12
  direction: 'direction'
12
13
  },
13
14
  hydrateModule: typeof window === 'undefined' ? import('@maggioli-design-system/magma/hydrate') : undefined,
@@ -8,7 +8,8 @@ export const MdsTable = /*@__PURE__*/ createComponent({
8
8
  properties: {
9
9
  interactive: 'interactive',
10
10
  selectable: 'selectable',
11
- selection: 'selection'
11
+ selection: 'selection',
12
+ sorting: 'sorting'
12
13
  },
13
14
  hydrateModule: typeof window === 'undefined' ? import('@maggioli-design-system/magma/hydrate') : undefined,
14
15
  clientModule: clientComponents.MdsTable,
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { createComponent } from '@stencil/react-output-target/runtime';
3
+ import React from 'react';
4
+ import { MdsToastRegion as MdsToastRegionElement, defineCustomElement as defineMdsToastRegion } from "@maggioli-design-system/magma/dist/components/mds-toast-region.js";
5
+ export const MdsToastRegion = /*@__PURE__*/ createComponent({
6
+ tagName: 'mds-toast-region',
7
+ elementClass: MdsToastRegionElement,
8
+ // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
9
+ react: React,
10
+ events: {},
11
+ defineCustomElement: defineMdsToastRegion
12
+ });