@spfx-fast/sharepoint-ui 0.0.0-stage → 0.4.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 (158) hide show
  1. package/AGENTS.md +211 -0
  2. package/LICENSE +21 -0
  3. package/README.md +897 -2
  4. package/components.json +5810 -0
  5. package/dist/appearance.d.ts +6 -0
  6. package/dist/appearance.js +217 -0
  7. package/dist/elements/accordion.d.ts +9 -0
  8. package/dist/elements/accordion.js +338 -0
  9. package/dist/elements/alert.d.ts +2 -0
  10. package/dist/elements/alert.js +62 -0
  11. package/dist/elements/avatar-group-primitives.d.ts +3 -0
  12. package/dist/elements/avatar-group-primitives.js +189 -0
  13. package/dist/elements/avatar-group.d.ts +2 -0
  14. package/dist/elements/avatar-group.js +110 -0
  15. package/dist/elements/avatar.d.ts +4 -0
  16. package/dist/elements/avatar.js +251 -0
  17. package/dist/elements/badge.d.ts +8 -0
  18. package/dist/elements/badge.js +182 -0
  19. package/dist/elements/breadcrumb.d.ts +4 -0
  20. package/dist/elements/breadcrumb.js +233 -0
  21. package/dist/elements/button-group.d.ts +1 -0
  22. package/dist/elements/button-group.js +20 -0
  23. package/dist/elements/button-variants.d.ts +6 -0
  24. package/dist/elements/button-variants.js +339 -0
  25. package/dist/elements/button.d.ts +5 -0
  26. package/dist/elements/button.js +233 -0
  27. package/dist/elements/card-primitives.d.ts +3 -0
  28. package/dist/elements/card-primitives.js +83 -0
  29. package/dist/elements/card.d.ts +5 -0
  30. package/dist/elements/card.js +213 -0
  31. package/dist/elements/carousel.d.ts +92 -0
  32. package/dist/elements/carousel.js +1112 -0
  33. package/dist/elements/color-picker.d.ts +24 -0
  34. package/dist/elements/color-picker.js +1004 -0
  35. package/dist/elements/combobox.d.ts +1 -0
  36. package/dist/elements/combobox.js +1012 -0
  37. package/dist/elements/data-grid-model.d.ts +117 -0
  38. package/dist/elements/data-grid-model.js +294 -0
  39. package/dist/elements/data-grid.d.ts +29 -0
  40. package/dist/elements/data-grid.js +1567 -0
  41. package/dist/elements/date-picker.d.ts +1 -0
  42. package/dist/elements/date-picker.js +486 -0
  43. package/dist/elements/dialog.d.ts +23 -0
  44. package/dist/elements/dialog.js +409 -0
  45. package/dist/elements/divider.d.ts +2 -0
  46. package/dist/elements/divider.js +66 -0
  47. package/dist/elements/drawer.d.ts +3 -0
  48. package/dist/elements/drawer.js +308 -0
  49. package/dist/elements/field-composition.d.ts +26 -0
  50. package/dist/elements/field-composition.js +133 -0
  51. package/dist/elements/field.d.ts +1 -0
  52. package/dist/elements/field.js +67 -0
  53. package/dist/elements/file-upload.d.ts +6 -0
  54. package/dist/elements/file-upload.js +211 -0
  55. package/dist/elements/floating-position.d.ts +26 -0
  56. package/dist/elements/floating-position.js +39 -0
  57. package/dist/elements/image.d.ts +28 -0
  58. package/dist/elements/image.js +38 -0
  59. package/dist/elements/info.d.ts +9 -0
  60. package/dist/elements/info.js +102 -0
  61. package/dist/elements/input.d.ts +5 -0
  62. package/dist/elements/input.js +255 -0
  63. package/dist/elements/label.d.ts +15 -0
  64. package/dist/elements/label.js +56 -0
  65. package/dist/elements/link.d.ts +1 -0
  66. package/dist/elements/link.js +92 -0
  67. package/dist/elements/list.d.ts +19 -0
  68. package/dist/elements/list.js +297 -0
  69. package/dist/elements/menu.d.ts +33 -0
  70. package/dist/elements/menu.js +1103 -0
  71. package/dist/elements/message-bar.d.ts +10 -0
  72. package/dist/elements/message-bar.js +299 -0
  73. package/dist/elements/nav.d.ts +32 -0
  74. package/dist/elements/nav.js +791 -0
  75. package/dist/elements/overflow.d.ts +9 -0
  76. package/dist/elements/overflow.js +218 -0
  77. package/dist/elements/persona.d.ts +3 -0
  78. package/dist/elements/persona.js +124 -0
  79. package/dist/elements/popover.d.ts +77 -0
  80. package/dist/elements/popover.js +840 -0
  81. package/dist/elements/progress-bar.d.ts +4 -0
  82. package/dist/elements/progress-bar.js +82 -0
  83. package/dist/elements/radio-group.d.ts +1 -0
  84. package/dist/elements/radio-group.js +303 -0
  85. package/dist/elements/rating-display.d.ts +2 -0
  86. package/dist/elements/rating-display.js +125 -0
  87. package/dist/elements/rating.d.ts +2 -0
  88. package/dist/elements/rating.js +206 -0
  89. package/dist/elements/rich-text-editor.d.ts +18 -0
  90. package/dist/elements/rich-text-editor.js +508 -0
  91. package/dist/elements/search.d.ts +3 -0
  92. package/dist/elements/search.js +207 -0
  93. package/dist/elements/select.d.ts +6 -0
  94. package/dist/elements/select.js +291 -0
  95. package/dist/elements/shared.d.ts +19 -0
  96. package/dist/elements/shared.js +396 -0
  97. package/dist/elements/skeleton.d.ts +6 -0
  98. package/dist/elements/skeleton.js +91 -0
  99. package/dist/elements/slider.d.ts +1 -0
  100. package/dist/elements/slider.js +248 -0
  101. package/dist/elements/spin-button.d.ts +7 -0
  102. package/dist/elements/spin-button.js +499 -0
  103. package/dist/elements/spinner.d.ts +4 -0
  104. package/dist/elements/spinner.js +124 -0
  105. package/dist/elements/swatch-picker.d.ts +5 -0
  106. package/dist/elements/swatch-picker.js +363 -0
  107. package/dist/elements/table.d.ts +21 -0
  108. package/dist/elements/table.js +261 -0
  109. package/dist/elements/tabs.d.ts +1 -0
  110. package/dist/elements/tabs.js +276 -0
  111. package/dist/elements/tag-picker.d.ts +29 -0
  112. package/dist/elements/tag-picker.js +697 -0
  113. package/dist/elements/tags.d.ts +21 -0
  114. package/dist/elements/tags.js +421 -0
  115. package/dist/elements/teaching-popover.d.ts +32 -0
  116. package/dist/elements/teaching-popover.js +412 -0
  117. package/dist/elements/text.d.ts +5 -0
  118. package/dist/elements/text.js +69 -0
  119. package/dist/elements/textarea.d.ts +1 -0
  120. package/dist/elements/textarea.js +182 -0
  121. package/dist/elements/toast.d.ts +25 -0
  122. package/dist/elements/toast.js +337 -0
  123. package/dist/elements/toaster.d.ts +6 -0
  124. package/dist/elements/toaster.js +356 -0
  125. package/dist/elements/toggle.d.ts +2 -0
  126. package/dist/elements/toggle.js +246 -0
  127. package/dist/elements/toolbar.d.ts +12 -0
  128. package/dist/elements/toolbar.js +381 -0
  129. package/dist/elements/tooltip.d.ts +76 -0
  130. package/dist/elements/tooltip.js +510 -0
  131. package/dist/elements/tree-model.d.ts +19 -0
  132. package/dist/elements/tree-model.js +34 -0
  133. package/dist/elements/tree.d.ts +5 -0
  134. package/dist/elements/tree.js +273 -0
  135. package/dist/elements/view-card.d.ts +2 -0
  136. package/dist/elements/view-card.js +78 -0
  137. package/dist/elements/virtual-list.d.ts +41 -0
  138. package/dist/elements/virtual-list.js +369 -0
  139. package/dist/elements.d.ts +72 -0
  140. package/dist/elements.js +207 -0
  141. package/dist/index.d.ts +76 -0
  142. package/dist/index.js +66 -0
  143. package/dist/react-theme-styles.d.ts +2 -0
  144. package/dist/react-theme-styles.js +75 -0
  145. package/dist/react.d.ts +4540 -0
  146. package/dist/react.js +6799 -0
  147. package/dist/theme.d.ts +169 -0
  148. package/dist/theme.js +167 -0
  149. package/dist/virtualizer-hooks.d.ts +80 -0
  150. package/dist/virtualizer-hooks.js +253 -0
  151. package/package.json +87 -4
  152. package/scripts/generate-token-index.mjs +43 -0
  153. package/scripts/sync-component-catalog-signatures.mjs +55 -0
  154. package/scripts/validate-component-catalog.mjs +44 -0
  155. package/skills/sharepoint-ui/SKILL.md +12 -0
  156. package/skills/sharepoint-ui/references/choosing-components.md +20 -0
  157. package/skills/sharepoint-ui/references/sharepoint-patterns.md +17 -0
  158. package/tokens.json +3777 -0
@@ -0,0 +1,251 @@
1
+ import { base } from "./shared.js";
2
+ const themeWatches = new WeakMap();
3
+ const namedColorTokens = {
4
+ "dark-red": { token: "DarkRed", fallback: "#d69ca5" }, cranberry: { token: "Cranberry", fallback: "#eeacb2" }, red: { token: "Red", fallback: "#f1bbbc" },
5
+ pumpkin: { token: "Pumpkin", fallback: "#efc4ad" }, peach: { token: "Peach", fallback: "#ffddb3" }, marigold: { token: "Marigold", fallback: "#f9e2ae" },
6
+ gold: { token: "Gold", fallback: "#ecdfa5" }, brass: { token: "Brass", fallback: "#e0cea2" }, brown: { token: "Brown", fallback: "#ddc3b0" },
7
+ forest: { token: "Forest", fallback: "#bdd99b" }, seafoam: { token: "Seafoam", fallback: "#a8f0cd" }, "dark-green": { token: "DarkGreen", fallback: "#9ad29a" },
8
+ "light-teal": { token: "LightTeal", fallback: "#a6e9ed" }, teal: { token: "Teal", fallback: "#9bd9db" }, steel: { token: "Steel", fallback: "#94c8d4" },
9
+ blue: { token: "Blue", fallback: "#a9d3f2" }, "royal-blue": { token: "RoyalBlue", fallback: "#9abfdc" }, cornflower: { token: "Cornflower", fallback: "#c8d1fa" },
10
+ navy: { token: "Navy", fallback: "#a3b2e8" }, lavender: { token: "Lavender", fallback: "#d2ccf8" }, purple: { token: "Purple", fallback: "#c6b1de" },
11
+ grape: { token: "Grape", fallback: "#d9a7e0" }, lilac: { token: "Lilac", fallback: "#e6bfed" }, pink: { token: "Pink", fallback: "#f7c0e3" },
12
+ magenta: { token: "Magenta", fallback: "#eca5d1" }, plum: { token: "Plum", fallback: "#d696c0" }, beige: { token: "Beige", fallback: "#d7d4d4" },
13
+ mink: { token: "Mink", fallback: "#cecccb" }, platinum: { token: "Platinum", fallback: "#cdd6d8" }, anchor: { token: "Anchor", fallback: "#bcc3c7" }
14
+ };
15
+ /** Small, theme-aware people and entity marker. Images are optional; name/initials are the fast fallback. */
16
+ export function defineAvatar() {
17
+ if (customElements.get("spui-avatar"))
18
+ return;
19
+ class SpuiAvatar extends HTMLElement {
20
+ static observedAttributes = ["name", "image", "initials", "size", "shape", "color", "id-for-color", "decorative"];
21
+ imageSource = "";
22
+ themeRoot;
23
+ image = document.createElement("img");
24
+ initials = document.createElement("span");
25
+ fallback = document.createElement("span");
26
+ surface = document.createElement("span");
27
+ connectedCallback() {
28
+ if (!this.shadowRoot)
29
+ this.render();
30
+ this.sync();
31
+ this.watchTheme();
32
+ }
33
+ disconnectedCallback() {
34
+ this.unwatchTheme();
35
+ }
36
+ attributeChangedCallback() {
37
+ this.sync();
38
+ if (this.isConnected) {
39
+ this.unwatchTheme();
40
+ this.watchTheme();
41
+ }
42
+ }
43
+ refreshThemeColor() {
44
+ const color = this.getAttribute("color");
45
+ const named = namedColorTokens[color];
46
+ if (named) {
47
+ this.dataset.namedColor = "";
48
+ this.style.setProperty("--spui-avatar-colorful-background", `var(--colorPalette${named.token}Background2, color-mix(in srgb, ${named.fallback} 18%, var(--spui-ui-surface, #fff)))`);
49
+ this.style.setProperty("--spui-avatar-colorful-foreground", `var(--colorPalette${named.token}Foreground2, var(--spui-ui-text, var(--spui-semantic-body-text, #242424)))`);
50
+ this.style.setProperty("--spui-avatar-active-color", `var(--colorPalette${named.token}BorderActive, var(--spui-ui-accent, #78716c))`);
51
+ return;
52
+ }
53
+ delete this.dataset.namedColor;
54
+ this.style.removeProperty("--spui-avatar-active-color");
55
+ if (color !== "colorful")
56
+ return;
57
+ const key = this.getAttribute("name") || this.getAttribute("id-for-color") || "sharepoint-ui";
58
+ const hash = hashString(key);
59
+ const rawColor = getComputedStyle(this).getPropertyValue("--spui-palette-theme-primary").trim()
60
+ || getComputedStyle(this).getPropertyValue("--spui-ui-accent").trim()
61
+ || "#78716c";
62
+ const rgb = parseColor(rawColor);
63
+ const shade = 0.18 + (hash % 5) * 0.1;
64
+ const derived = rgb?.map(channel => Math.round(channel * (1 - shade)));
65
+ const derivedColor = derived ? `#${derived.map(channel => channel.toString(16).padStart(2, "0")).join("")}` : rawColor;
66
+ this.style.setProperty("--spui-avatar-colorful-background", derivedColor);
67
+ this.style.setProperty("--spui-avatar-colorful-foreground", derived ? (relativeLuminance(derived) > 0.179 ? "#000000" : "#ffffff") : "var(--spui-semantic-primary-button-text, #ffffff)");
68
+ }
69
+ render() {
70
+ const shadow = this.attachShadow({ mode: "open" });
71
+ this.surface.className = "surface";
72
+ this.surface.part.add("surface");
73
+ this.image.className = "image";
74
+ this.image.part.add("image");
75
+ this.image.alt = "";
76
+ this.image.loading = "lazy";
77
+ this.image.decoding = "async";
78
+ this.image.addEventListener("load", () => { this.dataset.imageState = "loaded"; });
79
+ this.image.addEventListener("error", () => { this.dataset.imageState = "error"; });
80
+ this.initials.className = "initials";
81
+ this.initials.part.add("initials");
82
+ this.fallback.className = "fallback";
83
+ this.fallback.part.add("fallback");
84
+ this.fallback.setAttribute("aria-hidden", "true");
85
+ this.fallback.innerHTML = '<svg viewBox="0 0 24 24" focusable="false"><path d="M12 12a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9Zm0 2c-4.4 0-8 2.2-8 5v2h16v-2c0-2.8-3.6-5-8-5Z"/></svg>';
86
+ this.surface.append(this.image, this.initials, this.fallback);
87
+ const style = document.createElement("style");
88
+ style.textContent = `${base}:host{--spui-avatar-size:32px;display:inline-grid;flex:none;width:var(--spui-avatar-size);height:var(--spui-avatar-size);vertical-align:middle;line-height:1}:host([size]){width:var(--spui-avatar-size);height:var(--spui-avatar-size)}.surface{position:relative;box-sizing:border-box;display:grid;place-items:center;width:100%;height:100%;overflow:hidden;border:1px solid var(--spui-avatar-border,var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1)));border-radius:var(--spui-avatar-radius,50%);background:var(--spui-avatar-background,var(--spui-semantic-body-subtext,var(--colorNeutralBackground3,#f0f0f0)));color:var(--spui-avatar-foreground,var(--spui-semantic-body-text,var(--colorNeutralForeground1,#323130)));font:600 calc(var(--spui-avatar-size) * .36)/1 var(--spui-font-family,inherit);user-select:none}.image{position:absolute;inset:0;z-index:1;width:100%;height:100%;object-fit:cover}.initials{z-index:0;max-width:100%;overflow:hidden;padding:0 2px;text-overflow:clip;white-space:nowrap}.fallback{z-index:0;display:grid;place-items:center;width:62%;height:62%;color:currentColor}.initials:not(:empty)~.fallback{display:none}.fallback svg{display:block;width:100%;height:100%;fill:currentColor}:host([data-image-state=loading]) .image,:host([data-image-state=error]) .image{visibility:hidden}:host([data-image-state=loaded]) .initials,:host([data-image-state=loaded]) .fallback{visibility:hidden}:host([shape=square]) .surface{border-radius:var(--spui-avatar-radius,var(--spui-control-radius,6px))}:host([color=brand]) .surface{background:var(--spui-avatar-brand-background,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,var(--spui-avatar-active-color,var(--spui-ui-accent,#78716c)))));color:var(--spui-avatar-brand-foreground,var(--spui-semantic-primary-button-text,var(--colorNeutralForegroundOnBrand,#fff)))}:host([color=colorful]) .surface,:host([data-named-color]) .surface{background:var(--spui-avatar-colorful-background,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,var(--spui-avatar-active-color,var(--spui-ui-accent,#78716c)))));color:var(--spui-avatar-colorful-foreground,var(--spui-semantic-primary-button-text,#fff))}:host([active=active]:not([active-appearance])) .surface,:host([active=active][active-appearance=ring]) .surface{box-shadow:0 0 0 2px var(--spui-ui-surface,#fff),0 0 0 4px var(--spui-avatar-active-color,var(--spui-ui-accent,#78716c))}:host([active=active][active-appearance=shadow]) .surface{box-shadow:var(--spui-avatar-active-shadow,var(--spui-card-shadow,0 2px 8px rgb(0 0 0 / 24%)))}:host([active=active][active-appearance=ring-shadow]) .surface{box-shadow:0 0 0 2px var(--spui-ui-surface,#fff),0 0 0 4px var(--spui-avatar-active-color,var(--spui-ui-accent,#78716c)),var(--spui-avatar-active-shadow,var(--spui-card-shadow,0 2px 8px rgb(0 0 0 / 24%)))}:host([active=inactive]){opacity:.56}:host([data-custom-icon=true]) .initials,:host([data-custom-icon=true]) .fallback{display:none}:host([data-custom-icon=true]) .icon{z-index:0;display:grid;place-items:center;width:70%;height:70%;color:inherit}:host([data-custom-badge=true]) .badge{position:absolute;z-index:2;inset-block-end:0;inset-inline-end:0;display:grid;place-items:center;min-width:var(--spui-avatar-badge-size,10px);min-height:var(--spui-avatar-badge-size,10px);border:2px solid var(--spui-avatar-badge-border,var(--spui-ui-surface,#fff));border-radius:50%;background:var(--spui-avatar-badge-background,var(--spui-semantic-success-background,#13a10e));color:var(--spui-avatar-badge-foreground,#fff);font:600 9px/1 var(--spui-font-family,inherit)}:host(:not([data-custom-badge=true])) .badge{display:none}@media(forced-colors:active){.surface{border-color:CanvasText;background:Canvas;color:CanvasText;forced-color-adjust:none}:host([data-named-color]) .surface{border-color:CanvasText;background:Canvas;color:CanvasText}.image{forced-color-adjust:auto}:host([active=active]) .surface{outline:2px solid Highlight;outline-offset:2px;box-shadow:none}}`;
89
+ style.textContent += `.surface{background:var(--spui-avatar-background,var(--spui-palette-neutral-light,var(--colorNeutralBackground3,#f0f0f0)));font-size:clamp(10px,calc(var(--spui-avatar-size) * .36),48px)}`;
90
+ style.textContent += `@media(forced-colors:active){.surface{border-color:CanvasText;background:Canvas;color:CanvasText}}`;
91
+ const icon = document.createElement("span");
92
+ icon.className = "icon";
93
+ icon.part.add("icon");
94
+ icon.append(document.createElement("slot"));
95
+ icon.firstElementChild.setAttribute("name", "icon");
96
+ const badge = document.createElement("span");
97
+ badge.className = "badge";
98
+ badge.part.add("badge");
99
+ badge.append(document.createElement("slot"));
100
+ badge.firstElementChild.setAttribute("name", "badge");
101
+ const iconSlot = icon.firstElementChild;
102
+ const badgeSlot = badge.firstElementChild;
103
+ iconSlot.addEventListener("slotchange", () => this.toggleAttribute("data-custom-icon", iconSlot.assignedNodes({ flatten: true }).length > 0));
104
+ badgeSlot.addEventListener("slotchange", () => this.toggleAttribute("data-custom-badge", badgeSlot.assignedNodes({ flatten: true }).length > 0));
105
+ this.surface.append(icon, badge);
106
+ shadow.append(style, this.surface);
107
+ }
108
+ sync() {
109
+ if (!this.shadowRoot)
110
+ return;
111
+ const size = this.getAttribute("size")?.trim() || "32px";
112
+ const normalizedSize = /^\d+(?:\.\d+)?$/.test(size) ? `${size}px` : size;
113
+ this.style.setProperty("--spui-avatar-size", CSS.supports("width", normalizedSize) ? normalizedSize : "32px");
114
+ const shape = this.getAttribute("shape") === "square" ? "square" : "circular";
115
+ this.dataset.shape = shape;
116
+ if (this.getAttribute("shape") !== shape)
117
+ this.setAttribute("shape", shape);
118
+ const color = this.getAttribute("color");
119
+ if (!color || (!["neutral", "brand", "colorful"].includes(color) && !Object.hasOwn(namedColorTokens, color)))
120
+ this.setAttribute("color", "neutral");
121
+ const name = this.getAttribute("name")?.trim() ?? "";
122
+ const locale = this.closest("[lang]")?.getAttribute("lang") || this.ownerDocument.documentElement.lang || undefined;
123
+ const initials = this.getAttribute("initials")?.trim() || getInitials(name, Number.parseFloat(this.style.getPropertyValue("--spui-avatar-size")), locale, getComputedStyle(this).direction === "rtl");
124
+ this.initials.textContent = initials;
125
+ const source = this.getAttribute("image")?.trim() ?? "";
126
+ if (source !== this.imageSource) {
127
+ this.imageSource = source;
128
+ if (source) {
129
+ this.setAttribute("data-image-state", "loading");
130
+ this.image.src = source;
131
+ }
132
+ else {
133
+ this.image.removeAttribute("src");
134
+ this.setAttribute("data-image-state", "none");
135
+ }
136
+ }
137
+ else if (source && !this.dataset.imageState)
138
+ this.setAttribute("data-image-state", "loading");
139
+ const decorative = this.hasAttribute("decorative");
140
+ const hasExplicitName = (this.hasAttribute("aria-label") && this.dataset.autoLabel === undefined) || this.hasAttribute("aria-labelledby");
141
+ const accessibleName = name || initials;
142
+ if (decorative || (!hasExplicitName && !accessibleName)) {
143
+ if (this.dataset.autoLabel !== undefined) {
144
+ this.removeAttribute("aria-label");
145
+ delete this.dataset.autoLabel;
146
+ }
147
+ if (!this.hasAttribute("aria-hidden")) {
148
+ this.setAttribute("aria-hidden", "true");
149
+ this.dataset.autoHidden = "";
150
+ }
151
+ if (!this.hasAttribute("role")) {
152
+ this.setAttribute("role", "presentation");
153
+ this.dataset.autoRole = "";
154
+ }
155
+ }
156
+ else {
157
+ if (this.dataset.autoHidden !== undefined) {
158
+ this.removeAttribute("aria-hidden");
159
+ delete this.dataset.autoHidden;
160
+ }
161
+ if (this.dataset.autoRole !== undefined) {
162
+ this.removeAttribute("role");
163
+ delete this.dataset.autoRole;
164
+ }
165
+ if (!this.hasAttribute("role")) {
166
+ this.setAttribute("role", "img");
167
+ this.dataset.autoRole = "";
168
+ }
169
+ if (!this.hasAttribute("aria-labelledby") && (!this.hasAttribute("aria-label") || this.dataset.autoLabel !== undefined)) {
170
+ this.setAttribute("aria-label", accessibleName);
171
+ this.dataset.autoLabel = "";
172
+ }
173
+ }
174
+ this.refreshThemeColor();
175
+ }
176
+ watchTheme() {
177
+ if (this.getAttribute("color") !== "colorful" || !this.isConnected)
178
+ return;
179
+ const root = this.closest("[data-spui-appearance]");
180
+ if (!root)
181
+ return;
182
+ this.unwatchTheme();
183
+ this.themeRoot = root;
184
+ let watch = themeWatches.get(root);
185
+ if (!watch) {
186
+ const instances = new Set();
187
+ const observer = new MutationObserver(() => instances.forEach(avatar => avatar.refreshThemeColor()));
188
+ observer.observe(root, { attributes: true, attributeFilter: ["style"] });
189
+ watch = { instances, observer };
190
+ themeWatches.set(root, watch);
191
+ }
192
+ watch.instances.add(this);
193
+ }
194
+ unwatchTheme() {
195
+ if (!this.themeRoot)
196
+ return;
197
+ const watch = themeWatches.get(this.themeRoot);
198
+ watch?.instances.delete(this);
199
+ if (watch && watch.instances.size === 0) {
200
+ watch.observer.disconnect();
201
+ themeWatches.delete(this.themeRoot);
202
+ }
203
+ this.themeRoot = undefined;
204
+ }
205
+ }
206
+ customElements.define("spui-avatar", SpuiAvatar);
207
+ }
208
+ function getInitials(name, size, locale, rtl = false) {
209
+ const words = name.replace(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, " ").trim().split(/\s+/).filter(Boolean);
210
+ if (!words.length)
211
+ return "";
212
+ const selectedWords = size <= 20 ? [words[0]] : words.length === 2 ? words : words.length === 3 ? [words[0], words[2]] : [words[0]];
213
+ let initials = selectedWords.map(word => firstGrapheme(word, locale)).join("");
214
+ try {
215
+ initials = initials.toLocaleUpperCase(locale);
216
+ }
217
+ catch {
218
+ initials = initials.toUpperCase();
219
+ }
220
+ const characters = Array.from(initials);
221
+ return rtl && characters.length > 1 ? characters.reverse().join("") : initials;
222
+ }
223
+ function firstGrapheme(value, locale) {
224
+ const Segmenter = Intl.Segmenter;
225
+ if (Segmenter) {
226
+ try {
227
+ return [...new Segmenter(locale, { granularity: "grapheme" }).segment(value)][0]?.segment ?? "";
228
+ }
229
+ catch { /* Fall through for unsupported locale tags or older engines. */ }
230
+ }
231
+ return Array.from(value.normalize("NFC"))[0] ?? "";
232
+ }
233
+ function hashString(value) {
234
+ let hash = 2166136261;
235
+ for (const character of value)
236
+ hash = Math.imul(hash ^ character.codePointAt(0), 16777619);
237
+ return hash >>> 0;
238
+ }
239
+ function parseColor(value) {
240
+ const hex = /^#([\da-f]{3}|[\da-f]{6})$/i.exec(value);
241
+ if (hex) {
242
+ const expanded = hex[1].length === 3 ? [...hex[1]].map(character => character + character).join("") : hex[1];
243
+ return [0, 2, 4].map(index => parseInt(expanded.slice(index, index + 2), 16));
244
+ }
245
+ const rgb = /^rgba?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)/i.exec(value);
246
+ return rgb ? [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])] : null;
247
+ }
248
+ function relativeLuminance([red, green, blue]) {
249
+ const linear = (channel) => { const value = channel / 255; return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4; };
250
+ return linear(red) * 0.2126 + linear(green) * 0.7152 + linear(blue) * 0.0722;
251
+ }
@@ -0,0 +1,8 @@
1
+ export type BadgeAppearance = "filled" | "ghost" | "outline" | "tint";
2
+ export type BadgeColor = "brand" | "danger" | "important" | "informative" | "severe" | "subtle" | "success" | "warning";
3
+ export type BadgeShape = "circular" | "rounded" | "square";
4
+ export type BadgeSize = "tiny" | "extra-small" | "small" | "medium" | "large" | "extra-large";
5
+ export type PresenceBadgeStatus = "busy" | "out-of-office" | "away" | "available" | "offline" | "do-not-disturb" | "unknown" | "blocked";
6
+ export declare function defineBadge(): void;
7
+ export declare function defineCounterBadge(): void;
8
+ export declare function definePresenceBadge(): void;
@@ -0,0 +1,182 @@
1
+ import { base } from "./shared.js";
2
+ const badgeStyle = `${base}
3
+ :host{--badge-size:20px;--badge-pad:6px;--badge-status:var(--spui-ui-accent,var(--colorBrandBackground,#0078d4));--badge-filled-background:var(--spui-ui-accent,var(--colorBrandBackground,#0078d4));--badge-filled-foreground:var(--spui-ui-accent-text,#fff);--badge-filled-border:var(--colorTransparentStroke,transparent);--badge-tint-background:color-mix(in srgb,var(--badge-status) 12%,var(--spui-ui-surface,#fff));--badge-tint-foreground:var(--badge-status);--badge-tint-border:var(--badge-outline-border);--badge-outline-border:var(--badge-status);display:inline-flex;align-items:center;justify-content:center;gap:4px;box-sizing:border-box;min-width:var(--badge-size);min-height:var(--badge-size);padding-inline:var(--badge-pad);border:1px solid var(--badge-outline-border);border-radius:999px;background:var(--badge-filled-background);color:var(--badge-filled-foreground);font:600 12px/1 var(--spui-font-family,inherit);white-space:nowrap;vertical-align:middle}
4
+ :host([color=success]){--badge-status:var(--spui-ui-success,#107c10);--badge-color:var(--spui-ui-success-surface,#dff6dd);--badge-foreground:var(--badge-status);--badge-tint:var(--spui-ui-success-surface,#dff6dd)}
5
+ :host([color=warning]),:host([color=important]){--badge-status:var(--spui-ui-warning,#835b00);--badge-color:var(--spui-ui-warning-surface,#fff4ce);--badge-foreground:var(--badge-status);--badge-tint:var(--spui-ui-warning-surface,#fff4ce)}
6
+ :host([color=danger]),:host([color=severe]){--badge-status:var(--spui-ui-danger,#b10e1c);--badge-color:var(--spui-ui-danger-surface,#fde7e9);--badge-foreground:var(--badge-status);--badge-tint:var(--spui-ui-danger-surface,#fde7e9)}
7
+ :host([color=informative]){--badge-status:var(--spui-ui-accent,#0078d4);--badge-color:var(--spui-ui-accent,var(--colorBrandBackground,#0078d4));--badge-tint:color-mix(in srgb,var(--badge-status) 12%,var(--spui-ui-surface,#fff))}
8
+ :host([color=subtle]){--badge-status:var(--spui-ui-muted,#616161);--badge-color:color-mix(in srgb,var(--spui-ui-stroke,#d1d1d1) 25%,var(--spui-ui-surface,#fff));--badge-foreground:var(--spui-ui-text,#242424);--badge-tint:var(--badge-color)}
9
+ :host([color=brand]){--badge-filled-background:var(--colorBrandBackground,var(--spui-ui-accent,#0078d4));--badge-filled-foreground:var(--colorNeutralForegroundOnBrand,var(--spui-ui-accent-text,#fff));--badge-status:var(--colorBrandForeground1,var(--spui-ui-accent,#0078d4));--badge-tint-background:var(--colorBrandBackground2,color-mix(in srgb,var(--badge-status) 12%,var(--spui-ui-surface,#fff)));--badge-tint-foreground:var(--colorBrandForeground2,var(--badge-status));--badge-tint-border:var(--colorBrandStroke2,var(--badge-status));--badge-outline-border:var(--badge-status)}
10
+ :host([color=danger]){--badge-filled-background:var(--colorPaletteRedBackground3,color-mix(in srgb,var(--spui-ui-danger,#b10e1c) 85%,black));--badge-filled-foreground:var(--colorNeutralForegroundOnBrand,#fff);--badge-status:var(--colorPaletteRedForeground3,var(--spui-ui-danger,#b10e1c));--badge-tint-background:var(--colorPaletteRedBackground1,var(--spui-ui-danger-surface,#fde7e9));--badge-tint-foreground:var(--colorPaletteRedForeground1,var(--spui-ui-danger,#b10e1c));--badge-tint-border:var(--colorPaletteRedBorder1,var(--badge-status));--badge-outline-border:var(--colorPaletteRedBorder2,var(--badge-status))}
11
+ :host([color=severe]){--badge-filled-background:var(--colorPaletteDarkOrangeBackground3,color-mix(in srgb,var(--spui-ui-warning,#835b00) 88%,black));--badge-filled-foreground:var(--colorNeutralForegroundOnBrand,#fff);--badge-status:var(--colorPaletteDarkOrangeForeground3,var(--spui-ui-warning,#835b00));--badge-tint-background:var(--colorPaletteDarkOrangeBackground1,var(--spui-ui-warning-surface,#fff4ce));--badge-tint-foreground:var(--colorPaletteDarkOrangeForeground1,var(--spui-ui-warning,#835b00));--badge-tint-border:var(--colorPaletteDarkOrangeBorder1,var(--badge-status));--badge-outline-border:var(--badge-status)}
12
+ :host([color=success]){--badge-filled-background:var(--colorPaletteGreenBackground3,color-mix(in srgb,var(--spui-ui-success,#107c10) 85%,black));--badge-filled-foreground:var(--colorNeutralForegroundOnBrand,#fff);--badge-status:var(--colorPaletteGreenForeground3,var(--spui-ui-success,#107c10));--badge-tint-background:var(--colorPaletteGreenBackground1,var(--spui-ui-success-surface,#dff6dd));--badge-tint-foreground:var(--colorPaletteGreenForeground1,var(--spui-ui-success,#107c10));--badge-tint-border:var(--colorPaletteGreenBorder1,var(--badge-status));--badge-outline-border:var(--colorPaletteGreenBorder2,var(--badge-status))}
13
+ :host([color=warning]){--badge-filled-background:var(--colorPaletteYellowBackground3,color-mix(in srgb,var(--spui-ui-warning,#835b00) 82%,black));--badge-filled-foreground:var(--colorNeutralForeground1Static,#242424);--badge-status:var(--colorPaletteYellowForeground2,var(--spui-ui-warning,#835b00));--badge-tint-background:var(--colorPaletteYellowBackground1,var(--spui-ui-warning-surface,#fff4ce));--badge-tint-foreground:var(--colorPaletteYellowForeground1,var(--spui-ui-warning,#835b00));--badge-tint-border:var(--colorPaletteYellowBorder1,var(--badge-status));--badge-outline-border:var(--badge-status)}
14
+ :host([color=important]){--badge-filled-background:var(--colorNeutralForeground1,#242424);--badge-filled-foreground:var(--colorNeutralBackground1,#fff);--badge-status:var(--colorNeutralForeground1,#242424);--badge-tint-background:var(--colorNeutralForeground3,#616161);--badge-tint-foreground:var(--colorNeutralBackground1,#fff);--badge-tint-border:var(--colorTransparentStroke,transparent);--badge-outline-border:var(--colorNeutralStrokeAccessible,#616161)}
15
+ :host([color=informative]){--badge-filled-background:var(--colorNeutralBackground5,#e0e0e0);--badge-filled-foreground:var(--colorNeutralForeground3,#616161);--badge-status:var(--colorNeutralForeground3,#616161);--badge-tint-background:var(--colorNeutralBackground4,#f0f0f0);--badge-tint-foreground:var(--colorNeutralForeground3,#616161);--badge-tint-border:var(--colorNeutralStroke2,#d1d1d1);--badge-outline-border:var(--colorNeutralStroke2,#d1d1d1)}
16
+ :host([color=subtle]){--badge-filled-background:var(--colorNeutralBackground1,var(--spui-ui-surface,#fff));--badge-filled-foreground:var(--colorNeutralForeground1,var(--spui-ui-text,#242424));--badge-status:var(--colorNeutralForegroundStaticInverted,#fff);--badge-tint-background:var(--colorNeutralBackground1,var(--spui-ui-surface,#fff));--badge-tint-foreground:var(--colorNeutralForeground3,var(--spui-ui-muted,#616161));--badge-tint-border:var(--colorNeutralStroke2,var(--spui-ui-stroke,#d1d1d1));--badge-outline-border:var(--badge-status)}
17
+ :host([color=brand]){--badge-outline-foreground:var(--colorBrandForeground1,var(--spui-ui-accent,#0078d4))}:host([color=danger]){--badge-outline-foreground:var(--colorPaletteRedForeground3,var(--spui-ui-danger,#b10e1c))}:host([color=important]){--badge-outline-foreground:var(--colorNeutralForeground3,#616161)}:host([color=informative]){--badge-outline-foreground:var(--colorNeutralForeground3,#616161)}:host([color=severe]){--badge-outline-foreground:var(--colorPaletteDarkOrangeForeground3,var(--spui-ui-warning,#835b00))}:host([color=subtle]){--badge-outline-foreground:var(--colorNeutralForegroundStaticInverted,#fff)}:host([color=success]){--badge-outline-foreground:var(--colorPaletteGreenForeground3,var(--spui-ui-success,#107c10))}:host([color=warning]){--badge-outline-foreground:var(--colorPaletteYellowForeground2,var(--spui-ui-warning,#835b00))}
18
+ :host([appearance=ghost]){border-color:transparent;background:transparent;color:var(--badge-status)}
19
+ :host([appearance=outline]){background:transparent;color:var(--badge-outline-foreground,var(--badge-status))}
20
+ :host([appearance=filled]){border-color:var(--badge-filled-border)}:host([appearance=ghost]){border-color:transparent}:host([appearance=outline]){border-color:var(--badge-outline-border)}:host([appearance=tint]){border-color:var(--badge-tint-border);background:var(--badge-tint-background);color:var(--badge-tint-foreground)}
21
+ :host([shape=rounded]){border-radius:6px}:host([shape=square]){border-radius:2px}:host([shape=circular]){border-radius:999px}
22
+ :host([size=tiny]){--badge-size:6px;--badge-pad:0;width:6px;min-width:0;min-height:0;height:6px;padding:0;font-size:4px}:host([size=extra-small]){--badge-size:10px;--badge-pad:0;width:10px;min-width:0;min-height:0;height:10px;padding:0;font-size:6px}:host([size=small]){--badge-size:16px;--badge-pad:4px;font-size:10px}:host([size=large]){--badge-size:24px;--badge-pad:7px;font-size:14px}:host([size=extra-large]){--badge-size:32px;--badge-pad:9px;font-size:16px}
23
+ .content{display:inline-flex;align-items:center;justify-content:center;order:1}.icon{display:inline-flex;align-items:center;justify-content:center;order:0;line-height:0}slot[name=icon]{display:contents}
24
+ :host([icon-position=after]) .icon{order:2}:host([icon-position=after]) .content{order:1}
25
+ :host([dot]){width:var(--badge-size);min-width:var(--badge-size);padding:0}:host([dot]) .content,:host([dot]) .icon{display:none}:host([hidden]){display:none}
26
+ :host([kind=presence]){position:relative;width:var(--badge-size);min-width:var(--badge-size);padding:0;border-width:1px;background:var(--badge-color)}
27
+ :host([kind=presence]){background:var(--colorNeutralBackground1,var(--spui-ui-surface,#fff));border-color:var(--colorTransparentStroke,transparent);color:var(--badge-status)}:host([kind=presence][status=available]){--badge-status:var(--colorPaletteLightGreenForeground3,var(--spui-ui-success,#13a10e))}:host([kind=presence][status=away]){--badge-status:var(--colorPaletteMarigoldBackground3,var(--spui-ui-warning,#835b00))}:host([kind=presence][status=busy]),:host([kind=presence][status=do-not-disturb]),:host([kind=presence][status=blocked]){--badge-status:var(--colorPaletteRedBackground3,var(--spui-ui-danger,#c50f1f))}:host([kind=presence][status=out-of-office]){--badge-status:var(--colorPaletteBerryForeground3,var(--spui-ui-danger,#c50f1f))}:host([kind=presence][status=offline]),:host([kind=presence][status=unknown]){--badge-status:var(--colorNeutralForeground3,var(--spui-ui-muted,#616161))}
28
+ :host([kind=presence][status=available]){--badge-color:var(--spui-ui-success-surface,#dff6dd);--badge-foreground:var(--spui-ui-success,#107c10)}
29
+ :host([kind=presence][status=away]){--badge-color:var(--spui-ui-warning-surface,#fff4ce);--badge-foreground:var(--spui-ui-warning,#835b00)}
30
+ :host([kind=presence][status=busy]),:host([kind=presence][status=do-not-disturb]),:host([kind=presence][status=blocked]),:host([kind=presence][status=out-of-office]){--badge-color:var(--spui-ui-danger-surface,#fde7e9);--badge-foreground:var(--spui-ui-danger,#b10e1c)}
31
+ :host([kind=presence][status=offline]),:host([kind=presence][status=unknown]){--badge-color:color-mix(in srgb,var(--spui-ui-stroke,#d1d1d1) 25%,var(--spui-ui-surface,#fff));--badge-foreground:var(--spui-ui-muted,#616161)}
32
+ .icon svg{display:block;width:100%;height:100%}:host([kind=presence]) .icon{width:68%;height:68%}
33
+ @media(forced-colors:active){:host{border-color:CanvasText}:host([appearance=ghost]),:host([appearance=tint]){color:CanvasText}:host([kind=presence]){background:Canvas;color:CanvasText;border-color:CanvasText}}
34
+ @media(prefers-reduced-motion:reduce){:host{transition:none}}`;
35
+ function presenceIcon(status, outOfOffice) {
36
+ const ns = "http://www.w3.org/2000/svg";
37
+ const svg = document.createElementNS(ns, "svg");
38
+ svg.setAttribute("viewBox", "0 0 16 16");
39
+ svg.setAttribute("aria-hidden", "true");
40
+ svg.setAttribute("focusable", "false");
41
+ const shape = (name, attributes) => {
42
+ const element = document.createElementNS(ns, name);
43
+ for (const [key, value] of Object.entries(attributes))
44
+ element.setAttribute(key, value);
45
+ svg.append(element);
46
+ };
47
+ const stroke = { fill: "none", stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round", "stroke-linejoin": "round" };
48
+ if (status === "available")
49
+ shape("path", { ...stroke, d: "M3.4 8.2 6.5 11.3 12.8 4.9" });
50
+ else if (status === "away") {
51
+ shape("circle", { ...stroke, cx: "8", cy: "8", r: "5.4" });
52
+ shape("path", { ...stroke, d: "M8 4.8V8l2.3 1.5" });
53
+ }
54
+ else if (status === "busy")
55
+ shape("circle", { cx: "8", cy: "8", r: "4.7", fill: "currentColor" });
56
+ else if (status === "do-not-disturb") {
57
+ shape("circle", { ...stroke, cx: "8", cy: "8", r: "5.4" });
58
+ shape("path", { ...stroke, d: "M5.2 8h5.6" });
59
+ }
60
+ else if (status === "offline")
61
+ shape("circle", { ...stroke, cx: "8", cy: "8", r: "5.1" });
62
+ else if (status === "blocked") {
63
+ shape("circle", { ...stroke, cx: "8", cy: "8", r: "5.2" });
64
+ shape("path", { ...stroke, d: "m4.3 11.7 7.4-7.4" });
65
+ }
66
+ else if (status === "out-of-office") {
67
+ shape("path", { ...stroke, d: "M3.5 13.2V4.5l4.5-2 4.5 2v8.7M2.5 13.2h11M6 6.2h.1M9.9 6.2h.1M7.2 13.1V9.8h1.6v3.3" });
68
+ }
69
+ else {
70
+ shape("path", { ...stroke, d: "M5.8 5.7a2.3 2.3 0 1 1 3.8 1.7c-1 .8-1.6 1.1-1.6 2.3" });
71
+ shape("circle", { cx: "8", cy: "12.3", r: ".5", fill: "currentColor" });
72
+ }
73
+ if (outOfOffice && status !== "out-of-office") {
74
+ shape("circle", { cx: "12.1", cy: "12.1", r: "3.25", fill: "var(--spui-ui-surface,#fff)", stroke: "var(--spui-ui-danger,#b10e1c)", "stroke-width": ".75" });
75
+ shape("path", { d: "M10.7 13.4v-2.7h2.8v2.7m-1.9-2.7v.9m1-.9v.9", fill: "none", stroke: "var(--spui-ui-danger,#b10e1c)", "stroke-width": ".55", "stroke-linecap": "round", "stroke-linejoin": "round" });
76
+ }
77
+ return svg;
78
+ }
79
+ function renderBadge(host, shadow, options) {
80
+ const style = document.createElement("style");
81
+ style.textContent = badgeStyle;
82
+ const content = document.createElement("span");
83
+ content.className = "content";
84
+ content.part.add("content");
85
+ const defaultSlot = document.createElement("slot");
86
+ if (options.content !== undefined)
87
+ content.textContent = options.content;
88
+ else
89
+ content.append(defaultSlot);
90
+ const icon = document.createElement("span");
91
+ icon.className = "icon";
92
+ icon.part.add("icon");
93
+ const iconSlot = document.createElement("slot");
94
+ iconSlot.name = "icon";
95
+ if (options.icon && !host.querySelector('[slot="icon"]'))
96
+ icon.append(options.icon);
97
+ else
98
+ icon.append(iconSlot);
99
+ shadow.replaceChildren(style, icon, content);
100
+ if (options.presence) {
101
+ const status = host.getAttribute("status") ?? "available";
102
+ if (host.getAttribute("role") !== "img")
103
+ host.setAttribute("role", "img");
104
+ }
105
+ }
106
+ export function defineBadge() {
107
+ if (customElements.get("spui-badge"))
108
+ return;
109
+ class SpuiBadge extends HTMLElement {
110
+ static observedAttributes = ["appearance", "color", "icon-position", "shape", "size"];
111
+ connectedCallback() { if (!this.shadowRoot)
112
+ this.render(); }
113
+ attributeChangedCallback() { if (this.isConnected)
114
+ this.render(); }
115
+ render() { renderBadge(this, this.shadowRoot ?? this.attachShadow({ mode: "open" }), {}); }
116
+ }
117
+ customElements.define("spui-badge", SpuiBadge);
118
+ }
119
+ export function defineCounterBadge() {
120
+ if (customElements.get("spui-counter-badge"))
121
+ return;
122
+ class SpuiCounterBadge extends HTMLElement {
123
+ static observedAttributes = ["appearance", "aria-label", "color", "count", "dot", "overflow-count", "shape", "show-zero", "size"];
124
+ generatedLabel;
125
+ customLabel = false;
126
+ connectedCallback() { this.render(); }
127
+ attributeChangedCallback(name, _oldValue, newValue) {
128
+ if (name === "aria-label")
129
+ this.customLabel = newValue !== null && newValue !== this.generatedLabel;
130
+ if (this.isConnected)
131
+ this.render();
132
+ }
133
+ render() {
134
+ const parsedCount = Number(this.getAttribute("count") ?? 0);
135
+ const parsedMax = Number(this.getAttribute("overflow-count") ?? 99);
136
+ const count = Number.isFinite(parsedCount) ? Math.max(0, parsedCount) : 0;
137
+ const max = Number.isFinite(parsedMax) ? Math.max(0, parsedMax) : 99;
138
+ const dot = this.hasAttribute("dot");
139
+ const visible = dot || count > 0 || this.hasAttribute("show-zero");
140
+ this.toggleAttribute("hidden", !visible);
141
+ if (!dot && !this.customLabel) {
142
+ const label = `${count > max ? `${max}+` : count}`;
143
+ this.generatedLabel = label;
144
+ if (this.getAttribute("aria-label") !== label)
145
+ this.setAttribute("aria-label", label);
146
+ }
147
+ this.setAttribute("kind", "counter");
148
+ const content = dot ? undefined : String(count > max ? `${max}+` : count);
149
+ renderBadge(this, this.shadowRoot ?? this.attachShadow({ mode: "open" }), { content });
150
+ }
151
+ }
152
+ customElements.define("spui-counter-badge", SpuiCounterBadge);
153
+ }
154
+ export function definePresenceBadge() {
155
+ if (customElements.get("spui-presence-badge"))
156
+ return;
157
+ class SpuiPresenceBadge extends HTMLElement {
158
+ static observedAttributes = ["out-of-office", "size", "status", "aria-label"];
159
+ generatedLabel;
160
+ customLabel = false;
161
+ connectedCallback() { this.render(); }
162
+ attributeChangedCallback(name, _oldValue, newValue) {
163
+ if (name === "aria-label")
164
+ this.customLabel = newValue !== null && newValue !== this.generatedLabel;
165
+ if (this.isConnected)
166
+ this.render();
167
+ }
168
+ render() {
169
+ this.setAttribute("kind", "presence");
170
+ const status = this.getAttribute("status") ?? "available";
171
+ if (!this.customLabel) {
172
+ const status = this.getAttribute("status") ?? "available";
173
+ const label = `${status.replaceAll("-", " ")}${this.hasAttribute("out-of-office") && status !== "out-of-office" ? ", out of office" : ""}`;
174
+ this.generatedLabel = label;
175
+ if (this.getAttribute("aria-label") !== label)
176
+ this.setAttribute("aria-label", label);
177
+ }
178
+ renderBadge(this, this.shadowRoot ?? this.attachShadow({ mode: "open" }), { icon: presenceIcon(status, this.hasAttribute("out-of-office")), presence: true });
179
+ }
180
+ }
181
+ customElements.define("spui-presence-badge", SpuiPresenceBadge);
182
+ }
@@ -0,0 +1,4 @@
1
+ export declare function defineBreadcrumb(): void;
2
+ export declare function defineBreadcrumbItem(): void;
3
+ export declare function defineBreadcrumbDivider(): void;
4
+ export declare function defineBreadcrumbButton(): void;