ui-foundations 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +179 -36
  2. package/dist/assets/icons/checkmark.svg +1 -0
  3. package/dist/core/index.css +7 -7
  4. package/dist/macros/ui.njk +142 -0
  5. package/dist/main.css +465 -173
  6. package/dist/react/badge.js +41 -0
  7. package/dist/react/button.js +15 -6
  8. package/dist/react/checkbox.js +30 -0
  9. package/dist/react/icon.js +19 -1
  10. package/dist/react/index.js +2 -0
  11. package/dist/react/label.js +1 -1
  12. package/dist/react/radio.js +62 -0
  13. package/dist/react/switch.js +18 -0
  14. package/dist/tokens/css/{appearance-(modes).tokens.mode-dark.css → appearance-modes.tokens.mode-dark.css} +1 -1
  15. package/dist/tokens/css/{appearance-(modes).tokens.mode-light.css → appearance-modes.tokens.mode-light.css} +1 -1
  16. package/dist/tokens/css/{components-(ui).tokens.css → components-ui.tokens.css} +46 -3
  17. package/dist/tokens/css/{core-(primitives).tokens.css → core-primitives.tokens.css} +61 -19
  18. package/dist/tokens/css/{semantics-(roles).tokens.css → semantics-roles.tokens.css} +1 -1
  19. package/dist/tokens/css/themes-brands.tokens.brand-a.css +22 -0
  20. package/dist/tokens/css/{themes-(brands).tokens.brand-b.css → themes-brands.tokens.brand-b.css} +9 -9
  21. package/dist/tokens/json/appearance-modes.tokens.mode-dark.json +121 -0
  22. package/dist/tokens/json/appearance-modes.tokens.mode-light.json +121 -0
  23. package/dist/tokens/json/components-ui.tokens.json +715 -0
  24. package/dist/tokens/json/{core-(primitives).tokens.json → core-primitives.tokens.json} +227 -413
  25. package/dist/tokens/json/semantics-roles.tokens.json +141 -0
  26. package/dist/tokens/json/themes-brands.tokens.brand-a.json +81 -0
  27. package/dist/tokens/json/themes-brands.tokens.brand-b.json +81 -0
  28. package/dist/tokens/missing-tokens.json +43 -0
  29. package/dist/tokens/tokens.yaml +1254 -149
  30. package/dist/tokens/ts/{appearance-(modes).tokens.mode-dark.ts → appearance-modes.tokens.mode-dark.ts} +1 -1
  31. package/dist/tokens/ts/{appearance-(modes).tokens.mode-light.ts → appearance-modes.tokens.mode-light.ts} +1 -1
  32. package/dist/tokens/ts/{components-(ui).tokens.ts → components-ui.tokens.ts} +47 -4
  33. package/dist/tokens/ts/{core-(primitives).tokens.ts → core-primitives.tokens.ts} +62 -20
  34. package/dist/tokens/ts/{semantics-(roles).tokens.ts → semantics-roles.tokens.ts} +1 -1
  35. package/dist/tokens/ts/{themes-(brands).tokens.brand-a.ts → themes-brands.tokens.brand-a.ts} +9 -9
  36. package/dist/tokens/ts/{themes-(brands).tokens.brand-b.ts → themes-brands.tokens.brand-b.ts} +9 -9
  37. package/dist/ui/index.css +2 -0
  38. package/dist/ui/patterns/badge.css +49 -0
  39. package/dist/ui/patterns/checkbox.css +71 -22
  40. package/dist/ui/patterns/radio.css +109 -0
  41. package/docs/README.md +38 -0
  42. package/docs/agentic/README.md +34 -0
  43. package/docs/agentic/assistant-behavior-rules.md +48 -0
  44. package/docs/agentic/skills/ux-writing-coach.md +116 -0
  45. package/docs/foundations/README.md +31 -0
  46. package/docs/foundations/foundation-001-token-layering.md +6 -0
  47. package/docs/foundations/foundation-002-naming-and-grouping.md +6 -0
  48. package/docs/foundations/foundation-003-color-semantics-and-status.md +6 -0
  49. package/docs/foundations/foundation-004-typography-scale-and-line-height.md +6 -0
  50. package/docs/foundations/foundation-005-responsive-breakpoints-and-containers.md +6 -0
  51. package/docs/foundations/foundation-006-z-index-layering.md +6 -0
  52. package/docs/foundations/foundation-007-typography-selectors-and-specificity.md +6 -0
  53. package/docs/foundations/foundation-008-mode-activation-and-consumer-control.md +6 -0
  54. package/docs/foundations/foundation-009-component-boundaries-and-utility.md +6 -0
  55. package/docs/foundations/foundation-010-implementation-and-pipeline-workflow.md +6 -0
  56. package/docs/foundations/foundation-011-branching-and-release-governance.md +6 -0
  57. package/docs/foundations/foundation-012-minimal-markup-and-composition.md +6 -0
  58. package/package.json +16 -14
  59. package/dist/tokens/css/themes-(brands).tokens.brand-a.css +0 -22
  60. package/dist/tokens/json/appearance-(modes).tokens.mode-dark.json +0 -182
  61. package/dist/tokens/json/appearance-(modes).tokens.mode-light.json +0 -182
  62. package/dist/tokens/json/components-(ui).tokens.json +0 -739
  63. package/dist/tokens/json/semantics-(roles).tokens.json +0 -203
  64. package/dist/tokens/json/themes-(brands).tokens.brand-a.json +0 -115
  65. package/dist/tokens/json/themes-(brands).tokens.brand-b.json +0 -115
  66. package/docs/agentic/skills/README.md +0 -51
  67. package/docs/agentic/skills/design-ops-specialist/SKILL.md +0 -60
  68. package/docs/agentic/skills/design-system-architect/SKILL.md +0 -106
  69. package/docs/agentic/team-ai-playbook.md +0 -226
package/README.md CHANGED
@@ -1,80 +1,210 @@
1
1
  # UI Foundations
2
2
 
3
- A token-first design system that uses Figma as the single source of truth and automatically generates CSS, JSON, and TypeScript tokens.
3
+ Keep Figma and code in sync by default with tokens, not guesswork.
4
4
 
5
- ## Pipeline
5
+ - **Token-first architecture** — every value comes from a token, no hardcoded exceptions
6
+ - **Figma as single source of truth** — variables export directly into production code
7
+ - **Agent-ready workflows** — structured docs that give AI agents deterministic context
8
+ - **Reproducible pipeline** — same input, same output, validated by CI on every change
9
+
10
+ [Documentation](https://ui-foundations.netlify.app/) · [Starter Template](https://github.com/tbielich/ui-foundations-starter) · [npm](https://www.npmjs.com/package/ui-foundations) · [Figma Library](https://www.figma.com/design/uqMsy8fV1fPbQdAzgwlmBA/UI-Foundations)
11
+
12
+ ---
13
+
14
+ ## Why This Exists
15
+
16
+ Design systems break when design and code drift apart.
17
+ Manual syncing is slow, error-prone, and doesn't scale.
18
+
19
+ UI Foundations solves this with a pipeline that turns Figma variables into
20
+ production tokens automatically — and structures everything so AI agents can
21
+ work with the system reliably.
22
+
23
+ ---
24
+
25
+ ## Key Features
26
+
27
+ - **Token-first architecture** — Core → Semantic → Component → Theme, strictly separated
28
+ - **Figma ↔ code alignment** — `codeSyntax.WEB` maps Figma names directly to CSS
29
+ - **Multi-brand and dark mode** — `data-brand` and `data-mode` switch independently
30
+ - **Agent-ready documentation** — deterministic context for AI-assisted workflows
31
+ - **DTCG-compliant output** — 2025.10 format with proper alias syntax and hex colors
32
+ - **CI-enforced integrity** — full validation pipeline in one `npm run ci:check`
33
+
34
+ ---
35
+
36
+ ## How It Works
37
+
38
+ ### Token Flow
6
39
 
7
40
  ```
8
- Figma Variables → Plugin Export → figma/exports/*.tokens.json → extract-tokens.js → dist/ (CSS, JSON, TS, YAML)
41
+ Figma Variables
42
+
43
+ figma/exports/*.tokens.json
44
+
45
+ extract-tokens.js
46
+
47
+ dist/
9
48
  ```
10
49
 
11
- ## Features
50
+ The pipeline outputs:
12
51
 
13
- - 5 variable collections: Core Primitives, Themes (Brands), Appearance (Modes), Semantics (Roles), Components (UI)
14
- - Multi-brand support (Brand A/B) via `data-brand` selectors
15
- - Dark/light mode via `data-mode` selectors
16
- - Content-based scope detection (independent of filenames)
17
- - Figma plugin with Validate + Export tabs (see `figma/plugin/README.md`)
18
- - CI pipeline: lint, unit tests, build, smoke check, docs build
19
- - Docs site with Eleventy, auto-generated from token data
52
+ - CSS custom properties (`dist/tokens/css/`)
53
+ - DTCG-compliant JSON (`dist/tokens/json/`)
54
+ - TypeScript constants (`dist/tokens/ts/`)
55
+ - A flat YAML index (`dist/tokens/tokens.yaml`)
20
56
 
21
- ## Tech Stack
57
+ ### Layering
58
+
59
+ Tokens follow a strict hierarchy:
60
+
61
+ 1. **Core** — raw values (spacing, radii, colors, typography)
62
+ 2. **Semantic** — intent-based aliases (`--color-text-default`, `--color-fill-brand`)
63
+ 3. **Component** — scoped to one component (`--button-solid-container-background-hover`)
64
+ 4. **Theme** — brand and mode overrides via `data-brand` / `data-mode`
65
+
66
+ Components reference only Semantic or Core. Never raw values.
67
+
68
+ ### Component Integration
69
+
70
+ Every component ships with:
71
+ CSS pattern, React wrapper, Nunjucks macro, playground page, docs page,
72
+ and Code Connect mapping.
73
+
74
+ All surfaces must be present for the component to work predictably across
75
+ docs, playgrounds, and consumer apps.
76
+
77
+ ---
78
+
79
+ ## For Different Audiences
80
+
81
+ ### Designers
82
+
83
+ - Work in Figma variables — they are the source of truth
84
+ - Token names in Figma map directly to CSS variable names
85
+ - Brand and mode switching is built into the variable structure
86
+
87
+ ### Developers
88
+
89
+ - Use generated CSS custom properties — `var(--color-text-default)`
90
+ - No hardcoded values — everything comes from tokens
91
+ - Theming via `data-brand` and `data-mode` attributes on the root element
92
+
93
+ ### Agents
94
+
95
+ - Start with `AGENTS.md` — it defines context loading order
96
+ - Follow deterministic rules in `docs/agentic/assistant-behavior-rules.md`
97
+ - Select a mode from `docs/agentic/modes/` based on the task
98
+
99
+ ---
22
100
 
23
- Vanilla CSS (Custom Properties, Layers), Node.js scripts, Eleventy, Figma Plugin API, MCP.
101
+ ## Getting Started
24
102
 
25
- ## Install
103
+ ### Install
26
104
 
27
105
  ```bash
28
106
  npm install ui-foundations
29
107
  ```
30
108
 
31
- ## Usage
109
+ ### Import
32
110
 
33
111
  ```js
34
112
  import "ui-foundations/core.css";
35
113
  import "ui-foundations/ui.css";
36
114
  ```
37
115
 
38
- Runtime scope switching:
116
+ ### Apply Theming
39
117
 
40
118
  ```js
41
- const root = document.documentElement;
42
- root.dataset.brand = "a"; // "a" | "b"
43
- root.dataset.mode = "light"; // "light" | "dark"
119
+ document.documentElement.dataset.brand = "a"; // "a" | "b"
120
+ document.documentElement.dataset.mode = "light"; // "light" | "dark"
44
121
  ```
45
122
 
123
+ Explore the [docs site](https://ui-foundations.netlify.app/) or the
124
+ [vanilla starter](https://github.com/tbielich/ui-foundations-starter)
125
+ to see it in action.
126
+
127
+ ---
128
+
129
+ ## Components
130
+
131
+ Label, Button (solid / outline / ghost), ButtonGroup, Input, Icon, Checkbox,
132
+ Radio, RadioGroup, Switch, Slider, Link
133
+
134
+ Each component uses its own token layer and supports theming out of the box.
135
+
136
+ ---
137
+
138
+ ## Agent Integration
139
+
140
+ This repo is structured for agent consumption:
141
+
142
+ | File | Purpose |
143
+ |---|---|
144
+ | `AGENTS.md` | Entry point — behavior rules and context loading order |
145
+ | `docs/playbook.md` | Documentation hierarchy and operating model |
146
+ | `DESIGN.md` | Executive design contract |
147
+ | `docs/working-context.md` | Current priorities |
148
+ | `docs/context-manifest.json` | Machine-readable file index |
149
+ | `docs/agentic/modes/` | Task-specific modes (implementation, audit, pattern discovery, token proposal) |
150
+
151
+ Agents operate in modes:
152
+
153
+ - **Default** → Implementation
154
+ - **Exploratory tasks** → Pattern Discovery or Token Proposal
155
+ - **Review tasks** → Audit
156
+
157
+ ---
158
+
159
+ ## Documentation Structure
160
+
161
+ | Directory | Content |
162
+ |---|---|
163
+ | `docs/foundations/` | Token layering, naming, theming, parity, and 12 foundation ADRs |
164
+ | `docs/principles/` | Perception laws, heuristics, and accessibility intent |
165
+ | `docs/patterns/` | Pattern-level composition guidance |
166
+ | `docs/components/` | Component entry docs |
167
+ | `docs/agentic/` | Agent behavior rules, modes, workflows, rule pipeline |
168
+ | `docs/validation/` | CI pipeline, token parity, rule pipeline manifest |
169
+ | `docs/token-pipeline.md` | Token generation pipeline and format reference |
170
+ | `site/` | Docs site source (Eleventy) |
171
+
172
+ ---
173
+
46
174
  ## Local Development
47
175
 
176
+ ### Build
177
+
48
178
  ```bash
49
179
  npm run build:all # generate tokens + build CSS
50
180
  npm run docs:dev # build + serve docs site
51
181
  ```
52
182
 
53
- Figma sync workflow:
183
+ ### Figma Sync
54
184
 
55
185
  ```bash
56
- # 1. Export tokens via Figma plugin (📦 Export tab)
186
+ # 1. Export tokens from Figma
57
187
  # 2. Place JSON files in figma/exports/
58
- # 3. Build
59
188
  npm run build:all
60
189
  ```
61
190
 
62
- Validation:
191
+ ### Validation
63
192
 
64
193
  ```bash
65
- npm run lint
66
- npm run test:unit
67
- npm run ci:check
194
+ npm run ci:check # full pipeline
195
+ npm run tokens:validate # token structure
196
+ npm run dtcg:validate # DTCG compliance
197
+ npm run rules:validate # rule pipeline traceability
68
198
  ```
69
199
 
200
+ ---
201
+
70
202
  ## MCP Integration
71
203
 
72
- This repo supports Figma integration via MCP (Model Context Protocol). Two servers are used:
204
+ Figma integration via Model Context Protocol:
73
205
 
74
206
  - `figma-developer-mcp` — REST API read access (requires `FIGMA_TOKEN` in `.env`)
75
- - Figma Desktop MCP — local server via Figma Desktop app (enable in Dev Mode inspect panel)
76
-
77
- Configure these in your agent's MCP config. Example for the REST API server:
207
+ - Figma Desktop MCP — local server via Figma Desktop app
78
208
 
79
209
  ```json
80
210
  {
@@ -83,13 +213,16 @@ Configure these in your agent's MCP config. Example for the REST API server:
83
213
  }
84
214
  ```
85
215
 
86
- ## Documentation
216
+ ---
217
+
218
+ ## Contributing
219
+
220
+ - Follow token rules — no invented tokens, no hardcoded values
221
+ - Use semantic tokens over primitives
222
+ - Validate before commit: `npm run ci:check`
223
+ - Work on feature branches
87
224
 
88
- - Foundations: `docs/foundations/`
89
- - AI playbook: `docs/agentic/team-ai-playbook.md`
90
- - Figma plugin (Token Foundry): `figma/plugin/README.md`
91
- - Docs site: `site/`
92
- - Vanilla starter: `site/examples/vanilla-starter.md`
225
+ ---
93
226
 
94
227
  ## Release
95
228
 
@@ -98,3 +231,13 @@ npm run release:patch # or release:minor / release:major
98
231
  npm run release:push
99
232
  npm run release:publish
100
233
  ```
234
+
235
+ ---
236
+
237
+ ## Tech Stack
238
+
239
+ Vanilla CSS (Custom Properties, `@layer`) · Node.js · Eleventy · React (optional wrappers) · Nunjucks macros · Figma MCP
240
+
241
+ ---
242
+
243
+ Designed for consistency, built for scale, ready for agents.
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 12 10 18 20 6"/></svg>
@@ -2,11 +2,11 @@
2
2
  @import url("./base/fonts.css") layer(base);
3
3
  @import url("./base/base.css") layer(base);
4
4
  @import url("./base/typography.css") layer(base);
5
- @import url("../tokens/css/semantics-(roles).tokens.css") layer(tokens);
6
- @import url("../tokens/css/components-(ui).tokens.css") layer(tokens);
7
- @import url("../tokens/css/appearance-(modes).tokens.mode-dark.css") layer(tokens);
8
- @import url("../tokens/css/appearance-(modes).tokens.mode-light.css") layer(tokens);
9
- @import url("../tokens/css/core-(primitives).tokens.css") layer(tokens);
10
- @import url("../tokens/css/themes-(brands).tokens.brand-a.css") layer(tokens);
11
- @import url("../tokens/css/themes-(brands).tokens.brand-b.css") layer(tokens);
5
+ @import url("../tokens/css/core-primitives.tokens.css") layer(tokens);
6
+ @import url("../tokens/css/semantics-roles.tokens.css") layer(tokens);
7
+ @import url("../tokens/css/components-ui.tokens.css") layer(tokens);
8
+ @import url("../tokens/css/appearance-modes.tokens.mode-dark.css") layer(tokens);
9
+ @import url("../tokens/css/appearance-modes.tokens.mode-light.css") layer(tokens);
10
+ @import url("../tokens/css/themes-brands.tokens.brand-a.css") layer(tokens);
11
+ @import url("../tokens/css/themes-brands.tokens.brand-b.css") layer(tokens);
12
12
  @import url("./themes/mode.css") layer(themes);
@@ -0,0 +1,142 @@
1
+ {% macro toggleButton(label, dataName, dataValue, variant='outline') -%}
2
+ {%- set classes = "button" -%}
3
+ {%- if variant -%}{%- set classes = classes + " " + variant -%}{%- endif -%}
4
+ <button class="{{ classes }}" type="button"{% if dataName == "mode" %} data-mode="{{ dataValue }}"{% endif %}{% if dataName == "brand" %} data-brand="{{ dataValue }}"{% endif %}{% if dataName == "lang" %} data-lang="{{ dataValue }}"{% endif %} aria-pressed="false">{{ label }}</button>
5
+ {%- endmacro %}
6
+
7
+ {% macro button(label, variant='', disabled=false, type='button') -%}
8
+ {%- set classes = "button" -%}
9
+ {%- if variant -%}{%- set classes = classes + " " + variant -%}{%- endif -%}
10
+ <button type="{{ type }}" class="{{ classes }}"{% if disabled %} disabled{% endif %}>{{ label }}</button>
11
+ {%- endmacro %}
12
+
13
+ {% macro buttonGroup(attached=false, orientation='horizontal', justify='start', ariaLabel='', className='') -%}
14
+ {%- set resolvedOrientation = "vertical" if orientation == "vertical" else "horizontal" -%}
15
+ {%- set resolvedJustify = "stretch" if justify == "stretch" else "start" -%}
16
+ {%- set classes = "button-group" -%}
17
+ {%- if className -%}{%- set classes = classes + " " + className -%}{%- endif -%}
18
+ <div class="{{ classes }}" role="group" data-orientation="{{ resolvedOrientation }}" data-attached="{{ "true" if attached else "false" }}" data-justify="{{ resolvedJustify }}"{% if ariaLabel %} aria-label="{{ ariaLabel }}"{% endif %}>{{ caller() }}</div>
19
+ {%- endmacro %}
20
+
21
+ {% macro input(type='text', placeholder='', value='', state='default', disabled=false, className='', id='', name='', dataPlaygroundControl=false, dataProp='', dataSource='', dataValueType='', dataQueryParam='') -%}
22
+ {%- set classes = "input" -%}
23
+ {%- if state == "hover" -%}{%- set classes = classes + " is-hover" -%}{%- endif -%}
24
+ {%- if state == "active" -%}{%- set classes = classes + " is-active" -%}{%- endif -%}
25
+ {%- if state == "focus" -%}{%- set classes = classes + " is-focus-visible" -%}{%- endif -%}
26
+ {%- if state == "disabled" -%}{%- set classes = classes + " is-disabled" -%}{%- endif -%}
27
+ {%- if className -%}{%- set classes = classes + " " + className -%}{%- endif -%}
28
+ <input class="{{ classes }}" type="{{ type }}"{% if id %} id="{{ id }}"{% endif %}{% if name %} name="{{ name }}"{% endif %}{% if placeholder %} placeholder="{{ placeholder }}"{% endif %}{% if value %} value="{{ value }}"{% endif %}{% if dataPlaygroundControl %} data-playground-control{% endif %}{% if dataProp %} data-prop="{{ dataProp }}"{% endif %}{% if dataSource %} data-source="{{ dataSource }}"{% endif %}{% if dataValueType %} data-value-type="{{ dataValueType }}"{% endif %}{% if dataQueryParam %} data-query-param="{{ dataQueryParam }}"{% endif %}{% if disabled or state == "disabled" %} disabled{% endif %} />
29
+ {%- endmacro %}
30
+
31
+ {% macro checkbox(label='Checkbox', checked=false, disabled=false, state='default', indeterminate=false, className='', wrapperClassName='', id='', name='', value='on') -%}
32
+ {%- set checkboxClasses = "checkbox" -%}
33
+ {%- set fieldClasses = "checkbox-field" -%}
34
+ {%- if checked -%}{%- set checkboxClasses = checkboxClasses + " is-checked" -%}{%- endif -%}
35
+ {%- if indeterminate or state == "indeterminate" -%}{%- set checkboxClasses = checkboxClasses + " is-indeterminate" -%}{%- endif -%}
36
+ {%- if state == "hover" -%}{%- set checkboxClasses = checkboxClasses + " is-hover" -%}{%- endif -%}
37
+ {%- if state == "active" -%}{%- set checkboxClasses = checkboxClasses + " is-active" -%}{%- endif -%}
38
+ {%- if state == "focus" -%}{%- set checkboxClasses = checkboxClasses + " is-focus-visible" -%}{%- endif -%}
39
+ {%- if disabled or state == "disabled" -%}
40
+ {%- set checkboxClasses = checkboxClasses + " is-disabled" -%}
41
+ {%- set fieldClasses = fieldClasses + " is-disabled" -%}
42
+ {%- endif -%}
43
+ {%- if className -%}{%- set checkboxClasses = checkboxClasses + " " + className -%}{%- endif -%}
44
+ {%- if wrapperClassName -%}{%- set fieldClasses = fieldClasses + " " + wrapperClassName -%}{%- endif -%}
45
+ <label class="{{ fieldClasses }}">
46
+ <input class="{{ checkboxClasses }}" type="checkbox"{% if id %} id="{{ id }}"{% endif %}{% if name %} name="{{ name }}"{% endif %}{% if value %} value="{{ value }}"{% endif %}{% if checked %} checked{% endif %}{% if indeterminate or state == "indeterminate" %} aria-checked="mixed"{% endif %}{% if disabled or state == "disabled" %} disabled{% endif %} />
47
+ <span class="checkbox-field__text">{{ label }}</span>
48
+ </label>
49
+ {%- endmacro %}
50
+
51
+ {% macro radio(label='Option', checked=false, disabled=false, state='default', className='', wrapperClassName='', id='', name='', value='') -%}
52
+ {%- set radioClasses = "radio" -%}
53
+ {%- set fieldClasses = "radio-field" -%}
54
+ {%- if checked -%}{%- set radioClasses = radioClasses + " is-checked" -%}{%- endif -%}
55
+ {%- if state == "hover" -%}{%- set radioClasses = radioClasses + " is-hover" -%}{%- endif -%}
56
+ {%- if state == "active" -%}{%- set radioClasses = radioClasses + " is-active" -%}{%- endif -%}
57
+ {%- if state == "focus" -%}{%- set radioClasses = radioClasses + " is-focus-visible" -%}{%- endif -%}
58
+ {%- if disabled or state == "disabled" -%}
59
+ {%- set radioClasses = radioClasses + " is-disabled" -%}
60
+ {%- set fieldClasses = fieldClasses + " is-disabled" -%}
61
+ {%- endif -%}
62
+ {%- if className -%}{%- set radioClasses = radioClasses + " " + className -%}{%- endif -%}
63
+ {%- if wrapperClassName -%}{%- set fieldClasses = fieldClasses + " " + wrapperClassName -%}{%- endif -%}
64
+ <label class="{{ fieldClasses }}">
65
+ <input class="{{ radioClasses }}" type="radio"{% if id %} id="{{ id }}"{% endif %}{% if name %} name="{{ name }}"{% endif %}{% if value %} value="{{ value }}"{% endif %}{% if checked %} checked{% endif %}{% if disabled or state == "disabled" %} disabled{% endif %} />
66
+ <span class="radio-field__text">{{ label }}</span>
67
+ </label>
68
+ {%- endmacro %}
69
+
70
+ {% macro switch(label='Notifications', checked=false, disabled=false, state='default', className='', wrapperClassName='', id='', name='', value='on') -%}
71
+ {%- set switchClasses = "switch" -%}
72
+ {%- set fieldClasses = "switch-field" -%}
73
+ {%- if checked -%}{%- set switchClasses = switchClasses + " is-checked" -%}{%- endif -%}
74
+ {%- if state == "hover" -%}{%- set switchClasses = switchClasses + " is-hover" -%}{%- endif -%}
75
+ {%- if state == "active" -%}{%- set switchClasses = switchClasses + " is-active" -%}{%- endif -%}
76
+ {%- if state == "focus" -%}{%- set switchClasses = switchClasses + " is-focus-visible" -%}{%- endif -%}
77
+ {%- if disabled or state == "disabled" -%}
78
+ {%- set switchClasses = switchClasses + " is-disabled" -%}
79
+ {%- set fieldClasses = fieldClasses + " is-disabled" -%}
80
+ {%- endif -%}
81
+ {%- if className -%}{%- set switchClasses = switchClasses + " " + className -%}{%- endif -%}
82
+ {%- if wrapperClassName -%}{%- set fieldClasses = fieldClasses + " " + wrapperClassName -%}{%- endif -%}
83
+ <label class="{{ fieldClasses }}">
84
+ <input class="{{ switchClasses }}" type="checkbox" role="switch"{% if id %} id="{{ id }}"{% endif %}{% if name %} name="{{ name }}"{% endif %}{% if value %} value="{{ value }}"{% endif %}{% if checked %} checked{% endif %}{% if disabled or state == "disabled" %} disabled{% endif %} />
85
+ <span class="switch-field__text">{{ label }}</span>
86
+ </label>
87
+ {%- endmacro %}
88
+
89
+ {% macro colorChip(token) -%}
90
+ <div class="swatch" style="--swatch-color: var({{ token.cssVar }})">
91
+ <span class="swatch-name">{{ token.name }}</span>
92
+ <span class="swatch-meta">{{ token.value }}</span>
93
+ </div>
94
+ {%- endmacro %}
95
+
96
+ {% macro icon(name, label='', className='') -%}
97
+ {%- set classes = "icon" -%}
98
+ {%- if className -%}{%- set classes = classes + " " + className -%}{%- endif -%}
99
+ <span class="{{ classes }}" style="--icon-src: url('/assets/icons/{{ name }}.svg');"{% if label %} role="img" aria-label="{{ label }}"{% else %} aria-hidden="true"{% endif %}></span>
100
+ {%- endmacro %}
101
+
102
+ {% macro labelContent(text='', startIcon='', endIcon='', iconOnly=false) -%}
103
+ <span class="label-content{% if iconOnly %} is-icon-only{% endif %}">
104
+ {%- if startIcon %}<span class="icon" data-slot="start" style="--icon-src: url('/assets/icons/{{ startIcon }}.svg');" aria-hidden="true"></span>{% endif -%}
105
+ {%- if not iconOnly %}<span class="label-content__text">{{ text }}</span>{% endif -%}
106
+ {%- if endIcon %}<span class="icon" data-slot="end" style="--icon-src: url('/assets/icons/{{ endIcon }}.svg');" aria-hidden="true"></span>{% endif -%}
107
+ </span>
108
+ {%- endmacro %}
109
+
110
+ {% macro fieldLabel(text, htmlFor='', required=false, startIcon='') -%}
111
+ <label class="field-label"{% if htmlFor %} for="{{ htmlFor }}"{% endif %}>
112
+ <span class="label-content">
113
+ {%- if startIcon %}<span class="icon" data-slot="start" style="--icon-src: url('/assets/icons/{{ startIcon }}.svg');" aria-hidden="true"></span>{% endif -%}
114
+ <span class="label-content__text">{{ text }}</span>
115
+ </span>
116
+ {%- if required %}
117
+ <span class="field-label__required" aria-hidden="true">*</span>
118
+ <span class="field-label__required-text"> (required)</span>
119
+ {%- endif %}
120
+ </label>
121
+ {%- endmacro %}
122
+
123
+ {% macro link(text, href='#', startIcon='', endIcon='', state='', disabled=false) -%}
124
+ {%- set classes = "link" -%}
125
+ {%- if state -%}{%- set classes = classes + " is-" + state -%}{%- endif -%}
126
+ {%- if disabled -%}{%- set classes = classes + " is-disabled" -%}{%- endif -%}
127
+ <a class="{{ classes }}" href="{{ href }}"{% if disabled %} aria-disabled="true"{% endif %}>
128
+ {%- if startIcon %}<span class="icon" style="--icon-src: url('/assets/icons/{{ startIcon }}.svg');" aria-hidden="true"></span> {% endif -%}
129
+ {{ text }}
130
+ {%- if endIcon %} <span class="icon" style="--icon-src: url('/assets/icons/{{ endIcon }}.svg');" aria-hidden="true"></span>{% endif -%}
131
+ </a>
132
+ {%- endmacro %}
133
+
134
+ {% macro badge(text, variant='', size='', startIcon='') -%}
135
+ {%- set classes = "badge" -%}
136
+ {%- if variant -%}{%- set classes = classes + " " + variant -%}{%- endif -%}
137
+ {%- if size == "sm" -%}{%- set classes = classes + " sm" -%}{%- endif -%}
138
+ <span class="{{ classes }}">
139
+ {%- if startIcon %}<span class="icon" style="--icon-src: url('/assets/icons/{{ startIcon }}.svg');" aria-hidden="true"></span>{% endif -%}
140
+ <span class="badge__text">{{ text }}</span>
141
+ </span>
142
+ {%- endmacro %}