@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,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("label") || this.getAttribute("aria-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;