@ds-mo/ui 2.11.2 → 2.12.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 (226) hide show
  1. package/README.md +13 -13
  2. package/dist/.build-stamp +1 -1
  3. package/dist/components/ds-app-shell.js +1 -1
  4. package/dist/components/ds-banner.js +1 -1
  5. package/dist/components/ds-banner.js.map +1 -1
  6. package/dist/components/ds-bar-nav.js +1 -1
  7. package/dist/components/ds-bar-nav.js.map +1 -1
  8. package/dist/components/ds-button-filled.js +1 -1
  9. package/dist/components/{ds-accordion.d.ts → ds-button-unfilled.d.ts} +4 -4
  10. package/dist/components/ds-button-unfilled.js +2 -0
  11. package/dist/components/ds-card-data-viz.js +1 -1
  12. package/dist/components/ds-card-data-viz.js.map +1 -1
  13. package/dist/components/ds-card-setting.js +1 -1
  14. package/dist/components/ds-card-setting.js.map +1 -1
  15. package/dist/components/ds-chart-bar.js +1 -1
  16. package/dist/components/ds-chart-bar.js.map +1 -1
  17. package/dist/components/ds-chart-donut.js +1 -1
  18. package/dist/components/ds-chart-donut.js.map +1 -1
  19. package/dist/components/ds-chart-legend.js +1 -1
  20. package/dist/components/ds-chart-legend.js.map +1 -1
  21. package/dist/components/ds-chart-line.js +1 -1
  22. package/dist/components/ds-checkbox.js +1 -1
  23. package/dist/components/ds-checkbox.js.map +1 -1
  24. package/dist/components/ds-chip.js +1 -1
  25. package/dist/components/ds-chip.js.map +1 -1
  26. package/dist/components/ds-divider.js +1 -1
  27. package/dist/components/ds-empty-state.js +1 -1
  28. package/dist/components/ds-empty-state.js.map +1 -1
  29. package/dist/components/ds-field.js +1 -1
  30. package/dist/components/ds-field.js.map +1 -1
  31. package/dist/components/ds-header.js +1 -1
  32. package/dist/components/ds-header.js.map +1 -1
  33. package/dist/components/ds-icon.js +1 -1
  34. package/dist/components/ds-input.js +1 -1
  35. package/dist/components/ds-input.js.map +1 -1
  36. package/dist/components/ds-loader.js +1 -1
  37. package/dist/components/ds-loader.js.map +1 -1
  38. package/dist/components/ds-menu.js +1 -1
  39. package/dist/components/ds-modal.js +1 -1
  40. package/dist/components/ds-pagination.js +1 -1
  41. package/dist/components/ds-pagination.js.map +1 -1
  42. package/dist/components/ds-panel-nav.js +1 -1
  43. package/dist/components/ds-panel-nav.js.map +1 -1
  44. package/dist/components/ds-panel-tools.js +1 -1
  45. package/dist/components/ds-panel-tools.js.map +1 -1
  46. package/dist/components/ds-radio-group.js +1 -1
  47. package/dist/components/ds-radio-group.js.map +1 -1
  48. package/dist/components/ds-scrollbar.js +1 -1
  49. package/dist/components/ds-select.js +1 -1
  50. package/dist/components/ds-select.js.map +1 -1
  51. package/dist/components/ds-shell-gradient-picker.js +1 -1
  52. package/dist/components/ds-shell-gradient-swatch.js +1 -1
  53. package/dist/components/ds-skeleton.js +1 -1
  54. package/dist/components/ds-skeleton.js.map +1 -1
  55. package/dist/components/ds-slider.js +1 -1
  56. package/dist/components/ds-slider.js.map +1 -1
  57. package/dist/components/ds-tab-group-nav.js +1 -1
  58. package/dist/components/ds-tab-group.js +1 -1
  59. package/dist/components/ds-tab-group.js.map +1 -1
  60. package/dist/components/ds-table.js +1 -1
  61. package/dist/components/ds-table.js.map +1 -1
  62. package/dist/components/ds-tag.js +1 -1
  63. package/dist/components/ds-tag.js.map +1 -1
  64. package/dist/components/ds-text.js +1 -1
  65. package/dist/components/ds-toggle.js +1 -1
  66. package/dist/components/ds-toggle.js.map +1 -1
  67. package/dist/components/ds-tooltip-data-viz.js +1 -1
  68. package/dist/components/ds-tooltip-data-viz.js.map +1 -1
  69. package/dist/components/ds-tooltip.js +1 -1
  70. package/dist/components/ds-tooltip.js.map +1 -1
  71. package/dist/components/p-B9dHCgY-.js +2 -0
  72. package/dist/components/p-B9dHCgY-.js.map +1 -0
  73. package/dist/components/p-BPK76IsW.js +2 -0
  74. package/dist/components/p-BPK76IsW.js.map +1 -0
  75. package/dist/components/p-BQq26pt9.js.map +1 -1
  76. package/dist/components/p-BTC9Njj6.js +2 -0
  77. package/dist/components/p-BTC9Njj6.js.map +1 -0
  78. package/dist/components/p-BZIOTcnM.js +2 -0
  79. package/dist/components/p-BZIOTcnM.js.map +1 -0
  80. package/dist/components/{p-DdFUTZ3y.js → p-C3ORQUOp.js} +2 -2
  81. package/dist/components/{p-8Nt92j1-.js → p-CyFVn2Sc.js} +2 -2
  82. package/dist/components/p-DKdI8T8v.js +2 -0
  83. package/dist/components/p-DKdI8T8v.js.map +1 -0
  84. package/dist/components/{p-DOU4cbpc.js → p-DRqxVEye.js} +2 -2
  85. package/dist/components/p-DkcH8mRl.js +2 -0
  86. package/dist/components/p-DkcH8mRl.js.map +1 -0
  87. package/dist/components/p-DusYu-if.js +2 -0
  88. package/dist/components/p-DusYu-if.js.map +1 -0
  89. package/dist/components/p-EK1hOP19.js.map +1 -1
  90. package/dist/components/p-UbKTMQjv.js +2 -0
  91. package/dist/components/p-UbKTMQjv.js.map +1 -0
  92. package/dist/lib/nav/index.js +3 -0
  93. package/dist/lib/nav/index.js.map +2 -2
  94. package/dist/lib/utils/index.js +6 -0
  95. package/dist/lib/utils/index.js.map +2 -2
  96. package/dist/lib/utils/token-defaults.d.ts +3 -0
  97. package/dist/types/components/ButtonFilled/ButtonFilled.d.ts +17 -3
  98. package/dist/types/components/ButtonFilled/index.d.ts +1 -1
  99. package/dist/types/components/ButtonUnfilled/ButtonUnfilled.d.ts +66 -0
  100. package/dist/types/components/ButtonUnfilled/index.d.ts +2 -0
  101. package/dist/types/components/CardDataViz/CardDataViz.d.ts +1 -1
  102. package/dist/types/components/CardSetting/CardSetting.d.ts +1 -1
  103. package/dist/types/components/ChartDonut/ChartDonut.d.ts +7 -0
  104. package/dist/types/components/Checkbox/Checkbox.d.ts +1 -1
  105. package/dist/types/components/Chip/Chip.d.ts +18 -14
  106. package/dist/types/components/Chip/index.d.ts +1 -1
  107. package/dist/types/components/Input/Input.d.ts +1 -1
  108. package/dist/types/components/Pagination/Pagination.d.ts +1 -1
  109. package/dist/types/components/PanelNav/PanelNav.d.ts +2 -0
  110. package/dist/types/components/PanelTools/panel-tools-types.d.ts +1 -1
  111. package/dist/types/components/RadioGroup/RadioGroup.d.ts +2 -2
  112. package/dist/types/components/Select/Select.d.ts +2 -2
  113. package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +1 -1
  114. package/dist/types/components/Slider/Slider.d.ts +1 -1
  115. package/dist/types/components/TabGroup/TabGroup.d.ts +1 -1
  116. package/dist/types/components/TabGroup/tab-item-utils.d.ts +2 -1
  117. package/dist/types/components/TabGroupNav/TabGroupNav.d.ts +1 -1
  118. package/dist/types/components/Tag/Tag.d.ts +0 -2
  119. package/dist/types/components/Tag/index.d.ts +1 -1
  120. package/dist/types/components/Toggle/Toggle.d.ts +1 -1
  121. package/dist/types/components/Tooltip/Tooltip.d.ts +25 -6
  122. package/dist/types/components/TooltipDataViz/TooltipDataViz.d.ts +18 -0
  123. package/dist/types/components.d.ts +277 -476
  124. package/dist/types/utils/token-defaults.d.ts +3 -0
  125. package/package.json +6 -3
  126. package/src/angular/index.ts +1 -6
  127. package/src/angular/proxies.ts +33 -170
  128. package/src/react/components.ts +1 -6
  129. package/src/react/ds-button-unfilled.ts +33 -0
  130. package/src/react/ds-chip.ts +2 -10
  131. package/src/wc/components/BarNav/BarNav.tsx +3 -2
  132. package/src/wc/components/BarNav/bar-nav-tabs-menu-utils.ts +1 -1
  133. package/src/wc/components/ButtonFilled/ButtonFilled.tsx +90 -11
  134. package/src/wc/components/ButtonFilled/index.ts +6 -1
  135. package/src/wc/components/ButtonUnfilled/ButtonUnfilled.tsx +223 -0
  136. package/src/wc/components/ButtonUnfilled/index.ts +6 -0
  137. package/src/wc/components/CardDataViz/CardDataViz.tsx +1 -2
  138. package/src/wc/components/CardSetting/CardSetting.tsx +4 -6
  139. package/src/wc/components/ChartDonut/ChartDonut.tsx +50 -3
  140. package/src/wc/components/ChartLegend/ChartLegend.tsx +3 -0
  141. package/src/wc/components/Checkbox/Checkbox.tsx +5 -5
  142. package/src/wc/components/Chip/Chip.tsx +50 -67
  143. package/src/wc/components/Chip/index.ts +1 -1
  144. package/src/wc/components/Input/Input.tsx +4 -4
  145. package/src/wc/components/Menu/Menu.tsx +7 -4
  146. package/src/wc/components/Pagination/Pagination.tsx +6 -6
  147. package/src/wc/components/PanelNav/PanelNav.tsx +77 -48
  148. package/src/wc/components/PanelTools/PanelTools.tsx +19 -16
  149. package/src/wc/components/PanelTools/panel-tools-types.ts +1 -1
  150. package/src/wc/components/PanelTools/panel-tools-utils.ts +1 -1
  151. package/src/wc/components/RadioGroup/RadioGroup.tsx +7 -7
  152. package/src/wc/components/Select/Select.tsx +5 -5
  153. package/src/wc/components/ShellGradientSwatch/ShellGradientSwatch.tsx +4 -3
  154. package/src/wc/components/Slider/Slider.tsx +7 -3
  155. package/src/wc/components/TabGroup/TabGroup.tsx +13 -7
  156. package/src/wc/components/TabGroup/tab-item-utils.ts +2 -1
  157. package/src/wc/components/TabGroupNav/TabGroupNav.tsx +14 -13
  158. package/src/wc/components/Tag/Tag.tsx +25 -24
  159. package/src/wc/components/Tag/index.ts +1 -1
  160. package/src/wc/components/Toggle/Toggle.tsx +6 -6
  161. package/src/wc/components/Tooltip/Tooltip.tsx +166 -64
  162. package/src/wc/components/TooltipDataViz/TooltipDataViz.tsx +57 -2
  163. package/src/wc/components.d.ts +277 -476
  164. package/src/wc/utils/control-density.css +42 -0
  165. package/src/wc/utils/control-inactive.css +20 -0
  166. package/src/wc/utils/interaction-fill.css +162 -0
  167. package/src/wc/utils/scroll-edge-fade.css +5 -0
  168. package/src/wc/utils/token-defaults.ts +6 -0
  169. package/dist/components/ds-accordion.js +0 -2
  170. package/dist/components/ds-accordion.js.map +0 -1
  171. package/dist/components/ds-breadcrumb.d.ts +0 -11
  172. package/dist/components/ds-breadcrumb.js +0 -2
  173. package/dist/components/ds-breadcrumb.js.map +0 -1
  174. package/dist/components/ds-button-unfilled-icon.d.ts +0 -11
  175. package/dist/components/ds-button-unfilled-icon.js +0 -2
  176. package/dist/components/ds-fade.d.ts +0 -11
  177. package/dist/components/ds-fade.js +0 -2
  178. package/dist/components/ds-fade.js.map +0 -1
  179. package/dist/components/ds-surface.d.ts +0 -11
  180. package/dist/components/ds-surface.js +0 -2
  181. package/dist/components/ds-surface.js.map +0 -1
  182. package/dist/components/ds-toast-provider.d.ts +0 -11
  183. package/dist/components/ds-toast-provider.js +0 -2
  184. package/dist/components/ds-toast-provider.js.map +0 -1
  185. package/dist/components/p-BMQbEIrQ.js +0 -2
  186. package/dist/components/p-BMQbEIrQ.js.map +0 -1
  187. package/dist/components/p-BSFgy5r6.js +0 -2
  188. package/dist/components/p-BSFgy5r6.js.map +0 -1
  189. package/dist/components/p-CBUIn8dk.js +0 -2
  190. package/dist/components/p-CBUIn8dk.js.map +0 -1
  191. package/dist/components/p-ChVwCVHy.js +0 -2
  192. package/dist/components/p-ChVwCVHy.js.map +0 -1
  193. package/dist/components/p-CpNIQXz6.js +0 -2
  194. package/dist/components/p-CpNIQXz6.js.map +0 -1
  195. package/dist/components/p-CvgHQfvT.js +0 -2
  196. package/dist/components/p-CvgHQfvT.js.map +0 -1
  197. package/dist/components/p-bDf6yBQd.js +0 -2
  198. package/dist/components/p-bDf6yBQd.js.map +0 -1
  199. package/dist/types/components/Accordion/Accordion.d.ts +0 -28
  200. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +0 -16
  201. package/dist/types/components/ButtonUnfilledIcon/ButtonUnfilledIcon.d.ts +0 -45
  202. package/dist/types/components/ButtonUnfilledIcon/index.d.ts +0 -2
  203. package/dist/types/components/Fade/Fade.d.ts +0 -22
  204. package/dist/types/components/Fade/index.d.ts +0 -2
  205. package/dist/types/components/Surface/Surface.d.ts +0 -22
  206. package/dist/types/components/Toast/Toast.d.ts +0 -16
  207. package/dist/types/components/Toast/toast-service.d.ts +0 -24
  208. package/src/react/ds-accordion.ts +0 -27
  209. package/src/react/ds-breadcrumb.ts +0 -27
  210. package/src/react/ds-button-unfilled-icon.ts +0 -33
  211. package/src/react/ds-fade.ts +0 -26
  212. package/src/react/ds-surface.ts +0 -26
  213. package/src/react/ds-toast-provider.ts +0 -26
  214. package/src/wc/components/Accordion/Accordion.tsx +0 -144
  215. package/src/wc/components/Breadcrumb/Breadcrumb.tsx +0 -61
  216. package/src/wc/components/ButtonUnfilledIcon/ButtonUnfilledIcon.tsx +0 -129
  217. package/src/wc/components/ButtonUnfilledIcon/index.ts +0 -1
  218. package/src/wc/components/Fade/Fade.tsx +0 -58
  219. package/src/wc/components/Fade/index.ts +0 -1
  220. package/src/wc/components/Surface/Surface.tsx +0 -81
  221. package/src/wc/components/Toast/Toast.tsx +0 -179
  222. package/src/wc/components/Toast/toast-service.ts +0 -67
  223. /package/dist/components/{ds-button-unfilled-icon.js.map → ds-button-unfilled.js.map} +0 -0
  224. /package/dist/components/{p-DdFUTZ3y.js.map → p-C3ORQUOp.js.map} +0 -0
  225. /package/dist/components/{p-8Nt92j1-.js.map → p-CyFVn2Sc.js.map} +0 -0
  226. /package/dist/components/{p-DOU4cbpc.js.map → p-DRqxVEye.js.map} +0 -0
@@ -1,144 +0,0 @@
1
- import { Component, Prop, State, Event, EventEmitter, Element, Watch, h, Host } from '@stencil/core';
2
-
3
- export interface AccordionItemData {
4
- id: string;
5
- label: string;
6
- content?: string;
7
- inactive?: boolean;
8
- }
9
-
10
- let idCounter = 0;
11
-
12
- @Component({
13
- tag: 'ds-accordion',
14
- styleUrl: 'Accordion.css',
15
- scoped: true,
16
- })
17
- export class Accordion {
18
- @Element() el!: HTMLElement;
19
-
20
- @Prop() items: AccordionItemData[] = [];
21
- @Prop() multiple: boolean = false;
22
- /** Comma-separated list of expanded item IDs for controlled mode. */
23
- @Prop({ mutable: true }) expandedIds: string = '';
24
-
25
- @State() private internalIds: string[] = [];
26
- @State() private heights: Record<string, number> = {};
27
-
28
- @Event() dsExpandedChange!: EventEmitter<string[]>;
29
-
30
- private instanceId = ++idCounter;
31
- private resizeObservers: Map<string, ResizeObserver> = new Map();
32
-
33
- private get activeIds(): string[] {
34
- if (this.expandedIds) return this.expandedIds.split(',').map(s => s.trim()).filter(Boolean);
35
- return this.internalIds;
36
- }
37
-
38
- componentDidLoad() {
39
- this.bindResizeObservers();
40
- }
41
-
42
- disconnectedCallback() {
43
- this.resizeObservers.forEach(ro => ro.disconnect());
44
- this.resizeObservers.clear();
45
- }
46
-
47
- @Watch('items')
48
- onItemsChange() {
49
- requestAnimationFrame(() => {
50
- this.bindResizeObservers();
51
- this.measureAll();
52
- });
53
- }
54
-
55
- private bindResizeObservers() {
56
- this.resizeObservers.forEach(ro => ro.disconnect());
57
- this.resizeObservers.clear();
58
-
59
- this.items.forEach(item => {
60
- const inner = this.el.querySelector(`[data-inner="${item.id}"]`) as HTMLElement | null;
61
- if (!inner) return;
62
- const ro = new ResizeObserver(() => {
63
- this.heights = { ...this.heights, [item.id]: inner.scrollHeight };
64
- });
65
- ro.observe(inner);
66
- this.resizeObservers.set(item.id, ro);
67
- });
68
- }
69
-
70
- private measureAll() {
71
- const next: Record<string, number> = { ...this.heights };
72
- this.items.forEach(item => {
73
- const inner = this.el.querySelector(`[data-inner="${item.id}"]`) as HTMLElement | null;
74
- if (inner) next[item.id] = inner.scrollHeight;
75
- });
76
- this.heights = next;
77
- }
78
-
79
- private toggle(id: string) {
80
- const current = this.activeIds;
81
- let next: string[];
82
- if (current.includes(id)) {
83
- next = current.filter(x => x !== id);
84
- } else {
85
- next = this.multiple ? [...current, id] : [id];
86
- }
87
- this.internalIds = next;
88
- this.dsExpandedChange.emit(next);
89
- }
90
-
91
- render() {
92
- const activeIds = this.activeIds;
93
-
94
- return (
95
- <Host class="accordion">
96
- {this.items.map(item => {
97
- const isExpanded = activeIds.includes(item.id);
98
- const triggerId = `ds-accordion-${this.instanceId}-trigger-${item.id}`;
99
- const panelId = `ds-accordion-${this.instanceId}-panel-${item.id}`;
100
- const bodyHeight = this.heights[item.id] ?? 0;
101
-
102
- return (
103
- <div
104
- key={item.id}
105
- class={{ item: true, 'item--inactive': !!item.inactive }}
106
- >
107
- <button
108
- type="button"
109
- id={triggerId}
110
- class="trigger"
111
- onClick={() => !item.inactive && this.toggle(item.id)}
112
- aria-expanded={isExpanded}
113
- aria-controls={panelId}
114
- aria-disabled={item.inactive || undefined}
115
- tabIndex={item.inactive ? -1 : 0}
116
- >
117
- <span class="text-body-medium-emphasis">{item.label}</span>
118
- <span
119
- class={{ chevron: true, 'chevron--open': isExpanded }}
120
- aria-hidden="true"
121
- >&#x203A;</span>
122
- </button>
123
- <div
124
- id={panelId}
125
- role="region"
126
- aria-labelledby={triggerId}
127
- class="body"
128
- style={{ height: isExpanded ? `${bodyHeight}px` : '0' }}
129
- aria-hidden={!isExpanded}
130
- >
131
- <div class="body-inner" data-inner={item.id}>
132
- {item.content
133
- ? <span class="text-body-medium">{item.content}</span>
134
- : <slot name={item.id} />
135
- }
136
- </div>
137
- </div>
138
- </div>
139
- );
140
- })}
141
- </Host>
142
- );
143
- }
144
- }
@@ -1,61 +0,0 @@
1
- import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
2
-
3
- export interface BreadcrumbItem {
4
- label: string;
5
- href?: string;
6
- }
7
-
8
- @Component({
9
- tag: 'ds-breadcrumb',
10
- styleUrl: 'Breadcrumb.css',
11
- scoped: true,
12
- })
13
- export class Breadcrumb {
14
- @Prop() items: BreadcrumbItem[] = [];
15
- @Prop() separator: string = '/';
16
-
17
- @Event() dsNavigate!: EventEmitter<{ item: BreadcrumbItem; index: number }>;
18
-
19
- private handleClick(item: BreadcrumbItem, index: number, e: MouseEvent) {
20
- if (!item.href) {
21
- e.preventDefault();
22
- }
23
- this.dsNavigate.emit({ item, index });
24
- }
25
-
26
- render() {
27
- return (
28
- <Host>
29
- <nav aria-label="Breadcrumb" class="breadcrumb">
30
- <ol class="list">
31
- {this.items.map((item, i) => {
32
- const isLast = i === this.items.length - 1;
33
- return (
34
- <li class="item" key={i}>
35
- {isLast ? (
36
- <span class="text-body-medium-emphasis current" aria-current="page">
37
- {item.label}
38
- </span>
39
- ) : (
40
- <span class="item-inner">
41
- <a
42
- href={item.href ?? '#'}
43
- class="link text-body-medium"
44
- onClick={e => this.handleClick(item, i, e)}
45
- >
46
- {item.label}
47
- </a>
48
- <span class="separator text-body-small" aria-hidden="true">
49
- {this.separator}
50
- </span>
51
- </span>
52
- )}
53
- </li>
54
- );
55
- })}
56
- </ol>
57
- </nav>
58
- </Host>
59
- );
60
- }
61
- }
@@ -1,129 +0,0 @@
1
- import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';
2
-
3
- export type ButtonUnfilledIconOnBackgroundContrast = 'default' | 'medium' | 'bold' | 'strong';
4
-
5
- export type ButtonUnfilledIconBackground = 'always-dark' | 'navigation';
6
-
7
- @Component({
8
- tag: 'ds-button-unfilled-icon',
9
- styleUrl: 'ButtonUnfilledIcon.css',
10
- scoped: true,
11
- })
12
- export class ButtonUnfilledIcon {
13
- @Element() el!: HTMLElement;
14
-
15
- /** Icon name passed to <ds-icon>. */
16
- @Prop() icon: string = '';
17
-
18
- /** Active/selected visual state. */
19
- @Prop() isActive: boolean = false;
20
-
21
- /** When active, render the active interaction fill. Shell chrome can disable this while keeping active icon colour. */
22
- @Prop() activeFill: boolean = true;
23
-
24
- /** Show a 1px tertiary border without changing the interaction model. */
25
- @Prop() hasBorder: boolean = false;
26
-
27
- /** Show a notification dot at the top-right of the icon zone. */
28
- @Prop() dot: boolean = false;
29
-
30
- /** Disables interaction. */
31
- @Prop() inactive: boolean = false;
32
-
33
- /** Native button type. */
34
- @Prop() type: 'button' | 'submit' | 'reset' = 'button';
35
-
36
- /**
37
- * Foreground and interaction tokens when the button sits on a contrasting parent
38
- * background (default, medium, bold, or strong).
39
- */
40
- @Prop({ attribute: 'on-background-contrast' })
41
- backgroundContrast?: ButtonUnfilledIconOnBackgroundContrast;
42
-
43
- /** Parent surface context for navigation and always-dark chrome. */
44
- @Prop() background: ButtonUnfilledIconBackground | undefined;
45
-
46
- @Prop({ attribute: 'aria-label' }) ariaLabel: string = 'action';
47
- @Prop() controls: string | undefined;
48
- @Prop() expanded: boolean | undefined;
49
- @Prop() haspopup: string | undefined;
50
- @Prop() pressed: boolean | undefined;
51
-
52
- /**
53
- * Native `tabindex` for roving keyboard groups in shell chrome.
54
- * Omit for the default button tab stop (`0`).
55
- */
56
- @Prop({ attribute: 'tab-index' }) focusTabIndex?: number;
57
-
58
- @Event() dsClick!: EventEmitter<MouseEvent>;
59
- @Event() dsChange!: EventEmitter<boolean>;
60
-
61
- private buttonEl: HTMLButtonElement | null = null;
62
-
63
- @Method()
64
- async setFocus() {
65
- this.buttonEl?.focus();
66
- }
67
-
68
- private handleClick = (event: MouseEvent) => {
69
- if (this.inactive) return;
70
- this.dsClick.emit(event);
71
- this.dsChange.emit(!this.isActive);
72
- };
73
-
74
- private effectiveContrast(): ButtonUnfilledIconOnBackgroundContrast {
75
- return this.backgroundContrast ?? 'default';
76
- }
77
-
78
- render() {
79
- const bg = this.background;
80
- const contrast = this.effectiveContrast();
81
-
82
- const cls: Record<string, boolean> = {
83
- 'button-icon': true,
84
- 'ds-focus-ring-inset': true,
85
- 'button-icon--active': this.isActive,
86
- 'button-icon--active-fill': this.isActive && this.activeFill,
87
- 'button-icon--bordered': this.hasBorder,
88
- 'button-icon--inactive': this.inactive,
89
- 'button-icon--contrast-medium': contrast === 'medium',
90
- 'button-icon--contrast-bold': contrast === 'bold',
91
- 'button-icon--contrast-strong': contrast === 'strong',
92
- 'button-icon--on-always-dark': bg === 'always-dark',
93
- 'button-icon--on-navigation': bg === 'navigation',
94
- };
95
-
96
- return (
97
- <Host tabIndex={-1}>
98
- <button
99
- ref={el => {
100
- this.buttonEl = el ?? null;
101
- }}
102
- type={this.type}
103
- class={cls}
104
- disabled={this.inactive}
105
- tabIndex={this.focusTabIndex ?? 0}
106
- aria-label={this.ariaLabel}
107
- aria-controls={this.controls}
108
- aria-expanded={this.expanded === undefined ? undefined : String(this.expanded)}
109
- aria-haspopup={this.haspopup}
110
- aria-pressed={this.pressed === undefined ? undefined : String(this.pressed)}
111
- onClick={this.handleClick}
112
- >
113
- <span class="button-icon__icon-wrap">
114
- <ds-icon name={this.icon} size="md" color="inherit" />
115
- {this.dot && (
116
- <ds-badge
117
- class="button-icon__dot"
118
- variant="dot"
119
- background="var(--ds-button-unfilled-icon-dot-ring)"
120
- label=""
121
- aria-hidden="true"
122
- />
123
- )}
124
- </span>
125
- </button>
126
- </Host>
127
- );
128
- }
129
- }
@@ -1 +0,0 @@
1
- export type { ButtonUnfilledIconBackground, ButtonUnfilledIconOnBackgroundContrast } from './ButtonUnfilledIcon';
@@ -1,58 +0,0 @@
1
- import { Component, Prop, h, Host } from '@stencil/core';
2
- import {
3
- scrollEdgeFadeClassMap,
4
- scrollEdgeFadeSizeStyle,
5
- type ScrollEdgeFadeEdge,
6
- type ScrollEdgeFadeSize,
7
- type ScrollEdgeFadeSizeToken,
8
- } from '../../utils/scroll-edge-fade';
9
-
10
- /** @deprecated Use `ScrollEdgeFadeEdge` from `@ds-mo/ui/utils`. */
11
- export type FadeSide = ScrollEdgeFadeEdge;
12
-
13
- /** @deprecated Use `ScrollEdgeFadeSizeToken` from `@ds-mo/ui/utils`. */
14
- export type FadeSizeToken = ScrollEdgeFadeSizeToken;
15
-
16
- /** @deprecated Use `ScrollEdgeFadeSize` from `@ds-mo/ui/utils`. */
17
- export type FadeSize = ScrollEdgeFadeSize;
18
-
19
- @Component({
20
- tag: 'ds-fade',
21
- styleUrl: 'Fade.css',
22
- scoped: true,
23
- })
24
- export class Fade {
25
- /** Edge where content fades as it approaches the scroll boundary. */
26
- @Prop() side: FadeSide = 'bottom';
27
-
28
- /** Fade depth along the fade axis. Accepts dimension size token names or any CSS length. */
29
- @Prop() size: FadeSize = 'size-600';
30
-
31
- /**
32
- * Deprecated alias for size. Kept for existing consumers that pass a raw CSS length.
33
- * Prefer `size`.
34
- */
35
- @Prop() height: string | undefined;
36
-
37
- /** Controls the mask without removing the scroll container from layout. */
38
- @Prop() visible: boolean = true;
39
-
40
- render() {
41
- return (
42
- <Host>
43
- <div
44
- class={{
45
- 'fade__scroll': true,
46
- ...scrollEdgeFadeClassMap({
47
- edges: this.side,
48
- hidden: !this.visible,
49
- }),
50
- }}
51
- style={scrollEdgeFadeSizeStyle(this.size, this.height) as Record<string, string>}
52
- >
53
- <slot />
54
- </div>
55
- </Host>
56
- );
57
- }
58
- }
@@ -1 +0,0 @@
1
- export type { FadeSide, FadeSize, FadeSizeToken } from './Fade';
@@ -1,81 +0,0 @@
1
- import { Component, Prop, h, Host } from '@stencil/core';
2
-
3
- export type SurfaceIntent =
4
- | 'brand' | 'positive' | 'negative' | 'warning' | 'caution'
5
- | 'ai' | 'neutral' | 'walkthrough' | 'guide';
6
- export type SurfaceBackground = 'primary' | 'secondary' | 'transparent' | 'translucent';
7
- export type SurfaceContrast = 'faint' | 'medium' | 'bold' | 'strong';
8
- export type SurfaceElevation =
9
- | 'none' | 'depressed' | 'depressed-md' | 'flat' | 'elevated' | 'floating'
10
- | 'overlayTop' | 'overlayRight' | 'overlayBottom' | 'overlayLeft';
11
- export type SurfaceEdge = 'top' | 'right' | 'bottom' | 'left';
12
- export type SurfaceRadius = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | (string & {});
13
- export type SurfaceElement = 'div' | 'section' | 'aside' | 'article' | 'header' | 'footer' | 'main' | 'nav' | 'span';
14
-
15
- const RADIUS_PRESETS = new Set(['none', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', 'full']);
16
-
17
- @Component({
18
- tag: 'ds-surface',
19
- styleUrl: 'Surface.css',
20
- scoped: true,
21
- })
22
- export class Surface {
23
- @Prop() background: SurfaceBackground = 'transparent';
24
- @Prop() intent: SurfaceIntent | undefined;
25
- @Prop() contrast: SurfaceContrast = 'faint';
26
- @Prop() elevation: SurfaceElevation = 'none';
27
- /** Space-separated list of edges: "top bottom" etc. Only applies when elevation='none'. */
28
- @Prop() edge: string | undefined;
29
- @Prop() radius: SurfaceRadius | undefined;
30
- @Prop() interactive: boolean = false;
31
- @Prop() selected: boolean = false;
32
- @Prop() inactive: boolean = false;
33
- @Prop() as: SurfaceElement = 'div';
34
-
35
- render() {
36
- // Polymorphic element: TSX treats a variable tag as a component, so a
37
- // dynamic intrinsic element name must be cast to `any` to render.
38
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
- const Tag = this.as as any;
40
-
41
- const intentClass = this.intent
42
- ? `intent-${this.intent}-${this.contrast}`
43
- : `bg-${this.background}`;
44
-
45
- const elevClass = `elevation-${this.elevation}`;
46
-
47
- const edgeClasses = this.edge && this.elevation === 'none'
48
- ? this.edge.trim().split(/\s+/).map(e => `edge-${e}`)
49
- : [];
50
-
51
- const radiusClass = this.radius && RADIUS_PRESETS.has(this.radius)
52
- ? `radius-${this.radius}`
53
- : '';
54
-
55
- const customRadius = this.radius && !RADIUS_PRESETS.has(this.radius)
56
- ? this.radius
57
- : undefined;
58
-
59
- const cls = [
60
- 'surface',
61
- intentClass,
62
- elevClass,
63
- ...edgeClasses,
64
- radiusClass,
65
- this.interactive ? 'interactive' : '',
66
- this.selected ? 'selected' : '',
67
- this.inactive ? 'inactive' : '',
68
- ].filter(Boolean).join(' ');
69
-
70
- return (
71
- <Host style={{ display: 'contents' }}>
72
- <Tag
73
- class={cls}
74
- style={customRadius ? { borderRadius: customRadius } : undefined}
75
- >
76
- <slot />
77
- </Tag>
78
- </Host>
79
- );
80
- }
81
- }
@@ -1,179 +0,0 @@
1
- import { Component, Prop, State, h, Host } from '@stencil/core';
2
- import { resolveCssTimeMs, TOKEN_DEFAULTS } from '../../utils';
3
- import { subscribeToToasts, getToasts, toast as toastService, type ToastData, type ToastIntent } from './toast-service';
4
-
5
- export type ToastPosition = 'top-center' | 'top-right' | 'bottom-center' | 'bottom-right';
6
-
7
- const INTENT_BG: Record<ToastIntent, string> = {
8
- neutral: 'var(--color-background-bold-neutral)',
9
- brand: 'var(--color-background-bold-brand)',
10
- positive: 'var(--color-background-bold-positive)',
11
- negative: 'var(--color-background-bold-negative)',
12
- warning: 'var(--color-background-bold-warning)',
13
- caution: 'var(--color-background-bold-caution)',
14
- };
15
-
16
- interface ToastItemState {
17
- data: ToastData;
18
- exiting: boolean;
19
- timer: ReturnType<typeof setTimeout> | null;
20
- remaining: number;
21
- startedAt: number;
22
- paused: boolean;
23
- }
24
-
25
- @Component({
26
- tag: 'ds-toast-provider',
27
- styleUrl: 'Toast.css',
28
- scoped: true,
29
- })
30
- export class ToastProvider {
31
- @Prop() position: ToastPosition = 'top-center';
32
-
33
- @State() private items: ToastItemState[] = [];
34
-
35
- private unsubscribe: (() => void) | null = null;
36
-
37
- private get fadeOutMs(): number {
38
- return resolveCssTimeMs(TOKEN_DEFAULTS.motionShort3, TOKEN_DEFAULTS.animationDurationShort3);
39
- }
40
-
41
- connectedCallback() {
42
- this.unsubscribe = subscribeToToasts(() => this.syncFromStore());
43
- this.syncFromStore();
44
- }
45
-
46
- disconnectedCallback() {
47
- this.items.forEach(item => { if (item.timer) clearTimeout(item.timer); });
48
- this.unsubscribe?.();
49
- }
50
-
51
- private syncFromStore() {
52
- const storeToasts = getToasts();
53
- const existingIds = new Set(this.items.map(i => i.data.id));
54
- const storeIds = new Set(storeToasts.map(t => t.id));
55
-
56
- // Remove items no longer in store (instant, no animation since dismiss() already fires animation)
57
- const kept = this.items.filter(i => storeIds.has(i.data.id));
58
-
59
- // Add new items
60
- const newItems: ToastItemState[] = storeToasts
61
- .filter(t => !existingIds.has(t.id))
62
- .map(data => {
63
- const state: ToastItemState = {
64
- data,
65
- exiting: false,
66
- timer: null,
67
- remaining: data.duration,
68
- startedAt: 0,
69
- paused: false,
70
- };
71
- if (data.duration > 0) {
72
- state.startedAt = Date.now();
73
- state.timer = setTimeout(() => this.dismissItem(data.id), data.duration);
74
- }
75
- return state;
76
- });
77
-
78
- this.items = [...kept, ...newItems];
79
- }
80
-
81
- private dismissItem(id: string) {
82
- this.items = this.items.map(i =>
83
- i.data.id === id ? { ...i, exiting: true, timer: null } : i
84
- );
85
- setTimeout(() => {
86
- this.items = this.items.filter(i => i.data.id !== id);
87
- toastService.dismiss(id);
88
- }, this.fadeOutMs);
89
- }
90
-
91
- private pauseItem(id: string) {
92
- this.items = this.items.map(i => {
93
- if (i.data.id !== id || i.paused || !i.timer) return i;
94
- clearTimeout(i.timer);
95
- const elapsed = Date.now() - i.startedAt;
96
- return { ...i, paused: true, timer: null, remaining: Math.max(0, i.remaining - elapsed) };
97
- });
98
- }
99
-
100
- private resumeItem(id: string) {
101
- this.items = this.items.map(i => {
102
- if (i.data.id !== id || !i.paused || i.remaining <= 0) return i;
103
- const timer = setTimeout(() => this.dismissItem(id), i.remaining);
104
- return { ...i, paused: false, timer, startedAt: Date.now() };
105
- });
106
- }
107
-
108
- private getPositionStyle(): Record<string, string> {
109
- const base: Record<string, string> = {
110
- position: 'fixed',
111
- zIndex: '9999',
112
- display: 'flex',
113
- flexDirection: 'column',
114
- gap: 'var(--dimension-space-075)',
115
- pointerEvents: 'none',
116
- padding: 'var(--dimension-space-100)',
117
- maxWidth: `var(${TOKEN_DEFAULTS.panelWidthMd})`,
118
- width: '100%',
119
- boxSizing: 'border-box',
120
- };
121
- switch (this.position) {
122
- case 'top-center':
123
- return { ...base, top: '0', left: '50%', transform: 'translateX(-50%)', alignItems: 'center' };
124
- case 'top-right':
125
- return { ...base, top: '0', right: '0', alignItems: 'flex-end' };
126
- case 'bottom-center':
127
- return { ...base, bottom: '0', left: '50%', transform: 'translateX(-50%)', alignItems: 'center' };
128
- case 'bottom-right':
129
- return { ...base, bottom: '0', right: '0', alignItems: 'flex-end' };
130
- }
131
- }
132
-
133
- render() {
134
- return (
135
- <Host style={{ display: 'contents' }}>
136
- <div
137
- class="toast-container"
138
- role="region"
139
- aria-label="Notifications"
140
- aria-live="polite"
141
- style={this.getPositionStyle()}
142
- >
143
- {this.items.map(item => (
144
- <div
145
- key={item.data.id}
146
- class={{ toast: true, 'toast--exit': item.exiting }}
147
- role={item.data.intent === 'negative' ? 'alert' : 'status'}
148
- style={{
149
- backgroundColor: INTENT_BG[item.data.intent],
150
- borderRadius: 'var(--dimension-radius-125)',
151
- boxShadow: 'var(--effect-elevation-elevated-floating)',
152
- display: 'flex',
153
- alignItems: 'center',
154
- gap: 'var(--dimension-space-075)',
155
- padding: 'var(--dimension-space-075) var(--dimension-space-100)',
156
- minHeight: 'var(--dimension-size-400)',
157
- pointerEvents: 'auto',
158
- color: 'var(--color-foreground-on-bold-background-primary)',
159
- boxSizing: 'border-box',
160
- }}
161
- onMouseEnter={() => this.pauseItem(item.data.id)}
162
- onMouseLeave={() => this.resumeItem(item.data.id)}
163
- >
164
- <span class="text-body-medium" style={{ flex: '1' }}>{item.data.message}</span>
165
- <button
166
- type="button"
167
- class="toast-dismiss"
168
- onClick={() => this.dismissItem(item.data.id)}
169
- aria-label="Dismiss"
170
- >
171
- &times;
172
- </button>
173
- </div>
174
- ))}
175
- </div>
176
- </Host>
177
- );
178
- }
179
- }