@spfx-fast/sharepoint-ui 0.4.2 → 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 (276) hide show
  1. package/QUICKSTART.md +18 -0
  2. package/README.md +19 -24
  3. package/components.json +240 -5694
  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 -76
  55. package/dist/index.js +60 -66
  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 -4583
  89. package/dist/react.js +1 -6837
  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 -167
  117. package/dist/theme.js +36 -162
  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 +19 -42
  130. package/src/theme.css +125 -0
  131. package/AGENTS.md +0 -211
  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 -62
  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 -1112
  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 -117
  165. package/dist/elements/data-grid-model.js +0 -294
  166. package/dist/elements/data-grid.d.ts +0 -29
  167. package/dist/elements/data-grid.js +0 -1567
  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 -26
  183. package/dist/elements/floating-position.js +0 -39
  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 -299
  200. package/dist/elements/nav.d.ts +0 -32
  201. package/dist/elements/nav.js +0 -791
  202. package/dist/elements/overflow.d.ts +0 -9
  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 -18
  217. package/dist/elements/rich-text-editor.js +0 -508
  218. package/dist/elements/search.d.ts +0 -3
  219. package/dist/elements/search.js +0 -207
  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 -19
  223. package/dist/elements/shared.js +0 -396
  224. package/dist/elements/skeleton.d.ts +0 -6
  225. package/dist/elements/skeleton.js +0 -91
  226. package/dist/elements/slider.d.ts +0 -1
  227. package/dist/elements/slider.js +0 -248
  228. package/dist/elements/spin-button.d.ts +0 -7
  229. package/dist/elements/spin-button.js +0 -499
  230. package/dist/elements/spinner.d.ts +0 -4
  231. package/dist/elements/spinner.js +0 -124
  232. package/dist/elements/swatch-picker.d.ts +0 -5
  233. package/dist/elements/swatch-picker.js +0 -363
  234. package/dist/elements/table.d.ts +0 -21
  235. package/dist/elements/table.js +0 -261
  236. package/dist/elements/tabs.d.ts +0 -1
  237. package/dist/elements/tabs.js +0 -276
  238. package/dist/elements/tag-picker.d.ts +0 -29
  239. package/dist/elements/tag-picker.js +0 -697
  240. package/dist/elements/tags.d.ts +0 -21
  241. package/dist/elements/tags.js +0 -421
  242. package/dist/elements/teaching-popover.d.ts +0 -32
  243. package/dist/elements/teaching-popover.js +0 -412
  244. package/dist/elements/text.d.ts +0 -9
  245. package/dist/elements/text.js +0 -75
  246. package/dist/elements/textarea.d.ts +0 -1
  247. package/dist/elements/textarea.js +0 -182
  248. package/dist/elements/toast.d.ts +0 -25
  249. package/dist/elements/toast.js +0 -337
  250. package/dist/elements/toaster.d.ts +0 -6
  251. package/dist/elements/toaster.js +0 -356
  252. package/dist/elements/toggle.d.ts +0 -2
  253. package/dist/elements/toggle.js +0 -246
  254. package/dist/elements/toolbar.d.ts +0 -12
  255. package/dist/elements/toolbar.js +0 -381
  256. package/dist/elements/tooltip.d.ts +0 -76
  257. package/dist/elements/tooltip.js +0 -510
  258. package/dist/elements/tree-model.d.ts +0 -19
  259. package/dist/elements/tree-model.js +0 -34
  260. package/dist/elements/tree.d.ts +0 -5
  261. package/dist/elements/tree.js +0 -273
  262. package/dist/elements/view-card.d.ts +0 -2
  263. package/dist/elements/view-card.js +0 -78
  264. package/dist/elements/virtual-list.d.ts +0 -41
  265. package/dist/elements/virtual-list.js +0 -369
  266. package/dist/elements.d.ts +0 -72
  267. package/dist/elements.js +0 -207
  268. package/dist/virtualizer-hooks.d.ts +0 -80
  269. package/dist/virtualizer-hooks.js +0 -253
  270. package/scripts/generate-token-index.mjs +0 -43
  271. package/scripts/sync-component-catalog-signatures.mjs +0 -55
  272. package/scripts/validate-component-catalog.mjs +0 -44
  273. package/skills/sharepoint-ui/SKILL.md +0 -12
  274. package/skills/sharepoint-ui/references/choosing-components.md +0 -20
  275. package/skills/sharepoint-ui/references/sharepoint-patterns.md +0 -17
  276. package/tokens.json +0 -3777
@@ -1,409 +0,0 @@
1
- import { base } from "./shared.js";
2
- let dialogId = 0;
3
- const dialogParts = [
4
- ["spui-dialog-surface", "surface"],
5
- ["spui-dialog-title", "title"],
6
- ["spui-dialog-content", "content"],
7
- ["spui-dialog-body", "body"],
8
- ["spui-dialog-actions", "actions"],
9
- ["spui-dialog-trigger", "trigger"],
10
- ];
11
- const documentScrollLocks = new WeakMap();
12
- function acquireDocumentScrollLock(doc) {
13
- const active = documentScrollLocks.get(doc);
14
- if (active) {
15
- active.count++;
16
- return true;
17
- }
18
- const body = doc.body;
19
- const view = doc.defaultView;
20
- if (!body || !view || Math.floor(body.getBoundingClientRect().height) <= view.innerHeight)
21
- return false;
22
- const lock = { count: 1, htmlOverflowY: doc.documentElement.style.overflowY, bodyOverflowY: body.style.overflowY, scrollbarGutter: doc.documentElement.style.scrollbarGutter };
23
- documentScrollLocks.set(doc, lock);
24
- doc.documentElement.style.overflowY = "clip";
25
- doc.documentElement.style.scrollbarGutter = "stable";
26
- body.style.overflowY = "hidden";
27
- return true;
28
- }
29
- function releaseDocumentScrollLock(doc) {
30
- const lock = documentScrollLocks.get(doc);
31
- if (!lock || --lock.count > 0)
32
- return;
33
- if (doc.documentElement.style.overflowY === "clip")
34
- doc.documentElement.style.overflowY = lock.htmlOverflowY;
35
- if (doc.documentElement.style.scrollbarGutter === "stable")
36
- doc.documentElement.style.scrollbarGutter = lock.scrollbarGutter;
37
- if (doc.body?.style.overflowY === "hidden")
38
- doc.body.style.overflowY = lock.bodyOverflowY;
39
- documentScrollLocks.delete(doc);
40
- }
41
- function defineDialogPart(tag, styles, namedSlots = []) {
42
- if (customElements.get(tag))
43
- return;
44
- class SpuiDialogPart extends HTMLElement {
45
- connectedCallback() {
46
- if (this.shadowRoot)
47
- return;
48
- const shadow = this.attachShadow({ mode: "open" });
49
- const style = document.createElement("style");
50
- style.textContent = `${base}:host{${styles}}${tag === "spui-dialog-actions" ? ":host([position=start]){justify-content:flex-start}:host([fluid])::slotted(*){flex:1}" : tag === "spui-dialog-title" ? "slot:not([name]){flex:1;min-width:0}slot[name=action]{margin-inline-start:auto}" : ""}`;
51
- if (tag === "spui-dialog-title") {
52
- this.setAttribute("role", "heading");
53
- this.setAttribute("aria-level", "2");
54
- }
55
- const slot = document.createElement("slot");
56
- shadow.append(style, slot, ...namedSlots.map(name => { const named = document.createElement("slot"); named.name = name; return named; }));
57
- }
58
- }
59
- customElements.define(tag, SpuiDialogPart);
60
- }
61
- export function defineDialogSurface() { defineDialogPart("spui-dialog-surface", "display:block;min-width:0;color:inherit;background:inherit"); }
62
- export function defineDialogTitle() { defineDialogPart("spui-dialog-title", "display:flex;align-items:center;gap:12px;margin:0;padding:20px 20px 0;font-size:20px;line-height:1.3;font-weight:650", ["action"]); }
63
- export function defineDialogContent() { defineDialogPart("spui-dialog-content", "display:block"); }
64
- export function defineDialogBody() { defineDialogPart("spui-dialog-body", "display:block;padding:16px 20px 20px;line-height:1.5"); }
65
- export function defineDialogActions() {
66
- defineDialogPart("spui-dialog-actions", "display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px;padding:12px 20px 20px;border-top:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))");
67
- }
68
- export function defineDialogTrigger() {
69
- const tag = "spui-dialog-trigger";
70
- if (customElements.get(tag))
71
- return;
72
- class SpuiDialogTrigger extends HTMLElement {
73
- constructor() {
74
- super();
75
- this.addEventListener("click", event => this.dispatchEvent(new CustomEvent("spui-dialog-trigger", { bubbles: true, composed: true, detail: { action: this.getAttribute("action") ?? (this.closest('[slot="surface"],spui-dialog-surface') ? "close" : "open"), trigger: event.composedPath().find(node => node instanceof HTMLElement && node.matches("button,a[href],[role=button]")), originalEvent: event } })));
76
- }
77
- connectedCallback() {
78
- if (!this.hasAttribute("slot") && !this.closest('[slot="surface"],spui-dialog-surface'))
79
- this.slot = "trigger";
80
- if (!this.shadowRoot) {
81
- const shadow = this.attachShadow({ mode: "open" });
82
- const style = document.createElement("style");
83
- style.textContent = `${base}:host{display:contents}`;
84
- const slot = document.createElement("slot");
85
- shadow.append(style, slot);
86
- }
87
- }
88
- }
89
- customElements.define(tag, SpuiDialogTrigger);
90
- }
91
- export function defineDialog() {
92
- defineDialogSurface();
93
- defineDialogTitle();
94
- defineDialogContent();
95
- defineDialogBody();
96
- defineDialogActions();
97
- defineDialogTrigger();
98
- if (customElements.get("spui-dialog"))
99
- return;
100
- class SpuiDialog extends HTMLElement {
101
- static observedAttributes = ["open", "default-open", "motion", "motion-visible", "motion-exit-complete", "title", "dialog-label", "modal", "modal-type", "inert-trap-focus", "dismissible", "close-label", "aria-label"];
102
- titleObserver;
103
- previousFocus;
104
- fallbackTrapActive = false;
105
- refocusing = false;
106
- bodyScrollLockHeld = false;
107
- focusGuard;
108
- get open() { return this.hasAttribute("open"); }
109
- set open(value) { this.toggleAttribute("open", Boolean(value)); }
110
- connectedCallback() {
111
- if (!this.shadowRoot)
112
- this.render();
113
- if (!this.hasAttribute("open") && this.hasAttribute("default-open"))
114
- this.open = true;
115
- this.observeTitle();
116
- this.syncOpen();
117
- }
118
- disconnectedCallback() { this.titleObserver?.disconnect(); this.releaseBodyScrollLock(); }
119
- attributeChangedCallback() { if (this.isConnected)
120
- this.syncOpen(); }
121
- syncOpen() {
122
- const dialog = this.shadowRoot?.querySelector("dialog");
123
- if (!dialog)
124
- return;
125
- const motionExiting = this.hasAttribute("motion") && this.getAttribute("motion-visible") === "false" && !this.hasAttribute("motion-exit-complete");
126
- const shouldOpen = this.open || motionExiting;
127
- this.syncBodyScrollLock(shouldOpen);
128
- if (shouldOpen && !dialog.open) {
129
- this.previousFocus ??= document.activeElement instanceof HTMLElement ? document.activeElement : undefined;
130
- const modalType = this.getAttribute("modal-type");
131
- const nonModal = modalType === "non-modal" || (modalType == null && this.hasAttribute("modal") && this.getAttribute("modal") === "false");
132
- if (nonModal || this.getAttribute("inert-trap-focus") === "false" || this.hasAttribute("data-has-custom-backdrop")) {
133
- dialog.show();
134
- this.fallbackTrapActive = !nonModal;
135
- const backdrop = this.shadowRoot?.querySelector(".modal-backdrop");
136
- if (backdrop)
137
- backdrop.hidden = !this.fallbackTrapActive;
138
- if (this.fallbackTrapActive) {
139
- dialog.setAttribute("aria-modal", "true");
140
- queueMicrotask(() => (this.focusableElements()[0] ?? dialog).focus());
141
- this.focusGuard = event => {
142
- if (this.refocusing || event.composedPath().includes(dialog))
143
- return;
144
- this.refocusing = true;
145
- (this.focusableElements()[0] ?? dialog).focus();
146
- queueMicrotask(() => { this.refocusing = false; });
147
- };
148
- document.addEventListener("focus", this.focusGuard, true);
149
- }
150
- }
151
- else
152
- dialog.showModal();
153
- }
154
- else if (!shouldOpen) {
155
- if (dialog.open)
156
- dialog.close();
157
- const restoreFocus = this.fallbackTrapActive ? this.previousFocus : undefined;
158
- this.fallbackTrapActive = false;
159
- const backdrop = this.shadowRoot?.querySelector(".modal-backdrop");
160
- if (backdrop)
161
- backdrop.hidden = true;
162
- if (this.focusGuard)
163
- document.removeEventListener("focus", this.focusGuard, true);
164
- this.focusGuard = undefined;
165
- this.previousFocus = undefined;
166
- if (restoreFocus)
167
- window.setTimeout(() => { if (restoreFocus.isConnected)
168
- restoreFocus.focus(); }, 0);
169
- }
170
- dialog.inert = motionExiting;
171
- if (motionExiting)
172
- dialog.setAttribute("aria-hidden", "true");
173
- else
174
- dialog.removeAttribute("aria-hidden");
175
- if (this.getAttribute("modal-type") === "alert")
176
- dialog.setAttribute("role", "alertdialog");
177
- else
178
- dialog.removeAttribute("role");
179
- const title = this.getAttribute("title");
180
- const fallbackTitle = this.shadowRoot?.querySelector(".fallback-title");
181
- if (fallbackTitle)
182
- fallbackTitle.textContent = title ?? this.getAttribute("dialog-label") ?? "Dialog";
183
- const titleSlot = this.shadowRoot?.querySelector("slot[name=title]");
184
- if (fallbackTitle && titleSlot)
185
- fallbackTitle.hidden = titleSlot.assignedNodes().length > 0;
186
- const close = this.shadowRoot?.querySelector(".close");
187
- if (close) {
188
- close.setAttribute("aria-label", this.getAttribute("close-label") ?? "Close");
189
- close.hidden = this.getAttribute("modal-type") === "alert" || (this.hasAttribute("dismissible") && this.getAttribute("dismissible") === "false");
190
- }
191
- if (dialog)
192
- this.syncAccessibleName(dialog);
193
- }
194
- syncAccessibleName(dialog) {
195
- const explicitLabel = this.getAttribute("aria-label");
196
- const composedTitle = this.querySelector("[data-spui-dialog-title],spui-dialog-title");
197
- if (explicitLabel) {
198
- dialog.setAttribute("aria-label", explicitLabel);
199
- dialog.removeAttribute("aria-labelledby");
200
- }
201
- else if (composedTitle) {
202
- const titleText = composedTitle.matches("[data-spui-dialog-title]")
203
- ? [...composedTitle.childNodes].filter(node => !(node instanceof Element && node.hasAttribute("data-spui-dialog-title-action"))).map(node => node.textContent ?? "").join("").trim()
204
- : composedTitle.shadowRoot?.querySelector("slot:not([name])")?.assignedNodes({ flatten: true }).map(node => node.textContent ?? "").join("").trim();
205
- dialog.setAttribute("aria-label", titleText || this.getAttribute("title") || "Dialog");
206
- dialog.removeAttribute("aria-labelledby");
207
- }
208
- else {
209
- dialog.removeAttribute("aria-label");
210
- dialog.setAttribute("aria-labelledby", "title");
211
- }
212
- }
213
- emitOpenChange(data) {
214
- this.dispatchEvent(new CustomEvent("spui-open-change", { bubbles: true, composed: true, detail: data }));
215
- }
216
- focusableElements() {
217
- const selector = 'button,a[href],input,select,textarea,[tabindex]';
218
- const controls = [];
219
- const seen = new Set();
220
- const visit = (root) => {
221
- for (const element of root.querySelectorAll("*")) {
222
- if (element.closest('[slot="trigger"]'))
223
- continue;
224
- if (element.matches(selector) && !element.matches(":disabled") && element.tabIndex >= 0 && element.getClientRects().length > 0 && !seen.has(element)) {
225
- controls.push(element);
226
- seen.add(element);
227
- }
228
- if (element.shadowRoot)
229
- visit(element.shadowRoot);
230
- if (element instanceof HTMLSlotElement)
231
- for (const assigned of element.assignedElements({ flatten: true }))
232
- visit(assigned);
233
- }
234
- };
235
- visit(this);
236
- return controls;
237
- }
238
- closeDialog(type, event, trigger) {
239
- if (!this.open)
240
- return;
241
- if (this.hasAttribute("motion")) {
242
- if (this.getAttribute("motion-visible") === "false")
243
- return;
244
- this.emitOpenChange({ open: false, type, event, trigger });
245
- return;
246
- }
247
- this.removeAttribute("open");
248
- const dialog = this.shadowRoot?.querySelector("dialog");
249
- if (dialog?.open)
250
- dialog.close();
251
- this.emitOpenChange({ open: false, type, event, trigger });
252
- }
253
- isDismissible() { return !(this.hasAttribute("dismissible") && this.getAttribute("dismissible") === "false"); }
254
- isModal() {
255
- const modalType = this.getAttribute("modal-type");
256
- return modalType === "modal" || (modalType == null && this.getAttribute("modal") !== "false");
257
- }
258
- syncBodyScrollLock(shouldOpen) {
259
- const modalType = this.getAttribute("modal-type");
260
- const shouldLock = shouldOpen && modalType !== "non-modal" && (modalType != null || this.getAttribute("modal") !== "false");
261
- if (shouldLock && !this.bodyScrollLockHeld)
262
- this.bodyScrollLockHeld = acquireDocumentScrollLock(this.ownerDocument);
263
- else if (!shouldLock)
264
- this.releaseBodyScrollLock();
265
- }
266
- releaseBodyScrollLock() {
267
- if (!this.bodyScrollLockHeld)
268
- return;
269
- this.bodyScrollLockHeld = false;
270
- releaseDocumentScrollLock(this.ownerDocument);
271
- }
272
- render() {
273
- const shadow = this.attachShadow({ mode: "open" });
274
- const dialog = document.createElement("dialog");
275
- dialog.id = `spui-dialog-${++dialogId}`;
276
- dialog.part.add("surface");
277
- dialog.setAttribute("aria-labelledby", "title");
278
- const header = document.createElement("header");
279
- const heading = document.createElement("h2");
280
- heading.id = "title";
281
- const fallbackTitle = document.createElement("span");
282
- fallbackTitle.className = "fallback-title";
283
- fallbackTitle.textContent = this.getAttribute("title") ?? this.getAttribute("dialog-label") ?? "Dialog";
284
- const titleSlot = document.createElement("slot");
285
- titleSlot.name = "title";
286
- titleSlot.addEventListener("slotchange", () => { fallbackTitle.hidden = titleSlot.assignedNodes().length > 0; });
287
- heading.append(fallbackTitle, titleSlot);
288
- const close = document.createElement("button");
289
- close.type = "button";
290
- close.className = "close";
291
- close.part.add("close-button");
292
- const closeMark = document.createElement("span");
293
- closeMark.setAttribute("aria-hidden", "true");
294
- closeMark.textContent = "×";
295
- close.append(closeMark);
296
- close.addEventListener("click", event => this.closeDialog("triggerClick", event));
297
- header.append(heading, close);
298
- const body = document.createElement("div");
299
- body.className = "body";
300
- body.part.add("body");
301
- body.append(document.createElement("slot"));
302
- const footer = document.createElement("footer");
303
- footer.part.add("actions");
304
- footer.hidden = true;
305
- const actions = document.createElement("slot");
306
- actions.name = "actions";
307
- actions.addEventListener("slotchange", () => { footer.hidden = actions.assignedElements().length === 0; });
308
- footer.append(actions);
309
- dialog.append(header, body, footer);
310
- const surface = document.createElement("slot");
311
- surface.name = "surface";
312
- surface.addEventListener("slotchange", () => {
313
- const composed = surface.assignedElements().length > 0;
314
- header.hidden = false;
315
- heading.hidden = composed;
316
- body.hidden = composed;
317
- footer.hidden = composed;
318
- this.syncAccessibleName(dialog);
319
- if (this.fallbackTrapActive)
320
- requestAnimationFrame(() => (this.focusableElements()[0] ?? dialog).focus());
321
- });
322
- this.titleObserver = new MutationObserver(() => this.syncAccessibleName(dialog));
323
- dialog.insertBefore(surface, body);
324
- dialog.addEventListener("cancel", event => event.preventDefault());
325
- dialog.addEventListener("keydown", event => {
326
- if (event.key === "Escape") {
327
- if (event.defaultPrevented)
328
- return;
329
- window.setTimeout(() => {
330
- if (event.defaultPrevented || !this.open)
331
- return;
332
- event.preventDefault();
333
- if (this.isDismissible())
334
- this.closeDialog("escapeKeyDown", event);
335
- }, 0);
336
- return;
337
- }
338
- if (!this.fallbackTrapActive)
339
- return;
340
- if (event.key !== "Tab")
341
- return;
342
- const controls = this.focusableElements();
343
- if (!controls.length) {
344
- event.preventDefault();
345
- dialog.focus();
346
- return;
347
- }
348
- const target = event.composedPath()[0];
349
- const index = controls.indexOf(target instanceof HTMLElement ? target : document.activeElement);
350
- if (event.shiftKey && index <= 0) {
351
- event.preventDefault();
352
- controls.at(-1)?.focus();
353
- }
354
- else if (!event.shiftKey && index === controls.length - 1) {
355
- event.preventDefault();
356
- controls[0]?.focus();
357
- }
358
- });
359
- dialog.addEventListener("click", event => {
360
- if (event.target !== dialog || !this.isModal() || !this.isDismissible())
361
- return;
362
- const rect = dialog.getBoundingClientRect();
363
- if (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom)
364
- this.closeDialog("backdropClick", event);
365
- });
366
- const style = document.createElement("style");
367
- style.textContent = `${base}:host{display:contents}dialog{position:relative;z-index:2147483647;box-sizing:border-box;width:min(520px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);overflow:auto;padding:0;border:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1));border-radius:var(--spui-card-radius,12px);background:var(--spui-card-background,var(--spui-ui-surface,#fff));box-shadow:var(--spui-card-shadow,0 16px 48px #0004);color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424))}dialog::backdrop{background:color-mix(in srgb,var(--spui-ui-text,#242424) 42%,transparent);backdrop-filter:blur(2px)}:host([backdrop-appearance=transparent]) dialog::backdrop{background:transparent;backdrop-filter:none}header{display:flex;align-items:start;justify-content:space-between;gap:16px;padding:20px 20px 0}h2{margin:0;font-size:20px;line-height:1.3;font-weight:650}.close{display:inline-grid;place-items:center;flex:none;width:var(--spui-control-height,32px);height:var(--spui-control-height,32px);margin:-5px -6px 0 0;margin-left:auto;border:0;border-radius:var(--spui-control-radius,6px);background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.close:hover{background:var(--spui-ui-surface-hover,#f5f5f5)}.close:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}.body{padding:16px 20px 20px;line-height:1.5}footer{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px;padding:12px 20px 20px;border-top:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))}footer[hidden]{display:none}@media(forced-colors:active){dialog{border-color:CanvasText;box-shadow:none}dialog::backdrop{background:Canvas} .close:focus-visible{outline-color:Highlight}}`;
368
- const overlayStyle = document.createElement("style");
369
- overlayStyle.textContent = ".modal-backdrop{position:fixed;inset:0;z-index:2147483000;background:color-mix(in srgb,var(--spui-ui-text,#242424) 42%,transparent);backdrop-filter:blur(2px)}.modal-backdrop[hidden]{display:none}.modal-backdrop slot{position:absolute;inset:0}:host([data-has-custom-backdrop]) .modal-backdrop{background:transparent;backdrop-filter:none}:host([backdrop-appearance=transparent]) .modal-backdrop{background:transparent;backdrop-filter:none}::slotted([slot=backdrop]){position:absolute;inset:0;display:block;background:color-mix(in srgb,var(--spui-ui-text,#242424) 42%,transparent)}::slotted([slot=backdrop][data-appearance=transparent]){background:transparent}";
370
- const backdrop = document.createElement("div");
371
- backdrop.className = "modal-backdrop";
372
- backdrop.part.add("backdrop");
373
- backdrop.hidden = true;
374
- backdrop.setAttribute("aria-hidden", "true");
375
- const backdropSlot = document.createElement("slot");
376
- backdropSlot.name = "backdrop";
377
- backdrop.append(backdropSlot);
378
- backdrop.addEventListener("click", event => { if (this.isModal() && this.isDismissible())
379
- this.closeDialog("backdropClick", event); });
380
- const triggerSlot = document.createElement("slot");
381
- triggerSlot.name = "trigger";
382
- triggerSlot.addEventListener("slotchange", () => {
383
- for (const trigger of triggerSlot.assignedElements()) {
384
- const innerSlot = trigger.shadowRoot?.querySelector("slot");
385
- for (const target of innerSlot?.assignedElements({ flatten: true }) ?? []) {
386
- if (!trigger.hasAttribute("disable-button-enhancement") && !target.hasAttribute("aria-haspopup"))
387
- target.setAttribute("aria-haspopup", "dialog");
388
- }
389
- }
390
- });
391
- shadow.append(style, overlayStyle, triggerSlot, backdrop, dialog);
392
- this.addEventListener("spui-dialog-trigger", event => {
393
- const detail = event.detail;
394
- if (detail?.action === "close")
395
- this.closeDialog("triggerClick", detail.originalEvent, detail.trigger);
396
- else if (!this.open) {
397
- this.previousFocus = detail?.trigger ?? this.querySelector('spui-dialog-trigger[slot="trigger"] button,spui-dialog-trigger[slot="trigger"] a[href],[slot="trigger"] [role="button"]') ?? undefined;
398
- this.open = true;
399
- if (detail?.originalEvent)
400
- this.emitOpenChange({ open: true, type: "triggerClick", event: detail.originalEvent, trigger: detail.trigger });
401
- }
402
- });
403
- }
404
- observeTitle() {
405
- this.titleObserver?.observe(this, { subtree: true, childList: true, characterData: true });
406
- }
407
- }
408
- customElements.define("spui-dialog", SpuiDialog);
409
- }
@@ -1,2 +0,0 @@
1
- export type DividerAppearance = "brand" | "default" | "strong" | "subtle";
2
- export declare function defineDivider(): void;
@@ -1,66 +0,0 @@
1
- import { base } from "./shared.js";
2
- export function defineDivider() {
3
- if (customElements.get("spui-divider"))
4
- return;
5
- class SpuiDivider extends HTMLElement {
6
- static observedAttributes = ["orientation", "vertical", "align", "align-content", "appearance", "inset"];
7
- generatedAriaLabel;
8
- connectedCallback() {
9
- if (!this.shadowRoot)
10
- this.render();
11
- this.sync();
12
- }
13
- attributeChangedCallback() { if (this.isConnected)
14
- this.sync(); }
15
- sync() {
16
- const orientation = this.hasAttribute("vertical") || this.getAttribute("orientation") === "vertical" ? "vertical" : "horizontal";
17
- this.dataset.orientation = orientation;
18
- const wrapper = this.shadowRoot?.querySelector("slot[name=wrapper]");
19
- const slot = this.shadowRoot?.querySelector("slot:not([name])");
20
- const hasLabel = Boolean(wrapper?.assignedNodes().length
21
- ? wrapper.assignedNodes().some(node => node.nodeType === Node.ELEMENT_NODE || Boolean(node.textContent?.trim()))
22
- : slot?.assignedNodes().some(node => node.nodeType === Node.ELEMENT_NODE || Boolean(node.textContent?.trim())));
23
- this.dataset.hasLabel = String(hasLabel);
24
- this.dataset.alignContent = this.getAttribute("align-content") ?? this.getAttribute("align") ?? "center";
25
- this.dataset.dividerAppearance = this.getAttribute("appearance") ?? "default";
26
- this.setAttribute("role", "separator");
27
- this.setAttribute("aria-orientation", orientation);
28
- if (hasLabel && !this.hasAttribute("aria-labelledby")) {
29
- const label = this.textContent?.trim();
30
- if (label && (this.getAttribute("aria-label") === null || this.getAttribute("aria-label") === this.generatedAriaLabel)) {
31
- this.generatedAriaLabel = label;
32
- if (this.getAttribute("aria-label") !== label)
33
- this.setAttribute("aria-label", label);
34
- }
35
- }
36
- else if (this.generatedAriaLabel !== undefined && this.getAttribute("aria-label") === this.generatedAriaLabel) {
37
- this.removeAttribute("aria-label");
38
- this.generatedAriaLabel = undefined;
39
- }
40
- }
41
- render() {
42
- const shadow = this.attachShadow({ mode: "open" });
43
- const before = document.createElement("span");
44
- before.className = "line";
45
- before.part.add("line");
46
- before.setAttribute("aria-hidden", "true");
47
- const after = document.createElement("span");
48
- after.className = "line";
49
- after.part.add("line");
50
- after.setAttribute("aria-hidden", "true");
51
- const wrapper = document.createElement("div");
52
- wrapper.className = "wrapper";
53
- const wrapperSlot = document.createElement("slot");
54
- wrapperSlot.name = "wrapper";
55
- wrapperSlot.addEventListener("slotchange", () => this.sync());
56
- const slot = document.createElement("slot");
57
- slot.addEventListener("slotchange", () => this.sync());
58
- wrapperSlot.append(slot);
59
- wrapper.append(wrapperSlot);
60
- const style = document.createElement("style");
61
- style.textContent = `${base}:host{display:flex;align-items:center;gap:var(--spui-divider-gap,12px);min-width:0;margin-block:var(--spui-divider-margin-block,12px);color:var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161));font:inherit}:host([data-orientation=vertical]){display:inline-flex;flex-direction:column;align-self:stretch;min-height:1em;width:1px;margin-inline:var(--spui-divider-margin-inline,12px);margin-block:0}:host([data-has-label=false]) .wrapper{display:none}:host([data-has-label=false]) .line:last-of-type{display:none}:host([data-has-label=true]) .wrapper{font-size:.875em;line-height:1.25;text-align:center}.wrapper{min-width:0}.line{flex:1;min-height:1px;background:var(--spui-divider-color,var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1)))}:host([data-orientation=vertical]) .line{min-height:0;width:1px;height:auto;min-width:1px;background:var(--spui-divider-color,var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1)))}:host([data-divider-appearance=brand]) .line{background:var(--spui-divider-color,var(--spui-base-accent,var(--spui-ui-accent,#0078d4)))}:host([data-divider-appearance=strong]) .line{background:var(--spui-divider-color,color-mix(in srgb,var(--spui-ui-text,#242424) 44%,var(--spui-ui-stroke,#d1d1d1)))}:host([data-divider-appearance=subtle]) .line{background:var(--spui-divider-color,color-mix(in srgb,var(--spui-ui-stroke,#d1d1d1) 56%,transparent))}:host([data-align-content=start]) .line:first-of-type{flex:0}:host([data-align-content=end]) .line:last-of-type{flex:0}:host([data-align-content=center]) .line{flex:1}:host([inset]){margin-inline-start:var(--spui-divider-inset,16px)}@media(forced-colors:active){.line{background:CanvasText}}`;
62
- shadow.append(style, before, wrapper, after);
63
- }
64
- }
65
- customElements.define("spui-divider", SpuiDivider);
66
- }
@@ -1,3 +0,0 @@
1
- export declare function defineDrawer(): void;
2
- /** Non-modal, in-flow companion surface for navigation and supporting work. */
3
- export declare function defineInlineDrawer(): void;