@spfx-fast/sharepoint-ui 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/QUICKSTART.md +13 -128
  2. package/README.md +19 -26
  3. package/components.json +240 -5834
  4. package/dist/accordion.d.ts +11 -0
  5. package/dist/accordion.js +4 -0
  6. package/dist/alert.d.ts +3 -0
  7. package/dist/alert.js +4 -0
  8. package/dist/attachment-list.d.ts +15 -0
  9. package/dist/attachment-list.js +14 -0
  10. package/dist/avatar-group.d.ts +12 -0
  11. package/dist/avatar-group.js +7 -0
  12. package/dist/avatar.d.ts +6 -0
  13. package/dist/avatar.js +5 -0
  14. package/dist/badge.d.ts +3 -0
  15. package/dist/badge.js +4 -0
  16. package/dist/breadcrumb.d.ts +10 -0
  17. package/dist/breadcrumb.js +9 -0
  18. package/dist/button-group.d.ts +6 -0
  19. package/dist/button-group.js +4 -0
  20. package/dist/button.d.ts +3 -0
  21. package/dist/button.js +4 -0
  22. package/dist/card.d.ts +3 -0
  23. package/dist/card.js +4 -0
  24. package/dist/carousel.d.ts +11 -0
  25. package/dist/carousel.js +6 -0
  26. package/dist/checkbox.d.ts +3 -0
  27. package/dist/checkbox.js +4 -0
  28. package/dist/combobox.d.ts +9 -0
  29. package/dist/combobox.js +6 -0
  30. package/dist/command-bar.d.ts +6 -0
  31. package/dist/command-bar.js +4 -0
  32. package/dist/copy-button.d.ts +7 -0
  33. package/dist/copy-button.js +19 -0
  34. package/dist/data-grid.d.ts +25 -0
  35. package/dist/data-grid.js +39 -0
  36. package/dist/date-range-picker.d.ts +12 -0
  37. package/dist/date-range-picker.js +4 -0
  38. package/dist/dialog.d.ts +9 -0
  39. package/dist/dialog.js +21 -0
  40. package/dist/divider.d.ts +3 -0
  41. package/dist/divider.js +4 -0
  42. package/dist/drawer.d.ts +6 -0
  43. package/dist/drawer.js +5 -0
  44. package/dist/empty-state.d.ts +7 -0
  45. package/dist/empty-state.js +5 -0
  46. package/dist/field.d.ts +15 -0
  47. package/dist/field.js +11 -0
  48. package/dist/file-dropzone.d.ts +15 -0
  49. package/dist/file-dropzone.js +21 -0
  50. package/dist/filter-bar.d.ts +9 -0
  51. package/dist/filter-bar.js +9 -0
  52. package/dist/image.d.ts +5 -0
  53. package/dist/image.js +4 -0
  54. package/dist/index.d.ts +68 -78
  55. package/dist/index.js +60 -68
  56. package/dist/input.d.ts +3 -0
  57. package/dist/input.js +4 -0
  58. package/dist/label.d.ts +3 -0
  59. package/dist/label.js +4 -0
  60. package/dist/link.d.ts +3 -0
  61. package/dist/link.js +9 -0
  62. package/dist/list-view.d.ts +29 -0
  63. package/dist/list-view.js +14 -0
  64. package/dist/list.d.ts +6 -0
  65. package/dist/list.js +5 -0
  66. package/dist/lookup-picker.d.ts +12 -0
  67. package/dist/lookup-picker.js +4 -0
  68. package/dist/menu.d.ts +6 -0
  69. package/dist/menu.js +4 -0
  70. package/dist/nav.d.ts +12 -0
  71. package/dist/nav.js +4 -0
  72. package/dist/pagination.d.ts +11 -0
  73. package/dist/pagination.js +5 -0
  74. package/dist/person-picker.d.ts +13 -0
  75. package/dist/person-picker.js +4 -0
  76. package/dist/persona.d.ts +7 -0
  77. package/dist/persona.js +5 -0
  78. package/dist/popover.d.ts +6 -0
  79. package/dist/popover.js +4 -0
  80. package/dist/progress-bar.d.ts +5 -0
  81. package/dist/progress-bar.js +5 -0
  82. package/dist/radio-group.d.ts +6 -0
  83. package/dist/radio-group.js +4 -0
  84. package/dist/radio.d.ts +3 -0
  85. package/dist/radio.js +4 -0
  86. package/dist/rating.d.ts +8 -0
  87. package/dist/rating.js +5 -0
  88. package/dist/react.d.ts +1 -4715
  89. package/dist/react.js +1 -7097
  90. package/dist/select.d.ts +3 -0
  91. package/dist/select.js +4 -0
  92. package/dist/sharepoint-field.d.ts +18 -0
  93. package/dist/sharepoint-field.js +54 -0
  94. package/dist/skeleton.d.ts +6 -0
  95. package/dist/skeleton.js +9 -0
  96. package/dist/spinner.d.ts +5 -0
  97. package/dist/spinner.js +4 -0
  98. package/dist/swatch-picker.d.ts +17 -0
  99. package/dist/swatch-picker.js +11 -0
  100. package/dist/switch.d.ts +3 -0
  101. package/dist/switch.js +4 -0
  102. package/dist/table.d.ts +6 -0
  103. package/dist/table.js +4 -0
  104. package/dist/tabs.d.ts +14 -0
  105. package/dist/tabs.js +30 -0
  106. package/dist/tag-group.d.ts +6 -0
  107. package/dist/tag-group.js +4 -0
  108. package/dist/tag-picker.d.ts +12 -0
  109. package/dist/tag-picker.js +4 -0
  110. package/dist/tag.d.ts +7 -0
  111. package/dist/tag.js +5 -0
  112. package/dist/text.d.ts +5 -0
  113. package/dist/text.js +4 -0
  114. package/dist/textarea.d.ts +3 -0
  115. package/dist/textarea.js +4 -0
  116. package/dist/theme.d.ts +15 -175
  117. package/dist/theme.js +36 -239
  118. package/dist/toast.d.ts +9 -0
  119. package/dist/toast.js +12 -0
  120. package/dist/tree.d.ts +13 -0
  121. package/dist/tree.js +9 -0
  122. package/dist/view-card.d.ts +8 -0
  123. package/dist/view-card.js +4 -0
  124. package/dist/view-switcher.d.ts +13 -0
  125. package/dist/view-switcher.js +7 -0
  126. package/dist/virtual-list.d.ts +11 -0
  127. package/dist/virtual-list.js +25 -0
  128. package/measurements.json +365 -0
  129. package/package.json +14 -46
  130. package/src/theme.css +125 -0
  131. package/AGENTS.md +0 -231
  132. package/dist/appearance.d.ts +0 -6
  133. package/dist/appearance.js +0 -217
  134. package/dist/elements/accordion.d.ts +0 -9
  135. package/dist/elements/accordion.js +0 -338
  136. package/dist/elements/alert.d.ts +0 -2
  137. package/dist/elements/alert.js +0 -86
  138. package/dist/elements/avatar-group-primitives.d.ts +0 -3
  139. package/dist/elements/avatar-group-primitives.js +0 -189
  140. package/dist/elements/avatar-group.d.ts +0 -2
  141. package/dist/elements/avatar-group.js +0 -110
  142. package/dist/elements/avatar.d.ts +0 -4
  143. package/dist/elements/avatar.js +0 -251
  144. package/dist/elements/badge.d.ts +0 -8
  145. package/dist/elements/badge.js +0 -182
  146. package/dist/elements/breadcrumb.d.ts +0 -4
  147. package/dist/elements/breadcrumb.js +0 -233
  148. package/dist/elements/button-group.d.ts +0 -1
  149. package/dist/elements/button-group.js +0 -20
  150. package/dist/elements/button-variants.d.ts +0 -6
  151. package/dist/elements/button-variants.js +0 -339
  152. package/dist/elements/button.d.ts +0 -5
  153. package/dist/elements/button.js +0 -233
  154. package/dist/elements/card-primitives.d.ts +0 -3
  155. package/dist/elements/card-primitives.js +0 -83
  156. package/dist/elements/card.d.ts +0 -5
  157. package/dist/elements/card.js +0 -213
  158. package/dist/elements/carousel.d.ts +0 -92
  159. package/dist/elements/carousel.js +0 -1115
  160. package/dist/elements/color-picker.d.ts +0 -24
  161. package/dist/elements/color-picker.js +0 -1004
  162. package/dist/elements/combobox.d.ts +0 -1
  163. package/dist/elements/combobox.js +0 -1012
  164. package/dist/elements/data-grid-model.d.ts +0 -120
  165. package/dist/elements/data-grid-model.js +0 -294
  166. package/dist/elements/data-grid.d.ts +0 -30
  167. package/dist/elements/data-grid.js +0 -1576
  168. package/dist/elements/date-picker.d.ts +0 -1
  169. package/dist/elements/date-picker.js +0 -486
  170. package/dist/elements/dialog.d.ts +0 -23
  171. package/dist/elements/dialog.js +0 -409
  172. package/dist/elements/divider.d.ts +0 -2
  173. package/dist/elements/divider.js +0 -66
  174. package/dist/elements/drawer.d.ts +0 -3
  175. package/dist/elements/drawer.js +0 -308
  176. package/dist/elements/field-composition.d.ts +0 -26
  177. package/dist/elements/field-composition.js +0 -133
  178. package/dist/elements/field.d.ts +0 -1
  179. package/dist/elements/field.js +0 -67
  180. package/dist/elements/file-upload.d.ts +0 -6
  181. package/dist/elements/file-upload.js +0 -211
  182. package/dist/elements/floating-position.d.ts +0 -36
  183. package/dist/elements/floating-position.js +0 -92
  184. package/dist/elements/image.d.ts +0 -28
  185. package/dist/elements/image.js +0 -38
  186. package/dist/elements/info.d.ts +0 -9
  187. package/dist/elements/info.js +0 -102
  188. package/dist/elements/input.d.ts +0 -5
  189. package/dist/elements/input.js +0 -255
  190. package/dist/elements/label.d.ts +0 -15
  191. package/dist/elements/label.js +0 -56
  192. package/dist/elements/link.d.ts +0 -1
  193. package/dist/elements/link.js +0 -92
  194. package/dist/elements/list.d.ts +0 -19
  195. package/dist/elements/list.js +0 -297
  196. package/dist/elements/menu.d.ts +0 -33
  197. package/dist/elements/menu.js +0 -1103
  198. package/dist/elements/message-bar.d.ts +0 -10
  199. package/dist/elements/message-bar.js +0 -327
  200. package/dist/elements/nav.d.ts +0 -32
  201. package/dist/elements/nav.js +0 -794
  202. package/dist/elements/overflow.d.ts +0 -10
  203. package/dist/elements/overflow.js +0 -218
  204. package/dist/elements/persona.d.ts +0 -3
  205. package/dist/elements/persona.js +0 -125
  206. package/dist/elements/popover.d.ts +0 -77
  207. package/dist/elements/popover.js +0 -840
  208. package/dist/elements/progress-bar.d.ts +0 -4
  209. package/dist/elements/progress-bar.js +0 -82
  210. package/dist/elements/radio-group.d.ts +0 -1
  211. package/dist/elements/radio-group.js +0 -303
  212. package/dist/elements/rating-display.d.ts +0 -2
  213. package/dist/elements/rating-display.js +0 -125
  214. package/dist/elements/rating.d.ts +0 -2
  215. package/dist/elements/rating.js +0 -206
  216. package/dist/elements/rich-text-editor.d.ts +0 -32
  217. package/dist/elements/rich-text-editor.js +0 -1367
  218. package/dist/elements/search.d.ts +0 -3
  219. package/dist/elements/search.js +0 -200
  220. package/dist/elements/select.d.ts +0 -6
  221. package/dist/elements/select.js +0 -291
  222. package/dist/elements/shared.d.ts +0 -22
  223. package/dist/elements/shared.js +0 -409
  224. package/dist/elements/sharepoint-field-basic-controls.d.ts +0 -1
  225. package/dist/elements/sharepoint-field-basic-controls.js +0 -14
  226. package/dist/elements/sharepoint-fields.d.ts +0 -29
  227. package/dist/elements/sharepoint-fields.js +0 -460
  228. package/dist/elements/skeleton.d.ts +0 -6
  229. package/dist/elements/skeleton.js +0 -91
  230. package/dist/elements/slider.d.ts +0 -1
  231. package/dist/elements/slider.js +0 -248
  232. package/dist/elements/spin-button.d.ts +0 -7
  233. package/dist/elements/spin-button.js +0 -499
  234. package/dist/elements/spinner.d.ts +0 -4
  235. package/dist/elements/spinner.js +0 -124
  236. package/dist/elements/swatch-picker.d.ts +0 -5
  237. package/dist/elements/swatch-picker.js +0 -363
  238. package/dist/elements/table.d.ts +0 -21
  239. package/dist/elements/table.js +0 -261
  240. package/dist/elements/tabs.d.ts +0 -1
  241. package/dist/elements/tabs.js +0 -276
  242. package/dist/elements/tag-picker.d.ts +0 -29
  243. package/dist/elements/tag-picker.js +0 -715
  244. package/dist/elements/tags.d.ts +0 -21
  245. package/dist/elements/tags.js +0 -421
  246. package/dist/elements/teaching-popover.d.ts +0 -32
  247. package/dist/elements/teaching-popover.js +0 -412
  248. package/dist/elements/text.d.ts +0 -9
  249. package/dist/elements/text.js +0 -75
  250. package/dist/elements/textarea.d.ts +0 -1
  251. package/dist/elements/textarea.js +0 -182
  252. package/dist/elements/toast.d.ts +0 -25
  253. package/dist/elements/toast.js +0 -337
  254. package/dist/elements/toaster.d.ts +0 -6
  255. package/dist/elements/toaster.js +0 -357
  256. package/dist/elements/toggle.d.ts +0 -2
  257. package/dist/elements/toggle.js +0 -246
  258. package/dist/elements/toolbar.d.ts +0 -12
  259. package/dist/elements/toolbar.js +0 -381
  260. package/dist/elements/tooltip.d.ts +0 -76
  261. package/dist/elements/tooltip.js +0 -527
  262. package/dist/elements/tree-model.d.ts +0 -19
  263. package/dist/elements/tree-model.js +0 -34
  264. package/dist/elements/tree.d.ts +0 -5
  265. package/dist/elements/tree.js +0 -273
  266. package/dist/elements/view-card.d.ts +0 -2
  267. package/dist/elements/view-card.js +0 -78
  268. package/dist/elements/virtual-list.d.ts +0 -41
  269. package/dist/elements/virtual-list.js +0 -369
  270. package/dist/elements.d.ts +0 -73
  271. package/dist/elements.js +0 -210
  272. package/dist/sharepoint-fields.d.ts +0 -135
  273. package/dist/sharepoint-fields.js +0 -402
  274. package/dist/virtualizer-hooks.d.ts +0 -80
  275. package/dist/virtualizer-hooks.js +0 -253
  276. package/scripts/generate-token-index.mjs +0 -43
  277. package/scripts/sync-component-catalog-signatures.mjs +0 -55
  278. package/scripts/validate-component-catalog.mjs +0 -44
  279. package/skills/sharepoint-ui/SKILL.md +0 -12
  280. package/skills/sharepoint-ui/references/choosing-components.md +0 -20
  281. package/skills/sharepoint-ui/references/sharepoint-patterns.md +0 -17
  282. package/tokens.json +0 -3777
@@ -1,273 +0,0 @@
1
- import { base } from "./shared.js";
2
- import { flattenAllTree, flattenTree } from "./tree-model.js";
3
- /** Accessible framework-neutral tree with nested data and roving focus. */
4
- export function defineTree() {
5
- if (customElements.get("spui-tree"))
6
- return;
7
- class SpuiTree extends HTMLElement {
8
- static observedAttributes = ["aria-label", "label", "selection-mode", "toggle-label", "empty-label", "appearance", "size", "navigation-mode"];
9
- data = [];
10
- renderer;
11
- selected = new Set();
12
- checked = new Map();
13
- expanded = new Set();
14
- activeKey = "";
15
- root;
16
- typeAhead = { text: "", time: 0 };
17
- get items() { return this.data; }
18
- set items(value) { this.data = Array.isArray(value) ? value : []; this.paint(); }
19
- get renderItem() { return this.renderer; }
20
- set renderItem(value) { this.renderer = value; this.paint(); }
21
- get selectedKeys() { return [...this.selected]; }
22
- set selectedKeys(value) { this.selected = new Set((value ?? []).map(String)); this.checked = new Map([...this.selected].map(key => [key, true])); this.paint(); }
23
- get checkedItems() { return this.selectedKeys; }
24
- set checkedItems(value) {
25
- this.checked = new Map(Array.from(value ?? [], item => Array.isArray(item) ? [String(item[0]), item[1]] : [String(item), true]));
26
- this.selected = new Set([...this.checked].filter(([, checked]) => checked === true || checked === "mixed").map(([key]) => key));
27
- this.paint();
28
- }
29
- get expandedKeys() { return [...this.expanded]; }
30
- set expandedKeys(value) { this.expanded = new Set((value ?? []).map(String)); this.paint(); }
31
- get openItems() { return this.expandedKeys; }
32
- set openItems(value) { this.expandedKeys = value; }
33
- get defaultOpenItems() { return this.expandedKeys; }
34
- set defaultOpenItems(value) { if (!this.isConnected)
35
- this.expandedKeys = value; }
36
- connectedCallback() { if (!this.shadowRoot)
37
- this.render(); this.paint(); }
38
- attributeChangedCallback() { this.paint(); }
39
- render() {
40
- const shadow = this.attachShadow({ mode: "open" });
41
- const style = document.createElement("style");
42
- style.textContent = `${base}:host{display:block;min-width:0}.tree{box-sizing:border-box;min-width:0;outline:none;color:var(--spui-ui-text,var(--spui-semantic-body-text,#323130));font-family:var(--spui-font-family,inherit)}.tree:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:2px;border-radius:var(--spui-control-radius,4px)}.item{box-sizing:border-box;position:relative;display:flex;align-items:center;gap:8px;min-height:36px;padding-block:4px;padding-inline-end:8px;padding-inline-start:calc(8px + var(--spui-tree-level,0) * 20px);border-radius:var(--spui-control-radius,4px);cursor:default;user-select:none}.item:hover{background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.item[aria-selected=true],.item[aria-checked=true]{background:color-mix(in srgb,var(--spui-ui-accent,#0078d4) 12%,var(--spui-base-surface,var(--spui-ui-surface,#fff)));color:var(--spui-ui-text,var(--spui-semantic-body-text,#323130))}.item:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:-2px}.item[aria-disabled=true]{opacity:.55;cursor:not-allowed}.disclosure{flex:none;display:grid;place-items:center;width:24px;height:24px;padding:0;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:inherit;cursor:pointer}.disclosure:hover{background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.disclosure:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4))}.chevron{width:0;height:0;border-block:4px solid transparent;border-inline-start:5px solid currentColor;transition:transform var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}.disclosure[aria-expanded=true] .chevron{transform:rotate(90deg)}.check{flex:none;width:14px;height:14px;border:1px solid currentColor;border-radius:3px}.item[aria-checked=true] .check{background:var(--spui-ui-accent,#0078d4);box-shadow:inset 0 0 0 3px var(--spui-ui-surface,#fff)}.item[aria-checked=mixed] .check{background:linear-gradient(var(--spui-ui-accent,#0078d4),var(--spui-ui-accent,#0078d4)) center/8px 2px no-repeat}.item-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.empty{padding:12px;color:var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161))}@media(prefers-reduced-motion:reduce){.chevron{transition:none}}@media(forced-colors:active){.item[aria-selected=true],.item[aria-checked=true],.item[aria-checked=mixed]{outline:1px solid Highlight}.item:focus-visible,.disclosure:focus-visible{outline-color:Highlight}}`;
43
- style.textContent += `:host([size=small]) .item{min-height:28px}:host([appearance=transparent]) .item:hover,:host([appearance=transparent]) .item[aria-selected=true],:host([appearance=transparent]) .item[aria-checked=true]{background:transparent}:host([appearance=subtle-alpha]) .item:hover{background:color-mix(in srgb,var(--spui-ui-text,#323130) 5%,transparent)}`;
44
- this.root = document.createElement("div");
45
- this.root.className = "tree";
46
- this.root.setAttribute("role", "tree");
47
- this.root.addEventListener("click", event => this.onClick(event));
48
- this.root.addEventListener("keydown", event => this.onKeyDown(event));
49
- shadow.append(style, this.root);
50
- }
51
- visible() { return flattenTree(this.data, this.expanded); }
52
- allNodes() { return flattenAllTree(this.data); }
53
- isRtl() { return getComputedStyle(this).direction === "rtl"; }
54
- mode() { const mode = this.getAttribute("selection-mode"); return mode === "none" || mode === "single" ? mode : mode === "multiple" || mode === "multiselect" ? "multiple" : "none"; }
55
- paint(focusKey) {
56
- if (!this.isConnected || !this.root)
57
- return;
58
- const treeRoot = this.root.getRootNode();
59
- const active = focusKey ?? (treeRoot instanceof ShadowRoot ? treeRoot.activeElement?.closest("[data-tree-key]")?.dataset.treeKey : undefined);
60
- const rows = this.visible();
61
- if (!rows.some(row => row.key === this.activeKey))
62
- this.activeKey = rows[0]?.key ?? "";
63
- this.root.replaceChildren();
64
- this.root.setAttribute("aria-label", this.getAttribute("aria-label") || this.getAttribute("label") || "Tree");
65
- if (this.mode() === "multiple")
66
- this.root.setAttribute("aria-multiselectable", "true");
67
- else
68
- this.root.removeAttribute("aria-multiselectable");
69
- if (!rows.length) {
70
- const empty = document.createElement("div");
71
- empty.className = "empty";
72
- empty.textContent = this.getAttribute("empty-label") || "No items";
73
- this.root.append(empty);
74
- return;
75
- }
76
- const fragment = document.createDocumentFragment();
77
- rows.forEach(entry => {
78
- const row = document.createElement("div");
79
- row.className = "item";
80
- row.dataset.treeKey = entry.key;
81
- row.style.setProperty("--spui-tree-level", String(entry.level - 1));
82
- row.setAttribute("role", "treeitem");
83
- row.setAttribute("aria-level", String(entry.level));
84
- row.setAttribute("aria-posinset", String(entry.position));
85
- row.setAttribute("aria-setsize", String(entry.setSize));
86
- row.tabIndex = entry.key === this.activeKey ? 0 : -1;
87
- if (entry.node.children?.length)
88
- row.setAttribute("aria-expanded", String(this.expanded.has(entry.key)));
89
- if (this.mode() === "multiple")
90
- row.setAttribute("aria-checked", String(this.checked.get(entry.key) ?? this.selected.has(entry.key)));
91
- else if (this.mode() !== "none")
92
- row.setAttribute("aria-selected", String(this.selected.has(entry.key)));
93
- if (entry.node.disabled)
94
- row.setAttribute("aria-disabled", "true");
95
- if (entry.node.children?.length) {
96
- const disclosure = document.createElement("button");
97
- disclosure.type = "button";
98
- disclosure.className = "disclosure";
99
- disclosure.dataset.toggleTreeKey = entry.key;
100
- disclosure.tabIndex = -1;
101
- disclosure.disabled = Boolean(entry.node.disabled);
102
- disclosure.setAttribute("aria-label", `${this.getAttribute("toggle-label") || "Expand or collapse"} ${entry.node.label}`);
103
- disclosure.setAttribute("aria-expanded", String(this.expanded.has(entry.key)));
104
- const chevron = document.createElement("span");
105
- chevron.className = "chevron";
106
- chevron.setAttribute("aria-hidden", "true");
107
- disclosure.append(chevron);
108
- row.append(disclosure);
109
- }
110
- else {
111
- const spacer = document.createElement("span");
112
- spacer.className = "disclosure";
113
- spacer.setAttribute("aria-hidden", "true");
114
- row.append(spacer);
115
- }
116
- if (this.mode() === "multiple") {
117
- const check = document.createElement("span");
118
- check.className = "check";
119
- check.setAttribute("aria-hidden", "true");
120
- row.append(check);
121
- }
122
- const content = this.renderer?.(entry.node, entry.level) ?? entry.node.label;
123
- const label = document.createElement("span");
124
- label.className = "item-label";
125
- if (content instanceof Node)
126
- label.append(content);
127
- else
128
- label.textContent = String(content);
129
- row.append(label);
130
- fragment.append(row);
131
- });
132
- this.root.append(fragment);
133
- if (active)
134
- this.root.querySelector(`[data-tree-key="${CSS.escape(active)}"]`)?.focus();
135
- }
136
- onClick(event) {
137
- const target = event.target;
138
- const toggle = target.closest("[data-toggle-tree-key]");
139
- if (toggle) {
140
- this.toggleExpanded(toggle.dataset.toggleTreeKey);
141
- return;
142
- }
143
- const row = target.closest("[data-tree-key]");
144
- if (!row || target.closest("a,button,input,select,textarea"))
145
- return;
146
- const key = row.dataset.treeKey;
147
- this.activeKey = key;
148
- const node = this.visible().find(entry => entry.key === key)?.node;
149
- if (node && !node.disabled && this.mode() !== "none")
150
- this.toggleSelection(key);
151
- else
152
- this.paint(key);
153
- }
154
- onKeyDown(event) {
155
- const row = event.target.closest("[data-tree-key]");
156
- if (!row)
157
- return;
158
- const key = row.dataset.treeKey;
159
- const rows = this.visible();
160
- const index = rows.findIndex(entry => entry.key === key);
161
- const entry = rows[index];
162
- if (!entry)
163
- return;
164
- const treegrid = this.getAttribute("navigation-mode") === "treegrid";
165
- if (treegrid && event.target !== row) {
166
- if (event.key === (this.isRtl() ? "ArrowRight" : "ArrowLeft")) {
167
- event.preventDefault();
168
- row.focus();
169
- }
170
- return;
171
- }
172
- if (treegrid && event.key === (this.isRtl() ? "ArrowLeft" : "ArrowRight")) {
173
- const action = row.querySelector("button:not(.disclosure):not([disabled]),a[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex='-1'])");
174
- if (action) {
175
- event.preventDefault();
176
- action.focus();
177
- return;
178
- }
179
- }
180
- let focusKey;
181
- if (event.key === "ArrowDown")
182
- focusKey = rows[index + 1]?.key;
183
- else if (event.key === "ArrowUp")
184
- focusKey = rows[index - 1]?.key;
185
- else if (event.key === "Home")
186
- focusKey = rows[0]?.key;
187
- else if (event.key === "End")
188
- focusKey = rows.at(-1)?.key;
189
- else if ((event.key === (this.isRtl() ? "ArrowLeft" : "ArrowRight")) && entry.node.children?.length) {
190
- event.preventDefault();
191
- if (!this.expanded.has(key))
192
- this.toggleExpanded(key);
193
- else if (rows[index + 1]?.parentKey === key) {
194
- this.activeKey = rows[index + 1].key;
195
- this.paint(this.activeKey);
196
- }
197
- return;
198
- }
199
- else if (event.key === (this.isRtl() ? "ArrowRight" : "ArrowLeft")) {
200
- event.preventDefault();
201
- if (this.expanded.has(key))
202
- this.toggleExpanded(key);
203
- else if (entry.parentKey) {
204
- this.activeKey = entry.parentKey;
205
- this.paint(this.activeKey);
206
- }
207
- return;
208
- }
209
- else if (event.key === "Enter") {
210
- event.preventDefault();
211
- if (entry.node.children?.length)
212
- this.toggleExpanded(key);
213
- else if (!entry.node.disabled)
214
- this.toggleSelection(key);
215
- return;
216
- }
217
- else if (event.key === " ") {
218
- event.preventDefault();
219
- if (!entry.node.disabled)
220
- this.toggleSelection(key);
221
- return;
222
- }
223
- else if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
224
- const now = Date.now(), repeated = now - this.typeAhead.time <= 700 && this.typeAhead.text === event.key;
225
- const text = now - this.typeAhead.time > 700 ? event.key : repeated ? event.key : this.typeAhead.text + event.key;
226
- this.typeAhead = { text, time: now };
227
- const prefix = text.toLocaleLowerCase(this.lang || undefined);
228
- const found = [...rows.slice(index + 1), ...rows.slice(0, index + 1)].find(candidate => candidate.node.label.toLocaleLowerCase(this.lang || undefined).startsWith(prefix));
229
- if (found) {
230
- event.preventDefault();
231
- focusKey = found.key;
232
- }
233
- else
234
- return;
235
- }
236
- else
237
- return;
238
- event.preventDefault();
239
- if (focusKey) {
240
- this.activeKey = focusKey;
241
- this.paint(focusKey);
242
- }
243
- else
244
- this.paint(key);
245
- }
246
- toggleExpanded(key) {
247
- if (this.allNodes().find(entry => entry.key === key)?.node.disabled)
248
- return;
249
- if (this.expanded.has(key))
250
- this.expanded.delete(key);
251
- else
252
- this.expanded.add(key);
253
- this.activeKey = key;
254
- this.paint(key);
255
- this.dispatchEvent(new CustomEvent("spui-tree-expanded-change", { detail: { expandedKeys: [...this.expanded] }, bubbles: true, composed: true }));
256
- }
257
- toggleSelection(key) {
258
- if (this.mode() === "none")
259
- return;
260
- const current = this.checked.get(key) ?? this.selected.has(key);
261
- const checked = current === "mixed" ? true : !current;
262
- if (this.mode() === "single")
263
- this.checked = new Map();
264
- this.checked.set(key, checked);
265
- this.selected = new Set([...this.checked].filter(([, value]) => value === true || value === "mixed").map(([selectedKey]) => selectedKey));
266
- this.activeKey = key;
267
- this.paint(key);
268
- const selectedItems = this.allNodes().filter(entry => this.selected.has(entry.key)).map(entry => entry.node);
269
- this.dispatchEvent(new CustomEvent("spui-tree-selection-change", { detail: { selectedKeys: [...this.selected], selectedItems, checkedItems: new Map(this.checked), checked, selectionMode: this.mode() === "multiple" ? "multiselect" : "single" }, bubbles: true, composed: true }));
270
- }
271
- }
272
- customElements.define("spui-tree", SpuiTree);
273
- }
@@ -1,2 +0,0 @@
1
- /** A SharePoint-ready record card with stable semantic parts and freely composed slots. */
2
- export declare function defineViewCard(): void;
@@ -1,78 +0,0 @@
1
- import { base } from "./shared.js";
2
- /** A SharePoint-ready record card with stable semantic parts and freely composed slots. */
3
- export function defineViewCard() {
4
- if (customElements.get("spui-view-card"))
5
- return;
6
- class SpuiViewCard extends HTMLElement {
7
- static observedAttributes = ["kind", "title", "subtitle", "description"];
8
- connectedCallback() {
9
- if (this.shadowRoot)
10
- return;
11
- const shadow = this.attachShadow({ mode: "open" });
12
- const article = document.createElement("article");
13
- article.part.add("surface");
14
- const header = document.createElement("header");
15
- header.part.add("header");
16
- const leading = document.createElement("div");
17
- leading.className = "leading";
18
- leading.part.add("leading");
19
- leading.append(slot("leading"));
20
- const heading = document.createElement("div");
21
- heading.className = "heading";
22
- const eyebrow = document.createElement("div");
23
- eyebrow.className = "eyebrow";
24
- eyebrow.part.add("eyebrow");
25
- eyebrow.append(slot("eyebrow"));
26
- const title = document.createElement("h3");
27
- title.part.add("title");
28
- title.append(slot("title", "title"));
29
- const subtitle = document.createElement("p");
30
- subtitle.className = "subtitle";
31
- subtitle.part.add("subtitle");
32
- subtitle.append(slot("subtitle", "subtitle"));
33
- heading.append(eyebrow, title, subtitle);
34
- const status = document.createElement("div");
35
- status.className = "status";
36
- status.part.add("status");
37
- status.append(slot("status"));
38
- header.append(leading, heading, status);
39
- const description = document.createElement("p");
40
- description.className = "description";
41
- description.part.add("description");
42
- description.append(slot("description", "description"));
43
- const body = document.createElement("div");
44
- body.className = "body";
45
- body.part.add("body");
46
- body.append(slot());
47
- const footer = document.createElement("footer");
48
- footer.part.add("actions");
49
- footer.append(slot("actions"));
50
- article.append(header, description, body, footer);
51
- const style = document.createElement("style");
52
- style.textContent = `${base}:host{display:block;min-width:0}article{box-sizing:border-box;display:flex;flex-direction:column;gap:var(--spui-control-gap,12px);min-height:100%;padding:var(--spui-card-padding,16px);border:1px solid var(--spui-card-border,var(--spui-ui-stroke,var(--spui-semantic-card-border,#d1d1d1)));border-radius:var(--spui-card-radius,8px);background:var(--spui-card-background,var(--spui-ui-surface,var(--spui-semantic-card-background,#fff)));box-shadow:var(--spui-card-shadow,0 1px 3px #0001);color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit))}header{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:start;gap:var(--spui-control-gap,12px)}.leading:empty,.eyebrow:empty,.subtitle:empty,.description:empty,.status:empty,footer:empty,.body:empty{display:none}.leading{display:grid;place-items:center;min-width:36px;min-height:36px}.heading{min-width:0}.eyebrow{margin:0 0 3px;color:var(--spui-ui-muted,var(--spui-semantic-body-text,#616161));font-size:12px;font-weight:600;letter-spacing:.02em}h3{margin:0;font-size:16px;line-height:1.35;font-weight:650;overflow-wrap:anywhere}.subtitle,.description{margin:3px 0 0;color:var(--spui-ui-muted,var(--spui-semantic-body-text,#616161));font-size:13px;line-height:1.45}.description{margin:0;font-size:14px;color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit))}.status{justify-self:end;align-self:start;font-size:12px}.body{padding-top:10px;border-top:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1));font-size:13px}footer{display:flex;align-items:center;gap:var(--spui-control-gap,8px);margin-top:auto;padding-top:4px}::slotted([slot=leading]){max-width:48px;max-height:48px}::slotted([slot=status]){display:inline-flex;align-items:center;padding:4px 9px;border:1px solid var(--spui-base-stroke,var(--spui-ui-stroke,#d1d1d1));border-radius:999px;background:color-mix(in srgb,var(--spui-base-accent,var(--spui-ui-accent,#0078d4)) 12%,var(--spui-base-surface,var(--spui-ui-surface,#fff)));color:var(--spui-ui-text,inherit);font-size:12px;font-weight:600}::slotted([slot=actions]){font:inherit}:host([kind=person]) .leading{border-radius:50%;overflow:hidden}:host([kind=person]) .leading:empty{border-radius:50%;background:var(--spui-ui-canvas,#f5f5f5)}:host([data-spui-appearance=glass]),:host-context([data-spui-appearance=glass]) article{backdrop-filter:var(--spui-card-backdrop,none)}@media(prefers-reduced-motion:reduce){article{scroll-behavior:auto}}@media(forced-colors:active){article{border-color:CanvasText;box-shadow:none}}`;
53
- shadow.append(style, article);
54
- for (const name of SpuiViewCard.observedAttributes)
55
- this.updateFallback(name);
56
- }
57
- attributeChangedCallback(name) {
58
- this.updateFallback(name);
59
- }
60
- updateFallback(name) { const fallback = this.shadowRoot?.querySelector(`[data-fallback="${name}"]`); if (fallback)
61
- fallback.textContent = this.getAttribute(name) ?? ""; }
62
- }
63
- customElements.define("spui-view-card", SpuiViewCard);
64
- }
65
- function slot(name, attribute) {
66
- const element = document.createElement("slot");
67
- if (name)
68
- element.name = name;
69
- if (attribute) {
70
- const fallback = document.createElement("span");
71
- fallback.dataset.fallback = attribute;
72
- element.append(fallback);
73
- }
74
- else
75
- element.addEventListener("slotchange", () => { if (element.parentElement)
76
- element.parentElement.hidden = element.assignedElements().length === 0; });
77
- return element;
78
- }
@@ -1,41 +0,0 @@
1
- export type VirtualListItemRenderer<T = unknown> = (item: T, index: number) => Node | string | number | null;
2
- export interface VirtualListDataSource<T = unknown> {
3
- readonly length: number;
4
- getItem(index: number): T | undefined;
5
- loadRange(start: number, end: number, signal: AbortSignal): void | Promise<void>;
6
- subscribe?(listener: () => void): () => void;
7
- }
8
- export interface SharePointVirtualListElement extends HTMLElement {
9
- items: unknown[];
10
- dataSource?: VirtualListDataSource;
11
- renderItem?: VirtualListItemRenderer;
12
- itemKey?: (item: unknown, index: number) => string | number;
13
- axis: "vertical" | "horizontal";
14
- itemSize: number;
15
- rowHeight: number;
16
- measureItems: boolean;
17
- scrollToIndex(index: number, align?: "start" | "center" | "end", behavior?: ScrollBehavior): void;
18
- }
19
- declare global {
20
- interface HTMLElementTagNameMap {
21
- "spui-virtual-list": SharePointVirtualListElement;
22
- }
23
- }
24
- /** Prefix-sum index for measured rows; point updates and offset lookups are O(log n). */
25
- export declare class VariableSizeIndex {
26
- private sizes;
27
- private tree;
28
- private estimate;
29
- private count;
30
- private uniform;
31
- constructor(count?: number, estimate?: number, sizes?: readonly number[]);
32
- get length(): number;
33
- get totalSize(): number;
34
- reset(count: number, estimate: number, sizes?: readonly number[]): void;
35
- size(index: number): number;
36
- offset(index: number): number;
37
- set(index: number, size: number): number;
38
- indexAt(offset: number): number;
39
- }
40
- /** Fixed or measured one-dimensional virtual list. DOM work is bounded by the viewport plus overscan. */
41
- export declare function defineVirtualList(): void;