@spfx-fast/sharepoint-ui 0.0.0-stage → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/AGENTS.md +211 -0
  2. package/LICENSE +21 -0
  3. package/README.md +897 -2
  4. package/components.json +5810 -0
  5. package/dist/appearance.d.ts +6 -0
  6. package/dist/appearance.js +217 -0
  7. package/dist/elements/accordion.d.ts +9 -0
  8. package/dist/elements/accordion.js +338 -0
  9. package/dist/elements/alert.d.ts +2 -0
  10. package/dist/elements/alert.js +62 -0
  11. package/dist/elements/avatar-group-primitives.d.ts +3 -0
  12. package/dist/elements/avatar-group-primitives.js +189 -0
  13. package/dist/elements/avatar-group.d.ts +2 -0
  14. package/dist/elements/avatar-group.js +110 -0
  15. package/dist/elements/avatar.d.ts +4 -0
  16. package/dist/elements/avatar.js +251 -0
  17. package/dist/elements/badge.d.ts +8 -0
  18. package/dist/elements/badge.js +182 -0
  19. package/dist/elements/breadcrumb.d.ts +4 -0
  20. package/dist/elements/breadcrumb.js +233 -0
  21. package/dist/elements/button-group.d.ts +1 -0
  22. package/dist/elements/button-group.js +20 -0
  23. package/dist/elements/button-variants.d.ts +6 -0
  24. package/dist/elements/button-variants.js +339 -0
  25. package/dist/elements/button.d.ts +5 -0
  26. package/dist/elements/button.js +233 -0
  27. package/dist/elements/card-primitives.d.ts +3 -0
  28. package/dist/elements/card-primitives.js +83 -0
  29. package/dist/elements/card.d.ts +5 -0
  30. package/dist/elements/card.js +213 -0
  31. package/dist/elements/carousel.d.ts +92 -0
  32. package/dist/elements/carousel.js +1112 -0
  33. package/dist/elements/color-picker.d.ts +24 -0
  34. package/dist/elements/color-picker.js +1004 -0
  35. package/dist/elements/combobox.d.ts +1 -0
  36. package/dist/elements/combobox.js +1012 -0
  37. package/dist/elements/data-grid-model.d.ts +117 -0
  38. package/dist/elements/data-grid-model.js +294 -0
  39. package/dist/elements/data-grid.d.ts +29 -0
  40. package/dist/elements/data-grid.js +1567 -0
  41. package/dist/elements/date-picker.d.ts +1 -0
  42. package/dist/elements/date-picker.js +486 -0
  43. package/dist/elements/dialog.d.ts +23 -0
  44. package/dist/elements/dialog.js +409 -0
  45. package/dist/elements/divider.d.ts +2 -0
  46. package/dist/elements/divider.js +66 -0
  47. package/dist/elements/drawer.d.ts +3 -0
  48. package/dist/elements/drawer.js +308 -0
  49. package/dist/elements/field-composition.d.ts +26 -0
  50. package/dist/elements/field-composition.js +133 -0
  51. package/dist/elements/field.d.ts +1 -0
  52. package/dist/elements/field.js +67 -0
  53. package/dist/elements/file-upload.d.ts +6 -0
  54. package/dist/elements/file-upload.js +211 -0
  55. package/dist/elements/floating-position.d.ts +26 -0
  56. package/dist/elements/floating-position.js +39 -0
  57. package/dist/elements/image.d.ts +28 -0
  58. package/dist/elements/image.js +38 -0
  59. package/dist/elements/info.d.ts +9 -0
  60. package/dist/elements/info.js +102 -0
  61. package/dist/elements/input.d.ts +5 -0
  62. package/dist/elements/input.js +255 -0
  63. package/dist/elements/label.d.ts +15 -0
  64. package/dist/elements/label.js +56 -0
  65. package/dist/elements/link.d.ts +1 -0
  66. package/dist/elements/link.js +92 -0
  67. package/dist/elements/list.d.ts +19 -0
  68. package/dist/elements/list.js +297 -0
  69. package/dist/elements/menu.d.ts +33 -0
  70. package/dist/elements/menu.js +1103 -0
  71. package/dist/elements/message-bar.d.ts +10 -0
  72. package/dist/elements/message-bar.js +299 -0
  73. package/dist/elements/nav.d.ts +32 -0
  74. package/dist/elements/nav.js +791 -0
  75. package/dist/elements/overflow.d.ts +9 -0
  76. package/dist/elements/overflow.js +218 -0
  77. package/dist/elements/persona.d.ts +3 -0
  78. package/dist/elements/persona.js +124 -0
  79. package/dist/elements/popover.d.ts +77 -0
  80. package/dist/elements/popover.js +840 -0
  81. package/dist/elements/progress-bar.d.ts +4 -0
  82. package/dist/elements/progress-bar.js +82 -0
  83. package/dist/elements/radio-group.d.ts +1 -0
  84. package/dist/elements/radio-group.js +303 -0
  85. package/dist/elements/rating-display.d.ts +2 -0
  86. package/dist/elements/rating-display.js +125 -0
  87. package/dist/elements/rating.d.ts +2 -0
  88. package/dist/elements/rating.js +206 -0
  89. package/dist/elements/rich-text-editor.d.ts +18 -0
  90. package/dist/elements/rich-text-editor.js +508 -0
  91. package/dist/elements/search.d.ts +3 -0
  92. package/dist/elements/search.js +207 -0
  93. package/dist/elements/select.d.ts +6 -0
  94. package/dist/elements/select.js +291 -0
  95. package/dist/elements/shared.d.ts +19 -0
  96. package/dist/elements/shared.js +396 -0
  97. package/dist/elements/skeleton.d.ts +6 -0
  98. package/dist/elements/skeleton.js +91 -0
  99. package/dist/elements/slider.d.ts +1 -0
  100. package/dist/elements/slider.js +248 -0
  101. package/dist/elements/spin-button.d.ts +7 -0
  102. package/dist/elements/spin-button.js +499 -0
  103. package/dist/elements/spinner.d.ts +4 -0
  104. package/dist/elements/spinner.js +124 -0
  105. package/dist/elements/swatch-picker.d.ts +5 -0
  106. package/dist/elements/swatch-picker.js +363 -0
  107. package/dist/elements/table.d.ts +21 -0
  108. package/dist/elements/table.js +261 -0
  109. package/dist/elements/tabs.d.ts +1 -0
  110. package/dist/elements/tabs.js +276 -0
  111. package/dist/elements/tag-picker.d.ts +29 -0
  112. package/dist/elements/tag-picker.js +697 -0
  113. package/dist/elements/tags.d.ts +21 -0
  114. package/dist/elements/tags.js +421 -0
  115. package/dist/elements/teaching-popover.d.ts +32 -0
  116. package/dist/elements/teaching-popover.js +412 -0
  117. package/dist/elements/text.d.ts +5 -0
  118. package/dist/elements/text.js +69 -0
  119. package/dist/elements/textarea.d.ts +1 -0
  120. package/dist/elements/textarea.js +182 -0
  121. package/dist/elements/toast.d.ts +25 -0
  122. package/dist/elements/toast.js +337 -0
  123. package/dist/elements/toaster.d.ts +6 -0
  124. package/dist/elements/toaster.js +356 -0
  125. package/dist/elements/toggle.d.ts +2 -0
  126. package/dist/elements/toggle.js +246 -0
  127. package/dist/elements/toolbar.d.ts +12 -0
  128. package/dist/elements/toolbar.js +381 -0
  129. package/dist/elements/tooltip.d.ts +76 -0
  130. package/dist/elements/tooltip.js +510 -0
  131. package/dist/elements/tree-model.d.ts +19 -0
  132. package/dist/elements/tree-model.js +34 -0
  133. package/dist/elements/tree.d.ts +5 -0
  134. package/dist/elements/tree.js +273 -0
  135. package/dist/elements/view-card.d.ts +2 -0
  136. package/dist/elements/view-card.js +78 -0
  137. package/dist/elements/virtual-list.d.ts +41 -0
  138. package/dist/elements/virtual-list.js +369 -0
  139. package/dist/elements.d.ts +72 -0
  140. package/dist/elements.js +207 -0
  141. package/dist/index.d.ts +76 -0
  142. package/dist/index.js +66 -0
  143. package/dist/react-theme-styles.d.ts +2 -0
  144. package/dist/react-theme-styles.js +75 -0
  145. package/dist/react.d.ts +4540 -0
  146. package/dist/react.js +6799 -0
  147. package/dist/theme.d.ts +169 -0
  148. package/dist/theme.js +167 -0
  149. package/dist/virtualizer-hooks.d.ts +80 -0
  150. package/dist/virtualizer-hooks.js +253 -0
  151. package/package.json +87 -4
  152. package/scripts/generate-token-index.mjs +43 -0
  153. package/scripts/sync-component-catalog-signatures.mjs +55 -0
  154. package/scripts/validate-component-catalog.mjs +44 -0
  155. package/skills/sharepoint-ui/SKILL.md +12 -0
  156. package/skills/sharepoint-ui/references/choosing-components.md +20 -0
  157. package/skills/sharepoint-ui/references/sharepoint-patterns.md +17 -0
  158. package/tokens.json +3777 -0
@@ -0,0 +1,356 @@
1
+ import { defineToast } from "./toast.js";
2
+ export function defineToaster() {
3
+ if (customElements.get("spui-toaster"))
4
+ return;
5
+ defineToast();
6
+ class SpuiToaster extends HTMLElement {
7
+ static observedAttributes = ["position", "aria-label", "limit"];
8
+ announce;
9
+ lastFocused = null;
10
+ previousToastCount = 0;
11
+ restorePending = false;
12
+ toastSlot;
13
+ politeRegion;
14
+ assertiveRegion;
15
+ announcementQueue = [];
16
+ activeAnnouncement;
17
+ announcementTimer;
18
+ announceEnabled = true;
19
+ queuedToasts = new Set();
20
+ activeToasts = new Set();
21
+ toastById = new Map();
22
+ connectedCallback() {
23
+ if (!this.shadowRoot)
24
+ this.render();
25
+ this.setAttribute("role", "region");
26
+ if (!this.hasAttribute("position"))
27
+ this.setAttribute("position", "top-end");
28
+ if (!this.hasAttribute("aria-label"))
29
+ this.setAttribute("aria-label", "Notifications");
30
+ this.toastSlot.addEventListener("slotchange", this.onSlotChange);
31
+ this.addEventListener("spui-dismiss", this.onDismiss);
32
+ this.addEventListener("spui-toast-announce", this.onAnnounce);
33
+ this.addEventListener("keydown", this.onKeyDown);
34
+ this.addEventListener("focusin", this.onFocusIn);
35
+ this.addEventListener("focusout", this.onFocusOut);
36
+ }
37
+ disconnectedCallback() {
38
+ this.removeEventListener("spui-dismiss", this.onDismiss);
39
+ this.removeEventListener("spui-toast-announce", this.onAnnounce);
40
+ this.removeEventListener("keydown", this.onKeyDown);
41
+ this.removeEventListener("focusin", this.onFocusIn);
42
+ this.removeEventListener("focusout", this.onFocusOut);
43
+ this.toastSlot.removeEventListener("slotchange", this.onSlotChange);
44
+ if (this.announcementTimer !== undefined)
45
+ this.ownerDocument.defaultView?.clearTimeout(this.announcementTimer);
46
+ this.announcementTimer = undefined;
47
+ this.announcementQueue = [];
48
+ this.activeAnnouncement = undefined;
49
+ }
50
+ attributeChangedCallback(name) {
51
+ if (name === "position" && !["top-start", "top-end", "bottom-start", "bottom-end"].includes(this.getAttribute(name) ?? ""))
52
+ this.setAttribute(name, "top-end");
53
+ if (name === "limit")
54
+ this.syncQueue();
55
+ }
56
+ show(options) {
57
+ const existing = options.id ? this.toastById.get(options.id) : undefined;
58
+ if (existing) {
59
+ const id = existing.configure(options);
60
+ this.syncQueue();
61
+ return id;
62
+ }
63
+ this.captureFocus();
64
+ const toast = this.ownerDocument.createElement("spui-toast");
65
+ toast.slot = "toast";
66
+ toast.tabIndex = -1;
67
+ const id = toast.configure(options);
68
+ this.append(toast);
69
+ return id;
70
+ }
71
+ registerToast(toast) {
72
+ if (toast.localName !== "spui-toast")
73
+ return;
74
+ const node = toast;
75
+ if (!node.toastId || (node.hidden && !this.queuedToasts.has(node)))
76
+ return;
77
+ this.toastById.set(node.toastId, node);
78
+ if (this.queuedToasts.has(node)) {
79
+ node.hidden = true;
80
+ node.pause("queue");
81
+ return;
82
+ }
83
+ if (this.activeToasts.has(node))
84
+ return;
85
+ if (this.activeToasts.size >= this.limit)
86
+ this.queueToast(node);
87
+ else
88
+ this.activeToasts.add(node);
89
+ }
90
+ refreshQueue() { this.syncQueue(); }
91
+ captureFocus() {
92
+ const active = this.ownerDocument.activeElement;
93
+ if (!this.activeToasts.size && !this.queuedToasts.size && active && active !== this.ownerDocument.body && active.nodeType === 1 && !this.contains(active))
94
+ this.lastFocused = active;
95
+ }
96
+ update(id, options) {
97
+ const toast = this.toastById.get(id);
98
+ if (!toast)
99
+ return false;
100
+ toast.configure({ ...options, priority: options.priority ?? (Number(toast.getAttribute("priority")) || 0), id });
101
+ this.syncQueue();
102
+ return true;
103
+ }
104
+ dismiss(id, reason = "dismiss") {
105
+ const toast = this.toastById.get(id);
106
+ if (!toast)
107
+ return false;
108
+ if (this.queuedToasts.has(toast)) {
109
+ this.queuedToasts.delete(toast);
110
+ toast.hidden = false;
111
+ toast.play("queue");
112
+ }
113
+ toast.dismiss(reason);
114
+ return true;
115
+ }
116
+ dismissAll(reason = "dismiss-all") {
117
+ const toasts = [...this.toasts];
118
+ toasts.forEach(toast => this.dismiss(toast.toastId, reason));
119
+ return toasts.length;
120
+ }
121
+ pause(id) {
122
+ const toast = this.toastById.get(id);
123
+ if (!toast)
124
+ return false;
125
+ toast.pause();
126
+ return true;
127
+ }
128
+ play(id) {
129
+ const toast = this.toastById.get(id);
130
+ if (!toast)
131
+ return false;
132
+ toast.play();
133
+ return true;
134
+ }
135
+ focusNewest() {
136
+ const toast = [...this.toasts].reverse().find(item => !item.hidden);
137
+ if (!toast)
138
+ return false;
139
+ toast.focus();
140
+ return true;
141
+ }
142
+ get toasts() {
143
+ return Array.from(this.children).filter(element => element.localName === "spui-toast");
144
+ }
145
+ get limit() {
146
+ if (!this.hasAttribute("limit"))
147
+ return Number.POSITIVE_INFINITY;
148
+ const value = Number(this.getAttribute("limit"));
149
+ return Number.isFinite(value) && value >= 0 ? Math.floor(value) : Number.POSITIVE_INFINITY;
150
+ }
151
+ get visibleToasts() { return [...this.activeToasts].filter(toast => toast.isConnected && !toast.hidden); }
152
+ queueToast(toast) {
153
+ this.activeToasts.delete(toast);
154
+ this.queuedToasts.add(toast);
155
+ toast.hidden = true;
156
+ toast.pause("queue");
157
+ }
158
+ syncQueue() {
159
+ if (!this.isConnected)
160
+ return;
161
+ const toasts = this.toasts;
162
+ const children = new Set(toasts);
163
+ for (const [id, toast] of this.toastById)
164
+ if (!children.has(toast))
165
+ this.toastById.delete(id);
166
+ for (const toast of this.activeToasts)
167
+ if (!children.has(toast))
168
+ this.activeToasts.delete(toast);
169
+ for (const toast of this.queuedToasts)
170
+ if (!children.has(toast))
171
+ this.queuedToasts.delete(toast);
172
+ for (const toast of toasts)
173
+ this.registerToast(toast);
174
+ const limit = this.limit;
175
+ const visible = toasts.filter(toast => this.activeToasts.has(toast));
176
+ for (const toast of visible.slice(limit))
177
+ this.queueToast(toast);
178
+ const order = new Map(toasts.map((toast, index) => [toast, index]));
179
+ const queued = [...this.queuedToasts].filter(toast => children.has(toast)).sort((a, b) => {
180
+ const priorityA = Number(a.getAttribute("priority")) || 0;
181
+ const priorityB = Number(b.getAttribute("priority")) || 0;
182
+ return priorityA - priorityB || order.get(a) - order.get(b);
183
+ });
184
+ for (const toast of queued.slice(0, Math.max(0, limit - visible.length))) {
185
+ this.queuedToasts.delete(toast);
186
+ this.activeToasts.add(toast);
187
+ toast.hidden = false;
188
+ toast.play("queue");
189
+ }
190
+ }
191
+ onSlotChange = () => {
192
+ this.syncQueue();
193
+ const count = this.visibleToasts.length;
194
+ if (!this.previousToastCount && count && !this.lastFocused) {
195
+ const active = this.ownerDocument.activeElement;
196
+ if (active && active !== this.ownerDocument.body && active.nodeType === 1 && !this.contains(active))
197
+ this.lastFocused = active;
198
+ }
199
+ if (!count && this.previousToastCount && !this.restorePending)
200
+ this.lastFocused = null;
201
+ this.previousToastCount = count;
202
+ };
203
+ onDismiss = (event) => {
204
+ const toast = event.target;
205
+ if (!(toast instanceof HTMLElement) || toast.localName !== "spui-toast")
206
+ return;
207
+ const detail = event.detail;
208
+ const hadFocus = Boolean(detail?.hadFocus) || (this.contains(this.ownerDocument.activeElement) && (this.ownerDocument.activeElement === toast || toast.contains(this.ownerDocument.activeElement)));
209
+ if (hadFocus) {
210
+ this.restorePending = true;
211
+ this.ownerDocument.defaultView?.setTimeout(() => { this.restorePending = false; this.restoreFocus(toast); }, 0);
212
+ }
213
+ this.activeToasts.delete(toast);
214
+ this.queuedToasts.delete(toast);
215
+ const toastId = toast.toastId;
216
+ if (this.toastById.get(toastId) === toast)
217
+ this.toastById.delete(toastId);
218
+ this.syncQueue();
219
+ if (!this.hasAttribute("managed"))
220
+ this.ownerDocument.defaultView?.setTimeout(() => toast.remove(), 0);
221
+ };
222
+ onAnnounce = (event) => {
223
+ const detail = event.detail;
224
+ if (!this.announceEnabled || !detail?.message?.trim() || (this.activeAnnouncement?.message === detail.message))
225
+ return;
226
+ if (this.announcementQueue.some(item => item.id === detail.id && item.message === detail.message))
227
+ return;
228
+ const item = { ...detail, politeness: detail.politeness === "assertive" ? "assertive" : "polite" };
229
+ if (this.announce) {
230
+ this.announce(item.message, { politeness: item.politeness });
231
+ return;
232
+ }
233
+ const index = item.politeness === "assertive" ? this.announcementQueue.findIndex(queued => queued.politeness === "polite") : -1;
234
+ if (index < 0)
235
+ this.announcementQueue.push(item);
236
+ else
237
+ this.announcementQueue.splice(index, 0, item);
238
+ this.presentNextAnnouncement();
239
+ };
240
+ presentNextAnnouncement() {
241
+ if (this.activeAnnouncement || !this.announcementQueue.length)
242
+ return;
243
+ const announcement = this.announcementQueue.shift();
244
+ this.activeAnnouncement = announcement;
245
+ this.politeRegion.textContent = "";
246
+ this.assertiveRegion.textContent = "";
247
+ this.announcementTimer = this.ownerDocument.defaultView.setTimeout(() => {
248
+ const region = announcement.politeness === "assertive" ? this.assertiveRegion : this.politeRegion;
249
+ region.textContent = announcement.message;
250
+ this.announcementTimer = this.ownerDocument.defaultView.setTimeout(() => {
251
+ this.politeRegion.textContent = "";
252
+ this.assertiveRegion.textContent = "";
253
+ this.activeAnnouncement = undefined;
254
+ this.announcementTimer = undefined;
255
+ this.presentNextAnnouncement();
256
+ }, 500);
257
+ }, 50);
258
+ }
259
+ getVisibleFocusables() {
260
+ const focusables = [];
261
+ const visit = (node) => {
262
+ if (node instanceof HTMLElement) {
263
+ if (node.matches('a[href],button,input:not([type="hidden"]),select,textarea,[tabindex]') && node.tabIndex >= 0 && !node.hasAttribute("disabled") && !node.hidden && node.getAttribute("aria-hidden") !== "true" && node.getClientRects().length)
264
+ focusables.push(node);
265
+ if (node.shadowRoot) {
266
+ for (const child of node.shadowRoot.childNodes)
267
+ visit(child);
268
+ return;
269
+ }
270
+ }
271
+ if (node instanceof HTMLSlotElement) {
272
+ const assigned = node.assignedNodes();
273
+ for (const child of assigned.length ? assigned : node.childNodes)
274
+ visit(child);
275
+ return;
276
+ }
277
+ for (const child of node.childNodes)
278
+ visit(child);
279
+ };
280
+ for (const toast of this.visibleToasts)
281
+ visit(toast);
282
+ return focusables;
283
+ }
284
+ onKeyDown = (event) => {
285
+ if (event.key === "Tab") {
286
+ const focusables = this.getVisibleFocusables();
287
+ const target = event.composedPath()[0];
288
+ const current = focusables.findIndex(element => element === target || (target instanceof Node && element.contains(target)));
289
+ const edge = event.shiftKey ? 0 : focusables.length - 1;
290
+ if (focusables.length > 1 && current === edge) {
291
+ event.preventDefault();
292
+ focusables[event.shiftKey ? focusables.length - 1 : 0].focus();
293
+ }
294
+ return;
295
+ }
296
+ if (event.key === "ArrowUp" || event.key === "ArrowDown") {
297
+ const visible = this.toasts.filter(toast => !toast.hidden);
298
+ if (!visible.length)
299
+ return;
300
+ const active = this.ownerDocument.activeElement;
301
+ const current = visible.findIndex(toast => toast === active || toast.contains(active));
302
+ const delta = event.key === "ArrowUp" ? -1 : 1;
303
+ const next = current < 0 ? visible.length - 1 : (current + delta + visible.length) % visible.length;
304
+ event.preventDefault();
305
+ visible[next].focus();
306
+ return;
307
+ }
308
+ if (event.key !== "Escape" && event.key !== "Delete")
309
+ return;
310
+ const active = this.ownerDocument.activeElement;
311
+ const focused = this.toasts.find(toast => toast === active || toast.contains(active));
312
+ const target = event.key === "Delete" ? focused : focused ?? [...this.toasts].reverse().find(toast => !toast.hidden);
313
+ if (!target)
314
+ return;
315
+ event.preventDefault();
316
+ target.dismiss("keyboard");
317
+ };
318
+ onFocusIn = () => { this.announceEnabled = false; for (const toast of this.toasts)
319
+ toast.pause("toaster-focus"); };
320
+ onFocusOut = (event) => {
321
+ if (this.contains(event.relatedTarget))
322
+ return;
323
+ this.announceEnabled = true;
324
+ for (const toast of this.toasts)
325
+ toast.play("toaster-focus");
326
+ };
327
+ restoreFocus(dismissed) {
328
+ const next = [...this.toasts].reverse().find(item => item !== dismissed && !item.hidden);
329
+ if (next)
330
+ next.focus();
331
+ else {
332
+ if (this.lastFocused?.isConnected)
333
+ this.lastFocused.focus();
334
+ this.lastFocused = null;
335
+ }
336
+ }
337
+ render() {
338
+ const shadow = this.attachShadow({ mode: "open" });
339
+ this.toastSlot = this.ownerDocument.createElement("slot");
340
+ this.toastSlot.name = "toast";
341
+ const announcer = this.ownerDocument.createElement("div");
342
+ announcer.className = "announcer";
343
+ this.assertiveRegion = this.ownerDocument.createElement("div");
344
+ this.assertiveRegion.setAttribute("aria-live", "assertive");
345
+ this.assertiveRegion.setAttribute("aria-atomic", "true");
346
+ this.politeRegion = this.ownerDocument.createElement("div");
347
+ this.politeRegion.setAttribute("aria-live", "polite");
348
+ this.politeRegion.setAttribute("aria-atomic", "true");
349
+ announcer.append(this.assertiveRegion, this.politeRegion);
350
+ const style = this.ownerDocument.createElement("style");
351
+ style.textContent = `:host{position:fixed;z-index:var(--spui-toaster-z-index,var(--spui-layer-toast,10000));display:flex;flex-direction:column;gap:var(--spui-toaster-gap,10px);box-sizing:border-box;inline-size:min(100vw,460px);max-block-size:calc(100dvh - env(safe-area-inset-top,0px) - env(safe-area-inset-bottom,0px));overflow:auto;overscroll-behavior:contain;padding:calc(16px + env(safe-area-inset-top,0px)) calc(16px + env(safe-area-inset-right,0px)) calc(16px + env(safe-area-inset-bottom,0px)) calc(16px + env(safe-area-inset-left,0px));pointer-events:none}:host([position=top-start]){inset-block-start:0;inset-inline-start:0;align-items:flex-start}:host([position=top-end]){inset-block-start:0;inset-inline-end:0;align-items:flex-end}:host([position=bottom-start]){inset-block-end:0;inset-inline-start:0;align-items:flex-start;flex-direction:column-reverse}:host([position=bottom-end]){inset-block-end:0;inset-inline-end:0;align-items:flex-end;flex-direction:column-reverse}slot{display:contents}::slotted(spui-toast){max-inline-size:100%}.announcer{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;clip-path:inset(50%);border:0}:host([inline]){position:relative;inset:auto;inline-size:100%;max-block-size:none;overflow:visible;padding:0}:host([inline][position^=bottom]){flex-direction:column}`;
352
+ shadow.replaceChildren(style, this.toastSlot, announcer);
353
+ }
354
+ }
355
+ customElements.define("spui-toaster", SpuiToaster);
356
+ }
@@ -0,0 +1,2 @@
1
+ export declare const defineCheckbox: () => void;
2
+ export declare const defineSwitch: () => void;
@@ -0,0 +1,246 @@
1
+ import { base, rememberNativeFormControlDefaults, stopHostAccessibleNameSync, syncHostAccessibleName } from "./shared.js";
2
+ function defineToggle(name, type) {
3
+ if (customElements.get(name))
4
+ return;
5
+ class SpuiToggle extends HTMLElement {
6
+ static formAssociated = true;
7
+ static observedAttributes = ["checked", "default-checked", "disabled", "disabled-focusable", "required", "name", "value", "aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"];
8
+ internals;
9
+ checkedValue;
10
+ defaultCheckedValue;
11
+ formDisabledValue = false;
12
+ boundInput;
13
+ slotInputDefaults;
14
+ generatedLabelInput;
15
+ generatedLabel = "";
16
+ handleInputChange = (event) => {
17
+ const input = this.getInput();
18
+ if (!input)
19
+ return;
20
+ if (this.isDisabled()) {
21
+ this.syncInput();
22
+ this.syncFormState();
23
+ return;
24
+ }
25
+ const indicator = this.shadowRoot?.querySelector(".indicator");
26
+ if (indicator)
27
+ indicator.dataset.state = input.indeterminate ? "mixed" : input.checked ? "checked" : "unchecked";
28
+ this.syncFormState();
29
+ this.dispatchEvent(new CustomEvent("spui-change", { bubbles: true, composed: true, detail: { checked: input.indeterminate ? "mixed" : input.checked, value: input.value, sourceEvent: event } }));
30
+ };
31
+ handleInputClick = (event) => {
32
+ if (this.isDisabled() && this.isDisabledFocusable())
33
+ event.preventDefault();
34
+ };
35
+ constructor() { super(); this.internals = this.attachInternals(); }
36
+ get checked() { const input = this.getInput(); return input ? (input.indeterminate ? "mixed" : input.checked) : this.checkedValue ?? this.initialChecked(); }
37
+ set checked(value) { this.checkedValue = this.normalizeChecked(value); this.syncInput(); this.syncFormState(); }
38
+ get defaultChecked() { return this.defaultCheckedValue ?? this.initialDefaultChecked(); }
39
+ set defaultChecked(value) { this.defaultCheckedValue = this.normalizeChecked(value); if (this.checkedValue === undefined)
40
+ this.syncInput(); this.syncFormState(); }
41
+ get form() { return this.internals.form; }
42
+ get validity() { return this.internals.validity; }
43
+ get validationMessage() { return this.internals.validationMessage; }
44
+ get willValidate() { return this.internals.willValidate; }
45
+ checkValidity() { return this.internals.checkValidity(); }
46
+ reportValidity() { return this.internals.reportValidity(); }
47
+ formResetCallback() { this.checked = this.defaultChecked; }
48
+ formDisabledCallback(disabled) { this.formDisabledValue = disabled; this.syncInput(); this.syncFormState(); }
49
+ formStateRestoreCallback(state) {
50
+ if (typeof state === "string")
51
+ this.checked = state === "mixed" ? "mixed" : state === "checked";
52
+ }
53
+ getInput() {
54
+ const slot = this.shadowRoot?.querySelector('slot[name="input"]');
55
+ const assigned = slot?.assignedElements().find((element) => element instanceof HTMLInputElement);
56
+ const fallback = this.shadowRoot?.querySelector(".input-fallback");
57
+ if (fallback) {
58
+ fallback.hidden = Boolean(assigned);
59
+ fallback.toggleAttribute("aria-hidden", Boolean(assigned));
60
+ }
61
+ return assigned ?? fallback ?? this.shadowRoot?.querySelector("input") ?? null;
62
+ }
63
+ bindInput(input) {
64
+ if (this.boundInput === input)
65
+ return;
66
+ this.boundInput?.removeEventListener("change", this.handleInputChange);
67
+ this.boundInput?.removeEventListener("click", this.handleInputClick);
68
+ input.addEventListener("change", this.handleInputChange);
69
+ input.addEventListener("click", this.handleInputClick);
70
+ this.boundInput = input;
71
+ }
72
+ syncInputSlot() {
73
+ const slot = this.shadowRoot?.querySelector('slot[name="input"]');
74
+ const assigned = slot?.assignedElements().some(element => element instanceof HTMLInputElement) ?? false;
75
+ const fallback = this.shadowRoot?.querySelector(".input-fallback");
76
+ if (fallback)
77
+ fallback.hidden = assigned;
78
+ const input = this.getInput();
79
+ if (input && !input.classList.contains("input-fallback"))
80
+ this.slotInputDefaults = rememberNativeFormControlDefaults(this.slotInputDefaults, input);
81
+ if (input)
82
+ this.bindInput(input);
83
+ this.syncInput();
84
+ this.syncFormState();
85
+ }
86
+ isDisabled() { return this.formDisabledValue || this.hasAttribute("disabled"); }
87
+ isDisabledFocusable() { return this.isDisabled() && this.hasAttribute("disabled-focusable"); }
88
+ initialChecked() {
89
+ const initial = this.getAttribute("checked") ?? this.getAttribute("default-checked");
90
+ if (initial === null && this.slotInputDefaults)
91
+ return this.slotInputDefaults.checked;
92
+ return type === "checkbox" && initial === "mixed" ? "mixed" : initial !== null;
93
+ }
94
+ initialDefaultChecked() {
95
+ const initial = this.getAttribute("checked") ?? this.getAttribute("default-checked");
96
+ if (initial === null && this.slotInputDefaults)
97
+ return this.slotInputDefaults.defaultChecked;
98
+ return type === "checkbox" && initial === "mixed" ? "mixed" : initial !== null;
99
+ }
100
+ normalizeChecked(value) { return type === "checkbox" && value === "mixed" ? "mixed" : Boolean(value); }
101
+ syncInput() {
102
+ const input = this.getInput();
103
+ if (!input)
104
+ return;
105
+ if (!input.classList.contains("input-fallback"))
106
+ this.slotInputDefaults = rememberNativeFormControlDefaults(this.slotInputDefaults, input);
107
+ const defaults = input.classList.contains("input-fallback") ? undefined : this.slotInputDefaults;
108
+ const checked = this.checkedValue ?? this.defaultCheckedValue ?? this.initialChecked();
109
+ input.checked = checked === true;
110
+ input.indeterminate = checked === "mixed";
111
+ input.disabled = (this.isDisabled() && !this.isDisabledFocusable()) || Boolean(defaults?.disabled);
112
+ input.type = "checkbox";
113
+ if (type === "switch")
114
+ input.setAttribute("role", "switch");
115
+ input.required = this.hasAttribute("required") || Boolean(defaults?.required);
116
+ input.value = this.getAttribute("value") ?? defaults?.value ?? "on";
117
+ input.removeAttribute("name");
118
+ for (const attr of ["aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"]) {
119
+ const value = this.getAttribute(attr);
120
+ if (value !== null && !input.hasAttribute(attr))
121
+ input.setAttribute(attr, value);
122
+ }
123
+ syncHostAccessibleName(this, input);
124
+ if (this.generatedLabelInput && this.generatedLabelInput.getAttribute("aria-label") === this.generatedLabel)
125
+ this.generatedLabelInput.removeAttribute("aria-label");
126
+ this.generatedLabelInput = undefined;
127
+ this.generatedLabel = "";
128
+ if (!input.classList.contains("input-fallback") && !input.hasAttribute("aria-label") && !input.hasAttribute("aria-labelledby")) {
129
+ const labelSlot = this.shadowRoot?.querySelector('slot[name="label"]');
130
+ const label = labelSlot?.assignedNodes({ flatten: true }).map(node => node.textContent ?? "").join("").trim();
131
+ if (label) {
132
+ input.setAttribute("aria-label", label);
133
+ this.generatedLabelInput = input;
134
+ this.generatedLabel = label;
135
+ }
136
+ }
137
+ const indicator = this.shadowRoot?.querySelector(".indicator");
138
+ if (indicator)
139
+ indicator.dataset.state = input.indeterminate ? "mixed" : input.checked ? "checked" : "unchecked";
140
+ if (this.isDisabledFocusable()) {
141
+ input.setAttribute("aria-disabled", "true");
142
+ input.tabIndex = 0;
143
+ }
144
+ else {
145
+ input.removeAttribute("aria-disabled");
146
+ input.removeAttribute("tabindex");
147
+ }
148
+ }
149
+ syncFormState() {
150
+ const input = this.getInput();
151
+ if (!input)
152
+ return;
153
+ const disabled = this.formDisabledValue || input.disabled || this.hasAttribute("disabled");
154
+ const checked = input.checked && !disabled;
155
+ this.internals.setFormValue(checked ? input.value : null, checked ? "checked" : input.indeterminate ? "mixed" : "unchecked");
156
+ const missing = !disabled && input.required && !input.checked;
157
+ this.internals.setValidity(missing ? { valueMissing: true } : {}, missing ? input.validationMessage : "", missing ? input : undefined);
158
+ }
159
+ connectedCallback() {
160
+ if (!this.shadowRoot) {
161
+ const shadow = this.attachShadow({ mode: "open" });
162
+ const label = document.createElement("label");
163
+ const input = document.createElement("input");
164
+ input.type = "checkbox";
165
+ input.className = "input-fallback";
166
+ if (type === "switch")
167
+ input.setAttribute("role", "switch");
168
+ input.part.add("control");
169
+ label.part.add("label");
170
+ input.required = this.hasAttribute("required");
171
+ input.name = this.getAttribute("name") ?? "";
172
+ input.value = this.getAttribute("value") ?? "on";
173
+ for (const attr of ["aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"]) {
174
+ const value = this.getAttribute(attr);
175
+ if (value !== null)
176
+ input.setAttribute(attr, value);
177
+ }
178
+ const text = document.createElement("span");
179
+ const labelSlot = document.createElement("slot");
180
+ labelSlot.name = "label";
181
+ labelSlot.part.add("label");
182
+ labelSlot.append(document.createElement("slot"));
183
+ labelSlot.addEventListener("slotchange", () => this.syncInput());
184
+ text.append(labelSlot);
185
+ const inputSlot = document.createElement("slot");
186
+ inputSlot.name = "input";
187
+ inputSlot.part.add("input");
188
+ inputSlot.append(input);
189
+ inputSlot.addEventListener("slotchange", () => this.syncInputSlot());
190
+ const control = document.createElement("span");
191
+ control.className = "control";
192
+ control.part.add("control");
193
+ const indicator = document.createElement("span");
194
+ indicator.className = "indicator";
195
+ indicator.part.add("indicator");
196
+ indicator.setAttribute("aria-hidden", "true");
197
+ const indicatorSlot = document.createElement("slot");
198
+ indicatorSlot.name = "indicator";
199
+ const mark = document.createElement("span");
200
+ mark.className = "indicator-mark";
201
+ indicatorSlot.append(mark);
202
+ indicatorSlot.addEventListener("slotchange", () => indicator.toggleAttribute("data-custom", indicatorSlot.assignedElements().length > 0));
203
+ indicator.append(indicatorSlot);
204
+ this.bindInput(input);
205
+ control.append(inputSlot, indicator);
206
+ label.append(control, text);
207
+ const styles = type === "switch"
208
+ ? `input{appearance:none;position:relative;box-sizing:border-box;width:38px;height:22px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,var(--colorNeutralStroke1,#8a8886))));border-radius:999px;background:var(--spui-control-background,var(--spui-ui-surface-hover,var(--spui-semantic-input-background,var(--colorNeutralBackground1,#fff))));cursor:pointer;transition:background-color var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}input::after{content:'';position:absolute;top:2px;inset-inline-start:2px;width:16px;height:16px;border-radius:50%;background:var(--spui-ui-muted,var(--spui-semantic-input-foreground,var(--colorNeutralForeground2,#605e5c)));transition:transform var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}input:checked{border-color:var(--spui-primary-background,var(--spui-ui-accent,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,#0078d4))));background:var(--spui-primary-background,var(--spui-ui-accent,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,#0078d4))))}input:checked::after{background:var(--spui-ui-accent-text,var(--colorNeutralForegroundOnBrand,#fff));transform:translateX(16px)}@media(prefers-reduced-motion:reduce){input,input::after{transition:none}}`
209
+ : `input{appearance:none;display:grid;place-content:center;box-sizing:border-box;width:16px;height:16px;margin:0;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886)));border-radius:3px;background:var(--spui-control-background,var(--spui-ui-surface,#fff));color:var(--spui-ui-accent-text,#fff);cursor:pointer}input::before{content:'';width:4px;height:8px;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg) translate(-1px,-1px);opacity:0}input:checked{border-color:var(--spui-ui-accent,var(--spui-semantic-input-background-checked,#0f6cbd));background:var(--spui-ui-accent,var(--spui-semantic-input-background-checked,#0f6cbd))}input:checked::before{opacity:1}input:indeterminate{border-color:var(--spui-ui-accent,var(--spui-semantic-input-background-checked,#0f6cbd));background:var(--spui-ui-accent,var(--spui-semantic-input-background-checked,#0f6cbd))}input:indeterminate::before{width:8px;height:2px;border:0;border-radius:1px;background:currentColor;transform:none;opacity:1}:host([shape=circular]) input{border-radius:50%}:host([shape=circular]) input:indeterminate::before{width:6px;height:6px;border-radius:50%}`;
210
+ const style = document.createElement("style");
211
+ style.textContent = `${base}:host{display:inline-block}label{display:inline-flex;align-items:center;gap:8px;min-height:32px;padding-inline:4px;cursor:pointer}input{flex:none}input:disabled,input[aria-disabled=true]{cursor:not-allowed}label:has(input:disabled),label:has(input[aria-disabled=true]){opacity:.55;cursor:not-allowed}input:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,var(--colorStrokeFocus2,#005a9e)));outline-offset:2px}${styles}:host(:not([size=small])) input[role=switch]{width:40px;height:20px}:host(:not([size=small])) input[role=switch]::after{top:0;width:18px;height:18px}:host(:not([size=small])) input[role=switch]:checked::after{transform:translateX(18px)}:host([dir=rtl]:not([size=small])) input[role=switch]:checked::after,:host-context([dir=rtl]) :host(:not([size=small])) input[role=switch]:checked::after{transform:translateX(-18px)}:host([label-position=before]) label{flex-direction:row-reverse}:host([label-position=above]) label{flex-direction:column;align-items:flex-start}:host([size=small]) label{min-height:24px;gap:6px;padding-inline:5px}:host([size=small]) input[type=checkbox]{width:14px;height:14px}:host([size=small]) input[role=switch]{width:32px;height:16px}:host([size=small]) input[role=switch]::after{top:0;width:14px;height:14px}:host([size=small]) input[role=switch]:checked::after{transform:translateX(14px)}:host([size=small][dir=rtl]) input[role=switch]:checked::after,:host-context([dir=rtl]) :host([size=small]) input[role=switch]:checked::after{transform:translateX(-14px)}:host([size=large]) label{min-height:44px;gap:10px}:host([size=large]) input[type=checkbox]{width:20px;height:20px}:host([dir=rtl]) input:checked::after,:host-context([dir=rtl]) input:checked::after{transform:translateX(-16px)}@media(forced-colors:active){input{forced-color-adjust:none;border-color:ButtonText;background:Canvas}input:checked,input:indeterminate{border-color:Highlight;background:Highlight}input::before,input:checked::before,input:indeterminate::before{color:HighlightText;background:HighlightText}}`;
212
+ if (type === "checkbox")
213
+ style.textContent += `.control{position:relative;display:grid;place-items:center;flex:none;width:16px;height:16px}.control>slot[name=input]{position:absolute;inset:0;z-index:1;width:100%;height:100%}.control>slot[name=input]::slotted(input){position:absolute;inset:0;box-sizing:border-box;width:100%;height:100%;margin:0;appearance:none;opacity:0;cursor:pointer}.indicator{box-sizing:border-box;display:grid;place-items:center;width:100%;height:100%;border:1px solid var(--spui-checkbox-indicator-border,var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886))));border-radius:var(--spui-checkbox-indicator-radius,3px);background:var(--spui-checkbox-indicator-background,var(--spui-control-background,var(--spui-ui-surface,#fff)));color:var(--spui-checkbox-indicator-foreground,var(--spui-ui-accent-text,#fff));transition:background-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),border-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1));pointer-events:none}.indicator[data-state=checked],.indicator[data-state=mixed]{border-color:var(--spui-checkbox-checked-background,var(--spui-ui-accent,var(--colorBrandBackground,#0f6cbd)));background:var(--spui-checkbox-checked-background,var(--spui-ui-accent,var(--colorBrandBackground,#0f6cbd)))}.indicator:not([data-custom])[data-state=checked]::after{content:"";width:4px;height:8px;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg) translate(-1px,-1px)}.indicator:not([data-custom])[data-state=mixed]::after{content:"";width:8px;height:2px;border-radius:1px;background:currentColor}:host([shape=circular]) .indicator{border-radius:50%}:host([shape=circular]) .indicator:not([data-custom])[data-state=mixed]::after{width:6px;height:6px;border-radius:50%}.control:has(input:focus-visible) .indicator{outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,var(--colorStrokeFocus2,#005a9e)));outline-offset:2px}:host([size=small]) .control{width:14px;height:14px}:host([size=large]) .control{width:20px;height:20px}:host([disabled]) .indicator{opacity:.55}slot[name=indicator]::slotted(*){display:grid;place-items:center;max-width:100%;max-height:100%}@media(prefers-reduced-motion:reduce){.indicator{transition:none}}@media(forced-colors:active){.indicator{forced-color-adjust:none;border-color:ButtonText;background:Canvas;color:CanvasText}.indicator[data-state=checked],.indicator[data-state=mixed]{border-color:Highlight;background:Highlight;color:HighlightText}.control:has(input:focus-visible) .indicator{outline-color:Highlight}}`;
214
+ else
215
+ style.textContent += `.control{position:relative;display:grid;align-items:center;flex:none;width:40px;height:20px}.control>slot[name=input]{position:absolute;inset:0;z-index:1;width:100%;height:100%}.control>slot[name=input] input,.control>slot[name=input]::slotted(input){position:absolute;inset:0;box-sizing:border-box;width:100%;height:100%;margin:0;appearance:none;opacity:0;cursor:pointer}.indicator{position:relative;box-sizing:border-box;width:100%;height:100%;border:1px solid var(--spui-switch-track-border,var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886))));border-radius:999px;background:var(--spui-switch-track-background,var(--spui-control-background,var(--spui-ui-surface-hover,var(--colorNeutralBackground1,#fff))));transition:background-color var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),border-color var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1));pointer-events:none}.indicator:not([data-custom])::after{content:"";position:absolute;top:0;inset-inline-start:2px;width:18px;height:18px;border-radius:50%;background:var(--spui-switch-thumb,var(--spui-ui-muted,var(--spui-semantic-input-foreground,var(--colorNeutralForeground2,#605e5c))));transition:transform var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),background-color var(--spui-motion-duration-fast,.12s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}.indicator[data-state=checked]{border-color:var(--spui-switch-checked-background,var(--spui-ui-accent,var(--colorBrandBackground,#0078d4)));background:var(--spui-switch-checked-background,var(--spui-ui-accent,var(--colorBrandBackground,#0078d4)))}.indicator:not([data-custom])[data-state=checked]::after{background:var(--spui-ui-accent-text,var(--colorNeutralForegroundOnBrand,#fff));transform:translateX(18px)}:host([size=small]) .control{width:32px;height:16px}:host([size=small]) .indicator:not([data-custom])::after{width:14px;height:14px}:host([size=small]) .indicator:not([data-custom])[data-state=checked]::after{transform:translateX(14px)}:host([dir=rtl]) .indicator:not([data-custom])[data-state=checked]::after,:host-context([dir=rtl]) :host .indicator:not([data-custom])[data-state=checked]::after{transform:translateX(-18px)}:host([dir=rtl][size=small]) .indicator:not([data-custom])[data-state=checked]::after,:host-context([dir=rtl]) :host([size=small]) .indicator:not([data-custom])[data-state=checked]::after{transform:translateX(-14px)}.control:has(input:focus-visible) .indicator{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#005a9e));outline-offset:2px}:host([disabled]) .indicator{opacity:.55}slot[name=indicator]::slotted(*){display:grid;place-items:center;max-width:100%;max-height:100%}@media(prefers-reduced-motion:reduce){.indicator,.indicator::after{transition:none}}@media(forced-colors:active){.indicator{forced-color-adjust:none;border-color:ButtonText;background:Canvas}.indicator[data-state=checked]{border-color:Highlight;background:Highlight}.indicator:not([data-custom])::after{background:ButtonText}.control:has(input:focus-visible) .indicator{outline-color:Highlight}}`;
216
+ shadow.append(style, label);
217
+ }
218
+ this.syncInputSlot();
219
+ }
220
+ disconnectedCallback() { stopHostAccessibleNameSync(this); }
221
+ attributeChangedCallback(name) {
222
+ const input = this.getInput();
223
+ if (!input)
224
+ return;
225
+ if ((name === "checked" || name === "default-checked") && this.checkedValue === undefined)
226
+ this.syncInput();
227
+ if (name === "disabled" || name === "disabled-focusable")
228
+ this.syncInput();
229
+ if (name === "required")
230
+ input.required = this.hasAttribute(name) || Boolean(this.slotInputDefaults?.required);
231
+ if (name === "name")
232
+ input.removeAttribute("name");
233
+ if (name === "value")
234
+ input.value = this.getAttribute(name) ?? this.slotInputDefaults?.value ?? "on";
235
+ if (name === "aria-label" || name === "aria-labelledby" || name === "aria-description" || name === "aria-describedby" || name === "aria-invalid") {
236
+ const value = this.getAttribute(name);
237
+ value === null ? input.removeAttribute(name) : input.setAttribute(name, value);
238
+ syncHostAccessibleName(this, input);
239
+ }
240
+ this.syncFormState();
241
+ }
242
+ }
243
+ customElements.define(name, SpuiToggle);
244
+ }
245
+ export const defineCheckbox = () => defineToggle("spui-checkbox", "checkbox");
246
+ export const defineSwitch = () => defineToggle("spui-switch", "switch");
@@ -0,0 +1,12 @@
1
+ export type ToolbarCheckedValues = Record<string, readonly string[]>;
2
+ export type ToolbarCheckedValueChange = {
3
+ name: string;
4
+ checkedItems: string[];
5
+ sourceEvent?: Event;
6
+ currentTarget?: HTMLElement;
7
+ };
8
+ export declare function defineToolbarGroup(): void;
9
+ export declare function defineToolbarSeparator(): void;
10
+ export declare function defineToolbarRadioGroup(): void;
11
+ export declare function defineToolbarRadioButton(): void;
12
+ export declare function defineToolbar(): void;