@ds-mo/ui 9.0.0 → 9.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.
Files changed (122) hide show
  1. package/README.md +28 -0
  2. package/dist/.build-stamp +1 -1
  3. package/dist/agent-patterns.json +233 -0
  4. package/dist/agent.json +155 -19
  5. package/dist/angular/ds-menu.d.ts +6 -1
  6. package/dist/angular/ds-menu.js +7 -4
  7. package/dist/angular/ds-swatch-picker.d.ts +15 -0
  8. package/dist/angular/ds-swatch-picker.js +42 -0
  9. package/dist/angular/index.d.ts +1 -1
  10. package/dist/angular/index.js +1 -0
  11. package/dist/angular/proxies.d.ts +1 -0
  12. package/dist/angular/proxies.js +1 -0
  13. package/dist/components/ds-app-shell.js +1 -1
  14. package/dist/components/ds-bar-nav.js +1 -1
  15. package/dist/components/ds-bar-nav.js.map +1 -1
  16. package/dist/components/ds-menu.js +1 -1
  17. package/dist/components/ds-panel-nav.js +1 -1
  18. package/dist/components/ds-panel-nav.js.map +1 -1
  19. package/dist/components/ds-select-multi.js +1 -1
  20. package/dist/components/ds-select-multi.js.map +1 -1
  21. package/dist/components/ds-select.js +1 -1
  22. package/dist/components/ds-select.js.map +1 -1
  23. package/dist/components/ds-shell-gradient-picker.js +1 -1
  24. package/dist/components/ds-shell-gradient-picker.js.map +1 -1
  25. package/dist/components/ds-shell-gradient-swatch.js +1 -1
  26. package/dist/components/ds-shell-gradient-swatch.js.map +1 -1
  27. package/dist/components/ds-slider.js +1 -1
  28. package/dist/components/ds-slider.js.map +1 -1
  29. package/dist/components/ds-swatch-picker.d.ts +11 -0
  30. package/dist/components/ds-swatch-picker.js +2 -0
  31. package/dist/components/ds-swatch-picker.js.map +1 -0
  32. package/dist/components/ds-tooltip-data-viz.js +1 -1
  33. package/dist/components/p-D1HFMTdC.js +2 -0
  34. package/dist/components/p-D1HFMTdC.js.map +1 -0
  35. package/dist/components/p-HBIxvS5C.js +2 -0
  36. package/dist/components/p-HBIxvS5C.js.map +1 -0
  37. package/dist/components/p-l6PmnW_P.js +2 -0
  38. package/dist/components/p-l6PmnW_P.js.map +1 -0
  39. package/dist/components/p-tQ1QHeOE.js +2 -0
  40. package/dist/components/p-tQ1QHeOE.js.map +1 -0
  41. package/dist/docs/components.json +268 -30
  42. package/dist/lib/components/Menu/menu-placement.d.ts +6 -3
  43. package/dist/lib/shell/index.d.ts +2 -2
  44. package/dist/lib/shell/index.js +40 -39
  45. package/dist/lib/shell/index.js.map +3 -3
  46. package/dist/lib/shell/shell-gradient-presets.d.ts +15 -0
  47. package/dist/lib/utils/choice-popup-alignment.d.ts +20 -0
  48. package/dist/lib/utils/index.d.ts +2 -0
  49. package/dist/lib/utils/index.js +16 -0
  50. package/dist/lib/utils/index.js.map +3 -3
  51. package/dist/mcp/cli.js +31409 -0
  52. package/dist/mcp-data/registry/app-shell.json +210 -0
  53. package/dist/mcp-data/registry/badge.json +289 -0
  54. package/dist/mcp-data/registry/banner.json +206 -0
  55. package/dist/mcp-data/registry/bar-nav.json +341 -0
  56. package/dist/mcp-data/registry/button-filled.json +386 -0
  57. package/dist/mcp-data/registry/button-unfilled.json +537 -0
  58. package/dist/mcp-data/registry/card-data-viz-donut.json +143 -0
  59. package/dist/mcp-data/registry/card-setting.json +194 -0
  60. package/dist/mcp-data/registry/card-shell-data-viz.json +173 -0
  61. package/dist/mcp-data/registry/card.json +126 -0
  62. package/dist/mcp-data/registry/chart-bar.json +121 -0
  63. package/dist/mcp-data/registry/chart-donut.json +257 -0
  64. package/dist/mcp-data/registry/chart-legend.json +209 -0
  65. package/dist/mcp-data/registry/chart-line.json +153 -0
  66. package/dist/mcp-data/registry/checkbox.json +361 -0
  67. package/dist/mcp-data/registry/chip.json +276 -0
  68. package/dist/mcp-data/registry/divider.json +225 -0
  69. package/dist/mcp-data/registry/empty-state.json +197 -0
  70. package/dist/mcp-data/registry/field.json +222 -0
  71. package/dist/mcp-data/registry/icon.json +242 -0
  72. package/dist/mcp-data/registry/input.json +597 -0
  73. package/dist/mcp-data/registry/loader.json +192 -0
  74. package/dist/mcp-data/registry/menu.json +459 -0
  75. package/dist/mcp-data/registry/modal.json +150 -0
  76. package/dist/mcp-data/registry/panel-nav.json +622 -0
  77. package/dist/mcp-data/registry/panel-sub-nav.json +249 -0
  78. package/dist/mcp-data/registry/panel-tools.json +374 -0
  79. package/dist/mcp-data/registry/radio.json +374 -0
  80. package/dist/mcp-data/registry/registry.json +5389 -0
  81. package/dist/mcp-data/registry/select-multi.json +755 -0
  82. package/dist/mcp-data/registry/select.json +740 -0
  83. package/dist/mcp-data/registry/shell-gradient-picker.json +195 -0
  84. package/dist/mcp-data/registry/shell-gradient-swatch.json +215 -0
  85. package/dist/mcp-data/registry/skeleton.json +282 -0
  86. package/dist/mcp-data/registry/slider.json +657 -0
  87. package/dist/mcp-data/registry/swatch-picker.json +231 -0
  88. package/dist/mcp-data/registry/switch.json +361 -0
  89. package/dist/mcp-data/registry/tab-group.json +255 -0
  90. package/dist/mcp-data/registry/tag.json +352 -0
  91. package/dist/mcp-data/registry/text.json +371 -0
  92. package/dist/mcp-data/registry/tooltip-data-viz.json +158 -0
  93. package/dist/mcp-data/registry/tooltip.json +311 -0
  94. package/dist/react/components.d.ts +1 -0
  95. package/dist/react/components.js +1 -0
  96. package/dist/react/ds-menu.d.ts +1 -0
  97. package/dist/react/ds-menu.js +2 -1
  98. package/dist/react/ds-swatch-picker.d.ts +12 -0
  99. package/dist/react/ds-swatch-picker.js +12 -0
  100. package/dist/types/components/Menu/Menu.d.ts +7 -1
  101. package/dist/types/components/Menu/menu-placement.d.ts +6 -3
  102. package/dist/types/components/Menu/menu-types.d.ts +14 -1
  103. package/dist/types/components/ShellGradientPicker/ShellGradientPicker.d.ts +2 -5
  104. package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +1 -0
  105. package/dist/types/components/SwatchPicker/SwatchPicker.d.ts +21 -0
  106. package/dist/types/components/SwatchPicker/swatch-picker-types.d.ts +26 -0
  107. package/dist/types/components.d.ts +117 -0
  108. package/dist/types/shell/index.d.ts +2 -2
  109. package/dist/types/shell/shell-gradient-presets.d.ts +15 -0
  110. package/dist/types/utils/choice-popup-alignment.d.ts +21 -0
  111. package/dist/types/utils/index.d.ts +2 -0
  112. package/package.json +6 -2
  113. package/dist/components/p-Bafp65bw.js +0 -2
  114. package/dist/components/p-Bafp65bw.js.map +0 -1
  115. package/dist/components/p-BdnR3jxi.js +0 -2
  116. package/dist/components/p-BdnR3jxi.js.map +0 -1
  117. package/dist/components/p-C_cu-HIT.js +0 -2
  118. package/dist/components/p-C_cu-HIT.js.map +0 -1
  119. package/dist/components/p-D0B9uDTP.js +0 -2
  120. package/dist/components/p-D0B9uDTP.js.map +0 -1
  121. package/dist/components/p-DF0yLZG_.js +0 -2
  122. package/dist/components/p-DF0yLZG_.js.map +0 -1
@@ -0,0 +1,386 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "button-filled",
4
+ "title": "ButtonFilled",
5
+ "description": "Highest-emphasis command button for the single primary action in a local decision area, with semantic consequence and async progress treatments.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@ds-mo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/compomo/?path=/story/button-filled",
11
+ "source": "src/wc/components/ButtonFilled/ButtonFilled.tsx",
12
+ "intentStatus": "complete",
13
+ "intent": {
14
+ "audience": "general",
15
+ "status": "stable",
16
+ "summary": "Highest-emphasis command button for the single primary action in a local decision area, with semantic consequence and async progress treatments.",
17
+ "useWhen": [
18
+ "The user initiates the single primary command in a local decision area.",
19
+ "An action's consequence requires a matching semantic treatment.",
20
+ "A standalone compact primary action needs an icon-only presentation with an explicit accessible name."
21
+ ],
22
+ "avoidWhen": [
23
+ "Another filled action already exists in the same local decision area.",
24
+ "The action is unfilled icon-only shell or navigation chrome.",
25
+ "The element represents navigation rather than a command.",
26
+ "The content is a persistent selected state rather than an action.",
27
+ "A semantic color would be decorative or merely match the surrounding product area."
28
+ ],
29
+ "alternatives": [
30
+ {
31
+ "when": "The action is icon-only shell, navigation, overflow, or tool-rail chrome.",
32
+ "component": "component:ds-button-unfilled",
33
+ "reason": "Unfilled buttons provide the correct active, border, and surface-aware interaction states for chrome."
34
+ },
35
+ {
36
+ "when": "The user is choosing a destination in application navigation.",
37
+ "component": "component:ds-panel-nav",
38
+ "reason": "Navigation components own destination selection, active state, and navigation semantics."
39
+ }
40
+ ],
41
+ "commonlyComposedWith": [
42
+ "component:ds-modal",
43
+ "component:ds-field"
44
+ ],
45
+ "accessibility": [
46
+ "Provide an explicit accessible name for icon-only buttons.",
47
+ "Use inactive state only when the action must remain visible but unavailable.",
48
+ "Do not encode the action meaning through color alone.",
49
+ "Loading keeps the action focused and named, exposes busy and disabled state, and blocks activation; announce broader operation progress from the owning workflow when users need confirmation.",
50
+ "Use native submit behavior for form submission and handle the form submit event rather than submitting from the button click event."
51
+ ],
52
+ "states": [
53
+ "Use only one filled action per local decision area; render all secondary actions with ButtonUnfilled.",
54
+ "Choose brand or neutral for general commands. Reserve positive, negative, warning, and caution for matching action consequences, and AI, guide, or walkthrough for actions that enter those feature experiences.",
55
+ "Contrast serves both surface adaptation and hierarchy, but never permits a second filled action in the same decision area.",
56
+ "Rounded changes only the control radius to the half-radius treatment; it does not change hierarchy, size, variant, intent, or interaction semantics.",
57
+ "Loading prevents duplicate activation without applying inactive opacity or removing the current keyboard focus.",
58
+ "Icon and icon-label loading replace the icon in place. Label-only loading centers the loader while preserving the button's measured width."
59
+ ],
60
+ "responsiveBehavior": [
61
+ "Use fill width only when the parent layout calls for a full-width action, commonly on narrow form layouts."
62
+ ],
63
+ "frameworkCaveats": {
64
+ "customElements": [
65
+ "For form submission, use the native submit type and listen to the form submit event; use dsClick for non-submit commands."
66
+ ],
67
+ "react": [
68
+ "Keep async state in the owner and pass it to the loading state until the command settles."
69
+ ],
70
+ "angular": [
71
+ "Keep async state in the owner and pass it to the loading state until the command settles."
72
+ ]
73
+ },
74
+ "references": [
75
+ {
76
+ "label": "Storybook examples",
77
+ "path": "src/wc/components/ButtonFilled/ButtonFilled.stories.ts"
78
+ }
79
+ ]
80
+ },
81
+ "api": {
82
+ "props": {
83
+ "ariaLabel": {
84
+ "type": "string | null",
85
+ "resolvedType": "null | string",
86
+ "attribute": "aria-label",
87
+ "default": "null",
88
+ "required": false,
89
+ "mutable": false,
90
+ "description": "Accessible name override. Required for icon-only buttons."
91
+ },
92
+ "contrast": {
93
+ "type": "ButtonFilledContrast",
94
+ "resolvedType": "\"bold\" | \"faint\" | \"medium\" | \"strong\"",
95
+ "attribute": "contrast",
96
+ "default": "'bold'",
97
+ "required": false,
98
+ "mutable": false,
99
+ "description": "Background fill weight. Foreground uses the paired contrast token:\nbold → faint, strong → medium, medium → strong, faint → bold."
100
+ },
101
+ "icon": {
102
+ "type": "string",
103
+ "resolvedType": "string",
104
+ "attribute": "icon",
105
+ "default": "''",
106
+ "required": false,
107
+ "mutable": false,
108
+ "description": "Icon name passed to <ds-icon> for `icon` / `icon-label` variants."
109
+ },
110
+ "intent": {
111
+ "type": "ButtonFilledIntent",
112
+ "resolvedType": "\"ai\" | \"brand\" | \"caution\" | \"guide\" | \"negative\" | \"neutral\" | \"positive\" | \"walkthrough\" | \"warning\"",
113
+ "attribute": "intent",
114
+ "default": "'brand'",
115
+ "required": false,
116
+ "mutable": false,
117
+ "description": "Semantic colour intent."
118
+ },
119
+ "isInactive": {
120
+ "type": "boolean",
121
+ "resolvedType": "boolean",
122
+ "attribute": "is-inactive",
123
+ "default": "false",
124
+ "required": false,
125
+ "mutable": false,
126
+ "description": "Disables interaction."
127
+ },
128
+ "isLoading": {
129
+ "type": "boolean",
130
+ "resolvedType": "boolean",
131
+ "attribute": "is-loading",
132
+ "default": "false",
133
+ "required": false,
134
+ "mutable": false,
135
+ "description": "Shows an inline loader and prevents interaction without applying inactive opacity."
136
+ },
137
+ "label": {
138
+ "type": "string",
139
+ "resolvedType": "string",
140
+ "attribute": "label",
141
+ "default": "''",
142
+ "required": false,
143
+ "mutable": false,
144
+ "description": "Visible text for `label` / `icon-label` variants."
145
+ },
146
+ "rounded": {
147
+ "type": "boolean",
148
+ "resolvedType": "boolean",
149
+ "attribute": "rounded",
150
+ "default": "false",
151
+ "required": false,
152
+ "mutable": false,
153
+ "description": "Use the half-radius treatment instead of the default control radius."
154
+ },
155
+ "size": {
156
+ "type": "ButtonFilledSize",
157
+ "resolvedType": "\"md\" | \"sm\" | \"xs\"",
158
+ "attribute": "size",
159
+ "default": "'md'",
160
+ "required": false,
161
+ "mutable": false,
162
+ "description": "Control density (height, padding, icon, type)."
163
+ },
164
+ "type": {
165
+ "type": "'button' | 'submit' | 'reset'",
166
+ "resolvedType": "\"button\" | \"reset\" | \"submit\"",
167
+ "attribute": "type",
168
+ "default": "'button'",
169
+ "required": false,
170
+ "mutable": false,
171
+ "description": "Native button type."
172
+ },
173
+ "variant": {
174
+ "type": "ButtonFilledVariant",
175
+ "resolvedType": "\"icon\" | \"icon-label\" | \"label\"",
176
+ "attribute": "variant",
177
+ "default": "'label'",
178
+ "required": false,
179
+ "mutable": false,
180
+ "description": "Content layout. Default is label-only; pass `icon` for icon-only chrome\n(nav / tool rails) or `icon-label` for leading icon + text."
181
+ },
182
+ "width": {
183
+ "type": "ButtonFilledWidth",
184
+ "resolvedType": "\"fill\" | \"hug\"",
185
+ "attribute": "width",
186
+ "default": "'hug'",
187
+ "required": false,
188
+ "mutable": false,
189
+ "description": "Width fit — hug content (default) or fill the parent."
190
+ }
191
+ },
192
+ "events": [
193
+ {
194
+ "name": "dsClick",
195
+ "detail": "MouseEvent",
196
+ "bubbles": true,
197
+ "cancelable": true,
198
+ "composed": true
199
+ }
200
+ ],
201
+ "methods": [
202
+ {
203
+ "name": "setFocus",
204
+ "signature": "setFocus() => Promise<void>"
205
+ }
206
+ ],
207
+ "slots": []
208
+ },
209
+ "props": {
210
+ "ariaLabel": {
211
+ "type": "string | null",
212
+ "resolvedType": "null | string",
213
+ "attribute": "aria-label",
214
+ "default": "null",
215
+ "required": false,
216
+ "mutable": false,
217
+ "description": "Accessible name override. Required for icon-only buttons."
218
+ },
219
+ "contrast": {
220
+ "type": "ButtonFilledContrast",
221
+ "resolvedType": "\"bold\" | \"faint\" | \"medium\" | \"strong\"",
222
+ "attribute": "contrast",
223
+ "default": "'bold'",
224
+ "required": false,
225
+ "mutable": false,
226
+ "description": "Background fill weight. Foreground uses the paired contrast token:\nbold → faint, strong → medium, medium → strong, faint → bold."
227
+ },
228
+ "icon": {
229
+ "type": "string",
230
+ "resolvedType": "string",
231
+ "attribute": "icon",
232
+ "default": "''",
233
+ "required": false,
234
+ "mutable": false,
235
+ "description": "Icon name passed to <ds-icon> for `icon` / `icon-label` variants."
236
+ },
237
+ "intent": {
238
+ "type": "ButtonFilledIntent",
239
+ "resolvedType": "\"ai\" | \"brand\" | \"caution\" | \"guide\" | \"negative\" | \"neutral\" | \"positive\" | \"walkthrough\" | \"warning\"",
240
+ "attribute": "intent",
241
+ "default": "'brand'",
242
+ "required": false,
243
+ "mutable": false,
244
+ "description": "Semantic colour intent."
245
+ },
246
+ "isInactive": {
247
+ "type": "boolean",
248
+ "resolvedType": "boolean",
249
+ "attribute": "is-inactive",
250
+ "default": "false",
251
+ "required": false,
252
+ "mutable": false,
253
+ "description": "Disables interaction."
254
+ },
255
+ "isLoading": {
256
+ "type": "boolean",
257
+ "resolvedType": "boolean",
258
+ "attribute": "is-loading",
259
+ "default": "false",
260
+ "required": false,
261
+ "mutable": false,
262
+ "description": "Shows an inline loader and prevents interaction without applying inactive opacity."
263
+ },
264
+ "label": {
265
+ "type": "string",
266
+ "resolvedType": "string",
267
+ "attribute": "label",
268
+ "default": "''",
269
+ "required": false,
270
+ "mutable": false,
271
+ "description": "Visible text for `label` / `icon-label` variants."
272
+ },
273
+ "rounded": {
274
+ "type": "boolean",
275
+ "resolvedType": "boolean",
276
+ "attribute": "rounded",
277
+ "default": "false",
278
+ "required": false,
279
+ "mutable": false,
280
+ "description": "Use the half-radius treatment instead of the default control radius."
281
+ },
282
+ "size": {
283
+ "type": "ButtonFilledSize",
284
+ "resolvedType": "\"md\" | \"sm\" | \"xs\"",
285
+ "attribute": "size",
286
+ "default": "'md'",
287
+ "required": false,
288
+ "mutable": false,
289
+ "description": "Control density (height, padding, icon, type)."
290
+ },
291
+ "type": {
292
+ "type": "'button' | 'submit' | 'reset'",
293
+ "resolvedType": "\"button\" | \"reset\" | \"submit\"",
294
+ "attribute": "type",
295
+ "default": "'button'",
296
+ "required": false,
297
+ "mutable": false,
298
+ "description": "Native button type."
299
+ },
300
+ "variant": {
301
+ "type": "ButtonFilledVariant",
302
+ "resolvedType": "\"icon\" | \"icon-label\" | \"label\"",
303
+ "attribute": "variant",
304
+ "default": "'label'",
305
+ "required": false,
306
+ "mutable": false,
307
+ "description": "Content layout. Default is label-only; pass `icon` for icon-only chrome\n(nav / tool rails) or `icon-label` for leading icon + text."
308
+ },
309
+ "width": {
310
+ "type": "ButtonFilledWidth",
311
+ "resolvedType": "\"fill\" | \"hug\"",
312
+ "attribute": "width",
313
+ "default": "'hug'",
314
+ "required": false,
315
+ "mutable": false,
316
+ "description": "Width fit — hug content (default) or fill the parent."
317
+ }
318
+ },
319
+ "events": [
320
+ {
321
+ "name": "dsClick",
322
+ "detail": "MouseEvent",
323
+ "bubbles": true,
324
+ "cancelable": true,
325
+ "composed": true
326
+ }
327
+ ],
328
+ "methods": [
329
+ {
330
+ "name": "setFocus",
331
+ "signature": "setFocus() => Promise<void>"
332
+ }
333
+ ],
334
+ "slots": [],
335
+ "exports": {
336
+ "customElement": "ds-button-filled",
337
+ "react": "DsButtonFilled",
338
+ "angular": "DsButtonFilled"
339
+ },
340
+ "consumption": {
341
+ "install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
342
+ "cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
343
+ "customElements": {
344
+ "import": "import '@ds-mo/ui/dist/components/ds-button-filled.js';",
345
+ "example": "<ds-button-filled></ds-button-filled>"
346
+ },
347
+ "react": {
348
+ "import": "import { DsButtonFilled } from '@ds-mo/ui/react';",
349
+ "example": "<DsButtonFilled />"
350
+ },
351
+ "angular": {
352
+ "import": "import { DsButtonFilled } from '@ds-mo/ui/angular/ds-button-filled';",
353
+ "example": "<ds-button-filled></ds-button-filled>"
354
+ },
355
+ "peerDependencies": {
356
+ "required": [
357
+ "@ds-mo/tokens ^3.1.1",
358
+ "@ds-mo/icons ^6.2.0"
359
+ ],
360
+ "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
361
+ }
362
+ }
363
+ },
364
+ "dependencies": [
365
+ "@ds-mo/ui",
366
+ "@ds-mo/tokens",
367
+ "@ds-mo/icons"
368
+ ],
369
+ "registryDependencies": [
370
+ "icon",
371
+ "loader",
372
+ "text"
373
+ ],
374
+ "files": [
375
+ {
376
+ "path": "src/wc/components/ButtonFilled/ButtonFilled.css",
377
+ "content": "@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n@import '../../utils/control-inactive.css';\n@import '../../utils/control-density.css';\n@import '../../utils/control-width.css';\n\n:host {\n display: inline-flex;\n outline: none;\n --ds-button-filled-bg: var(--color-background-bold-brand);\n --ds-button-filled-fg: var(--color-foreground-faint-brand);\n}\n\n/* Icon-only: fixed square from density height (hug). Fill stretches the hit target. */\n:host(.button-filled-host--icon.ds-control-width--hug) {\n width: var(--ds-control-height, var(--dimension-size-400));\n height: var(--ds-control-height, var(--dimension-size-400));\n min-width: var(--ds-control-height, var(--dimension-size-400));\n min-height: var(--ds-control-height, var(--dimension-size-400));\n}\n\n:host(.button-filled-host--icon.ds-control-width--fill) {\n height: var(--ds-control-height, var(--dimension-size-400));\n min-height: var(--ds-control-height, var(--dimension-size-400));\n}\n\n:host(.ds-control-width--fill) .button-filled {\n width: 100%;\n}\n\n.button-filled {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n height: var(--ds-control-height, var(--dimension-size-400));\n padding: 0 var(--ds-control-padding-inline, var(--dimension-space-075));\n gap: var(--ds-control-gap, var(--dimension-space-050));\n border: none;\n border-radius: var(--ds-control-radius, var(--dimension-radius-025));\n background-color: var(--ds-button-filled-bg);\n color: var(--ds-button-filled-fg);\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n overflow: hidden;\n transition:\n background-color var(--effect-motion-short-2),\n color var(--effect-motion-short-2),\n transform var(--effect-motion-short-2);\n /* Hover/press: `.ds-interaction-fill` + contrast → `--on-*` (token overlay, not color-mix). */\n}\n\n.button-filled--icon {\n width: 100%;\n height: 100%;\n padding: 0;\n}\n\n.button-filled--rounded {\n --ds-control-radius: var(--dimension-radius-half);\n}\n\n.button-filled:active:not(:disabled):not(.ds-control-inactive) {\n transform: scale(var(--dimension-scale-subtle));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .button-filled {\n transition:\n background-color var(--effect-motion-short-2),\n color var(--effect-motion-short-2);\n }\n\n .button-filled:active:not(:disabled):not(.ds-control-inactive) {\n transform: none;\n }\n}\n\n/* Inactive: `.ds-control-inactive` (25% opacity). */\n\n.button-filled__icon-wrap {\n position: relative;\n width: var(--ds-control-icon, var(--dimension-iconography-md));\n height: var(--ds-control-icon, var(--dimension-iconography-md));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 2;\n}\n\n.button-filled__label {\n position: relative;\n z-index: 2;\n padding: 0 var(--ds-control-label-inset, var(--dimension-space-025));\n white-space: nowrap;\n flex-shrink: 0;\n min-width: 0;\n}\n\n.button-filled__label--loading {\n visibility: hidden;\n}\n\n.button-filled > .button-filled__loader-overlay {\n position: absolute;\n inset: 0;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n}\n\n/* ── Intent + contrast (bold default) ─────────────────────────────────────── */\n\n.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-bold-neutral);\n --ds-button-filled-fg: var(--color-foreground-faint-neutral);\n}\n\n.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-bold-brand);\n --ds-button-filled-fg: var(--color-foreground-faint-brand);\n}\n\n.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-bold-ai);\n --ds-button-filled-fg: var(--color-foreground-faint-ai);\n}\n\n.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-bold-negative);\n --ds-button-filled-fg: var(--color-foreground-faint-negative);\n}\n\n.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-bold-warning);\n --ds-button-filled-fg: var(--color-foreground-faint-warning);\n}\n\n.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-bold-caution);\n --ds-button-filled-fg: var(--color-foreground-faint-caution);\n}\n\n.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-bold-positive);\n --ds-button-filled-fg: var(--color-foreground-faint-positive);\n}\n\n.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-bold-guide);\n --ds-button-filled-fg: var(--color-foreground-faint-guide);\n}\n\n.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-bold-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-faint-walkthrough);\n}\n\n/* strong → medium fg */\n.button-filled--contrast-strong.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-strong-neutral);\n --ds-button-filled-fg: var(--color-foreground-medium-neutral);\n}\n\n.button-filled--contrast-strong.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-strong-brand);\n --ds-button-filled-fg: var(--color-foreground-medium-brand);\n}\n\n.button-filled--contrast-strong.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-strong-ai);\n --ds-button-filled-fg: var(--color-foreground-medium-ai);\n}\n\n.button-filled--contrast-strong.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-strong-negative);\n --ds-button-filled-fg: var(--color-foreground-medium-negative);\n}\n\n.button-filled--contrast-strong.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-strong-warning);\n --ds-button-filled-fg: var(--color-foreground-medium-warning);\n}\n\n.button-filled--contrast-strong.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-strong-caution);\n --ds-button-filled-fg: var(--color-foreground-medium-caution);\n}\n\n.button-filled--contrast-strong.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-strong-positive);\n --ds-button-filled-fg: var(--color-foreground-medium-positive);\n}\n\n.button-filled--contrast-strong.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-strong-guide);\n --ds-button-filled-fg: var(--color-foreground-medium-guide);\n}\n\n.button-filled--contrast-strong.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-strong-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-medium-walkthrough);\n}\n\n/* medium → strong fg */\n.button-filled--contrast-medium.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-medium-neutral);\n --ds-button-filled-fg: var(--color-foreground-strong-neutral);\n}\n\n.button-filled--contrast-medium.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-medium-brand);\n --ds-button-filled-fg: var(--color-foreground-strong-brand);\n}\n\n.button-filled--contrast-medium.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-medium-ai);\n --ds-button-filled-fg: var(--color-foreground-strong-ai);\n}\n\n.button-filled--contrast-medium.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-medium-negative);\n --ds-button-filled-fg: var(--color-foreground-strong-negative);\n}\n\n.button-filled--contrast-medium.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-medium-warning);\n --ds-button-filled-fg: var(--color-foreground-strong-warning);\n}\n\n.button-filled--contrast-medium.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-medium-caution);\n --ds-button-filled-fg: var(--color-foreground-strong-caution);\n}\n\n.button-filled--contrast-medium.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-medium-positive);\n --ds-button-filled-fg: var(--color-foreground-strong-positive);\n}\n\n.button-filled--contrast-medium.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-medium-guide);\n --ds-button-filled-fg: var(--color-foreground-strong-guide);\n}\n\n.button-filled--contrast-medium.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-medium-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-strong-walkthrough);\n}\n\n/* faint → bold fg */\n.button-filled--contrast-faint.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-faint-neutral);\n --ds-button-filled-fg: var(--color-foreground-bold-neutral);\n}\n\n.button-filled--contrast-faint.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-faint-brand);\n --ds-button-filled-fg: var(--color-foreground-bold-brand);\n}\n\n.button-filled--contrast-faint.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-faint-ai);\n --ds-button-filled-fg: var(--color-foreground-bold-ai);\n}\n\n.button-filled--contrast-faint.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-faint-negative);\n --ds-button-filled-fg: var(--color-foreground-bold-negative);\n}\n\n.button-filled--contrast-faint.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-faint-warning);\n --ds-button-filled-fg: var(--color-foreground-bold-warning);\n}\n\n.button-filled--contrast-faint.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-faint-caution);\n --ds-button-filled-fg: var(--color-foreground-bold-caution);\n}\n\n.button-filled--contrast-faint.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-faint-positive);\n --ds-button-filled-fg: var(--color-foreground-bold-positive);\n}\n\n.button-filled--contrast-faint.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-faint-guide);\n --ds-button-filled-fg: var(--color-foreground-bold-guide);\n}\n\n.button-filled--contrast-faint.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-faint-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-bold-walkthrough);\n}\n",
378
+ "type": "registry:ui"
379
+ },
380
+ {
381
+ "path": "src/wc/components/ButtonFilled/ButtonFilled.tsx",
382
+ "content": "import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';\nimport { controlWidthClass, CONTROL_TEXT_VARIANT, type ControlWidth } from '../../utils';\n\nexport type ButtonFilledIntent =\n | 'neutral'\n | 'brand'\n | 'ai'\n | 'negative'\n | 'warning'\n | 'caution'\n | 'positive'\n | 'guide'\n | 'walkthrough';\n\nexport type ButtonFilledContrast = 'bold' | 'strong' | 'medium' | 'faint';\n\nexport type ButtonFilledVariant = 'icon' | 'label' | 'icon-label';\n\nexport type ButtonFilledSize = 'md' | 'sm' | 'xs';\n\nexport type ButtonFilledWidth = ControlWidth;\n\n/**\n * `ds-icon` size prop matching control-density icon metrics\n * (md→20 / sm→16 / xs→12 via `--dimension-iconography-*`).\n */\nconst ICON_SIZE: Record<ButtonFilledSize, 'md' | 'sm' | 'xs'> = {\n md: 'md',\n sm: 'sm',\n xs: 'xs',\n};\n\n@Component({\n tag: 'ds-button-filled',\n styleUrl: 'ButtonFilled.css',\n scoped: true,\n})\nexport class ButtonFilled {\n @Element() el!: HTMLElement;\n\n /**\n * Content layout. Default is label-only; pass `icon` for icon-only chrome\n * (nav / tool rails) or `icon-label` for leading icon + text.\n */\n @Prop() variant: ButtonFilledVariant = 'label';\n\n /** Control density (height, padding, icon, type). */\n @Prop() size: ButtonFilledSize = 'md';\n\n /** Width fit — hug content (default) or fill the parent. */\n @Prop() width: ButtonFilledWidth = 'hug';\n\n /** Visible text for `label` / `icon-label` variants. */\n @Prop() label: string = '';\n\n /** Icon name passed to <ds-icon> for `icon` / `icon-label` variants. */\n @Prop() icon: string = '';\n\n /** Semantic colour intent. */\n @Prop() intent: ButtonFilledIntent = 'brand';\n\n /**\n * Background fill weight. Foreground uses the paired contrast token:\n * bold → faint, strong → medium, medium → strong, faint → bold.\n */\n @Prop() contrast: ButtonFilledContrast = 'bold';\n\n /** Use the half-radius treatment instead of the default control radius. */\n @Prop() rounded: boolean = false;\n\n /** Disables interaction. */\n @Prop() isInactive: boolean = false;\n\n /** Shows an inline loader and prevents interaction without applying inactive opacity. */\n @Prop() isLoading: boolean = false;\n\n /** Native button type. */\n @Prop() type: 'button' | 'submit' | 'reset' = 'button';\n\n /** Accessible name override. Required for icon-only buttons. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n\n @Event() dsClick!: EventEmitter<MouseEvent>;\n\n private buttonEl: HTMLButtonElement | null = null;\n\n @Method()\n async setFocus() {\n this.buttonEl?.focus();\n }\n\n private handleClick = (event: MouseEvent) => {\n if (this.isInactive || this.isLoading) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.dsClick.emit(event);\n };\n\n private get showIcon(): boolean {\n return this.variant === 'icon' || this.variant === 'icon-label';\n }\n\n private get showLabel(): boolean {\n return this.variant === 'label' || this.variant === 'icon-label';\n }\n\n private get accessibleName(): string | undefined {\n if (this.ariaLabel) return this.ariaLabel;\n if (this.isLoading && this.variant === 'label' && this.label) return this.label;\n return undefined;\n }\n\n render() {\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const iconSize = ICON_SIZE[this.size];\n\n const cls: Record<string, boolean> = {\n 'button-filled': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': !this.isInactive,\n /* Bold is the default filled contrast — on-bold interaction tokens. */\n 'ds-interaction-fill--on-bold': this.contrast === 'bold',\n 'ds-interaction-fill--on-strong': this.contrast === 'strong',\n 'ds-interaction-fill--on-medium': this.contrast === 'medium',\n /* faint → default app interaction tokens (no --on-*). */\n 'ds-control-inactive': this.isInactive,\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n 'button-filled--icon': this.variant === 'icon',\n 'button-filled--label': this.variant === 'label',\n 'button-filled--icon-label': this.variant === 'icon-label',\n 'button-filled--rounded': this.rounded,\n [`button-filled--intent-${this.intent}`]: true,\n [`button-filled--contrast-${this.contrast}`]: this.contrast !== 'bold',\n };\n\n return (\n <Host\n class={{\n 'button-filled-host': true,\n 'button-filled-host--icon': this.variant === 'icon',\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n ...controlWidthClass(this.width),\n }}\n tabIndex={-1}\n >\n <button\n ref={el => {\n this.buttonEl = el ?? null;\n }}\n type={this.type}\n class={cls}\n disabled={this.isInactive}\n aria-label={this.accessibleName}\n aria-busy={this.isLoading ? 'true' : undefined}\n aria-disabled={this.isLoading ? 'true' : undefined}\n onClick={this.handleClick}\n >\n {this.showIcon && (\n <span class=\"button-filled__icon-wrap ds-interaction-fill__content\">\n {this.isLoading\n ? <ds-loader size={iconSize} color=\"inherit\" />\n : <ds-icon name={this.icon} size={iconSize} color=\"inherit\" />\n }\n </span>\n )}\n {this.showLabel && (\n <ds-text\n class={{\n 'button-filled__label': true,\n 'button-filled__label--loading': this.isLoading && this.variant === 'label',\n 'ds-interaction-fill__content': true,\n }}\n as=\"span\"\n variant={textVariant}\n emphasis\n color=\"inherit\"\n >\n {this.label}\n </ds-text>\n )}\n {this.isLoading && this.variant === 'label' && (\n <span class=\"button-filled__loader-overlay ds-interaction-fill__content\">\n <ds-loader size={iconSize} color=\"inherit\" />\n </span>\n )}\n </button>\n </Host>\n );\n }\n}\n",
383
+ "type": "registry:ui"
384
+ }
385
+ ]
386
+ }