@spfx-fast/sharepoint-ui 0.4.3 → 0.5.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 (282) hide show
  1. package/QUICKSTART.md +13 -128
  2. package/README.md +19 -26
  3. package/components.json +240 -5834
  4. package/dist/accordion.d.ts +11 -0
  5. package/dist/accordion.js +4 -0
  6. package/dist/alert.d.ts +3 -0
  7. package/dist/alert.js +4 -0
  8. package/dist/attachment-list.d.ts +15 -0
  9. package/dist/attachment-list.js +14 -0
  10. package/dist/avatar-group.d.ts +12 -0
  11. package/dist/avatar-group.js +7 -0
  12. package/dist/avatar.d.ts +6 -0
  13. package/dist/avatar.js +5 -0
  14. package/dist/badge.d.ts +3 -0
  15. package/dist/badge.js +4 -0
  16. package/dist/breadcrumb.d.ts +10 -0
  17. package/dist/breadcrumb.js +9 -0
  18. package/dist/button-group.d.ts +6 -0
  19. package/dist/button-group.js +4 -0
  20. package/dist/button.d.ts +3 -0
  21. package/dist/button.js +4 -0
  22. package/dist/card.d.ts +3 -0
  23. package/dist/card.js +4 -0
  24. package/dist/carousel.d.ts +11 -0
  25. package/dist/carousel.js +6 -0
  26. package/dist/checkbox.d.ts +3 -0
  27. package/dist/checkbox.js +4 -0
  28. package/dist/combobox.d.ts +9 -0
  29. package/dist/combobox.js +6 -0
  30. package/dist/command-bar.d.ts +6 -0
  31. package/dist/command-bar.js +4 -0
  32. package/dist/copy-button.d.ts +7 -0
  33. package/dist/copy-button.js +19 -0
  34. package/dist/data-grid.d.ts +25 -0
  35. package/dist/data-grid.js +39 -0
  36. package/dist/date-range-picker.d.ts +12 -0
  37. package/dist/date-range-picker.js +4 -0
  38. package/dist/dialog.d.ts +9 -0
  39. package/dist/dialog.js +21 -0
  40. package/dist/divider.d.ts +3 -0
  41. package/dist/divider.js +4 -0
  42. package/dist/drawer.d.ts +6 -0
  43. package/dist/drawer.js +5 -0
  44. package/dist/empty-state.d.ts +7 -0
  45. package/dist/empty-state.js +5 -0
  46. package/dist/field.d.ts +15 -0
  47. package/dist/field.js +11 -0
  48. package/dist/file-dropzone.d.ts +15 -0
  49. package/dist/file-dropzone.js +21 -0
  50. package/dist/filter-bar.d.ts +9 -0
  51. package/dist/filter-bar.js +9 -0
  52. package/dist/image.d.ts +5 -0
  53. package/dist/image.js +4 -0
  54. package/dist/index.d.ts +68 -78
  55. package/dist/index.js +60 -68
  56. package/dist/input.d.ts +3 -0
  57. package/dist/input.js +4 -0
  58. package/dist/label.d.ts +3 -0
  59. package/dist/label.js +4 -0
  60. package/dist/link.d.ts +3 -0
  61. package/dist/link.js +9 -0
  62. package/dist/list-view.d.ts +29 -0
  63. package/dist/list-view.js +14 -0
  64. package/dist/list.d.ts +6 -0
  65. package/dist/list.js +5 -0
  66. package/dist/lookup-picker.d.ts +12 -0
  67. package/dist/lookup-picker.js +4 -0
  68. package/dist/menu.d.ts +6 -0
  69. package/dist/menu.js +4 -0
  70. package/dist/nav.d.ts +12 -0
  71. package/dist/nav.js +4 -0
  72. package/dist/pagination.d.ts +11 -0
  73. package/dist/pagination.js +5 -0
  74. package/dist/person-picker.d.ts +13 -0
  75. package/dist/person-picker.js +4 -0
  76. package/dist/persona.d.ts +7 -0
  77. package/dist/persona.js +5 -0
  78. package/dist/popover.d.ts +6 -0
  79. package/dist/popover.js +4 -0
  80. package/dist/progress-bar.d.ts +5 -0
  81. package/dist/progress-bar.js +5 -0
  82. package/dist/radio-group.d.ts +6 -0
  83. package/dist/radio-group.js +4 -0
  84. package/dist/radio.d.ts +3 -0
  85. package/dist/radio.js +4 -0
  86. package/dist/rating.d.ts +8 -0
  87. package/dist/rating.js +5 -0
  88. package/dist/react.d.ts +1 -4715
  89. package/dist/react.js +1 -7097
  90. package/dist/select.d.ts +3 -0
  91. package/dist/select.js +4 -0
  92. package/dist/sharepoint-field.d.ts +18 -0
  93. package/dist/sharepoint-field.js +54 -0
  94. package/dist/skeleton.d.ts +6 -0
  95. package/dist/skeleton.js +9 -0
  96. package/dist/spinner.d.ts +5 -0
  97. package/dist/spinner.js +4 -0
  98. package/dist/swatch-picker.d.ts +17 -0
  99. package/dist/swatch-picker.js +11 -0
  100. package/dist/switch.d.ts +3 -0
  101. package/dist/switch.js +4 -0
  102. package/dist/table.d.ts +6 -0
  103. package/dist/table.js +4 -0
  104. package/dist/tabs.d.ts +14 -0
  105. package/dist/tabs.js +30 -0
  106. package/dist/tag-group.d.ts +6 -0
  107. package/dist/tag-group.js +4 -0
  108. package/dist/tag-picker.d.ts +12 -0
  109. package/dist/tag-picker.js +4 -0
  110. package/dist/tag.d.ts +7 -0
  111. package/dist/tag.js +5 -0
  112. package/dist/text.d.ts +5 -0
  113. package/dist/text.js +4 -0
  114. package/dist/textarea.d.ts +3 -0
  115. package/dist/textarea.js +4 -0
  116. package/dist/theme.d.ts +15 -175
  117. package/dist/theme.js +36 -239
  118. package/dist/toast.d.ts +9 -0
  119. package/dist/toast.js +12 -0
  120. package/dist/tree.d.ts +13 -0
  121. package/dist/tree.js +9 -0
  122. package/dist/view-card.d.ts +8 -0
  123. package/dist/view-card.js +4 -0
  124. package/dist/view-switcher.d.ts +13 -0
  125. package/dist/view-switcher.js +7 -0
  126. package/dist/virtual-list.d.ts +11 -0
  127. package/dist/virtual-list.js +25 -0
  128. package/measurements.json +365 -0
  129. package/package.json +14 -46
  130. package/src/theme.css +125 -0
  131. package/AGENTS.md +0 -231
  132. package/dist/appearance.d.ts +0 -6
  133. package/dist/appearance.js +0 -217
  134. package/dist/elements/accordion.d.ts +0 -9
  135. package/dist/elements/accordion.js +0 -338
  136. package/dist/elements/alert.d.ts +0 -2
  137. package/dist/elements/alert.js +0 -86
  138. package/dist/elements/avatar-group-primitives.d.ts +0 -3
  139. package/dist/elements/avatar-group-primitives.js +0 -189
  140. package/dist/elements/avatar-group.d.ts +0 -2
  141. package/dist/elements/avatar-group.js +0 -110
  142. package/dist/elements/avatar.d.ts +0 -4
  143. package/dist/elements/avatar.js +0 -251
  144. package/dist/elements/badge.d.ts +0 -8
  145. package/dist/elements/badge.js +0 -182
  146. package/dist/elements/breadcrumb.d.ts +0 -4
  147. package/dist/elements/breadcrumb.js +0 -233
  148. package/dist/elements/button-group.d.ts +0 -1
  149. package/dist/elements/button-group.js +0 -20
  150. package/dist/elements/button-variants.d.ts +0 -6
  151. package/dist/elements/button-variants.js +0 -339
  152. package/dist/elements/button.d.ts +0 -5
  153. package/dist/elements/button.js +0 -233
  154. package/dist/elements/card-primitives.d.ts +0 -3
  155. package/dist/elements/card-primitives.js +0 -83
  156. package/dist/elements/card.d.ts +0 -5
  157. package/dist/elements/card.js +0 -213
  158. package/dist/elements/carousel.d.ts +0 -92
  159. package/dist/elements/carousel.js +0 -1115
  160. package/dist/elements/color-picker.d.ts +0 -24
  161. package/dist/elements/color-picker.js +0 -1004
  162. package/dist/elements/combobox.d.ts +0 -1
  163. package/dist/elements/combobox.js +0 -1012
  164. package/dist/elements/data-grid-model.d.ts +0 -120
  165. package/dist/elements/data-grid-model.js +0 -294
  166. package/dist/elements/data-grid.d.ts +0 -30
  167. package/dist/elements/data-grid.js +0 -1576
  168. package/dist/elements/date-picker.d.ts +0 -1
  169. package/dist/elements/date-picker.js +0 -486
  170. package/dist/elements/dialog.d.ts +0 -23
  171. package/dist/elements/dialog.js +0 -409
  172. package/dist/elements/divider.d.ts +0 -2
  173. package/dist/elements/divider.js +0 -66
  174. package/dist/elements/drawer.d.ts +0 -3
  175. package/dist/elements/drawer.js +0 -308
  176. package/dist/elements/field-composition.d.ts +0 -26
  177. package/dist/elements/field-composition.js +0 -133
  178. package/dist/elements/field.d.ts +0 -1
  179. package/dist/elements/field.js +0 -67
  180. package/dist/elements/file-upload.d.ts +0 -6
  181. package/dist/elements/file-upload.js +0 -211
  182. package/dist/elements/floating-position.d.ts +0 -36
  183. package/dist/elements/floating-position.js +0 -92
  184. package/dist/elements/image.d.ts +0 -28
  185. package/dist/elements/image.js +0 -38
  186. package/dist/elements/info.d.ts +0 -9
  187. package/dist/elements/info.js +0 -102
  188. package/dist/elements/input.d.ts +0 -5
  189. package/dist/elements/input.js +0 -255
  190. package/dist/elements/label.d.ts +0 -15
  191. package/dist/elements/label.js +0 -56
  192. package/dist/elements/link.d.ts +0 -1
  193. package/dist/elements/link.js +0 -92
  194. package/dist/elements/list.d.ts +0 -19
  195. package/dist/elements/list.js +0 -297
  196. package/dist/elements/menu.d.ts +0 -33
  197. package/dist/elements/menu.js +0 -1103
  198. package/dist/elements/message-bar.d.ts +0 -10
  199. package/dist/elements/message-bar.js +0 -327
  200. package/dist/elements/nav.d.ts +0 -32
  201. package/dist/elements/nav.js +0 -794
  202. package/dist/elements/overflow.d.ts +0 -10
  203. package/dist/elements/overflow.js +0 -218
  204. package/dist/elements/persona.d.ts +0 -3
  205. package/dist/elements/persona.js +0 -125
  206. package/dist/elements/popover.d.ts +0 -77
  207. package/dist/elements/popover.js +0 -840
  208. package/dist/elements/progress-bar.d.ts +0 -4
  209. package/dist/elements/progress-bar.js +0 -82
  210. package/dist/elements/radio-group.d.ts +0 -1
  211. package/dist/elements/radio-group.js +0 -303
  212. package/dist/elements/rating-display.d.ts +0 -2
  213. package/dist/elements/rating-display.js +0 -125
  214. package/dist/elements/rating.d.ts +0 -2
  215. package/dist/elements/rating.js +0 -206
  216. package/dist/elements/rich-text-editor.d.ts +0 -32
  217. package/dist/elements/rich-text-editor.js +0 -1367
  218. package/dist/elements/search.d.ts +0 -3
  219. package/dist/elements/search.js +0 -200
  220. package/dist/elements/select.d.ts +0 -6
  221. package/dist/elements/select.js +0 -291
  222. package/dist/elements/shared.d.ts +0 -22
  223. package/dist/elements/shared.js +0 -409
  224. package/dist/elements/sharepoint-field-basic-controls.d.ts +0 -1
  225. package/dist/elements/sharepoint-field-basic-controls.js +0 -14
  226. package/dist/elements/sharepoint-fields.d.ts +0 -29
  227. package/dist/elements/sharepoint-fields.js +0 -460
  228. package/dist/elements/skeleton.d.ts +0 -6
  229. package/dist/elements/skeleton.js +0 -91
  230. package/dist/elements/slider.d.ts +0 -1
  231. package/dist/elements/slider.js +0 -248
  232. package/dist/elements/spin-button.d.ts +0 -7
  233. package/dist/elements/spin-button.js +0 -499
  234. package/dist/elements/spinner.d.ts +0 -4
  235. package/dist/elements/spinner.js +0 -124
  236. package/dist/elements/swatch-picker.d.ts +0 -5
  237. package/dist/elements/swatch-picker.js +0 -363
  238. package/dist/elements/table.d.ts +0 -21
  239. package/dist/elements/table.js +0 -261
  240. package/dist/elements/tabs.d.ts +0 -1
  241. package/dist/elements/tabs.js +0 -276
  242. package/dist/elements/tag-picker.d.ts +0 -29
  243. package/dist/elements/tag-picker.js +0 -715
  244. package/dist/elements/tags.d.ts +0 -21
  245. package/dist/elements/tags.js +0 -421
  246. package/dist/elements/teaching-popover.d.ts +0 -32
  247. package/dist/elements/teaching-popover.js +0 -412
  248. package/dist/elements/text.d.ts +0 -9
  249. package/dist/elements/text.js +0 -75
  250. package/dist/elements/textarea.d.ts +0 -1
  251. package/dist/elements/textarea.js +0 -182
  252. package/dist/elements/toast.d.ts +0 -25
  253. package/dist/elements/toast.js +0 -337
  254. package/dist/elements/toaster.d.ts +0 -6
  255. package/dist/elements/toaster.js +0 -357
  256. package/dist/elements/toggle.d.ts +0 -2
  257. package/dist/elements/toggle.js +0 -246
  258. package/dist/elements/toolbar.d.ts +0 -12
  259. package/dist/elements/toolbar.js +0 -381
  260. package/dist/elements/tooltip.d.ts +0 -76
  261. package/dist/elements/tooltip.js +0 -527
  262. package/dist/elements/tree-model.d.ts +0 -19
  263. package/dist/elements/tree-model.js +0 -34
  264. package/dist/elements/tree.d.ts +0 -5
  265. package/dist/elements/tree.js +0 -273
  266. package/dist/elements/view-card.d.ts +0 -2
  267. package/dist/elements/view-card.js +0 -78
  268. package/dist/elements/virtual-list.d.ts +0 -41
  269. package/dist/elements/virtual-list.js +0 -369
  270. package/dist/elements.d.ts +0 -73
  271. package/dist/elements.js +0 -210
  272. package/dist/sharepoint-fields.d.ts +0 -135
  273. package/dist/sharepoint-fields.js +0 -402
  274. package/dist/virtualizer-hooks.d.ts +0 -80
  275. package/dist/virtualizer-hooks.js +0 -253
  276. package/scripts/generate-token-index.mjs +0 -43
  277. package/scripts/sync-component-catalog-signatures.mjs +0 -55
  278. package/scripts/validate-component-catalog.mjs +0 -44
  279. package/skills/sharepoint-ui/SKILL.md +0 -12
  280. package/skills/sharepoint-ui/references/choosing-components.md +0 -20
  281. package/skills/sharepoint-ui/references/sharepoint-patterns.md +0 -17
  282. package/tokens.json +0 -3777
@@ -1,338 +0,0 @@
1
- import { base } from "./shared.js";
2
- const normalizeItems = (value) => (Array.isArray(value) ? value : value === undefined || value === null ? [] : [value]).map(String);
3
- const directItems = (accordion) => [...accordion.children].filter((child) => child instanceof HTMLElement && child.localName === "spui-accordion-item");
4
- export function defineAccordionHeader() {
5
- if (customElements.get("spui-accordion-header"))
6
- return;
7
- class SpuiAccordionHeader extends HTMLElement {
8
- static observedAttributes = ["expand-icon-position", "inline", "size"];
9
- connectedCallback() {
10
- if (this.shadowRoot)
11
- return;
12
- const shadow = this.attachShadow({ mode: "open" });
13
- const style = document.createElement("style");
14
- style.textContent = base + ':host{display:contents}.header{display:flex;align-items:center;gap:8px}.content{min-width:0}.icon,.expand{display:inline-flex;align-items:center;justify-content:center;flex:none}.icon[hidden],.expand[hidden]{display:none}:host([expand-icon-position=start]) .expand{order:-1}:host([open]) .expand{transform:rotate(90deg)}:host(:dir(rtl)) .expand{transform:rotate(180deg)}:host([open]:dir(rtl)) .expand{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.expand{transition:none}}';
15
- const header = document.createElement("div");
16
- header.className = "header";
17
- const icon = document.createElement("span");
18
- icon.className = "icon";
19
- icon.setAttribute("aria-hidden", "true");
20
- const iconSlot = document.createElement("slot");
21
- iconSlot.name = "icon";
22
- icon.append(iconSlot);
23
- const content = document.createElement("span");
24
- content.className = "content";
25
- const defaultSlot = document.createElement("slot");
26
- content.append(defaultSlot);
27
- const expand = document.createElement("span");
28
- expand.className = "expand";
29
- expand.setAttribute("aria-hidden", "true");
30
- const expandSlot = document.createElement("slot");
31
- expandSlot.name = "expand-icon";
32
- expand.append(expandSlot);
33
- header.append(icon, content, expand);
34
- shadow.append(style, header);
35
- const syncExpand = () => {
36
- const hasExpand = expandSlot.assignedNodes({ flatten: true }).length > 0;
37
- this.toggleAttribute("has-expand-icon", hasExpand);
38
- this.dispatchEvent(new CustomEvent("spui-header-slots-change", { bubbles: true, composed: true }));
39
- };
40
- expandSlot.addEventListener("slotchange", syncExpand);
41
- syncExpand();
42
- }
43
- }
44
- customElements.define("spui-accordion-header", SpuiAccordionHeader);
45
- }
46
- export function defineAccordionPanel() {
47
- if (customElements.get("spui-accordion-panel"))
48
- return;
49
- class SpuiAccordionPanel extends HTMLElement {
50
- connectedCallback() { if (!this.shadowRoot) {
51
- const shadow = this.attachShadow({ mode: "open" });
52
- const style = document.createElement("style");
53
- style.textContent = `${base}:host{display:block;min-width:0}`;
54
- shadow.append(style, document.createElement("slot"));
55
- } }
56
- }
57
- customElements.define("spui-accordion-panel", SpuiAccordionPanel);
58
- }
59
- export function defineAccordion() {
60
- if (customElements.get("spui-accordion"))
61
- return;
62
- defineAccordionHeader();
63
- defineAccordionPanel();
64
- if (!customElements.get("spui-accordion-item")) {
65
- class SpuiAccordionItem extends HTMLElement {
66
- static observedAttributes = ["heading", "value", "open", "disabled", "disabled-focusable"];
67
- panelId = `spui-accordion-panel-${crypto.randomUUID()}`;
68
- triggerId = `spui-accordion-trigger-${crypto.randomUUID()}`;
69
- wasOpen = false;
70
- panelExitPending = false;
71
- panelExitGeneration = 0;
72
- buttonSlotAttributes = new Set();
73
- connectedCallback() { if (!this.hasAttribute("value"))
74
- this.setAttribute("value", this.id || crypto.randomUUID()); if (!this.shadowRoot)
75
- this.render(); this.sync(); }
76
- attributeChangedCallback() { if (this.isConnected)
77
- this.sync(); }
78
- get open() { return this.hasAttribute("open"); }
79
- set open(value) { this.toggleAttribute("open", Boolean(value)); }
80
- sync() {
81
- const button = this.shadowRoot?.querySelector("button");
82
- const panel = this.shadowRoot?.querySelector(".panel");
83
- if (!button || !panel)
84
- return;
85
- const isOpen = this.open;
86
- button.setAttribute("aria-expanded", String(isOpen));
87
- button.disabled = this.hasAttribute("disabled");
88
- if (button.disabled || this.hasAttribute("disabled-focusable"))
89
- button.setAttribute("aria-disabled", "true");
90
- else
91
- button.removeAttribute("aria-disabled");
92
- const motionPanel = this.shadowRoot?.querySelector("slot[name=panel]")?.assignedElements({ flatten: true }).some(element => element.localName === "spui-accordion-panel" && element.hasAttribute("motion")) ?? false;
93
- if (isOpen) {
94
- this.panelExitGeneration++;
95
- this.panelExitPending = false;
96
- panel.hidden = false;
97
- panel.inert = false;
98
- panel.removeAttribute("aria-hidden");
99
- }
100
- else if (motionPanel && this.wasOpen) {
101
- this.panelExitPending = true;
102
- panel.hidden = false;
103
- panel.inert = true;
104
- panel.setAttribute("aria-hidden", "true");
105
- this.finishPanelExit(panel);
106
- }
107
- else if (!this.panelExitPending) {
108
- panel.hidden = true;
109
- panel.inert = false;
110
- panel.removeAttribute("aria-hidden");
111
- }
112
- this.wasOpen = isOpen;
113
- const heading = button.querySelector("slot[name=heading]");
114
- const header = heading?.assignedElements({ flatten: true }).find(element => element.localName === "spui-accordion-header");
115
- const icon = button.querySelector(".icon");
116
- const buttonSlot = header?.button;
117
- button.className = "trigger";
118
- button.style.cssText = "";
119
- for (const attribute of this.buttonSlotAttributes)
120
- button.removeAttribute(attribute);
121
- this.buttonSlotAttributes.clear();
122
- if (buttonSlot) {
123
- if (typeof buttonSlot.className === "string")
124
- button.classList.add(...buttonSlot.className.split(/\s+/).filter(Boolean));
125
- if (buttonSlot.style && typeof buttonSlot.style === "object")
126
- Object.assign(button.style, buttonSlot.style);
127
- for (const [name, value] of Object.entries(buttonSlot)) {
128
- if (name === "className" || name === "style" || name === "children" || name === "disabled" || name === "type" || name === "tabIndex" || name === "onClick" || value == null || typeof value === "function")
129
- continue;
130
- const attribute = name.startsWith("aria-") || name.startsWith("data-") ? name : { title: "title", name: "name", value: "value", form: "form", accessKey: "accesskey", id: "id" }[name];
131
- if (attribute) {
132
- button.setAttribute(attribute, String(value));
133
- this.buttonSlotAttributes.add(attribute);
134
- }
135
- }
136
- }
137
- if (icon && heading) {
138
- const iconAtStart = header?.getAttribute("expand-icon-position") === "start";
139
- button.insertBefore(icon, iconAtStart ? heading : null);
140
- icon.hidden = header?.hasAttribute("has-expand-icon") ?? false;
141
- }
142
- header?.toggleAttribute("open", isOpen);
143
- const fallback = heading?.firstChild;
144
- if (fallback?.nodeType === Node.TEXT_NODE)
145
- fallback.textContent = this.getAttribute("heading") || "Section";
146
- }
147
- finishPanelExit(panel) {
148
- if (!this.panelExitPending)
149
- return;
150
- const generation = ++this.panelExitGeneration;
151
- requestAnimationFrame(() => requestAnimationFrame(() => {
152
- const animations = new Set();
153
- const visit = (element) => {
154
- for (const animation of element.getAnimations())
155
- if (animation.playState === "running")
156
- animations.add(animation);
157
- if (element.shadowRoot)
158
- for (const child of element.shadowRoot.children)
159
- visit(child);
160
- if (element instanceof HTMLSlotElement)
161
- for (const child of element.assignedElements({ flatten: true }))
162
- visit(child);
163
- for (const child of element.children)
164
- visit(child);
165
- };
166
- for (const assigned of this.shadowRoot?.querySelector("slot[name=panel]")?.assignedElements({ flatten: true }) ?? [])
167
- visit(assigned);
168
- const finish = () => {
169
- if (generation !== this.panelExitGeneration || this.open || !this.panelExitPending)
170
- return;
171
- this.panelExitPending = false;
172
- panel.hidden = true;
173
- };
174
- if (animations.size)
175
- void Promise.allSettled([...animations].map(animation => animation.finished)).then(finish);
176
- else
177
- finish();
178
- }));
179
- }
180
- render() {
181
- const shadow = this.attachShadow({ mode: "open" });
182
- const style = document.createElement("style");
183
- style.textContent = `${base}:host{display:block;border-block-end:1px solid var(--spui-accordion-divider,var(--spui-ui-stroke,#d1d1d1))}.trigger{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-height:44px;padding:var(--spui-accordion-padding,12px 16px);border:0;background:transparent;color:var(--spui-ui-text,#242424);font:inherit;font-weight:600;text-align:start;cursor:pointer}.trigger:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,#78716c));outline-offset:-2px}.trigger:disabled{color:var(--spui-ui-muted,#616161);cursor:not-allowed}.icon{display:grid;place-items:center;flex:0 0 24px;width:24px;height:24px;transition:transform var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}.icon:before{content:"";width:7px;height:7px;border-block-start:2px solid currentColor;border-inline-end:2px solid currentColor;transform:rotate(45deg)}.trigger[aria-expanded=true] .icon{transform:rotate(90deg)}:host(:dir(rtl)) .icon{transform:rotate(180deg)}:host(:dir(rtl)) .trigger[aria-expanded=true] .icon{transform:rotate(90deg)}.panel{padding:0 var(--spui-accordion-padding-inline,16px) 16px;color:var(--spui-ui-text,#242424)}.panel[hidden]{display:none}@media(prefers-reduced-motion:reduce){.icon{transition:none}}@media(forced-colors:active){.trigger:focus-visible{outline-color:Highlight}}`;
184
- const button = document.createElement("button");
185
- button.type = "button";
186
- button.id = this.triggerId;
187
- button.className = "trigger";
188
- button.part.add("trigger");
189
- button.setAttribute("aria-controls", this.panelId);
190
- const heading = document.createElement("slot");
191
- heading.name = "heading";
192
- heading.append(document.createTextNode(this.getAttribute("heading") || "Section"));
193
- const icon = document.createElement("span");
194
- icon.className = "icon";
195
- icon.part.add("icon");
196
- icon.setAttribute("aria-hidden", "true");
197
- button.append(heading, icon);
198
- const panel = document.createElement("div");
199
- panel.className = "panel";
200
- panel.part.add("panel");
201
- panel.id = this.panelId;
202
- panel.setAttribute("role", "region");
203
- panel.setAttribute("aria-labelledby", this.triggerId);
204
- const panelSlot = document.createElement("slot");
205
- panelSlot.name = "panel";
206
- panelSlot.append(document.createElement("slot"));
207
- panel.append(panelSlot);
208
- button.addEventListener("click", event => {
209
- const header = button.querySelector("slot[name=heading]")?.assignedElements({ flatten: true }).find(element => element.localName === "spui-accordion-header");
210
- header?.button?.onClickCapture?.(event);
211
- }, true);
212
- button.addEventListener("click", event => {
213
- const heading = button.querySelector("slot[name=heading]");
214
- const header = heading?.assignedElements({ flatten: true }).find(element => element.localName === "spui-accordion-header");
215
- header?.button?.onClick?.(event);
216
- if (event.defaultPrevented)
217
- return;
218
- this.open = !this.open;
219
- this.dispatchEvent(new CustomEvent("spui-item-toggle", { bubbles: true, composed: true, detail: { value: this.getAttribute("value") ?? "", open: this.open, sourceEvent: event } }));
220
- });
221
- heading.addEventListener("slotchange", () => this.sync());
222
- button.addEventListener("spui-header-slots-change", () => this.sync());
223
- shadow.append(style, button, panel);
224
- }
225
- }
226
- customElements.define("spui-accordion-item", SpuiAccordionItem);
227
- }
228
- class SpuiAccordion extends HTMLElement {
229
- static observedAttributes = ["mode", "multiple", "collapsible", "navigation"];
230
- controlledItems;
231
- uncontrolledItems = [];
232
- hasInitialState = false;
233
- hasDefaultItems = false;
234
- syncing = false;
235
- events;
236
- get openItems() { return this.controlledItems; }
237
- set openItems(value) { this.controlledItems = value === undefined ? undefined : normalizeItems(value); this.syncItems(); }
238
- set defaultOpenItems(value) { if (!this.controlledItems && !this.hasDefaultItems && value !== undefined) {
239
- this.uncontrolledItems = normalizeItems(value);
240
- this.hasInitialState = true;
241
- this.hasDefaultItems = true;
242
- this.syncItems();
243
- } }
244
- get defaultOpenItems() { return this.uncontrolledItems; }
245
- get multiple() { return this.hasAttribute("mode") ? this.getAttribute("mode") !== "single" : this.hasAttribute("multiple"); }
246
- get collapsible() { return this.hasAttribute("collapsible"); }
247
- connectedCallback() {
248
- this.events?.abort();
249
- this.events = new AbortController();
250
- this.addEventListener("spui-item-toggle", this.onToggle, { signal: this.events.signal });
251
- this.addEventListener("keydown", this.onKeyDown, { signal: this.events.signal });
252
- if (!this.hasInitialState && !this.controlledItems) {
253
- this.uncontrolledItems = directItems(this).filter(item => item.hasAttribute("open")).map(item => item.getAttribute("value") ?? "");
254
- this.hasInitialState = true;
255
- }
256
- this.sync();
257
- }
258
- disconnectedCallback() { this.events?.abort(); }
259
- attributeChangedCallback() { if (this.isConnected)
260
- this.sync(); }
261
- get selectedItems() { return this.controlledItems ?? this.uncontrolledItems; }
262
- syncItems() {
263
- if (!this.isConnected)
264
- return;
265
- const values = this.multiple ? this.selectedItems : this.selectedItems.slice(0, 1);
266
- this.syncing = true;
267
- const disabledFocusableValue = !this.multiple && !this.collapsible && values.length === 1 ? values[0] : undefined;
268
- for (const item of directItems(this)) {
269
- const value = item.getAttribute("value") ?? "";
270
- item.toggleAttribute("open", values.includes(value));
271
- item.toggleAttribute("disabled-focusable", value === disabledFocusableValue && item.hasAttribute("open"));
272
- }
273
- this.syncing = false;
274
- this.updateTabStops();
275
- }
276
- sync() {
277
- this.dataset.mode = this.multiple ? "multiple" : "single";
278
- this.syncItems();
279
- }
280
- onToggle = (event) => {
281
- if (event.target.closest("spui-accordion") !== this || this.syncing)
282
- return;
283
- const { value, open, sourceEvent } = event.detail;
284
- const clickedItem = event.target;
285
- const current = this.controlledItems ?? directItems(this).filter(item => item.hasAttribute("open") && !(item === clickedItem && open) || item === clickedItem && !open).map(item => item.getAttribute("value") ?? "");
286
- let next = open ? (this.multiple ? [...current.filter(item => item !== value), value] : [value]) : current.filter(item => item !== value);
287
- if (!this.multiple && !this.collapsible && current.includes(value) && next.length === 0) {
288
- event.target.setAttribute("open", "");
289
- return;
290
- }
291
- if (this.controlledItems)
292
- this.syncItems();
293
- else {
294
- this.uncontrolledItems = next;
295
- this.syncItems();
296
- }
297
- const detail = { value, openItems: next };
298
- this.dispatchEvent(new CustomEvent("spui-toggle", { bubbles: true, composed: true, detail: { ...detail, sourceEvent } }));
299
- };
300
- enabledTriggers() { return directItems(this).filter(item => !item.hasAttribute("disabled")).map(item => item.shadowRoot?.querySelector("button")).filter((button) => Boolean(button)); }
301
- updateTabStops() {
302
- const triggers = this.enabledTriggers();
303
- if (!triggers.length)
304
- return;
305
- if (!this.hasAttribute("navigation")) {
306
- triggers.forEach(button => { button.tabIndex = 0; });
307
- return;
308
- }
309
- const active = triggers.includes(this.ownerDocument.activeElement) ? this.ownerDocument.activeElement : triggers.find(button => button.tabIndex === 0) ?? triggers[0];
310
- triggers.forEach(button => { button.tabIndex = button === active ? 0 : -1; });
311
- }
312
- onKeyDown = (event) => {
313
- const navigation = this.getAttribute("navigation");
314
- if (navigation !== "linear" && navigation !== "circular")
315
- return;
316
- const triggers = this.enabledTriggers();
317
- const target = event.composedPath().find(node => node instanceof HTMLButtonElement && triggers.includes(node));
318
- if (!target)
319
- return;
320
- const index = triggers.indexOf(target);
321
- let next;
322
- if (event.key === "ArrowDown" || event.key === "ArrowRight")
323
- next = triggers[index + 1] ?? (navigation === "circular" ? triggers[0] : undefined);
324
- else if (event.key === "ArrowUp" || event.key === "ArrowLeft")
325
- next = triggers[index - 1] ?? (navigation === "circular" ? triggers.at(-1) : undefined);
326
- else if (event.key === "Home")
327
- next = triggers[0];
328
- else if (event.key === "End")
329
- next = triggers.at(-1);
330
- if (!next)
331
- return;
332
- event.preventDefault();
333
- triggers.forEach(button => { button.tabIndex = button === next ? 0 : -1; });
334
- next.focus();
335
- };
336
- }
337
- customElements.define("spui-accordion", SpuiAccordion);
338
- }
@@ -1,2 +0,0 @@
1
- export type AlertAppearance = "primary" | "inverted";
2
- export declare function defineAlert(): void;
@@ -1,86 +0,0 @@
1
- import { base } from "./shared.js";
2
- const alertIconPaths = {
3
- info: "M10 2.5a7.5 7.5 0 1 0 0 15 7.5 7.5 0 0 0 0-15ZM10 9v5m0-7h.01",
4
- success: "M10 2.5a7.5 7.5 0 1 0 0 15 7.5 7.5 0 0 0 0-15ZM6.5 10l2.3 2.3 4.7-5.1",
5
- warning: "m10 2.5 8 14H2l8-14ZM10 7v4m0 3.5h.01",
6
- error: "M10 2.5a7.5 7.5 0 1 0 0 15 7.5 7.5 0 0 0 0-15ZM7 7l6 6m0-6-6 6",
7
- };
8
- export function defineAlert() {
9
- if (customElements.get("spui-alert"))
10
- return;
11
- class SpuiAlert extends HTMLElement {
12
- static observedAttributes = ["intent", "appearance", "assertive", "dismissible", "dismiss-label"];
13
- connectedCallback() { if (!this.shadowRoot)
14
- this.render(); this.syncSemantics(); }
15
- attributeChangedCallback() { if (this.isConnected)
16
- this.syncSemantics(); }
17
- syncSemantics() {
18
- const intent = this.getAttribute("intent");
19
- const assertive = this.hasAttribute("assertive") ? this.getAttribute("assertive") !== "false" : intent === "error" || intent === "warning";
20
- this.setAttribute("role", assertive ? "alert" : "status");
21
- this.setAttribute("aria-live", assertive ? "assertive" : "polite");
22
- this.setAttribute("aria-atomic", "true");
23
- const button = this.shadowRoot?.querySelector("button");
24
- if (button) {
25
- button.hidden = !this.hasAttribute("dismissible");
26
- button.setAttribute("aria-label", this.getAttribute("dismiss-label") ?? "Dismiss");
27
- }
28
- const icon = this.shadowRoot?.querySelector('slot[name="icon"]');
29
- const avatar = this.shadowRoot?.querySelector('slot[name="avatar"]');
30
- if (icon && avatar)
31
- icon.hidden = avatar.assignedElements().length > 0;
32
- const iconPath = icon?.querySelector(".icon path");
33
- if (iconPath)
34
- iconPath.setAttribute("d", alertIconPaths[intent ?? "info"] ?? alertIconPaths.info);
35
- }
36
- render() {
37
- const shadow = this.attachShadow({ mode: "open" });
38
- const avatar = document.createElement("slot");
39
- avatar.name = "avatar";
40
- avatar.part.add("avatar");
41
- avatar.addEventListener("slotchange", () => this.syncSemantics());
42
- const icon = document.createElement("slot");
43
- icon.name = "icon";
44
- icon.part.add("icon");
45
- const defaultIcon = document.createElement("span");
46
- defaultIcon.className = "icon";
47
- defaultIcon.setAttribute("aria-hidden", "true");
48
- icon.append(defaultIcon);
49
- const iconSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
50
- iconSvg.setAttribute("viewBox", "0 0 20 20");
51
- iconSvg.setAttribute("focusable", "false");
52
- const iconPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
53
- iconPath.setAttribute("d", alertIconPaths.info);
54
- iconSvg.append(iconPath);
55
- defaultIcon.append(iconSvg);
56
- const content = document.createElement("div");
57
- content.className = "content";
58
- content.part.add("content");
59
- content.append(document.createElement("slot"));
60
- const action = document.createElement("slot");
61
- action.name = "action";
62
- action.part.add("action");
63
- const actions = document.createElement("slot");
64
- actions.name = "actions";
65
- actions.part.add("actions");
66
- const button = document.createElement("button");
67
- button.type = "button";
68
- button.hidden = !this.hasAttribute("dismissible");
69
- button.part.add("dismiss");
70
- const closeSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
71
- closeSvg.classList.add("dismiss-icon");
72
- closeSvg.setAttribute("viewBox", "0 0 20 20");
73
- closeSvg.setAttribute("aria-hidden", "true");
74
- closeSvg.setAttribute("focusable", "false");
75
- const closePath = document.createElementNS("http://www.w3.org/2000/svg", "path");
76
- closePath.setAttribute("d", "m5 5 10 10M15 5 5 15");
77
- closeSvg.append(closePath);
78
- button.append(closeSvg);
79
- button.addEventListener("click", () => { this.hidden = true; this.dispatchEvent(new CustomEvent("spui-dismiss", { bubbles: true, composed: true })); });
80
- const style = document.createElement("style");
81
- style.textContent = `${base}:host{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,#d1d1d1));border-inline-start:2px solid var(--spui-ui-accent,#0f6cbd);border-radius:var(--spui-control-radius,6px);background:var(--spui-ui-canvas,#f5f5f5);line-height:1.45}:host([hidden]){display:none}.content{flex:1;min-width:0}.icon{display:inline-flex;flex:none;align-items:center;justify-content:center;color:var(--spui-ui-accent,#0f6cbd)}.icon svg,.dismiss-icon{display:block;width:1em;height:1em;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.icon svg{width:18px;height:18px}slot[name=actions]::slotted(*){display:flex;align-items:center;gap:8px}slot[name=action]::slotted(button){border:0;border-radius:4px;background:transparent;color:inherit;font:inherit;cursor:pointer}slot[name=action]::slotted(button:focus-visible){outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}:host([intent=success]){border-inline-start-color:var(--spui-ui-success,#107c10);background:var(--spui-success-surface,var(--spui-ui-success-surface,#dff6dd))}:host([intent=success]) .icon{color:var(--spui-ui-success,#107c10)}:host([intent=warning]){border-inline-start-color:var(--spui-ui-warning,#835b00);background:var(--spui-warning-surface,var(--spui-ui-warning-surface,#fff4ce))}:host([intent=warning]) .icon{color:var(--spui-ui-warning,#835b00)}:host([intent=error]){border-inline-start-color:var(--spui-ui-danger,#b10e1c);background:var(--spui-danger-surface,var(--spui-ui-danger-surface,#fde7e9))}:host([intent=error]) .icon{color:var(--spui-ui-danger,#b10e1c)}:host([appearance=inverted]){color:var(--colorNeutralForegroundInverted2,var(--spui-ui-surface,#fff));background:var(--colorNeutralBackgroundInverted,var(--spui-ui-text,#242424));border-color:var(--spui-alert-inverted-border,transparent)}:host([appearance=inverted]) .icon{color:currentColor}button{border:0;border-radius:4px;background:transparent;color:inherit;font:inherit;line-height:1;padding:2px 6px;cursor:pointer}button:hover{background:var(--spui-ui-surface-hover,#0001)}button:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}button[hidden]{display:none}:host([data-spui-appearance=glass]),:host-context([data-spui-appearance=glass]){backdrop-filter:var(--spui-card-backdrop,none);border-color:var(--spui-card-border,#ffffff80)}@media(forced-colors:active){:host{border-color:CanvasText;color:CanvasText;background:Canvas}.icon{color:CanvasText}}`;
82
- shadow.append(style, avatar, icon, content, action, actions, button);
83
- }
84
- }
85
- customElements.define("spui-alert", SpuiAlert);
86
- }
@@ -1,3 +0,0 @@
1
- /** Fluent-compatible identity item and overflow popover for AvatarGroup. */
2
- export declare function defineAvatarGroupItem(): void;
3
- export declare function defineAvatarGroupPopover(): void;
@@ -1,189 +0,0 @@
1
- import { base } from "./shared.js";
2
- import { defineAvatar } from "./avatar.js";
3
- import { definePopover } from "./popover.js";
4
- /** Fluent-compatible identity item and overflow popover for AvatarGroup. */
5
- export function defineAvatarGroupItem() {
6
- if (customElements.get("spui-avatar-group-item"))
7
- return;
8
- defineAvatar();
9
- class SpuiAvatarGroupItem extends HTMLElement {
10
- static observedAttributes = ["name", "image", "initials", "size", "shape", "color", "active", "id-for-color"];
11
- avatar;
12
- name;
13
- overflowLabelFallback;
14
- connectedCallback() {
15
- if (!this.shadowRoot)
16
- this.render();
17
- this.sync();
18
- queueMicrotask(() => this.syncContext());
19
- }
20
- attributeChangedCallback() { this.sync(); }
21
- render() {
22
- const shadow = this.attachShadow({ mode: "open" });
23
- const avatar = document.createElement("spui-avatar");
24
- avatar.setAttribute("decorative", "");
25
- const icon = document.createElement("slot");
26
- icon.name = "icon";
27
- icon.slot = "icon";
28
- const badge = document.createElement("slot");
29
- badge.name = "badge";
30
- badge.slot = "badge";
31
- avatar.append(icon, badge);
32
- const name = document.createElement("span");
33
- name.className = "name";
34
- name.part.add("name");
35
- const style = document.createElement("style");
36
- style.textContent = `${base}:host{display:inline-grid;place-items:center;box-sizing:content-box;width:var(--spui-avatar-group-item-size,32px);height:var(--spui-avatar-group-item-size,32px);vertical-align:middle;line-height:1}:host([data-overflow-item]){display:flex;align-items:center;justify-content:flex-start;gap:10px;box-sizing:border-box;width:100%;height:auto;min-height:40px;padding:6px 8px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424));font:var(--spui-font-family,inherit);text-align:start}:host([data-overflow-item]:hover){background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.name{display:none;min-width:0;overflow-wrap:anywhere}:host([data-overflow-item]) .name{display:block}.name:empty{display:none}:host([data-overflow-item]) spui-avatar{flex:none;width:24px;height:24px}@media(forced-colors:active){:host([data-overflow-item]:hover){outline:1px solid Highlight}}`;
37
- const avatarSlot = document.createElement("slot");
38
- avatarSlot.name = "avatar";
39
- avatarSlot.append(avatar);
40
- avatarSlot.addEventListener("slotchange", () => this.sync());
41
- const overflowLabel = document.createElement("slot");
42
- overflowLabel.name = "overflowLabel";
43
- const fallbackLabel = document.createElement("span");
44
- fallbackLabel.textContent = this.getAttribute("name") ?? "";
45
- overflowLabel.append(fallbackLabel);
46
- name.append(overflowLabel);
47
- shadow.append(style, avatarSlot, name);
48
- this.avatar = avatar;
49
- this.name = name;
50
- this.overflowLabelFallback = fallbackLabel;
51
- }
52
- sync() {
53
- if (!this.avatar)
54
- return;
55
- for (const name of SpuiAvatarGroupItem.observedAttributes) {
56
- const value = this.getAttribute(name);
57
- if (value === null)
58
- this.avatar.removeAttribute(name);
59
- else
60
- this.avatar.setAttribute(name, value);
61
- }
62
- const personName = this.getAttribute("name") || "";
63
- if (this.overflowLabelFallback)
64
- this.overflowLabelFallback.textContent = personName;
65
- this.avatar.setAttribute("decorative", "");
66
- if (this.hasAttribute("data-overflow-item")) {
67
- this.setAttribute("role", "listitem");
68
- this.removeAttribute("aria-label");
69
- }
70
- else {
71
- this.setAttribute("role", "img");
72
- if (personName && this.dataset.autoLabel === undefined) {
73
- this.setAttribute("aria-label", personName);
74
- this.dataset.autoLabel = "";
75
- }
76
- else if (!personName && this.dataset.autoLabel !== undefined) {
77
- this.removeAttribute("aria-label");
78
- delete this.dataset.autoLabel;
79
- }
80
- }
81
- const px = Number.parseFloat(this.getAttribute("size") || "32");
82
- this.style.setProperty("--spui-avatar-group-item-size", `${Number.isFinite(px) && px > 0 ? px : 32}px`);
83
- }
84
- syncContext() {
85
- const overflow = this.closest("spui-avatar-group-popover") !== null;
86
- this.toggleAttribute("data-overflow-item", overflow);
87
- this.sync();
88
- }
89
- }
90
- customElements.define("spui-avatar-group-item", SpuiAvatarGroupItem);
91
- }
92
- export function defineAvatarGroupPopover() {
93
- if (customElements.get("spui-avatar-group-popover"))
94
- return;
95
- definePopover();
96
- class SpuiAvatarGroupPopover extends HTMLElement {
97
- static observedAttributes = ["count", "indicator", "label", "trigger-label", "open", "placement"];
98
- popoverElement = document.createElement("spui-popover");
99
- button = document.createElement("button");
100
- list = document.createElement("ul");
101
- slotElement = document.createElement("slot");
102
- observer;
103
- isOpen = false;
104
- get open() { return this.isOpen; }
105
- set open(value) { this.setOpen(Boolean(value)); }
106
- connectedCallback() {
107
- if (!this.shadowRoot)
108
- this.render();
109
- this.observer?.disconnect();
110
- this.observer = new MutationObserver(() => this.sync());
111
- this.observer.observe(this, { childList: true, subtree: true });
112
- this.isOpen = this.hasAttribute("open");
113
- this.sync();
114
- }
115
- disconnectedCallback() { this.observer?.disconnect(); }
116
- attributeChangedCallback(name) {
117
- if (name === "open" && this.isConnected)
118
- this.setOpen(this.hasAttribute("open"), false);
119
- else
120
- this.sync();
121
- }
122
- render() {
123
- const shadow = this.attachShadow({ mode: "open" });
124
- this.popoverElement.setAttribute("placement", "bottom");
125
- this.button.type = "button";
126
- this.button.slot = "trigger";
127
- this.button.className = "trigger";
128
- this.button.part.add("trigger");
129
- this.list.slot = "content";
130
- this.list.className = "list";
131
- this.list.setAttribute("role", "list");
132
- this.slotElement.addEventListener("slotchange", () => this.sync());
133
- this.list.append(this.slotElement);
134
- this.popoverElement.append(this.button, this.list);
135
- this.popoverElement.addEventListener("spui-open-change", event => {
136
- const open = Boolean(event.detail?.open);
137
- if (open === this.isOpen)
138
- return;
139
- this.isOpen = open;
140
- if (this.hasAttribute("open") !== open)
141
- this.toggleAttribute("open", open);
142
- });
143
- const style = document.createElement("style");
144
- style.textContent = `${base}:host{display:inline-flex;align-items:center;vertical-align:middle}.trigger{box-sizing:border-box;display:inline-grid;place-items:center;min-width:32px;height:32px;padding:0 6px;border:2px solid var(--spui-avatar-group-border,var(--spui-ui-surface,#fff));border-radius:999px;background:var(--spui-avatar-group-background,var(--spui-ui-surface-hover,#f5f5f5));color:var(--spui-avatar-group-foreground,var(--spui-ui-text,var(--spui-semantic-body-text,#323130)));font:600 12px/1 var(--spui-font-family,inherit);cursor:pointer}.trigger:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,#005a9e));outline-offset:2px}.list{box-sizing:border-box;display:grid;gap:2px;min-width:180px;max-width:min(320px,calc(100vw - 32px));max-height:min(60vh,480px);overflow:auto;margin:0;padding:4px;list-style:none}.list:empty{display:none}slot::slotted(li){box-sizing:border-box;display:flex;align-items:center;gap:10px;min-height:40px;padding:6px 8px;border-radius:var(--spui-control-radius,4px);color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424));font:var(--spui-font-family,inherit);text-align:start}slot::slotted(li:hover){background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}:host([data-indicator=icon]) .trigger{min-width:32px}.trigger[hidden]{display:none}@media(prefers-reduced-motion:reduce){.trigger{scroll-behavior:auto}}@media(forced-colors:active){.trigger{border-color:ButtonText;background:Canvas;color:CanvasText}}`;
145
- shadow.append(style, this.popoverElement);
146
- }
147
- sync() {
148
- if (!this.shadowRoot)
149
- return;
150
- const members = this.slotElement.assignedElements({ flatten: true });
151
- members.forEach(member => member.toggleAttribute("data-overflow-item", true));
152
- const count = Math.max(0, Number.parseInt(this.getAttribute("count") || String(members.length), 10) || 0);
153
- const icon = this.getAttribute("indicator") === "icon";
154
- this.dataset.indicator = icon ? "icon" : "count";
155
- this.button.hidden = count === 0;
156
- if (icon) {
157
- this.button.replaceChildren();
158
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
159
- svg.setAttribute("viewBox", "0 0 16 16");
160
- svg.setAttribute("width", "16");
161
- svg.setAttribute("height", "16");
162
- svg.setAttribute("aria-hidden", "true");
163
- const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
164
- path.setAttribute("fill", "currentColor");
165
- path.setAttribute("d", "M6 7a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Zm5-.5a2 2 0 1 0 0-4 2 2 0 0 0 0 4ZM1 12.2c0-2.2 2.2-3.7 5-3.7s5 1.5 5 3.7v1H1v-1Zm10.5-3.5c2 0 3.5 1.2 3.5 3v1h-2v-.5a4.5 4.5 0 0 0-1.5-3.5Z");
166
- svg.append(path);
167
- this.button.append(svg);
168
- }
169
- else
170
- this.button.textContent = `+${count}`;
171
- this.button.setAttribute("aria-label", (this.getAttribute("trigger-label") || "View more people").replace("{count}", String(count)));
172
- this.popoverElement.setAttribute("label", this.getAttribute("label") || "More people");
173
- this.popoverElement.setAttribute("placement", this.getAttribute("placement") || "bottom");
174
- this.popoverElement.toggleAttribute("open", this.isOpen);
175
- }
176
- setOpen(value, emit = true) {
177
- const next = Boolean(value);
178
- if (next === this.isOpen)
179
- return;
180
- this.isOpen = next;
181
- if (this.hasAttribute("open") !== next)
182
- this.toggleAttribute("open", next);
183
- this.popoverElement.toggleAttribute("open", next);
184
- if (emit)
185
- this.dispatchEvent(new CustomEvent("spui-open-change", { bubbles: true, composed: true, detail: { open: next } }));
186
- }
187
- }
188
- customElements.define("spui-avatar-group-popover", SpuiAvatarGroupPopover);
189
- }
@@ -1,2 +0,0 @@
1
- /** A compact, accessible stack of Avatar elements with an expandable overflow. */
2
- export declare function defineAvatarGroup(): void;