@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,527 +0,0 @@
1
- import { getFloatingPosition } from "./floating-position.js";
2
- import { getDirectionFromLanguage } from "./shared.js";
3
- const nextId = (() => { let value = 0; return () => `spui-tooltip-${++value}`; })();
4
- let activeTooltip;
5
- function rectEdges(rect) {
6
- const left = "left" in rect ? rect.left : rect.x;
7
- const top = "top" in rect ? rect.top : rect.y;
8
- return { left, top, right: left + rect.width, bottom: top + rect.height };
9
- }
10
- function parentElement(element) {
11
- if (element.parentElement)
12
- return element.parentElement;
13
- const root = element.getRootNode();
14
- return root instanceof ShadowRoot ? root.host : null;
15
- }
16
- function getLayoutDirection(element) {
17
- let explicitDirection;
18
- let language;
19
- for (let current = element; current; current = parentElement(current)) {
20
- if (!explicitDirection && current.hasAttribute("dir"))
21
- explicitDirection = current;
22
- if (!language && (current.hasAttribute("lang") || current.hasAttribute("xml:lang")))
23
- language = current;
24
- }
25
- if (explicitDirection)
26
- return explicitDirection.ownerDocument.defaultView?.getComputedStyle(explicitDirection).direction === "rtl" ? "rtl" : "ltr";
27
- const derived = getDirectionFromLanguage(language?.getAttribute("lang") ?? language?.getAttribute("xml:lang"));
28
- if (derived)
29
- return derived;
30
- return element.ownerDocument.defaultView?.getComputedStyle(element).direction === "rtl" ? "rtl" : "ltr";
31
- }
32
- function intersectRects(rects) {
33
- if (!rects.length)
34
- return undefined;
35
- const left = Math.max(...rects.map(rect => rect.left));
36
- const top = Math.max(...rects.map(rect => rect.top));
37
- return { left, top, right: Math.max(left, Math.min(...rects.map(rect => rect.right))), bottom: Math.max(top, Math.min(...rects.map(rect => rect.bottom))) };
38
- }
39
- function getPositioningBoundary(boundary, context) {
40
- if (!boundary || boundary === "window")
41
- return undefined;
42
- if (Array.isArray(boundary))
43
- return intersectRects(boundary.map(element => rectEdges(element.getBoundingClientRect())));
44
- if (typeof boundary === "object" && "getBoundingClientRect" in boundary)
45
- return rectEdges(boundary.getBoundingClientRect());
46
- if (typeof boundary === "object" && "width" in boundary)
47
- return rectEdges(boundary);
48
- if ((boundary === "clippingParents" || boundary === "scrollParent") && context) {
49
- const win = context.ownerDocument.defaultView;
50
- if (!win)
51
- return undefined;
52
- const viewport = { left: 0, top: 0, right: win.innerWidth, bottom: win.innerHeight };
53
- const rects = boundary === "clippingParents" ? [viewport] : [];
54
- let current = parentElement(context);
55
- while (current) {
56
- const style = win.getComputedStyle(current);
57
- const clipsX = /^(auto|scroll|hidden|clip|overlay)$/.test(style.overflowX);
58
- const clipsY = /^(auto|scroll|hidden|clip|overlay)$/.test(style.overflowY);
59
- const isScrollParent = /^(auto|scroll|hidden|overlay)$/.test(style.overflowX) || /^(auto|scroll|hidden|overlay)$/.test(style.overflowY);
60
- if (boundary === "clippingParents" ? clipsX || clipsY : isScrollParent) {
61
- const bounds = current.getBoundingClientRect();
62
- const left = bounds.left + current.clientLeft;
63
- const top = bounds.top + current.clientTop;
64
- const rect = { left: clipsX ? left : 0, right: clipsX ? left + current.clientWidth : win.innerWidth, top: clipsY ? top : 0, bottom: clipsY ? top + current.clientHeight : win.innerHeight };
65
- if (boundary === "scrollParent")
66
- return rect;
67
- rects.push(rect);
68
- }
69
- current = parentElement(current);
70
- }
71
- return boundary === "clippingParents" ? intersectRects(rects) : undefined;
72
- }
73
- return undefined;
74
- }
75
- function normalizePosition(position, direction) {
76
- if (position === "above")
77
- return "top";
78
- if (position === "below")
79
- return "bottom";
80
- if (position === "before")
81
- return direction === "rtl" ? "right" : "left";
82
- if (position === "after")
83
- return direction === "rtl" ? "left" : "right";
84
- return position;
85
- }
86
- export function defineTooltip() {
87
- if (customElements.get("spui-tooltip"))
88
- return;
89
- class SpuiTooltip extends HTMLElement {
90
- static observedAttributes = ["content", "placement", "positioning", "align", "offset", "disabled", "open", "delay", "show-delay", "hide-delay", "relationship", "appearance", "with-arrow"];
91
- observer;
92
- sizeObserver;
93
- events;
94
- timer;
95
- trigger;
96
- ariaBefore;
97
- tooltip;
98
- isOpen = false;
99
- inTopLayer = false;
100
- positioningValue;
101
- positioningRef;
102
- tooltipElementValue;
103
- positioningHandle = { updatePosition: () => this.position(), setTarget: target => this.setPositioningTarget(target) };
104
- connectedCallback() {
105
- this.style.display ||= "contents";
106
- this.events?.abort();
107
- this.events = new AbortController();
108
- const options = { signal: this.events.signal };
109
- this.addEventListener("pointerenter", this.onPointerEnter, options);
110
- this.addEventListener("pointerleave", this.onPointerLeave, options);
111
- this.addEventListener("focusin", this.onFocusIn, options);
112
- this.addEventListener("focusout", this.onFocusOut, options);
113
- this.ownerDocument.addEventListener("keydown", this.onDocumentKeyDown, { ...options, capture: true });
114
- this.ownerDocument.addEventListener("visibilitychange", this.onVisibilityChange, options);
115
- window.addEventListener("resize", this.position, options);
116
- window.addEventListener("scroll", this.position, { ...options, capture: true });
117
- this.observer = new MutationObserver(() => this.sync());
118
- this.observer.observe(this, { childList: true });
119
- this.isOpen = this.hasAttribute("open");
120
- const positioningOptions = typeof this.positioningValue === "object" && this.positioningValue !== null ? this.positioningValue : undefined;
121
- this.setPositioningRef(positioningOptions?.positioningRef);
122
- this.sync();
123
- this.observeSize();
124
- }
125
- disconnectedCallback() {
126
- this.observer?.disconnect();
127
- this.sizeObserver?.disconnect();
128
- this.events?.abort();
129
- this.clearTimer();
130
- if (activeTooltip?.element === this)
131
- activeTooltip = undefined;
132
- this.tooltip?.hidePopover?.();
133
- this.restoreAria();
134
- this.setPositioningRef(undefined);
135
- }
136
- get positioning() { return this.positioningValue; }
137
- set positioning(value) {
138
- this.positioningValue = value;
139
- const options = typeof value === "object" && value !== null ? value : undefined;
140
- this.setPositioningRef(options?.positioningRef);
141
- this.observeSize();
142
- this.position();
143
- }
144
- get tooltipElement() { return this.tooltipElementValue; }
145
- set tooltipElement(value) {
146
- const next = value ?? undefined;
147
- if (this.tooltipElementValue === next)
148
- return;
149
- this.tooltipElementValue = next;
150
- if (this.isConnected)
151
- this.sync();
152
- }
153
- setPositioningRef(ref) {
154
- if (this.positioningRef === ref)
155
- return;
156
- if (typeof this.positioningRef === "function")
157
- this.positioningRef(null);
158
- else if (this.positioningRef)
159
- this.positioningRef.current = null;
160
- this.positioningRef = ref;
161
- if (typeof ref === "function")
162
- ref(this.positioningHandle);
163
- else if (ref)
164
- ref.current = this.positioningHandle;
165
- }
166
- setPositioningTarget(target) {
167
- const current = typeof this.positioningValue === "object" && this.positioningValue !== null ? this.positioningValue : {};
168
- this.positioningValue = { ...current, target };
169
- this.observeSize();
170
- this.position();
171
- }
172
- attributeChangedCallback(name) {
173
- if (name === "open") {
174
- const next = this.hasAttribute("open");
175
- if (next !== this.isOpen) {
176
- if (next)
177
- this.claimActiveTooltip();
178
- else if (activeTooltip?.element === this)
179
- activeTooltip = undefined;
180
- this.isOpen = next;
181
- this.syncVisibility();
182
- this.emitOpenChange();
183
- }
184
- }
185
- else if (this.isConnected) {
186
- if (name === "disabled" && this.hasAttribute("disabled"))
187
- this.setOpen(false);
188
- else
189
- this.sync();
190
- }
191
- }
192
- get open() { return this.isOpen; }
193
- set open(value) { this.setOpen(Boolean(value)); }
194
- sync() {
195
- const content = this.tooltipElementValue ?? [...this.querySelectorAll("[slot=tooltip]")].find(element => element.dataset.spuiTooltipGenerated === undefined);
196
- const generated = this.querySelector("[data-spui-tooltip-generated]");
197
- if (content) {
198
- generated?.remove();
199
- this.tooltip = content;
200
- }
201
- else if (this.hasAttribute("content")) {
202
- this.tooltip = generated ?? document.createElement("span");
203
- this.tooltip.setAttribute("slot", "tooltip");
204
- this.tooltip.dataset.spuiTooltipGenerated = "";
205
- this.tooltip.textContent = this.getAttribute("content") ?? "";
206
- if (!generated)
207
- this.append(this.tooltip);
208
- }
209
- else {
210
- generated?.remove();
211
- this.tooltip = undefined;
212
- }
213
- if (this.tooltip) {
214
- if (!this.tooltip.id)
215
- this.tooltip.id = nextId();
216
- this.tooltip.setAttribute("role", "tooltip");
217
- this.styleTooltip();
218
- }
219
- const trigger = [...this.children].find((child) => child instanceof HTMLElement && child !== this.tooltip && child.getAttribute("slot") !== "tooltip");
220
- if (trigger !== this.trigger) {
221
- this.restoreAria();
222
- this.trigger = trigger;
223
- this.ariaBefore = trigger ? new Map(["aria-label", "aria-labelledby", "aria-describedby", "aria-description"].map(name => [name, trigger.getAttribute(name)])) : undefined;
224
- }
225
- this.applyRelationship();
226
- this.observeSize();
227
- this.syncVisibility();
228
- }
229
- styleTooltip() {
230
- if (!this.tooltip)
231
- return;
232
- this.tooltip.setAttribute("popover", "manual");
233
- Object.assign(this.tooltip.style, {
234
- position: "fixed",
235
- zIndex: "10000",
236
- boxSizing: "border-box",
237
- maxWidth: "min(320px, calc(100vw - 16px))",
238
- maxHeight: "calc(100vh - 16px)",
239
- padding: "6px 10px",
240
- border: "1px solid var(--spui-tooltip-border, var(--colorNeutralStroke1, #666))",
241
- borderRadius: "var(--spui-tooltip-radius, var(--spui-control-radius, 4px))",
242
- background: this.appearance === "inverted" ? "var(--spui-tooltip-background, var(--colorNeutralBackgroundInverted, #292929))" : "var(--spui-tooltip-background, var(--colorNeutralBackground1, #fff))",
243
- color: this.appearance === "inverted" ? "var(--spui-tooltip-color, var(--colorNeutralForegroundInverted, #fff))" : "var(--spui-tooltip-color, var(--colorNeutralForeground1, #242424))",
244
- boxShadow: "0 2px 8px rgb(0 0 0 / 18%)",
245
- font: "500 12px/1.4 var(--spui-font-family, inherit)",
246
- overflowWrap: "anywhere",
247
- overflowY: "auto",
248
- pointerEvents: "none",
249
- margin: "0"
250
- });
251
- this.tooltip.dataset.appearance = this.appearance;
252
- let arrow = this.tooltip.querySelector(":scope > [data-spui-tooltip-arrow]");
253
- if (this.hasAttribute("with-arrow")) {
254
- if (!arrow) {
255
- arrow = document.createElement("span");
256
- arrow.dataset.spuiTooltipArrow = "";
257
- arrow.setAttribute("aria-hidden", "true");
258
- Object.assign(arrow.style, { position: "absolute", width: "8px", height: "8px", transform: "rotate(45deg)", background: "inherit", border: "inherit", pointerEvents: "none" });
259
- this.tooltip.append(arrow);
260
- }
261
- }
262
- else
263
- arrow?.remove();
264
- }
265
- syncVisibility() {
266
- if (!this.tooltip)
267
- return;
268
- const visible = this.isOpen && !this.hasAttribute("disabled");
269
- const surface = this.tooltip;
270
- if (visible) {
271
- surface.hidden = false;
272
- try {
273
- surface.showPopover?.();
274
- this.inTopLayer = typeof surface.showPopover === "function";
275
- }
276
- catch {
277
- this.inTopLayer = false;
278
- }
279
- requestAnimationFrame(this.position);
280
- }
281
- else {
282
- this.inTopLayer = false;
283
- surface.hidePopover?.();
284
- surface.hidden = true;
285
- }
286
- }
287
- position = () => {
288
- const trigger = this.trigger;
289
- const tooltip = this.tooltip;
290
- const options = this.positioningOptions;
291
- const target = options?.target;
292
- if (!this.isOpen || !tooltip || tooltip.hidden || (!trigger && !target))
293
- return;
294
- const targetContext = target && "contextElement" in target ? target.contextElement : target && "nodeType" in target ? target : undefined;
295
- const targetRect = target?.getBoundingClientRect();
296
- const anchor = targetRect ?? trigger.getBoundingClientRect();
297
- const direction = getLayoutDirection(targetContext ?? trigger ?? this);
298
- const rtl = direction === "rtl";
299
- const [requested, align, rawPosition] = this.getRequestedPosition(rtl ? "rtl" : "ltr");
300
- const configuredOffset = options?.offset;
301
- const functionOffset = typeof configuredOffset === "function" ? configuredOffset({
302
- positionedRect: { x: 0, y: 0, width: tooltip.offsetWidth, height: tooltip.offsetHeight },
303
- targetRect: { x: anchor.x, y: anchor.y, width: anchor.width, height: anchor.height },
304
- position: (rawPosition === "above" || rawPosition === "below" || rawPosition === "before" || rawPosition === "after" ? rawPosition : "above"),
305
- alignment: align,
306
- }) : configuredOffset;
307
- const offset = typeof functionOffset === "number" ? functionOffset : functionOffset?.mainAxis ?? 0;
308
- const crossAxisOffset = typeof functionOffset === "object" ? functionOffset.crossAxis ?? 0 : 0;
309
- const gap = configuredOffset === undefined ? this.hasAttribute("offset") ? Math.max(0, Number(this.getAttribute("offset")) || 0) : this.hasAttribute("with-arrow") ? 12 : 8 : Math.max(0, offset);
310
- const boundaryContext = targetContext ?? trigger ?? this;
311
- const flipBoundary = getPositioningBoundary(options?.flipBoundary, boundaryContext);
312
- const overflowBoundary = getPositioningBoundary(options?.overflowBoundary, boundaryContext);
313
- const rawPadding = options?.overflowBoundaryPadding;
314
- const padding = typeof rawPadding === "number" ? { top: rawPadding, right: rawPadding, bottom: rawPadding, left: rawPadding } : {
315
- top: rawPadding?.top ?? 0,
316
- bottom: rawPadding?.bottom ?? 0,
317
- left: rtl ? rawPadding?.end ?? 0 : rawPadding?.start ?? 0,
318
- right: rtl ? rawPadding?.start ?? 0 : rawPadding?.end ?? 0,
319
- };
320
- const strategy = options?.strategy ?? (options?.positionFixed === true ? "fixed" : options?.positionFixed === false ? "absolute" : this.inTopLayer ? "absolute" : "fixed");
321
- tooltip.style.position = strategy;
322
- tooltip.style.transform = "";
323
- tooltip.style.maxWidth = "min(320px, calc(100vw - 16px))";
324
- tooltip.style.maxHeight = "calc(100vh - 16px)";
325
- tooltip.style.width = options?.matchTargetSize === "width" ? `${anchor.width}px` : "";
326
- tooltip.style.height = "";
327
- tooltip.style.overflowX = "";
328
- tooltip.style.overflowY = "auto";
329
- const surface = { width: tooltip.offsetWidth, height: tooltip.offsetHeight };
330
- const viewport = { width: window.innerWidth, height: window.innerHeight };
331
- const fallback = (options?.fallbackPositions ?? []).map(value => {
332
- const [side, fallbackAlign] = this.parsePosition(value, rtl ? "rtl" : "ltr");
333
- return { placement: side, align: fallbackAlign };
334
- });
335
- const pinned = options?.pinned === true;
336
- const coverTarget = options?.coverTarget === true;
337
- const modifiers = { crossAxisOffset, coverTarget, overflowBoundaryPadding: padding };
338
- let position = getFloatingPosition(anchor, surface, requested, rtl ? "rtl" : "ltr", gap, viewport, align, fallback, pinned, flipBoundary, overflowBoundary, modifiers);
339
- const flipBounds = flipBoundary ?? { left: 0, top: 0, right: viewport.width, bottom: viewport.height };
340
- const overflows = position.left < flipBounds.left || position.top < flipBounds.top || position.left + surface.width > flipBounds.right || position.top + surface.height > flipBounds.bottom;
341
- if (options?.shiftToCoverTarget && overflows && !coverTarget)
342
- position = getFloatingPosition(anchor, surface, requested, rtl ? "rtl" : "ltr", gap, viewport, align, fallback, pinned, flipBoundary, overflowBoundary, { ...modifiers, coverTarget: true });
343
- const autoSize = options?.autoSize;
344
- const applyMaxWidth = autoSize === true || autoSize === "always" || autoSize === "width" || autoSize === "width-always";
345
- const applyMaxHeight = autoSize === true || autoSize === "always" || autoSize === "height" || autoSize === "height-always";
346
- const bounds = overflowBoundary ?? { left: 0, top: 0, right: viewport.width, bottom: viewport.height };
347
- const availableWidth = Math.max(0, (position.placement === "left" ? anchor.left - bounds.left - padding.left - gap : position.placement === "right" ? bounds.right - padding.right - anchor.right - gap : bounds.right - padding.right - bounds.left - padding.left - gap * 2));
348
- const availableHeight = Math.max(0, (position.placement === "top" ? anchor.top - bounds.top - padding.top - gap : position.placement === "bottom" ? bounds.bottom - padding.bottom - anchor.bottom - gap : bounds.bottom - padding.bottom - bounds.top - padding.top - gap * 2));
349
- if (applyMaxWidth)
350
- tooltip.style.maxWidth = `${availableWidth}px`;
351
- if (applyMaxHeight)
352
- tooltip.style.maxHeight = `${availableHeight}px`;
353
- const pageOffset = strategy === "absolute" ? { x: window.scrollX, y: window.scrollY } : { x: 0, y: 0 };
354
- const useTransform = options?.useTransform !== false;
355
- tooltip.style.left = useTransform ? "0px" : `${position.left + pageOffset.x}px`;
356
- tooltip.style.top = useTransform ? "0px" : `${position.top + pageOffset.y}px`;
357
- if (useTransform)
358
- tooltip.style.transform = `translate3d(${position.left + pageOffset.x}px, ${position.top + pageOffset.y}px, 0)`;
359
- tooltip.dataset.placement = position.placement;
360
- const arrow = tooltip.querySelector("[data-spui-tooltip-arrow]");
361
- if (arrow) {
362
- Object.assign(arrow.style, { insetInlineStart: "", insetInlineEnd: "", top: "", right: "", bottom: "", left: "" });
363
- const surfaceRect = tooltip.getBoundingClientRect();
364
- const anchorCenterX = anchor.left + anchor.width / 2 - surfaceRect.left - 4;
365
- const anchorCenterY = anchor.top + anchor.height / 2 - surfaceRect.top - 4;
366
- const arrowPadding = Math.max(0, options?.arrowPadding ?? 4);
367
- const arrowLeft = `${Math.max(arrowPadding, Math.min(anchorCenterX, surfaceRect.width - arrowPadding - 8))}px`;
368
- const arrowTop = `${Math.max(arrowPadding, Math.min(anchorCenterY, surfaceRect.height - arrowPadding - 8))}px`;
369
- if (position.placement === "top")
370
- Object.assign(arrow.style, { bottom: "-4px", left: arrowLeft, borderTop: "0", borderLeft: "0" });
371
- else if (position.placement === "bottom")
372
- Object.assign(arrow.style, { top: "-4px", left: arrowLeft, borderRight: "0", borderBottom: "0" });
373
- else if (position.placement === "left")
374
- Object.assign(arrow.style, { right: "-4px", top: arrowTop, borderLeft: "0", borderBottom: "0" });
375
- else
376
- Object.assign(arrow.style, { left: "-4px", top: arrowTop, borderTop: "0", borderRight: "0" });
377
- }
378
- const inlinePlacement = position.placement === "top" || position.placement === "bottom" ? position.align === "start" || position.align === "end" ? `-${position.align}` : "" : position.align === "top" ? "-start" : position.align === "bottom" ? "-end" : "";
379
- const detail = {
380
- placement: `${position.placement}${inlinePlacement}`,
381
- escaped: position.left < bounds.left || position.top < bounds.top || position.left + tooltip.offsetWidth > bounds.right || position.top + tooltip.offsetHeight > bounds.bottom,
382
- referenceHidden: anchor.bottom <= 0 || anchor.top >= window.innerHeight || anchor.right <= 0 || anchor.left >= window.innerWidth,
383
- };
384
- options?.onPositioningEnd?.(new CustomEvent("fui-positioningend", { detail }));
385
- tooltip.dispatchEvent(new CustomEvent("fui-positioningend", { bubbles: true, detail }));
386
- };
387
- onPointerEnter = (event) => {
388
- if (event.pointerType === "touch")
389
- return;
390
- if (this.hasAttribute("disabled"))
391
- return;
392
- this.clearTimer();
393
- this.timer = setTimeout(() => this.setOpen(true, event), this.showDelay);
394
- };
395
- onPointerLeave = (event) => {
396
- if (event.pointerType === "touch")
397
- return;
398
- if (event.relatedTarget instanceof Node && this.contains(event.relatedTarget))
399
- return;
400
- this.clearTimer();
401
- this.timer = setTimeout(() => this.setOpen(false, event), this.hideDelay);
402
- };
403
- onFocusIn = (event) => { if (!this.hasAttribute("disabled")) {
404
- this.clearTimer();
405
- this.timer = setTimeout(() => this.setOpen(true, event), this.showDelay);
406
- } };
407
- onFocusOut = (event) => {
408
- if (event.relatedTarget instanceof Node && this.contains(event.relatedTarget))
409
- return;
410
- this.clearTimer();
411
- this.timer = setTimeout(() => this.setOpen(false, event), this.hideDelay);
412
- };
413
- onDocumentKeyDown = (event) => {
414
- if (event.key === "Escape" && this.isOpen && !event.defaultPrevented) {
415
- event.preventDefault();
416
- event.stopPropagation();
417
- this.setOpen(false, event);
418
- }
419
- };
420
- onVisibilityChange = () => { if (this.ownerDocument.visibilityState === "hidden")
421
- this.setOpen(false); };
422
- observeSize() {
423
- if (!this.isConnected || typeof ResizeObserver === "undefined")
424
- return;
425
- this.sizeObserver ??= new ResizeObserver(this.position);
426
- this.sizeObserver.disconnect();
427
- if (this.positioningOptions?.disableUpdateOnResize)
428
- return;
429
- if (this.trigger)
430
- this.sizeObserver.observe(this.trigger);
431
- if (this.tooltip)
432
- this.sizeObserver.observe(this.tooltip);
433
- const target = this.positioningOptions?.target;
434
- const targetContext = target && "contextElement" in target ? target.contextElement : target && "nodeType" in target ? target : undefined;
435
- if (targetContext)
436
- this.sizeObserver.observe(targetContext);
437
- }
438
- claimActiveTooltip() {
439
- if (activeTooltip && activeTooltip.element !== this)
440
- activeTooltip.close();
441
- activeTooltip = { element: this, close: () => this.setOpen(false) };
442
- }
443
- setOpen(value, sourceEvent) {
444
- const next = Boolean(value) && !this.hasAttribute("disabled");
445
- if (next === this.isOpen)
446
- return;
447
- if (next)
448
- this.claimActiveTooltip();
449
- else if (activeTooltip?.element === this)
450
- activeTooltip = undefined;
451
- this.isOpen = next;
452
- if (this.hasAttribute("open") !== next)
453
- this.toggleAttribute("open", next);
454
- this.syncVisibility();
455
- this.emitOpenChange(sourceEvent);
456
- }
457
- emitOpenChange(sourceEvent) {
458
- const documentKeyboardEvent = sourceEvent instanceof KeyboardEvent ? sourceEvent : undefined;
459
- const event = documentKeyboardEvent ? undefined : sourceEvent;
460
- this.dispatchEvent(new CustomEvent("spui-open-change", { bubbles: true, composed: true, detail: { open: this.isOpen, visible: this.isOpen, event, documentKeyboardEvent } }));
461
- }
462
- clearTimer() { if (this.timer !== undefined)
463
- clearTimeout(this.timer); this.timer = undefined; }
464
- get appearance() { return this.getAttribute("appearance") === "inverted" ? "inverted" : "normal"; }
465
- get positioningOptions() { return typeof this.positioningValue === "object" && this.positioningValue !== null ? this.positioningValue : undefined; }
466
- parsePosition(raw, direction) {
467
- const parts = raw.split("-");
468
- const placement = normalizePosition(parts[0], direction);
469
- const suffix = parts[1];
470
- const requestedAlign = suffix === "start" || suffix === "end" || suffix === "top" || suffix === "bottom" ? suffix : "center";
471
- const vertical = placement === "top" || placement === "bottom";
472
- const align = vertical ? requestedAlign === "start" || requestedAlign === "end" ? requestedAlign : "center" : requestedAlign === "top" || requestedAlign === "bottom" ? requestedAlign : "center";
473
- return [placement, align];
474
- }
475
- getRequestedPosition(direction) {
476
- const configured = this.positioningValue;
477
- const raw = typeof configured === "string" ? configured : configured?.position ?? this.getAttribute("positioning") ?? this.getAttribute("placement") ?? "above";
478
- const [placement, suffixAlign] = this.parsePosition(raw, direction);
479
- const configuredAlign = typeof configured === "object" && configured !== null ? configured.align : undefined;
480
- const attributeAlign = this.getAttribute("align");
481
- const requestedAlign = configuredAlign ?? attributeAlign ?? suffixAlign;
482
- const vertical = placement === "top" || placement === "bottom";
483
- const align = vertical ? requestedAlign === "start" || requestedAlign === "end" ? requestedAlign : "center" : requestedAlign === "top" || requestedAlign === "bottom" ? requestedAlign : "center";
484
- return [placement, align, raw];
485
- }
486
- get relationship() {
487
- const value = this.getAttribute("relationship");
488
- return value === "label" || value === "inaccessible" ? value : "description";
489
- }
490
- get showDelay() { return this.parseDelay(this.getAttribute("show-delay") ?? this.getAttribute("delay"), 250); }
491
- get hideDelay() { return this.parseDelay(this.getAttribute("hide-delay"), 250); }
492
- parseDelay(value, fallback) { if (value === null || value.trim() === "")
493
- return fallback; const delay = Number(value); return Number.isFinite(delay) && delay >= 0 ? delay : fallback; }
494
- applyRelationship() {
495
- const trigger = this.trigger;
496
- if (!trigger || !this.ariaBefore)
497
- return;
498
- this.restoreAriaValues();
499
- if (!this.tooltip || this.relationship === "inaccessible")
500
- return;
501
- if ((trigger.shadowRoot || trigger.localName.includes("-")) && this.tooltip.getRootNode() !== trigger.shadowRoot && this.relationship === "description") {
502
- const values = [this.ariaBefore.get("aria-description"), this.tooltip.textContent?.trim()].filter(Boolean);
503
- if (values.length)
504
- trigger.setAttribute("aria-description", values.join(" "));
505
- return;
506
- }
507
- const attribute = this.relationship === "label" ? "aria-labelledby" : "aria-describedby";
508
- const values = new Set((this.ariaBefore.get(attribute) ?? "").split(/\s+/).filter(Boolean));
509
- values.add(this.tooltip.id);
510
- trigger.setAttribute(attribute, [...values].join(" "));
511
- }
512
- restoreAriaValues() {
513
- if (!this.trigger || !this.ariaBefore)
514
- return;
515
- for (const [name, value] of this.ariaBefore)
516
- value === null ? this.trigger.removeAttribute(name) : this.trigger.setAttribute(name, value);
517
- }
518
- restoreAria() {
519
- if (!this.trigger)
520
- return;
521
- this.restoreAriaValues();
522
- this.trigger = undefined;
523
- this.ariaBefore = undefined;
524
- }
525
- }
526
- customElements.define("spui-tooltip", SpuiTooltip);
527
- }
@@ -1,19 +0,0 @@
1
- export type TreeNode<T = unknown> = {
2
- id: string | number;
3
- label: string;
4
- disabled?: boolean;
5
- open?: boolean;
6
- children?: readonly TreeNode<T>[];
7
- value?: T;
8
- };
9
- export type VisibleTreeNode<T = unknown> = {
10
- node: TreeNode<T>;
11
- key: string;
12
- parentKey?: string;
13
- level: number;
14
- position: number;
15
- setSize: number;
16
- };
17
- export declare function treeNodeKey<T>(node: TreeNode<T>): string;
18
- export declare function flattenTree<T>(nodes: readonly TreeNode<T>[], expandedKeys: ReadonlySet<string>): VisibleTreeNode<T>[];
19
- export declare function flattenAllTree<T>(nodes: readonly TreeNode<T>[]): VisibleTreeNode<T>[];
@@ -1,34 +0,0 @@
1
- export function treeNodeKey(node) { return String(node.id); }
2
- export function flattenTree(nodes, expandedKeys) {
3
- const result = [];
4
- const seenIds = new Set();
5
- const stack = [];
6
- for (let index = nodes.length - 1; index >= 0; index--)
7
- stack.push({ node: nodes[index], level: 1, position: index + 1, setSize: nodes.length });
8
- while (stack.length) {
9
- const entry = stack.pop();
10
- const key = treeNodeKey(entry.node);
11
- if (seenIds.has(key))
12
- continue;
13
- seenIds.add(key);
14
- result.push({ ...entry, key });
15
- const children = entry.node.children ?? [];
16
- if (children.length && expandedKeys.has(key)) {
17
- for (let index = children.length - 1; index >= 0; index--)
18
- stack.push({ node: children[index], parentKey: key, level: entry.level + 1, position: index + 1, setSize: children.length });
19
- }
20
- }
21
- return result;
22
- }
23
- export function flattenAllTree(nodes) {
24
- const expanded = new Set(), stack = [...nodes];
25
- while (stack.length) {
26
- const node = stack.pop(), key = treeNodeKey(node);
27
- if (expanded.has(key))
28
- continue;
29
- expanded.add(key);
30
- if (node.children)
31
- stack.push(...node.children);
32
- }
33
- return flattenTree(nodes, expanded);
34
- }
@@ -1,5 +0,0 @@
1
- import { type TreeNode } from "./tree-model.js";
2
- export type TreeItemRenderer<T = unknown> = (node: TreeNode<T>, level: number) => Node | string | number | null;
3
- export type TreeCheckedItem = string | number | readonly [string | number, boolean | "mixed"];
4
- /** Accessible framework-neutral tree with nested data and roving focus. */
5
- export declare function defineTree(): void;