@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,261 +0,0 @@
1
- import { base } from "./shared.js";
2
- export function createTableColumn(options) {
3
- return { columnId: options.columnId, compare: options.compare ?? (() => 0), renderHeaderCell: options.renderHeaderCell ?? (() => null), renderCell: options.renderCell ?? (() => null) };
4
- }
5
- function defineSlotted({ tag, role, display, css, attributes = [], namedSlots = [], sync }) {
6
- if (customElements.get(tag))
7
- return;
8
- class SpuiTablePart extends HTMLElement {
9
- static observedAttributes = attributes;
10
- connectedCallback() {
11
- if (!this.shadowRoot) {
12
- const shadow = this.attachShadow({ mode: "open" });
13
- const style = document.createElement("style");
14
- const closesHostRule = css.includes("}");
15
- style.textContent = `${base}:host{box-sizing:border-box;display:${display};min-width:0;color:inherit;font:inherit;${css}${closesHostRule ? "" : "}"}`;
16
- const slot = document.createElement("slot");
17
- shadow.append(style, slot, ...namedSlots.map(name => { const named = document.createElement("slot"); named.name = name; return named; }));
18
- if (!this.hasAttribute("role"))
19
- this.setAttribute("role", role);
20
- }
21
- sync?.(this, this.shadowRoot);
22
- }
23
- attributeChangedCallback() { if (this.isConnected)
24
- sync?.(this, this.shadowRoot); }
25
- }
26
- customElements.define(tag, SpuiTablePart);
27
- }
28
- export function defineTableCellActions() {
29
- defineSlotted({ tag: "spui-table-cell-actions", role: "presentation", display: "inline-flex", attributes: ["visible"], css: `gap:var(--spui-table-action-gap,4px);align-items:center;margin-inline-start:auto;opacity:0;transition:opacity var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}:host([visible]),:host(:focus-within),:host(:hover){opacity:1}:host([hidden]){display:none}@media(prefers-reduced-motion:reduce){:host{transition:none}}@media(forced-colors:active){:host{opacity:1}}` });
30
- }
31
- export function defineTableCellLayout() {
32
- defineSlotted({ tag: "spui-table-cell-layout", role: "presentation", display: "flex", attributes: ["appearance", "truncate"], namedSlots: ["media", "main", "description"], css: `align-items:center;gap:var(--spui-table-cell-gap,8px);min-width:0;min-height:inherit}:host([appearance=primary]){font-weight:600}:host([truncate]){overflow:hidden;text-overflow:ellipsis;white-space:nowrap}::slotted([slot=media]){display:inline-flex;flex:none;align-items:center}::slotted([slot=main]){flex:1;min-width:0}::slotted([slot=description]){color:var(--spui-ui-muted,var(--colorNeutralForeground2,#616161));font-size:.9em}` });
33
- }
34
- export function defineTableCell() {
35
- defineSlotted({ tag: "spui-table-cell", role: "cell", display: "table-cell", css: `padding:var(--spui-table-cell-padding,10px 12px);border-block-end:1px solid var(--spui-ui-stroke,var(--colorNeutralStroke2,#e1dfdd));vertical-align:middle;overflow-wrap:anywhere}:host-context(spui-table[no-native-elements]){display:flex;flex:1 1 0;min-width:0;align-items:center}` });
36
- }
37
- export function defineTableHeaderCell() {
38
- defineSlotted({
39
- tag: "spui-table-header-cell", role: "columnheader", display: "table-cell", attributes: ["sortable", "sort-direction"], namedSlots: ["button", "aside"],
40
- css: `position:relative;padding:var(--spui-table-header-padding,10px 12px);border-block-end:1px solid var(--spui-ui-stroke,var(--colorNeutralStroke1,#d1d1d1));color:var(--spui-ui-text,var(--colorNeutralForeground1,#242424));font-weight:600;text-align:start;vertical-align:middle}:host([sortable]){padding:0}:host([aria-sort=ascending]),:host([aria-sort=descending]){color:var(--spui-ui-accent,var(--colorBrandForeground1,#0f6cbd))}.sort-button,::slotted([slot=button]){box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-height:40px;padding:10px 12px;border:0;background:transparent;color:inherit;font:inherit;text-align:inherit}.sort-button[role=button],::slotted([slot=button][role=button]){cursor:pointer}.sort-button[role=button]:hover,::slotted([slot=button][role=button]:hover){background:var(--spui-ui-surface-hover,var(--colorNeutralBackground1Hover,#f5f5f5))}.sort-button[role=button]:focus-visible,::slotted([slot=button][role=button]:focus-visible){outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:-2px}.sort-icon{display:inline-flex;align-items:center;justify-content:center;width:8px;height:8px;flex:none;opacity:.55}.sort-icon::before{content:"";display:block;width:6px;height:6px;border:solid currentColor;border-width:0 1.5px 1.5px 0;transform:rotate(45deg) translate(-1px,-1px)}.sort-icon.custom::before{display:none}.sort-icon slot::slotted(*){display:inline-flex;align-items:center;justify-content:center}:host([sort-direction=ascending]) .sort-icon::before{transform:rotate(225deg) translate(-1px,-1px)}:host(:not([sortable])) .sort-icon{display:none}@media(forced-colors:active){.sort-button:focus-visible,::slotted([slot=button][role=button]:focus-visible){outline-color:Highlight}}:host-context(spui-table[no-native-elements]){display:flex;flex:1 1 0;min-width:0;align-items:center}`,
41
- sync: (host, root) => {
42
- const sortable = host.hasAttribute("sortable");
43
- host.toggleAttribute("data-sortable", sortable);
44
- const direction = host.getAttribute("sort-direction");
45
- if (direction === "ascending" || direction === "descending")
46
- host.setAttribute("aria-sort", direction);
47
- else
48
- host.removeAttribute("aria-sort");
49
- const buttonSlot = root.querySelector('slot[name="button"]');
50
- let button = buttonSlot.querySelector(".sort-button");
51
- if (!button) {
52
- button = document.createElement("div");
53
- button.className = "sort-button";
54
- button.part.add("sort-button");
55
- const content = document.createElement("span");
56
- content.part.add("content");
57
- const contentSlot = root.querySelector("slot:not([name])");
58
- content.append(contentSlot);
59
- const icon = document.createElement("span");
60
- icon.className = "sort-icon";
61
- icon.setAttribute("aria-hidden", "true");
62
- icon.part.add("sort-icon");
63
- const iconSlot = document.createElement("slot");
64
- iconSlot.name = "sort-icon";
65
- iconSlot.addEventListener("slotchange", () => icon.classList.toggle("custom", iconSlot.assignedNodes({ flatten: true }).length > 0));
66
- icon.append(iconSlot);
67
- button.append(content, icon);
68
- buttonSlot.append(button);
69
- }
70
- if (sortable)
71
- button.setAttribute("role", "button");
72
- else
73
- button.removeAttribute("role");
74
- button.tabIndex = sortable ? 0 : -1;
75
- const assignedButton = buttonSlot.assignedElements({ flatten: true }).find(element => element instanceof HTMLElement);
76
- if (assignedButton) {
77
- if (sortable) {
78
- if (!assignedButton.hasAttribute("role"))
79
- assignedButton.setAttribute("role", "button");
80
- if (!assignedButton.hasAttribute("tabindex"))
81
- assignedButton.tabIndex = 0;
82
- }
83
- }
84
- if (!host.__spuiHeaderSortListener) {
85
- host.__spuiHeaderSortListener = true;
86
- const sort = () => {
87
- if (!host.hasAttribute("sortable"))
88
- return;
89
- const next = host.getAttribute("sort-direction") === "ascending" ? "descending" : "ascending";
90
- host.dispatchEvent(new CustomEvent("spui-table-sort", { bubbles: true, composed: true, detail: { direction: next, columnId: host.getAttribute("column-id") } }));
91
- };
92
- const isTrigger = (event) => event.composedPath().some(node => node === button || buttonSlot.assignedElements({ flatten: true }).includes(node));
93
- host.addEventListener("click", event => { if (isTrigger(event))
94
- sort(); });
95
- host.addEventListener("keydown", event => {
96
- if ((event.key === "Enter" || event.key === " ") && isTrigger(event)) {
97
- const path = event.composedPath();
98
- const target = buttonSlot.assignedElements({ flatten: true }).find(element => path.includes(element)) ?? button;
99
- if (target.tagName === "BUTTON" || (event.key === "Enter" && target.tagName === "A"))
100
- return;
101
- event.preventDefault();
102
- sort();
103
- }
104
- });
105
- }
106
- },
107
- });
108
- }
109
- export function defineTableRow() {
110
- defineSlotted({ tag: "spui-table-row", role: "row", display: "table-row", attributes: ["appearance", "selected"], css: `color:var(--spui-ui-text,var(--colorNeutralForeground1,#242424))}:host(:hover){background:var(--spui-table-row-hover,var(--spui-ui-surface-hover,#f5f5f5))}:host([selected]){background:color-mix(in srgb,var(--spui-ui-accent,#0f6cbd) 10%,var(--spui-ui-surface,#fff))}:host([appearance=brand]){background:color-mix(in srgb,var(--spui-ui-accent,#0f6cbd) 10%,var(--spui-ui-surface,#fff))}:host([appearance=neutral]){background:var(--spui-ui-surface-hover,#f5f5f5)}:host([appearance=none]){background:transparent}:host([selected]) spui-table-cell,:host([selected]) spui-table-header-cell{font-weight:600}@media(forced-colors:active){:host([selected]){outline:1px solid Highlight}}:host-context(spui-table[no-native-elements]){display:flex;align-items:stretch;width:100%;min-width:100%}`, sync: host => { if (host.hasAttribute("selected"))
111
- host.setAttribute("aria-selected", "true");
112
- else
113
- host.removeAttribute("aria-selected"); } });
114
- }
115
- export function defineTableHeader() {
116
- defineSlotted({ tag: "spui-table-header", role: "rowgroup", display: "table-header-group", css: `background:var(--spui-table-header-background,var(--spui-ui-surface-subtle,var(--colorNeutralBackground2,#faf9f8)))}:host-context(spui-table[no-native-elements]){display:flex;flex-direction:column}` });
117
- }
118
- export function defineTableBody() {
119
- defineSlotted({ tag: "spui-table-body", role: "rowgroup", display: "table-row-group", css: `:host-context(spui-table[no-native-elements]){display:flex;flex-direction:column}` });
120
- }
121
- export function defineTableSelectionCell() {
122
- defineSlotted({
123
- tag: "spui-table-selection-cell", role: "cell", display: "table-cell", attributes: ["type", "checked", "subtle", "invisible", "hidden"], namedSlots: ["checkbox-indicator", "radio-indicator"],
124
- css: `position:relative;width:44px;min-width:44px;padding:4px 8px;text-align:center;vertical-align:middle}:host([hidden]){display:none}:host([invisible]){visibility:hidden}.select{box-sizing:border-box;display:inline-grid;place-items:center;width:20px;height:20px;margin:0;accent-color:var(--spui-ui-accent,#0f6cbd);cursor:pointer;transition:opacity var(--spui-motion-duration-fast,100ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}:host([data-custom-indicator]) .select{position:absolute;inset:0;margin:auto;opacity:0}:host([subtle]) .select{opacity:0}:host([subtle][checked]) .select,:host([subtle]:focus-within) .select,:host-context(spui-table-row:hover) .select{opacity:1}:host([data-custom-indicator]) .select{opacity:0}::slotted([slot=checkbox-indicator]),::slotted([slot=radio-indicator]){display:inline-flex;align-items:center;justify-content:center;pointer-events:none}::slotted([data-indeterminate=true]){forced-color-adjust:auto}.select:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:2px}:host([data-custom-indicator]:focus-within) ::slotted([data-checked]),:host([data-custom-indicator]:focus-within) ::slotted([slot=checkbox-indicator]),:host([data-custom-indicator]:focus-within) ::slotted([slot=radio-indicator]){outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:2px;border-radius:var(--spui-control-radius,4px)}@media(prefers-reduced-motion:reduce){.select{transition:none}}@media(forced-colors:active){.select{accent-color:Highlight}:host([subtle]) .select{opacity:1}}:host-context(spui-table[no-native-elements]){display:flex;flex:0 0 44px;align-items:center;justify-content:center}`,
125
- sync: (host, root) => {
126
- let input = root.querySelector("input");
127
- if (!input) {
128
- input = document.createElement("input");
129
- input.className = "select";
130
- input.part.add("input");
131
- root.append(input);
132
- input.addEventListener("change", () => {
133
- host.toggleAttribute("checked", input.checked);
134
- host.dispatchEvent(new CustomEvent("spui-table-selection-change", { bubbles: true, composed: true, detail: { checked: input.checked, type: input.type } }));
135
- });
136
- }
137
- input.type = host.getAttribute("type") === "radio" ? "radio" : "checkbox";
138
- input.checked = host.hasAttribute("checked");
139
- input.indeterminate = host.getAttribute("checked") === "mixed";
140
- const slotName = input.type === "radio" ? "radio-indicator" : "checkbox-indicator";
141
- const indicatorSlot = root.querySelector(`slot[name="${slotName}"]`);
142
- const indicators = indicatorSlot.assignedElements({ flatten: true });
143
- host.toggleAttribute("data-custom-indicator", indicators.length > 0);
144
- for (const indicator of indicators) {
145
- indicator.setAttribute("data-checked", String(input.checked));
146
- indicator.toggleAttribute("data-indeterminate", input.indeterminate);
147
- }
148
- input.setAttribute("aria-label", host.getAttribute("aria-label") || (input.type === "radio" ? "Select row" : "Select row"));
149
- input.disabled = host.hasAttribute("disabled");
150
- },
151
- });
152
- }
153
- export function defineTableResizeHandle() {
154
- defineSlotted({
155
- tag: "spui-table-resize-handle", role: "presentation", display: "inline-flex", attributes: ["value", "min", "max", "step", "label"],
156
- css: `position:absolute;inset-block:0;inset-inline-end:-4px;z-index:1;display:flex;align-items:center;justify-content:center;width:12px;min-height:40px;touch-action:none;cursor:col-resize}.handle{width:2px;height:60%;min-height:20px;border-radius:2px;background:var(--spui-ui-stroke,var(--colorNeutralStroke1,#d1d1d1));opacity:.55}.handle:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:2px}:host(:hover) .handle,:host(:focus-visible) .handle{background:var(--spui-ui-accent,#0f6cbd);opacity:1}`,
157
- sync: (host, root) => {
158
- let handle = root.querySelector(".handle");
159
- if (!handle) {
160
- handle = document.createElement("div");
161
- handle.className = "handle";
162
- handle.tabIndex = 0;
163
- handle.setAttribute("role", "separator");
164
- handle.setAttribute("aria-orientation", "vertical");
165
- handle.part.add("handle");
166
- root.append(handle);
167
- }
168
- const value = Number(host.getAttribute("value"));
169
- if (Number.isFinite(value))
170
- handle.setAttribute("aria-valuenow", String(value));
171
- else
172
- handle.removeAttribute("aria-valuenow");
173
- for (const name of ["min", "max"]) {
174
- const item = host.getAttribute(name);
175
- if (item)
176
- handle.setAttribute(`aria-value${name}`, item);
177
- else
178
- handle.removeAttribute(`aria-value${name}`);
179
- }
180
- handle.setAttribute("aria-label", host.getAttribute("label") || "Resize column");
181
- const resizeTo = (requested, sourceEvent) => {
182
- const current = Number(host.getAttribute("value")) || 0;
183
- const minAttribute = host.getAttribute("min");
184
- const maxAttribute = host.getAttribute("max");
185
- const minimum = minAttribute === null ? -Infinity : Number(minAttribute);
186
- const maximum = maxAttribute === null ? Infinity : Number(maxAttribute);
187
- const next = Math.max(Number.isFinite(minimum) ? minimum : -Infinity, Math.min(Number.isFinite(maximum) ? maximum : Infinity, requested));
188
- if (next === current)
189
- return;
190
- host.setAttribute("value", String(next));
191
- host.dispatchEvent(new CustomEvent("spui-table-resize", { bubbles: true, composed: true, detail: { delta: next - current, value: next, sourceEvent } }));
192
- };
193
- handle.onkeydown = event => {
194
- if (!(event instanceof KeyboardEvent) || !["ArrowLeft", "ArrowRight"].includes(event.key))
195
- return;
196
- event.preventDefault();
197
- const step = Math.max(1, Number(host.getAttribute("step")) || 8);
198
- const rtl = getComputedStyle(host).direction === "rtl";
199
- const delta = (event.key === "ArrowRight" ? 1 : -1) * (rtl ? -1 : 1) * step;
200
- const current = Number(host.getAttribute("value")) || 0;
201
- resizeTo(current + delta, event);
202
- };
203
- handle.onpointerdown = event => {
204
- if (!(event instanceof PointerEvent) || event.button !== 0)
205
- return;
206
- event.preventDefault();
207
- const startX = event.clientX;
208
- const startWidth = Number(host.getAttribute("value")) || 0;
209
- const rtl = getComputedStyle(host).direction === "rtl";
210
- const move = (moveEvent) => { if (moveEvent.pointerId === event.pointerId)
211
- resizeTo(startWidth + (moveEvent.clientX - startX) * (rtl ? -1 : 1), moveEvent); };
212
- const finish = (finishEvent) => {
213
- if (finishEvent.pointerId !== event.pointerId)
214
- return;
215
- document.removeEventListener("pointermove", move);
216
- document.removeEventListener("pointerup", finish);
217
- document.removeEventListener("pointercancel", finish);
218
- };
219
- document.addEventListener("pointermove", move);
220
- document.addEventListener("pointerup", finish);
221
- document.addEventListener("pointercancel", finish);
222
- };
223
- },
224
- });
225
- }
226
- export function defineTable() {
227
- defineTableHeader();
228
- defineTableBody();
229
- defineTableRow();
230
- defineTableHeaderCell();
231
- defineTableCell();
232
- defineTableCellLayout();
233
- defineTableCellActions();
234
- defineTableResizeHandle();
235
- defineTableSelectionCell();
236
- if (customElements.get("spui-table"))
237
- return;
238
- class SpuiTable extends HTMLElement {
239
- static observedAttributes = ["size", "appearance", "no-native-elements"];
240
- connectedCallback() {
241
- if (this.shadowRoot)
242
- return;
243
- const shadow = this.attachShadow({ mode: "open" });
244
- const style = document.createElement("style");
245
- style.textContent = `${base}:host{box-sizing:border-box;display:block;width:var(--spui-table-width,100%);max-width:100%;min-width:0;background:var(--spui-table-background,var(--spui-ui-surface,#fff));color:var(--spui-ui-text,var(--colorNeutralForeground1,#242424));font-family:var(--spui-font-family,inherit);font-size:var(--spui-table-font-size,14px);line-height:1.4}.viewport{max-width:100%;overflow-x:auto}.table{display:table;width:100%;min-width:100%;border-collapse:collapse;border-spacing:0}:host([no-native-elements]) .table{display:flex;flex-direction:column}slot{display:contents}:host([size=small]){--spui-table-font-size:12px;--spui-table-cell-padding:6px 8px;--spui-table-header-padding:6px 8px}:host([size=large]){--spui-table-font-size:16px;--spui-table-cell-padding:14px 16px;--spui-table-header-padding:14px 16px}:host([appearance=dividers]){--spui-table-row-hover:transparent}:host([appearance=subtle]){--spui-table-header-background:transparent}@media(forced-colors:active){.table{border-color:CanvasText;color:CanvasText}}`;
246
- const viewport = document.createElement("div");
247
- viewport.className = "viewport";
248
- viewport.part.add("viewport");
249
- const table = document.createElement("div");
250
- table.className = "table";
251
- table.part.add("table");
252
- table.setAttribute("role", "presentation");
253
- table.append(document.createElement("slot"));
254
- viewport.append(table);
255
- shadow.append(style, viewport);
256
- if (!this.hasAttribute("role"))
257
- this.setAttribute("role", "table");
258
- }
259
- }
260
- customElements.define("spui-table", SpuiTable);
261
- }
@@ -1 +0,0 @@
1
- export declare function defineTabs(): void;
@@ -1,276 +0,0 @@
1
- import { base } from "./shared.js";
2
- const valueOf = (element) => element.getAttribute("value") ?? "";
3
- export function defineTabs() {
4
- if (customElements.get("spui-tab"))
5
- return;
6
- class SpuiTab extends HTMLElement {
7
- static observedAttributes = ["disabled", "data-list-disabled", "selected", "tabindex", "aria-controls", "appearance", "size", "vertical", "reserve-selected-tab-space"];
8
- connectedCallback() { if (!this.shadowRoot)
9
- this.render(); this.sync(); }
10
- attributeChangedCallback() { if (this.isConnected)
11
- this.sync(); }
12
- get value() { return valueOf(this); }
13
- get disabled() { return this.hasAttribute("disabled") || this.hasAttribute("data-list-disabled"); }
14
- getContentText() {
15
- const named = this.shadowRoot?.querySelector('slot[name="content"]')?.assignedNodes({ flatten: true });
16
- const fallback = this.shadowRoot?.querySelector("slot:not([name])")?.assignedNodes({ flatten: true });
17
- const assigned = named?.length ? named : fallback;
18
- return (assigned?.length ? assigned : [...this.childNodes].filter(node => !(node instanceof Element && node.slot)))
19
- .map(node => node.textContent ?? "").join("").replace(/\s+/g, " ").trim();
20
- }
21
- sync() {
22
- this.setAttribute("role", "tab");
23
- this.setAttribute("aria-selected", String(this.getAttribute("selected") === "true"));
24
- if (this.disabled)
25
- this.setAttribute("aria-disabled", "true");
26
- else
27
- this.removeAttribute("aria-disabled");
28
- const reserved = this.shadowRoot?.querySelector(".reserved");
29
- if (reserved)
30
- reserved.textContent = this.hasAttribute("reserve-selected-tab-space") ? this.getContentText() : "";
31
- }
32
- render() {
33
- const shadow = this.attachShadow({ mode: "open" });
34
- const style = document.createElement("style");
35
- style.textContent = `${base}:host{box-sizing:border-box;position:relative;display:inline-flex;align-items:center;justify-content:center;gap:8px;min-width:44px;min-height:40px;padding:8px 12px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:var(--spui-ui-muted,var(--spui-semantic-body-text,#616161));font:inherit;line-height:1.25;text-align:center;white-space:nowrap;cursor:pointer;user-select:none}slot[name=icon]{display:inline-flex;align-items:center;justify-content:center;flex:none}.content{display:grid;min-width:0}.content slot,.reserved{grid-area:1/1}.reserved{display:none;visibility:hidden;white-space:pre;font-weight:600}:host([reserve-selected-tab-space][aria-selected=false]) .reserved{display:block}:host([size=small]){min-height:32px;padding:6px 10px;font-size:12px}:host([size=large]){min-height:48px;padding:10px 16px;font-size:16px}:host([aria-selected=true]){color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424));font-weight:600}:host::after{position:absolute;inset-inline:10px;inset-block-end:0;height:2px;border-radius:2px;background:var(--spui-ui-accent,var(--spui-semantic-accent,#78716c));content:"";opacity:0;transform:scaleX(.65);transition:opacity var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),transform var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}:host([aria-selected=true])::after{opacity:1;transform:scaleX(1)}:host(:focus-visible){z-index:1;outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,#78716c));outline-offset:-2px}:host([disabled]),:host([data-list-disabled]){color:var(--spui-ui-muted,#777);cursor:not-allowed;opacity:.6}:host([appearance=subtle-circular]),:host([appearance=filled-circular]){border-radius:999px}:host([appearance=subtle-circular]){border:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))}:host([appearance=subtle-circular][aria-selected=true]){background:color-mix(in srgb,var(--spui-ui-accent,#78716c) 12%,var(--spui-base-surface,var(--spui-ui-surface,#fff)))}:host([appearance=filled-circular][aria-selected=true]){background:color-mix(in srgb,var(--spui-ui-accent,#78716c) 18%,var(--spui-base-surface,var(--spui-ui-surface,#fff)))}:host([vertical]){justify-content:flex-start;width:100%;text-align:start}:host([vertical])::after{inset-block:8px;inset-inline-start:0;inset-inline-end:auto;width:2px;height:auto}:host([appearance=filled-circular])::after{display:none}@media(prefers-reduced-motion:reduce){:host::after{transition:none}}@media(forced-colors:active){:host::after{background:Highlight}:host(:focus-visible){outline-color:Highlight}:host([aria-selected=true]){color:CanvasText}}`;
36
- style.textContent += `:host([appearance=transparent]:hover:not([disabled])),:host([appearance=transparent]:active:not([disabled])){background:var(--colorTransparentBackgroundHover,var(--spui-ui-surface-hover,#f5f5f5))}:host([appearance=transparent]:active:not([disabled])){background:var(--colorTransparentBackgroundPressed,var(--spui-ui-surface-hover,#e0e0e0))}:host([appearance=subtle]){background:var(--colorSubtleBackground,transparent)}:host([appearance=subtle]:hover:not([disabled])){background:var(--colorSubtleBackgroundHover,var(--spui-ui-surface-hover,#f5f5f5))}:host([appearance=subtle]:active:not([disabled])){background:var(--colorSubtleBackgroundPressed,var(--spui-ui-surface-hover,#e0e0e0))}:host([appearance=subtle-circular]){border-color:var(--colorTransparentStroke,transparent);background:var(--colorSubtleBackground,transparent)}:host([appearance=subtle-circular]:hover:not([disabled])){border-color:var(--colorNeutralStroke1Hover,var(--spui-ui-stroke,#d1d1d1));background:var(--colorSubtleBackgroundHover,var(--spui-ui-surface-hover,#f5f5f5))}:host([appearance=subtle-circular][aria-selected=true]){border-color:var(--colorCompoundBrandStroke,color-mix(in srgb,var(--spui-ui-accent,#78716c) 52%,var(--spui-base-surface,var(--spui-ui-surface,#fff))));background:var(--colorBrandBackground2,color-mix(in srgb,var(--spui-ui-accent,#78716c) 18%,var(--spui-base-surface,var(--spui-ui-surface,#fff))));color:var(--colorBrandForeground2,var(--spui-ui-accent,#78716c))}:host([appearance=filled-circular]){border-color:transparent;background:var(--colorNeutralBackground3,var(--spui-ui-surface-hover,#f0f0f0))}:host([appearance=filled-circular][aria-selected=true]){border-color:transparent;background:var(--colorBrandBackground,var(--spui-ui-accent,#78716c));color:var(--colorNeutralForegroundOnBrand,#fff)}:host([appearance=subtle-circular])::after,:host([appearance=filled-circular])::after{display:none}@media(forced-colors:active){:host([appearance=subtle-circular][aria-selected=true]){border-color:Highlight}:host([appearance=filled-circular][aria-selected=true]){border-color:ButtonText;background:ButtonText;color:ButtonFace}}`;
37
- const content = document.createElement("span");
38
- content.className = "content";
39
- const textSlot = document.createElement("slot");
40
- textSlot.name = "content";
41
- const fallbackSlot = document.createElement("slot");
42
- textSlot.append(fallbackSlot);
43
- textSlot.addEventListener("slotchange", () => this.sync());
44
- fallbackSlot.addEventListener("slotchange", () => this.sync());
45
- content.append(textSlot);
46
- const reserved = document.createElement("span");
47
- reserved.className = "reserved";
48
- reserved.setAttribute("aria-hidden", "true");
49
- content.append(reserved);
50
- const iconSlot = document.createElement("slot");
51
- iconSlot.name = "icon";
52
- shadow.append(style, iconSlot, content);
53
- }
54
- }
55
- customElements.define("spui-tab", SpuiTab);
56
- class SpuiTabList extends HTMLElement {
57
- static observedAttributes = ["selected-value", "default-selected-value", "select-on-focus", "reserve-selected-tab-space", "vertical", "disabled", "appearance", "size", "aria-label"];
58
- events;
59
- observer;
60
- connectedCallback() {
61
- if (!this.shadowRoot)
62
- this.render();
63
- this.observer = new MutationObserver(() => this.sync());
64
- this.observer.observe(this, { childList: true, subtree: true, attributes: true, attributeFilter: ["disabled", "value"] });
65
- this.events?.abort();
66
- this.events = new AbortController();
67
- this.addEventListener("click", this.onClick, { signal: this.events.signal });
68
- this.addEventListener("keydown", this.onKeyDown, { signal: this.events.signal });
69
- this.addEventListener("focusin", this.onFocusIn, { signal: this.events.signal });
70
- queueMicrotask(() => this.sync());
71
- }
72
- disconnectedCallback() { this.events?.abort(); this.observer?.disconnect(); }
73
- attributeChangedCallback() { if (this.isConnected)
74
- this.sync(); }
75
- get selectedValue() {
76
- return this.getAttribute("selected-value") ?? this.dataset.selectedValue ?? this.getAttribute("default-selected-value") ?? this.tabs().find(tab => !tab.disabled)?.value ?? null;
77
- }
78
- tabs() { return [...this.children].filter((child) => child.localName === "spui-tab"); }
79
- sync() {
80
- const tabs = this.tabs();
81
- const selected = this.selectedValue;
82
- const focusValue = this.dataset.focusValue;
83
- const focusTab = tabs.find(tab => tab.value === focusValue && !tab.disabled) ?? tabs.find(tab => tab.value === selected && !tab.disabled) ?? tabs.find(tab => !tab.disabled);
84
- this.dataset.orientation = this.hasAttribute("vertical") ? "vertical" : "horizontal";
85
- const role = this.shadowRoot?.querySelector("[role=tablist]");
86
- role?.setAttribute("aria-orientation", this.hasAttribute("vertical") ? "vertical" : "horizontal");
87
- const label = this.getAttribute("aria-label");
88
- if (label)
89
- role?.setAttribute("aria-label", label);
90
- else
91
- role?.removeAttribute("aria-label");
92
- tabs.forEach(tab => {
93
- if (this.hasAttribute("disabled"))
94
- tab.setAttribute("data-list-disabled", "");
95
- else
96
- tab.removeAttribute("data-list-disabled");
97
- if (this.hasAttribute("vertical"))
98
- tab.setAttribute("vertical", "");
99
- else
100
- tab.removeAttribute("vertical");
101
- tab.setAttribute("selected", String(tab.value === selected));
102
- tab.setAttribute("tabindex", String(tab === focusTab ? 0 : -1));
103
- if (this.hasAttribute("appearance"))
104
- tab.setAttribute("appearance", this.getAttribute("appearance"));
105
- else
106
- tab.removeAttribute("appearance");
107
- if (this.hasAttribute("size"))
108
- tab.setAttribute("size", this.getAttribute("size"));
109
- else
110
- tab.removeAttribute("size");
111
- const reserveSpace = this.getAttribute("reserve-selected-tab-space") !== "false";
112
- if (reserveSpace)
113
- tab.setAttribute("reserve-selected-tab-space", "");
114
- else
115
- tab.removeAttribute("reserve-selected-tab-space");
116
- const reserved = tab.shadowRoot?.querySelector(".reserved");
117
- if (reserved)
118
- reserved.textContent = reserveSpace ? tab.getContentText() : "";
119
- });
120
- if (selected !== null && this.dataset.lastEmittedValue !== selected) {
121
- this.dataset.lastEmittedValue = selected;
122
- this.dispatchEvent(new CustomEvent("spui-tab-selection-change", { bubbles: true, composed: true, detail: { value: selected } }));
123
- }
124
- }
125
- onFocusIn = (event) => {
126
- const tab = event.composedPath().find(target => target instanceof SpuiTab);
127
- if (!tab || tab.disabled)
128
- return;
129
- this.dataset.focusValue = tab.value;
130
- this.sync();
131
- if (this.hasAttribute("select-on-focus"))
132
- this.select(tab, event);
133
- };
134
- onClick = (event) => {
135
- const tab = event.composedPath().find(target => target instanceof SpuiTab);
136
- if (tab)
137
- this.select(tab, event);
138
- };
139
- onKeyDown = (event) => {
140
- const tabs = this.tabs().filter(tab => !tab.disabled);
141
- const current = event.composedPath().find(target => target instanceof SpuiTab);
142
- if (!current || !tabs.length)
143
- return;
144
- const index = tabs.indexOf(current);
145
- const vertical = this.hasAttribute("vertical");
146
- const rtl = getComputedStyle(this).direction === "rtl";
147
- const nextKey = vertical ? "ArrowDown" : rtl ? "ArrowLeft" : "ArrowRight";
148
- const previousKey = vertical ? "ArrowUp" : rtl ? "ArrowRight" : "ArrowLeft";
149
- let next;
150
- if (event.key === nextKey)
151
- next = tabs[(index + 1) % tabs.length];
152
- else if (event.key === previousKey)
153
- next = tabs[(index - 1 + tabs.length) % tabs.length];
154
- else if (event.key === "Home")
155
- next = tabs[0];
156
- else if (event.key === "End")
157
- next = tabs.at(-1);
158
- else if (event.key === "Enter" || event.key === " ") {
159
- event.preventDefault();
160
- this.select(current, event);
161
- return;
162
- }
163
- if (!next)
164
- return;
165
- event.preventDefault();
166
- this.dataset.focusValue = next.value;
167
- this.sync();
168
- next.focus();
169
- };
170
- select(tab, sourceEvent) {
171
- if (tab.disabled || this.hasAttribute("disabled"))
172
- return;
173
- if (!this.hasAttribute("selected-value"))
174
- this.dataset.selectedValue = tab.value;
175
- this.dataset.focusValue = tab.value;
176
- this.sync();
177
- this.dispatchEvent(new CustomEvent("spui-tab-select", { bubbles: true, composed: true, detail: { value: tab.value, valueType: tab.getAttribute("data-spui-tab-value-type") ?? undefined, sourceEvent, currentTarget: tab } }));
178
- }
179
- render() {
180
- const shadow = this.attachShadow({ mode: "open" });
181
- const style = document.createElement("style");
182
- style.textContent = `${base}:host{display:block;min-width:0;--spui-tab-gap:4px}.list{display:flex;align-items:center;gap:var(--spui-tab-gap);min-width:0;overflow:auto;scrollbar-width:thin;border-block-end:1px solid var(--spui-tabs-divider,var(--spui-ui-stroke,#d1d1d1))}:host([vertical]) .list{flex-direction:column;align-items:stretch;border-block-end:0;border-inline-end:1px solid var(--spui-tabs-divider,var(--spui-ui-stroke,#d1d1d1))}::slotted(spui-tab){flex:none}@media(forced-colors:active){.list{border-color:CanvasText}}`;
183
- const list = document.createElement("div");
184
- list.className = "list";
185
- list.setAttribute("role", "tablist");
186
- list.append(document.createElement("slot"));
187
- shadow.append(style, list);
188
- }
189
- }
190
- customElements.define("spui-tab-list", SpuiTabList);
191
- class SpuiTabPanel extends HTMLElement {
192
- static observedAttributes = ["selected", "labelledby"];
193
- connectedCallback() { if (!this.shadowRoot)
194
- this.render(); this.sync(); }
195
- attributeChangedCallback() { if (this.isConnected)
196
- this.sync(); }
197
- get value() { return valueOf(this); }
198
- sync() {
199
- const selected = this.getAttribute("selected") === "true";
200
- this.setAttribute("role", "tabpanel");
201
- this.hidden = !selected;
202
- this.setAttribute("tabindex", "0");
203
- const labelledBy = this.getAttribute("labelledby");
204
- if (labelledBy)
205
- this.setAttribute("aria-labelledby", labelledBy);
206
- else
207
- this.removeAttribute("aria-labelledby");
208
- }
209
- render() {
210
- const shadow = this.attachShadow({ mode: "open" });
211
- const style = document.createElement("style");
212
- style.textContent = `${base}:host{display:block;min-width:0;padding-block:16px;color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424))}:host([hidden]){display:none}:host(:focus-visible){outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,#78716c));outline-offset:2px}@media(forced-colors:active){:host(:focus-visible){outline-color:Highlight}}`;
213
- shadow.append(style, document.createElement("slot"));
214
- }
215
- }
216
- customElements.define("spui-tab-panel", SpuiTabPanel);
217
- class SpuiTabs extends HTMLElement {
218
- static observedAttributes = ["selected-value", "default-selected-value", "disabled"];
219
- observer;
220
- events;
221
- connectedCallback() {
222
- if (!this.shadowRoot)
223
- this.render();
224
- this.observer = new MutationObserver(() => this.sync());
225
- this.observer.observe(this, { childList: true, subtree: true, attributes: true, attributeFilter: ["value", "selected-value", "default-selected-value", "disabled"] });
226
- this.events?.abort();
227
- this.events = new AbortController();
228
- this.addEventListener("spui-tab-selection-change", this.sync, { signal: this.events.signal });
229
- queueMicrotask(() => this.sync());
230
- }
231
- disconnectedCallback() { this.observer?.disconnect(); this.events?.abort(); }
232
- attributeChangedCallback() { if (this.isConnected)
233
- this.sync(); }
234
- sync = () => {
235
- const list = [...this.querySelectorAll("spui-tab-list")].find(item => item.closest("spui-tabs") === this);
236
- if (!list)
237
- return;
238
- if (this.hasAttribute("disabled")) {
239
- if (!list.hasAttribute("disabled"))
240
- list.setAttribute("disabled", "");
241
- }
242
- else if (list.hasAttribute("disabled"))
243
- list.removeAttribute("disabled");
244
- if (this.hasAttribute("selected-value")) {
245
- const selected = this.getAttribute("selected-value");
246
- list.dataset.rootSelectedValue = selected;
247
- if (list.getAttribute("selected-value") !== selected)
248
- list.setAttribute("selected-value", selected);
249
- }
250
- else if (list.hasAttribute("data-root-selected-value")) {
251
- delete list.dataset.rootSelectedValue;
252
- list.removeAttribute("selected-value");
253
- }
254
- else if (this.hasAttribute("default-selected-value") && !list.hasAttribute("default-selected-value"))
255
- list.setAttribute("default-selected-value", this.getAttribute("default-selected-value"));
256
- const selected = this.getAttribute("selected-value") ?? list.selectedValue ?? this.getAttribute("default-selected-value");
257
- const tabs = [...this.querySelectorAll("spui-tab")].filter(tab => tab.closest("spui-tab-list") === list);
258
- const panels = [...this.querySelectorAll("spui-tab-panel")].filter(panel => panel.closest("spui-tabs") === this);
259
- for (const tab of tabs) {
260
- const panel = panels.find(candidate => candidate.value === tab.value);
261
- if (!tab.id)
262
- tab.id = `spui-tab-${crypto.randomUUID()}`;
263
- if (panel) {
264
- if (!panel.id)
265
- panel.id = `spui-tabpanel-${crypto.randomUUID()}`;
266
- tab.setAttribute("aria-controls", panel.id);
267
- panel.setAttribute("labelledby", tab.id);
268
- }
269
- }
270
- for (const panel of panels)
271
- panel.setAttribute("selected", String(panel.value === selected));
272
- };
273
- render() { const shadow = this.attachShadow({ mode: "open" }); const style = document.createElement("style"); style.textContent = `${base}:host{display:block;min-width:0;color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424))}`; shadow.append(style, document.createElement("slot")); }
274
- }
275
- customElements.define("spui-tabs", SpuiTabs);
276
- }
@@ -1,29 +0,0 @@
1
- export type TagPickerOpenChangeType = "click" | "keydown" | "input" | "focus" | "focusout" | "blur" | "pointerdown" | "programmatic";
2
- export type TagPickerOnOpenChangeData = {
3
- open: boolean;
4
- reason: string;
5
- } & ({
6
- event: MouseEvent;
7
- type: "click";
8
- } | {
9
- event: KeyboardEvent;
10
- type: "keydown";
11
- } | {
12
- event: Event;
13
- type: Exclude<TagPickerOpenChangeType, "click" | "keydown" | "programmatic">;
14
- } | {
15
- event: Event;
16
- type: "programmatic";
17
- });
18
- export type TagPickerOnOptionSelectData = {
19
- value: string;
20
- selectedOptions: string[];
21
- } & ({
22
- event: MouseEvent;
23
- type: "click";
24
- } | {
25
- event: KeyboardEvent;
26
- type: "keydown";
27
- });
28
- /** Searchable multi-select picker with native form association and light-DOM options. */
29
- export declare function defineTagPicker(): void;