@spfx-fast/sharepoint-ui 0.4.2 → 0.4.3

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 (57) hide show
  1. package/AGENTS.md +23 -3
  2. package/QUICKSTART.md +133 -0
  3. package/README.md +3 -1
  4. package/components.json +168 -28
  5. package/dist/appearance.js +4 -4
  6. package/dist/elements/alert.js +26 -2
  7. package/dist/elements/avatar.js +1 -1
  8. package/dist/elements/button.js +1 -1
  9. package/dist/elements/carousel.js +5 -2
  10. package/dist/elements/color-picker.js +1 -1
  11. package/dist/elements/combobox.js +5 -5
  12. package/dist/elements/data-grid-model.d.ts +3 -0
  13. package/dist/elements/data-grid.d.ts +2 -1
  14. package/dist/elements/data-grid.js +19 -10
  15. package/dist/elements/date-picker.js +1 -1
  16. package/dist/elements/dialog.js +1 -1
  17. package/dist/elements/file-upload.js +1 -1
  18. package/dist/elements/floating-position.d.ts +10 -0
  19. package/dist/elements/floating-position.js +53 -0
  20. package/dist/elements/info.js +1 -1
  21. package/dist/elements/input.js +2 -2
  22. package/dist/elements/link.js +1 -1
  23. package/dist/elements/message-bar.js +33 -5
  24. package/dist/elements/nav.js +4 -1
  25. package/dist/elements/overflow.d.ts +1 -0
  26. package/dist/elements/overflow.js +2 -2
  27. package/dist/elements/popover.js +1 -1
  28. package/dist/elements/rating.js +3 -3
  29. package/dist/elements/rich-text-editor.d.ts +15 -1
  30. package/dist/elements/rich-text-editor.js +938 -79
  31. package/dist/elements/search.js +3 -10
  32. package/dist/elements/select.js +2 -2
  33. package/dist/elements/shared.d.ts +4 -1
  34. package/dist/elements/shared.js +14 -1
  35. package/dist/elements/sharepoint-field-basic-controls.d.ts +1 -0
  36. package/dist/elements/sharepoint-field-basic-controls.js +14 -0
  37. package/dist/elements/sharepoint-fields.d.ts +29 -0
  38. package/dist/elements/sharepoint-fields.js +460 -0
  39. package/dist/elements/spin-button.js +2 -2
  40. package/dist/elements/tag-picker.js +29 -11
  41. package/dist/elements/textarea.js +2 -2
  42. package/dist/elements/toaster.js +2 -1
  43. package/dist/elements/tooltip.js +18 -1
  44. package/dist/elements/tree.js +1 -1
  45. package/dist/elements.d.ts +3 -2
  46. package/dist/elements.js +4 -1
  47. package/dist/index.d.ts +6 -4
  48. package/dist/index.js +4 -2
  49. package/dist/react.d.ts +142 -10
  50. package/dist/react.js +306 -46
  51. package/dist/sharepoint-fields.d.ts +135 -0
  52. package/dist/sharepoint-fields.js +402 -0
  53. package/dist/theme.d.ts +9 -1
  54. package/dist/theme.js +78 -1
  55. package/package.json +11 -2
  56. package/skills/sharepoint-ui/SKILL.md +1 -1
  57. package/skills/sharepoint-ui/references/sharepoint-patterns.md +1 -1
@@ -34,7 +34,7 @@ export function getSharePointUIStyleTokens(appearance = "fluent", overrides, bas
34
34
  "--spui-ui-warning-surface": "var(--spui-semantic-warning-background, #fff4ce)",
35
35
  "--spui-ui-danger": "var(--spui-semantic-error-text, #b10e1c)",
36
36
  "--spui-ui-danger-surface": "var(--spui-semantic-error-background, #fde7e9)",
37
- "--spui-focus-ring": "var(--spui-ui-border-focus)"
37
+ "--spui-focus-ring": "var(--spui-semantic-focus-border, var(--colorStrokeFocus2, var(--spui-ui-accent)))"
38
38
  });
39
39
  else {
40
40
  const presetText = String(tokens["--spui-ui-text"]);
@@ -61,7 +61,7 @@ export function getSharePointUIStyleTokens(appearance = "fluent", overrides, bas
61
61
  "--spui-ui-warning-surface": `var(--spui-semantic-warning-background, ${tokens["--spui-ui-warning-surface"]})`,
62
62
  "--spui-ui-danger": `var(--spui-semantic-error-text, ${tokens["--spui-ui-danger"]})`,
63
63
  "--spui-ui-danger-surface": `var(--spui-semantic-error-background, ${tokens["--spui-ui-danger-surface"]})`,
64
- "--spui-focus-ring": "var(--spui-ui-border-focus)"
64
+ "--spui-focus-ring": "var(--spui-semantic-focus-border, var(--colorStrokeFocus2, var(--spui-ui-accent)))"
65
65
  });
66
66
  }
67
67
  if (selectedBase === "ios") {
@@ -85,7 +85,7 @@ export function getSharePointUIStyleTokens(appearance = "fluent", overrides, bas
85
85
  "--spui-ui-warning-surface": "light-dark(var(--spui-semantic-warning-background, #fff3d6), color-mix(in srgb, var(--spui-semantic-warning-background, #342900) 28%, black 72%))",
86
86
  "--spui-ui-danger": "light-dark(var(--spui-semantic-error-text, #d70015), color-mix(in srgb, var(--spui-semantic-error-text, #d70015) 30%, white 70%))",
87
87
  "--spui-ui-danger-surface": "light-dark(var(--spui-semantic-error-background, #ffe5e8), color-mix(in srgb, var(--spui-semantic-error-background, #3a1114) 28%, black 72%))",
88
- "--spui-focus-ring": "var(--spui-ui-border-focus)"
88
+ "--spui-focus-ring": "var(--spui-semantic-focus-border, var(--colorStrokeFocus2, var(--spui-ui-accent)))"
89
89
  });
90
90
  }
91
91
  // Stable shared roles for applications that style slots or compose their own
@@ -202,7 +202,7 @@ export function getSharePointUIStyleTokens(appearance = "fluent", overrides, bas
202
202
  "--spui-control-height": scalePresetLength(tokens["--spui-base-control-height"], 1.04),
203
203
  "--spui-card-padding": scalePresetLength(tokens["--spui-base-card-padding"], 1.12),
204
204
  "--spui-control-gap": scalePresetLength(tokens["--spui-base-control-gap"], 1.12),
205
- "--spui-color-scheme": "light"
205
+ "--spui-color-scheme": tokens["--spui-color-scheme"] ?? "light"
206
206
  });
207
207
  if (appearance === "glass") {
208
208
  // Directly specified finished values win; base values still flow through
@@ -1,4 +1,10 @@
1
1
  import { base } from "./shared.js";
2
+ const alertIconPaths = {
3
+ info: "M10 2.5a7.5 7.5 0 1 0 0 15 7.5 7.5 0 0 0 0-15ZM10 9v5m0-7h.01",
4
+ success: "M10 2.5a7.5 7.5 0 1 0 0 15 7.5 7.5 0 0 0 0-15ZM6.5 10l2.3 2.3 4.7-5.1",
5
+ warning: "m10 2.5 8 14H2l8-14ZM10 7v4m0 3.5h.01",
6
+ error: "M10 2.5a7.5 7.5 0 1 0 0 15 7.5 7.5 0 0 0 0-15ZM7 7l6 6m0-6-6 6",
7
+ };
2
8
  export function defineAlert() {
3
9
  if (customElements.get("spui-alert"))
4
10
  return;
@@ -23,6 +29,9 @@ export function defineAlert() {
23
29
  const avatar = this.shadowRoot?.querySelector('slot[name="avatar"]');
24
30
  if (icon && avatar)
25
31
  icon.hidden = avatar.assignedElements().length > 0;
32
+ const iconPath = icon?.querySelector(".icon path");
33
+ if (iconPath)
34
+ iconPath.setAttribute("d", alertIconPaths[intent ?? "info"] ?? alertIconPaths.info);
26
35
  }
27
36
  render() {
28
37
  const shadow = this.attachShadow({ mode: "open" });
@@ -37,6 +46,13 @@ export function defineAlert() {
37
46
  defaultIcon.className = "icon";
38
47
  defaultIcon.setAttribute("aria-hidden", "true");
39
48
  icon.append(defaultIcon);
49
+ const iconSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
50
+ iconSvg.setAttribute("viewBox", "0 0 20 20");
51
+ iconSvg.setAttribute("focusable", "false");
52
+ const iconPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
53
+ iconPath.setAttribute("d", alertIconPaths.info);
54
+ iconSvg.append(iconPath);
55
+ defaultIcon.append(iconSvg);
40
56
  const content = document.createElement("div");
41
57
  content.className = "content";
42
58
  content.part.add("content");
@@ -49,12 +65,20 @@ export function defineAlert() {
49
65
  actions.part.add("actions");
50
66
  const button = document.createElement("button");
51
67
  button.type = "button";
52
- button.textContent = "×";
53
68
  button.hidden = !this.hasAttribute("dismissible");
54
69
  button.part.add("dismiss");
70
+ const closeSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
71
+ closeSvg.classList.add("dismiss-icon");
72
+ closeSvg.setAttribute("viewBox", "0 0 20 20");
73
+ closeSvg.setAttribute("aria-hidden", "true");
74
+ closeSvg.setAttribute("focusable", "false");
75
+ const closePath = document.createElementNS("http://www.w3.org/2000/svg", "path");
76
+ closePath.setAttribute("d", "m5 5 10 10M15 5 5 15");
77
+ closeSvg.append(closePath);
78
+ button.append(closeSvg);
55
79
  button.addEventListener("click", () => { this.hidden = true; this.dispatchEvent(new CustomEvent("spui-dismiss", { bubbles: true, composed: true })); });
56
80
  const style = document.createElement("style");
57
- style.textContent = `${base}:host{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,#d1d1d1));border-inline-start:4px solid var(--spui-ui-accent,#0f6cbd);border-radius:var(--spui-control-radius,6px);background:var(--spui-ui-canvas,#f5f5f5);line-height:1.45}:host([hidden]){display:none}.content{flex:1;min-width:0}.icon{font-weight:700;color:var(--spui-ui-accent,#0f6cbd)}.icon:before{content:'ℹ'}slot[name=actions]::slotted(*){display:flex;align-items:center;gap:8px}slot[name=action]::slotted(button){border:0;border-radius:4px;background:transparent;color:inherit;font:inherit;cursor:pointer}slot[name=action]::slotted(button:focus-visible){outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}:host([intent=success]){border-inline-start-color:var(--spui-ui-success,#107c10);background:var(--spui-success-surface,var(--spui-ui-success-surface,#dff6dd))}:host([intent=success]) .icon{color:var(--spui-ui-success,#107c10)}:host([intent=success]) .icon:before{content:'✓'}:host([intent=warning]){border-inline-start-color:var(--spui-ui-warning,#835b00);background:var(--spui-warning-surface,var(--spui-ui-warning-surface,#fff4ce))}:host([intent=warning]) .icon{color:var(--spui-ui-warning,#835b00)}:host([intent=warning]) .icon:before{content:'⚠'}:host([intent=error]){border-inline-start-color:var(--spui-ui-danger,#b10e1c);background:var(--spui-danger-surface,var(--spui-ui-danger-surface,#fde7e9))}:host([intent=error]) .icon{color:var(--spui-ui-danger,#b10e1c)}:host([intent=error]) .icon:before{content:'!'}:host([appearance=inverted]){color:var(--colorNeutralForegroundInverted2,var(--spui-ui-surface,#fff));background:var(--colorNeutralBackgroundInverted,var(--spui-ui-text,#242424));border-color:var(--spui-alert-inverted-border,transparent)}:host([appearance=inverted]) .icon{color:currentColor}button{border:0;border-radius:4px;background:transparent;color:inherit;font:inherit;font-size:18px;line-height:1;padding:2px 6px;cursor:pointer}button:hover{background:var(--spui-ui-surface-hover,#0001)}button:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}button[hidden]{display:none}:host([data-spui-appearance=glass]),:host-context([data-spui-appearance=glass]){backdrop-filter:var(--spui-card-backdrop,none);border-color:var(--spui-card-border,#ffffff80)}@media(forced-colors:active){:host{border-color:CanvasText;color:CanvasText;background:Canvas}.icon{color:CanvasText}}`;
81
+ style.textContent = `${base}:host{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,#d1d1d1));border-inline-start:2px solid var(--spui-ui-accent,#0f6cbd);border-radius:var(--spui-control-radius,6px);background:var(--spui-ui-canvas,#f5f5f5);line-height:1.45}:host([hidden]){display:none}.content{flex:1;min-width:0}.icon{display:inline-flex;flex:none;align-items:center;justify-content:center;color:var(--spui-ui-accent,#0f6cbd)}.icon svg,.dismiss-icon{display:block;width:1em;height:1em;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.icon svg{width:18px;height:18px}slot[name=actions]::slotted(*){display:flex;align-items:center;gap:8px}slot[name=action]::slotted(button){border:0;border-radius:4px;background:transparent;color:inherit;font:inherit;cursor:pointer}slot[name=action]::slotted(button:focus-visible){outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}:host([intent=success]){border-inline-start-color:var(--spui-ui-success,#107c10);background:var(--spui-success-surface,var(--spui-ui-success-surface,#dff6dd))}:host([intent=success]) .icon{color:var(--spui-ui-success,#107c10)}:host([intent=warning]){border-inline-start-color:var(--spui-ui-warning,#835b00);background:var(--spui-warning-surface,var(--spui-ui-warning-surface,#fff4ce))}:host([intent=warning]) .icon{color:var(--spui-ui-warning,#835b00)}:host([intent=error]){border-inline-start-color:var(--spui-ui-danger,#b10e1c);background:var(--spui-danger-surface,var(--spui-ui-danger-surface,#fde7e9))}:host([intent=error]) .icon{color:var(--spui-ui-danger,#b10e1c)}:host([appearance=inverted]){color:var(--colorNeutralForegroundInverted2,var(--spui-ui-surface,#fff));background:var(--colorNeutralBackgroundInverted,var(--spui-ui-text,#242424));border-color:var(--spui-alert-inverted-border,transparent)}:host([appearance=inverted]) .icon{color:currentColor}button{border:0;border-radius:4px;background:transparent;color:inherit;font:inherit;line-height:1;padding:2px 6px;cursor:pointer}button:hover{background:var(--spui-ui-surface-hover,#0001)}button:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}button[hidden]{display:none}:host([data-spui-appearance=glass]),:host-context([data-spui-appearance=glass]){backdrop-filter:var(--spui-card-backdrop,none);border-color:var(--spui-card-border,#ffffff80)}@media(forced-colors:active){:host{border-color:CanvasText;color:CanvasText;background:Canvas}.icon{color:CanvasText}}`;
58
82
  shadow.append(style, avatar, icon, content, action, actions, button);
59
83
  }
60
84
  }
@@ -85,7 +85,7 @@ export function defineAvatar() {
85
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
86
  this.surface.append(this.image, this.initials, this.fallback);
87
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}}`;
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{position:absolute;inset:0;z-index:0;display:flex;align-items:center;justify-content:center;max-width:100%;overflow:hidden;padding:0 2px;text-align:center;line-height:1;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
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
90
  style.textContent += `@media(forced-colors:active){.surface{border-color:CanvasText;background:Canvas;color:CanvasText}}`;
91
91
  const icon = document.createElement("span");
@@ -1,5 +1,5 @@
1
1
  import { base, stopHostAccessibleNameSync, syncHostAccessibleName } from "./shared.js";
2
- const buttonCss = `${base}button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:var(--spui-control-height,32px);padding-inline:var(--spui-control-padding-inline,14px);border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-button-border,var(--colorNeutralStroke1,#8a8886))));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-button-background,var(--colorNeutralBackground1,#fff))));box-shadow:var(--spui-control-shadow,none);color:var(--spui-ui-text,var(--spui-semantic-button-text,var(--colorNeutralForeground1,#323130)));font:inherit;line-height:1.25;text-align:center;text-decoration:none;cursor:pointer;transition:background-color var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),border-color var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),transform var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}button:hover:not(:disabled):not([aria-disabled=true]){background:var(--spui-button-secondary-hover,color-mix(in srgb,var(--spui-control-background,var(--spui-ui-surface,#fff)) 90%,var(--spui-ui-text,#242424) 10%))}button:active:not(:disabled):not([aria-disabled=true]){transform:scale(.98)}button.primary{border-color:var(--spui-primary-background,var(--spui-ui-accent,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,#0078d4))));background:var(--spui-primary-background,var(--spui-ui-accent,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,#0078d4))));color:var(--spui-ui-accent-text,var(--spui-semantic-primary-button-text,var(--colorNeutralForegroundOnBrand,#fff)))}button.primary:hover:not(:disabled):not([aria-disabled=true]){background:var(--spui-primary-hover,var(--spui-ui-accent-hover,var(--colorBrandBackgroundHover,#106ebe)))}button.primary:active:not(:disabled):not([aria-disabled=true]){background:var(--spui-ui-accent-pressed,var(--colorBrandBackgroundPressed,var(--spui-ui-accent-hover,#106ebe)))}button.outline{background:transparent}button.subtle,button.transparent{border-color:transparent;box-shadow:none}button.subtle{background:var(--spui-button-subtle-background,transparent)}button.transparent{background:transparent}button:disabled,button[aria-disabled=true]{opacity:.55;cursor:not-allowed}:host([size=small]) button{min-height:24px;padding-inline:8px;font-size:12px}:host([size=large]) button{min-height:40px;padding-inline:16px;font-size:16px}:host([shape=circular]) button{border-radius:999px}:host([shape=square]) button{border-radius:0}:host([data-spui-split-primary]) button{border-start-end-radius:0;border-end-end-radius:0}:host([data-spui-split-trigger]) button{border-start-start-radius:0;border-end-start-radius:0}:host([icon-only]) button{min-width:var(--spui-control-height,32px);padding-inline:0}:host([size=small][icon-only]) button{min-width:24px}:host([size=large][icon-only]) button{min-width:40px}:host([vertical]) button{flex-direction:column}.icon{display:inline-flex;align-items:center;justify-content:center;line-height:0}:host([vertical]) .icon{font-size:24px}.content{display:inline-flex;align-items:center;justify-content:center}:host([icon-position=after]) .icon{order:2}:host([icon-position=after]) .content{order:1}@media(prefers-reduced-motion:reduce){button{transition:none}}@media(forced-colors:active){button{border-color:ButtonText}button.primary{border-color:Highlight;background:Highlight;color:HighlightText}}`;
2
+ const buttonCss = `${base}button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:var(--spui-control-height,32px);padding-inline:var(--spui-control-padding-inline,14px);border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-button-border,var(--colorNeutralStroke1,#8a8886))));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-button-background,var(--colorNeutralBackground1,#fff))));box-shadow:var(--spui-control-shadow,none);color:var(--spui-ui-text,var(--spui-semantic-button-text,var(--colorNeutralForeground1,#323130)));font:inherit;line-height:1.25;text-align:center;text-decoration:none;cursor:pointer;transition:background-color var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),border-color var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),transform var(--spui-motion-duration-normal,.15s) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}button:hover:not(:disabled):not([aria-disabled=true]){background:var(--spui-button-secondary-hover,color-mix(in srgb,var(--spui-control-background,var(--spui-ui-surface,#fff)) 90%,var(--spui-ui-text,#242424) 10%))}button:active:not(:disabled):not([aria-disabled=true]){transform:scale(.98)}button.primary{border-color:var(--spui-primary-background,var(--spui-ui-accent,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,#0078d4))));background:var(--spui-primary-background,var(--spui-ui-accent,var(--spui-semantic-primary-button-background,var(--colorBrandBackground,#0078d4))));color:var(--spui-ui-accent-text,var(--spui-semantic-primary-button-text,var(--colorNeutralForegroundOnBrand,#fff)))}button.primary:hover:not(:disabled):not([aria-disabled=true]){background:var(--spui-primary-hover,var(--spui-ui-accent-hover,var(--colorBrandBackgroundHover,#106ebe)))}button.primary:active:not(:disabled):not([aria-disabled=true]){background:var(--spui-ui-accent-pressed,var(--colorBrandBackgroundPressed,var(--spui-ui-accent-hover,#106ebe)))}button.outline{background:transparent}button.subtle,button.transparent{border-color:transparent;box-shadow:none}button.subtle{background:var(--spui-button-subtle-background,transparent)}button.transparent{background:transparent}:host([data-spui-appearance=glass]) button:not(.primary),:host-context([data-spui-appearance=glass]) button:not(.primary){backdrop-filter:var(--spui-card-backdrop,blur(16px) saturate(150%))}button:disabled,button[aria-disabled=true]{opacity:.55;cursor:not-allowed}:host([size=small]) button{min-height:24px;padding-inline:8px;font-size:12px}:host([size=large]) button{min-height:40px;padding-inline:16px;font-size:16px}:host([shape=circular]) button{border-radius:999px}:host([shape=square]) button{border-radius:0}:host([data-spui-split-primary]) button{border-start-end-radius:0;border-end-end-radius:0}:host([data-spui-split-trigger]) button{border-start-start-radius:0;border-end-start-radius:0}:host([icon-only]) button{min-width:var(--spui-control-height,32px);padding-inline:0}:host([size=small][icon-only]) button{min-width:24px}:host([size=large][icon-only]) button{min-width:40px}:host([vertical]) button{flex-direction:column}.icon{display:inline-flex;align-items:center;justify-content:center;line-height:0}:host([vertical]) .icon{font-size:24px}.content{display:inline-flex;align-items:center;justify-content:center}:host([icon-position=after]) .icon{order:2}:host([icon-position=after]) .content{order:1}@media(prefers-reduced-motion:reduce){button{transition:none}}@media(forced-colors:active){button{border-color:ButtonText}button.primary{border-color:Highlight;background:Highlight;color:HighlightText}}`;
3
3
  export const buttonControlCss = buttonCss.replace(/\bbutton(?=[.#:[\s,{])/g, ":is(button,a)");
4
4
  const buttonSheets = new WeakMap();
5
5
  const buttonSheetUnsupported = new WeakSet();
@@ -30,7 +30,7 @@ export function defineCarouselNav() {
30
30
  return;
31
31
  const root = this.attachShadow({ mode: "open" });
32
32
  const style = document.createElement("style");
33
- style.textContent = `${base}:host{display:flex;align-items:center;justify-content:center;gap:4px;min-width:0}:host([appearance=brand]){--spui-carousel-indicator:var(--spui-ui-accent,#0078d4)}slot{display:contents}`;
33
+ style.textContent = `${base}:host{display:flex;align-items:center;justify-content:center;gap:4px;min-width:0}:host([appearance=brand]){--spui-carousel-indicator:var(--spui-ui-accent,#0078d4)}:host([appearance=thumbnails]){justify-content:flex-start;max-width:100%;overflow-x:auto;overscroll-behavior-inline:contain;scroll-snap-type:inline mandatory;scrollbar-width:thin;padding-block:4px}:host([appearance=thumbnails]) div[role=group]{display:flex;align-items:center;gap:8px;width:max-content;min-width:100%}:host([appearance=thumbnails]) ::slotted(spui-carousel-nav-image-button){scroll-snap-align:start}slot{display:contents}`;
34
34
  const group = document.createElement("div");
35
35
  group.setAttribute("role", "group");
36
36
  group.setAttribute("aria-label", this.getAttribute("aria-label") || "Slide navigation");
@@ -63,6 +63,9 @@ function defineCarouselNavControl(tag, image) {
63
63
  this.button.type = "button";
64
64
  if (image) {
65
65
  this.picture = document.createElement("img");
66
+ this.picture.loading = "lazy";
67
+ this.picture.decoding = "async";
68
+ this.picture.draggable = false;
66
69
  const imageSlot = document.createElement("slot");
67
70
  imageSlot.name = "image";
68
71
  imageSlot.append(this.picture);
@@ -460,7 +463,7 @@ export function defineCarousel() {
460
463
  this.slides.forEach(slide => { this.restoreSlideState(slide); this.restoreSlideLayout(slide); });
461
464
  }
462
465
  attributeChangedCallback(name) {
463
- if (!this.isConnected)
466
+ if (!this.isConnected || !this.controls)
464
467
  return;
465
468
  if ((name === "selected-index" || name === "active-index") && this.hasAttribute("controlled"))
466
469
  this.setIndex(Number(this.getAttribute(name)), false);
@@ -136,7 +136,7 @@ export function defineColorArea() {
136
136
  render() {
137
137
  const shadow = this.attachShadow({ mode: "open" });
138
138
  const style = document.createElement("style");
139
- style.textContent = `${base}:host{display:block;min-width:0}.area{position:relative;width:min(260px,100%);height:160px;border:1px solid var(--spui-ui-stroke,var(--colorNeutralStroke1,#8a8886));border-radius:var(--picker-radius,var(--spui-control-radius,8px));background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,hsl(var(--picker-hue,0deg) 100% 50%));touch-action:none;cursor:crosshair}.thumb{position:absolute;inset-inline-start:var(--picker-saturation,0%);top:var(--picker-brightness,100%);width:14px;height:14px;border:2px solid #fff;border-radius:50%;box-shadow:0 0 0 1px #000;transform:translate(-50%,-50%);pointer-events:none}.area:focus-within{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:3px}.inputs{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.inputs slot{display:contents}.inputs input{position:absolute;width:1px;height:1px}@media(forced-colors:active){.area{border-color:FieldText}.area:focus-within{outline-color:Highlight}.thumb{border-color:Canvas;box-shadow:0 0 0 1px CanvasText}}`;
139
+ style.textContent = `${base}:host{display:block;min-width:0}.area{box-sizing:border-box;position:relative;width:min(260px,100%);height:160px;border:1px solid var(--spui-ui-stroke,var(--colorNeutralStroke1,#8a8886));border-radius:var(--picker-radius,var(--spui-control-radius,8px));background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,hsl(var(--picker-hue,0deg) 100% 50%));touch-action:none;cursor:crosshair}.thumb{position:absolute;inset-inline-start:var(--picker-saturation,0%);top:var(--picker-brightness,100%);width:14px;height:14px;border:2px solid #fff;border-radius:50%;box-shadow:0 0 0 1px #000;transform:translate(-50%,-50%);pointer-events:none}.area:focus-within{border-width:2px;border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline:0;box-shadow:none}.inputs{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.inputs slot{display:contents}.inputs input{position:absolute;width:1px;height:1px}@media(forced-colors:active){.area{border-color:FieldText}.area:focus-within{border-color:Highlight;outline:0}.thumb{border-color:Canvas;box-shadow:0 0 0 1px CanvasText}}`;
140
140
  this.area = document.createElement("div");
141
141
  this.area.className = "area";
142
142
  this.area.setAttribute("role", "group");
@@ -4,7 +4,7 @@ export function defineCombobox() {
4
4
  return;
5
5
  class SpuiCombobox extends HTMLElement {
6
6
  static formAssociated = true;
7
- static observedAttributes = ["label", "value", "selected-value", "selected-options", "default-selected-options", "multiselect", "disabled", "required", "name", "placeholder", "allow-freeform", "read-only", "button-trigger", "open", "default-open", "clearable", "clear-label", "disable-auto-focus", "appearance", "size", "positioning", "inline-popup", "no-results", "remove-selected-label", "selected-label", "aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"];
7
+ static observedAttributes = ["label", "value", "selected-value", "selected-options", "default-selected-options", "multiselect", "disabled", "required", "required-message", "name", "placeholder", "allow-freeform", "read-only", "button-trigger", "open", "default-open", "clearable", "clear-label", "disable-auto-focus", "appearance", "size", "positioning", "inline-popup", "no-results", "remove-selected-label", "selected-label", "aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"];
8
8
  internals;
9
9
  observer;
10
10
  positionEvents;
@@ -304,7 +304,7 @@ export function defineCombobox() {
304
304
  this.internals?.setFormValue(formValue || null, this.hasAttribute("multiselect") ? JSON.stringify(this.selectedOptionsState) : typeof formValue === "string" ? formValue : null);
305
305
  const missing = this.hasAttribute("required") && (this.hasAttribute("multiselect") ? this.selectedOptionsState.length === 0 : !formValue);
306
306
  try {
307
- this.internals?.setValidity(missing ? { valueMissing: true } : {}, missing ? "Choose an option." : "", this.hasAttribute("button-trigger") ? undefined : this.getInput() ?? undefined);
307
+ this.internals?.setValidity(missing ? { valueMissing: true } : {}, missing ? this.getAttribute("required-message") || "Choose an option." : "", this.hasAttribute("button-trigger") ? undefined : this.getInput() ?? undefined);
308
308
  }
309
309
  catch { /* Keep native input semantics if an engine rejects the validity anchor. */ }
310
310
  }
@@ -998,10 +998,10 @@ export function defineCombobox() {
998
998
  empty.hidden = true;
999
999
  wrapper.append(selected, triggerSlot, inputSlot, expand, clearSlot, listboxSlot, empty);
1000
1000
  const style = document.createElement("style");
1001
- style.textContent = `${base}:host{display:grid;gap:var(--spui-control-gap,6px)}label{font-size:14px;font-weight:600;color:var(--spui-ui-muted,var(--spui-semantic-body-text,inherit))}.control{position:relative;display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:4px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,var(--colorNeutralStroke1,#8a8886))));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,var(--colorNeutralBackground1,#fff))));box-shadow:var(--spui-control-shadow,none)}.selected{display:flex;flex-wrap:wrap;gap:4px;min-width:0}.selected[hidden]{display:none}.tag{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;border:1px solid var(--spui-tag-border,var(--spui-ui-stroke,#d1d1d1));border-radius:var(--spui-tag-radius,4px);background:var(--spui-tag-background,var(--spui-ui-surface-hover,#f5f5f5));color:var(--spui-ui-text,inherit);font-size:.9em}.remove,.clear{width:24px;height:24px;border:0;border-radius:3px;background:transparent;color:inherit;cursor:pointer}.remove:hover,.clear:hover{background:var(--spui-ui-surface-hover,#f5f5f5)}input{box-sizing:border-box;flex:1 1 120px;min-width:80px;min-height:calc(var(--spui-control-height,36px) - 10px);padding:4px 8px;border:0;outline:0;background:transparent;color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}input:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:1px}input:disabled{opacity:.55}ul{position:absolute;z-index:var(--spui-layer-dropdown,20);top:calc(100% + 4px);inset-inline:0;box-sizing:border-box;max-height:240px;overflow:auto;margin:0;padding:4px;list-style:none;border:1px solid var(--spui-ui-stroke,#d1d1d1);border-radius:var(--spui-card-radius,8px);background:var(--spui-ui-surface,#fff);box-shadow:var(--spui-card-shadow,0 4px 14px #0002)}:host([positioning^=above]) ul{top:auto;bottom:calc(100% + 4px)}ul[hidden]{display:none}.option-group{display:grid;gap:2px;padding-block:2px}.group-label{padding:6px 10px;color:var(--spui-ui-muted,inherit);font-size:12px;font-weight:600}[role=option],li.empty{display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:var(--spui-control-radius,4px);color:var(--spui-ui-text,inherit);cursor:pointer}[role=option][data-active=true],[role=option][aria-selected=true]{background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.check{display:inline-grid;place-items:center;width:16px;height:16px;flex:none;border:1px solid var(--spui-ui-stroke,#8a8886);border-radius:3px;color:var(--spui-ui-accent,#0f6cbd);font-size:12px}[role=option][aria-selected=true] .check{border-color:var(--spui-ui-accent,#0f6cbd);background:var(--spui-ui-canvas,#f5f5f5)}[role=option][aria-disabled=true]{opacity:.5;cursor:not-allowed}li.empty{color:var(--spui-ui-muted,inherit);cursor:default}:host([size=small]) input{min-height:30px}:host([size=large]) input{min-height:44px}:host([appearance=filled-darker]) input{background:var(--spui-ui-surface-sunken,#f0f0f0)}:host([appearance=filled-lighter]) input{background:var(--spui-ui-surface,#fff)}:host([appearance=underline]) input{border-radius:0;border-width:0 0 1px}@media(forced-colors:active){.control,ul{border-color:CanvasText;box-shadow:none}.tag{border-color:CanvasText}.check{border-color:CanvasText}li[role=option][data-active=true]{outline:1px solid Highlight}}:host(:not([multiselect])) .control{display:block;gap:0;padding:0;border:0;background:transparent;box-shadow:none}:host(:not([multiselect])) input{box-sizing:border-box;width:100%;min-height:var(--spui-control-height,36px);padding:8px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886)));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,#fff)));box-shadow:var(--spui-control-shadow,none);color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}:host(:not([multiselect])) input:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}:host([multiselect]) .control:focus-within{border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));box-shadow:0 0 0 1px var(--spui-focus-ring,var(--spui-ui-accent,#0078d4))}@media(forced-colors:active){:host(:not([multiselect])) input{border-color:FieldText;background:Field;color:FieldText}}`;
1002
- style.textContent += ".expand{display:inline-flex;align-items:center;justify-content:center;flex:none;color:inherit}.expand[hidden]{display:none}::slotted([slot=clear-button]){cursor:pointer}:host([read-only]) .expand,:host([button-trigger]) .expand{position:absolute;inset-inline-end:6px;top:6px}:host([read-only]) .clear,:host([read-only]) ::slotted([slot=clear-button]),:host([button-trigger]) .clear,:host([button-trigger]) ::slotted([slot=clear-button]){position:absolute;inset-inline-end:32px;top:6px}:host([read-only]) input{width:calc(100% - 56px)}:host([read-only]:not([clearable])) input{width:calc(100% - 28px)}.trigger,::slotted([slot=button]){box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-height:var(--spui-control-height,36px);padding:8px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886)));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,#fff)));box-shadow:var(--spui-control-shadow,none);color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit;text-align:start;cursor:pointer}.trigger:focus-visible,::slotted([slot=button]:focus-visible){outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,#005a9e));outline-offset:2px}.trigger:disabled,::slotted([slot=button][disabled]){opacity:.55;cursor:not-allowed}:host([button-trigger][size=small]) .trigger,:host([button-trigger][size=small]) ::slotted([slot=button]){min-height:30px}:host([button-trigger][size=large]) .trigger,:host([button-trigger][size=large]) ::slotted([slot=button]){min-height:44px}:host([button-trigger]) .trigger-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(forced-colors:active){.trigger,:host([button-trigger]) ::slotted([slot=button]){border-color:ButtonText;background:ButtonFace;color:ButtonText}.trigger:focus-visible,:host([button-trigger]) ::slotted([slot=button]:focus-visible){outline-color:Highlight}}";
1001
+ style.textContent = `${base}:host{display:grid;gap:var(--spui-control-gap,6px)}label{font-size:14px;font-weight:600;color:var(--spui-ui-muted,var(--spui-semantic-body-text,inherit))}.control{position:relative;display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:4px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,var(--colorNeutralStroke1,#8a8886))));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,var(--colorNeutralBackground1,#fff))));box-shadow:var(--spui-control-shadow,none)}.selected{display:flex;flex-wrap:wrap;gap:4px;min-width:0}.selected[hidden]{display:none}.tag{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;border:1px solid var(--spui-tag-border,var(--spui-ui-stroke,#d1d1d1));border-radius:var(--spui-tag-radius,4px);background:var(--spui-tag-background,var(--spui-ui-surface-hover,#f5f5f5));color:var(--spui-ui-text,inherit);font-size:.9em}.remove,.clear{width:24px;height:24px;border:0;border-radius:3px;background:transparent;color:inherit;cursor:pointer}.remove:hover,.clear:hover{background:var(--spui-ui-surface-hover,#f5f5f5)}input{box-sizing:border-box;flex:1 1 120px;min-width:80px;min-height:calc(var(--spui-control-height,36px) - 10px);padding:4px 8px;border:0;outline:0;background:transparent;color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}input:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:1px}input:disabled{opacity:.55}ul{position:absolute;z-index:var(--spui-layer-dropdown,20);top:calc(100% + 4px);inset-inline:0;box-sizing:border-box;max-height:240px;overflow:auto;margin:0;padding:4px;list-style:none;border:1px solid var(--spui-ui-stroke,#d1d1d1);border-radius:var(--spui-card-radius,8px);background:var(--spui-ui-surface,#fff);box-shadow:var(--spui-card-shadow,0 4px 14px #0002)}:host([positioning^=above]) ul{top:auto;bottom:calc(100% + 4px)}ul[hidden]{display:none}.option-group{display:grid;gap:2px;padding-block:2px}.group-label{padding:6px 10px;color:var(--spui-ui-muted,inherit);font-size:12px;font-weight:600}[role=option],li.empty{display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:var(--spui-control-radius,4px);color:var(--spui-ui-text,inherit);cursor:pointer}[role=option][data-active=true],[role=option][aria-selected=true]{background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.check{display:inline-grid;place-items:center;width:16px;height:16px;flex:none;border:1px solid var(--spui-ui-stroke,#8a8886);border-radius:3px;color:var(--spui-ui-accent,#0f6cbd);font-size:12px}[role=option][aria-selected=true] .check{border-color:var(--spui-ui-accent,#0f6cbd);background:var(--spui-ui-canvas,#f5f5f5)}[role=option][aria-disabled=true]{opacity:.5;cursor:not-allowed}li.empty{color:var(--spui-ui-muted,inherit);cursor:default}:host([size=small]) input{min-height:30px}:host([size=large]) input{min-height:44px}:host([appearance=filled-darker]) input{background:var(--spui-ui-surface-sunken,#f0f0f0)}:host([appearance=filled-lighter]) input{background:var(--spui-ui-surface,#fff)}:host([appearance=underline]) input{border-radius:0;border-width:0 0 1px}@media(forced-colors:active){.control,ul{border-color:CanvasText;box-shadow:none}.tag{border-color:CanvasText}.check{border-color:CanvasText}li[role=option][data-active=true]{outline:1px solid Highlight}}:host(:not([multiselect])) .control{display:block;gap:0;padding:0;border:0;background:transparent;box-shadow:none}:host(:not([multiselect])) input{box-sizing:border-box;width:100%;min-height:var(--spui-control-height,36px);padding:8px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886)));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,#fff)));box-shadow:var(--spui-control-shadow,none);color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}:host(:not([multiselect])) input:focus-visible{border-width:2px;border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline:0}:host([appearance=underline]:not([multiselect])) input:focus-visible{border-width:0 0 2px}:host([multiselect]) .control:focus-within{border-width:2px;border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));box-shadow:none}:host([multiselect]) .control input:focus-visible{outline:0}:host([aria-invalid]:not([aria-invalid=false])) .control,:host([aria-invalid]:not([aria-invalid=false])) input,:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=input]),:host([aria-invalid]:not([aria-invalid=false])) .trigger,:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=button]){border-color:var(--spui-input-invalid-border,var(--spui-ui-danger,var(--colorPaletteRedBorder2,#c50f1f)))}:host([aria-invalid]:not([aria-invalid=false])) input:focus-visible,:host([aria-invalid]:not([aria-invalid=false])) .trigger:focus-visible,:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=input]:focus-visible),:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=button]:focus-visible){border-color:var(--spui-input-invalid-border,var(--spui-ui-danger,var(--colorPaletteRedBorder2,#c50f1f)))}@media(forced-colors:active){:host(:not([multiselect])) input{border-color:FieldText;background:Field;color:FieldText}:host(:not([multiselect])) input:focus-visible{border-color:Highlight}:host([multiselect]) .control:focus-within{border-color:Highlight}:host([aria-invalid]:not([aria-invalid=false])) .control,:host([aria-invalid]:not([aria-invalid=false])) input,:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=input]),:host([aria-invalid]:not([aria-invalid=false])) .trigger,:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=button]){border-color:CanvasText}:host([aria-invalid]:not([aria-invalid=false])) input:focus-visible,:host([aria-invalid]:not([aria-invalid=false])) .trigger:focus-visible,:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=input]:focus-visible),:host([aria-invalid]:not([aria-invalid=false])) ::slotted([slot=button]:focus-visible){border-color:Highlight!important}:host(:not([multiselect])) ::slotted([slot=input]:focus-visible){border-color:Highlight!important}:host([button-trigger]) ::slotted([slot=button]:focus-visible){border-color:Highlight!important}}`;
1002
+ style.textContent += ".expand{display:inline-flex;align-items:center;justify-content:center;flex:none;color:inherit}.expand[hidden]{display:none}::slotted([slot=clear-button]){cursor:pointer}:host([read-only]) .expand,:host([button-trigger]) .expand{position:absolute;inset-inline-end:6px;top:6px}:host([read-only]) .clear,:host([read-only]) ::slotted([slot=clear-button]),:host([button-trigger]) .clear,:host([button-trigger]) ::slotted([slot=clear-button]){position:absolute;inset-inline-end:32px;top:6px}:host([read-only]) input{width:calc(100% - 56px)}:host([read-only]:not([clearable])) input{width:calc(100% - 28px)}.trigger,::slotted([slot=button]){box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-height:var(--spui-control-height,36px);padding:8px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886)));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,#fff)));box-shadow:var(--spui-control-shadow,none);color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit;text-align:start;cursor:pointer}.trigger:focus-visible{border-width:2px;border-color:var(--spui-focus-ring,var(--spui-semantic-focus-border,#005a9e));outline:0;outline-offset:0;box-shadow:none}::slotted([slot=button]:focus-visible){border-width:2px!important;border-color:var(--spui-focus-ring,var(--spui-semantic-focus-border,#005a9e))!important;outline:0!important;outline-offset:0;box-shadow:none!important}:host([appearance=underline]) .trigger:focus-visible,:host([appearance=underline]) ::slotted([slot=button]:focus-visible){border-width:0 0 2px!important}.trigger:disabled,::slotted([slot=button][disabled]){opacity:.55;cursor:not-allowed}:host([button-trigger][size=small]) .trigger,:host([button-trigger][size=small]) ::slotted([slot=button]){min-height:30px}:host([button-trigger][size=large]) .trigger,:host([button-trigger][size=large]) ::slotted([slot=button]){min-height:44px}:host([button-trigger]) .trigger-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(forced-colors:active){.trigger,:host([button-trigger]) ::slotted([slot=button]){border-color:ButtonText;background:ButtonFace;color:ButtonText}.trigger:focus-visible,:host([button-trigger]) ::slotted([slot=button]:focus-visible){border-color:Highlight!important;outline:0!important}}";
1003
1003
  style.textContent = style.textContent?.replaceAll("li.empty", ".empty") ?? "";
1004
- style.textContent += `::slotted([slot=input]){box-sizing:border-box;flex:1 1 120px;min-width:80px;min-height:calc(var(--spui-control-height,36px) - 10px);padding:4px 8px;border:0;outline:0;background:transparent;color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}::slotted([slot=input]:focus-visible){outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:1px}:host(:not([multiselect])) ::slotted([slot=input]){box-sizing:border-box;width:100%;min-height:var(--spui-control-height,36px);padding:8px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886)));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,#fff)));color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}`;
1004
+ style.textContent += `::slotted([slot=input]){box-sizing:border-box;flex:1 1 120px;min-width:80px;min-height:calc(var(--spui-control-height,36px) - 10px);padding:4px 8px;border:0;outline:0;background:transparent;color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}:host([multiselect]) ::slotted([slot=input]){border:0!important;outline:0!important;box-shadow:none!important}::slotted([slot=input]:focus-visible){border:0!important;outline:0!important;outline-offset:0;box-shadow:none!important}:host(:not([multiselect])) ::slotted([slot=input]:focus-visible){border-style:solid!important;border-width:2px!important;border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4))!important}:host([appearance=underline]:not([multiselect])) ::slotted([slot=input]:focus-visible){border-width:0 0 2px!important}:host(:not([multiselect])) ::slotted([slot=input]){box-sizing:border-box;width:100%;min-height:var(--spui-control-height,36px);padding:8px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886)));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,#fff)));color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}`;
1005
1005
  shadow.replaceChildren(style, label, wrapper);
1006
1006
  this.bindInput();
1007
1007
  this.syncExpandIcon();
@@ -93,6 +93,9 @@ export type DataGridCellEdit<T = unknown> = {
93
93
  previousValue: unknown;
94
94
  value: DataGridEditValue;
95
95
  };
96
+ export type DataGridCellEditError<T = unknown> = DataGridCellEdit<T> & {
97
+ error: string;
98
+ };
96
99
  /** Bound row sizes to keep a consumer callback from creating pathological virtual scroll extents. */
97
100
  export declare function clampDataGridRowHeight(height: number | undefined, estimate: number): number;
98
101
  export declare function getDataGridCellValue<T>(item: T, column: DataGridColumn<T>): unknown;
@@ -1,4 +1,4 @@
1
- import { type DataGridCellEdit, type DataGridColumn, type DataGridDataSource, type DataGridColumnSizingOptions, type DataGridFocusMode, type DataGridSelectionAppearance, type DataGridSelectionModel } from "./data-grid-model.js";
1
+ import { type DataGridCellEdit, type DataGridCellEditError, type DataGridColumn, type DataGridDataSource, type DataGridColumnSizingOptions, type DataGridFocusMode, type DataGridSelectionAppearance, type DataGridSelectionModel } from "./data-grid-model.js";
2
2
  export type DataGridCellRenderer<T = unknown> = (item: T, column: DataGridColumn<T>, rowIndex: number) => Node | string | number | null;
3
3
  export type DataGridRowHeightGetter<T = unknown> = (item: T, rowIndex: number) => number;
4
4
  export type DataGridCellsEditHandler = (edits: readonly DataGridCellEdit[]) => void | Promise<void>;
@@ -19,6 +19,7 @@ export interface SharePointDataGridElement extends HTMLElement {
19
19
  onDataSourceSelectionChange?: DataGridSourceSelectionHandler;
20
20
  getRowHeight?: DataGridRowHeightGetter;
21
21
  onCellsEdit?: DataGridCellsEditHandler;
22
+ onCellEditError?: (error: DataGridCellEditError) => void;
22
23
  }
23
24
  declare global {
24
25
  interface HTMLElementTagNameMap {
@@ -7,7 +7,7 @@ export function defineDataGrid() {
7
7
  if (customElements.get("spui-data-grid"))
8
8
  return;
9
9
  class SpuiDataGrid extends HTMLElement {
10
- static observedAttributes = ["aria-label", "label", "focus-mode", "selection-mode", "selection-appearance", "subtle-selection", "auto-fit-columns", "container-width-offset", "row-height", "overscan", "virtualize-columns", "select-label", "select-all-label", "empty-label", "no-results-label", "filterable", "filter-label", "sort-priority-label", "resizable-columns", "resize-label", "reorderable-columns", "reorder-label", "group-by", "empty-group-label", "expand-group-label", "collapse-group-label", "row-label", "edit-hint"];
10
+ static observedAttributes = ["aria-label", "label", "focus-mode", "selection-mode", "selection-appearance", "subtle-selection", "auto-fit-columns", "container-width-offset", "row-height", "overscan", "virtualize-columns", "select-label", "select-all-label", "empty-label", "no-results-label", "loading-label", "load-error-label", "edit-error-label", "filterable", "filter-label", "sort-priority-label", "resizable-columns", "resize-label", "reorderable-columns", "reorder-label", "reorder-hint-label", "group-by", "empty-group-label", "expand-group-label", "collapse-group-label", "row-label", "edit-hint", "selection-copied-label", "copy-failed-label", "paste-one-label", "paste-many-label", "paste-failed-label"];
11
11
  data = [];
12
12
  source;
13
13
  sourceUnsubscribe;
@@ -85,6 +85,7 @@ export function defineDataGrid() {
85
85
  editedValues = new Map();
86
86
  editingCell;
87
87
  editCallback;
88
+ editErrorCallback;
88
89
  cellsEditCallback;
89
90
  dataSourceGroupToggleCallback;
90
91
  dataSourceSelectionCallback;
@@ -187,6 +188,8 @@ export function defineDataGrid() {
187
188
  set collapsedGroupKeys(value) { this.collapsedGroups = new Set(value ?? []); this.paint(true); }
188
189
  get onCellEdit() { return this.editCallback; }
189
190
  set onCellEdit(value) { this.editCallback = value; }
191
+ get onCellEditError() { return this.editErrorCallback; }
192
+ set onCellEditError(value) { this.editErrorCallback = value; }
190
193
  get validateCellEdit() { return this.editValidator; }
191
194
  set validateCellEdit(value) { this.editValidator = value; }
192
195
  get onCellsEdit() { return this.cellsEditCallback; }
@@ -210,6 +213,9 @@ export function defineDataGrid() {
210
213
  }
211
214
  disconnectedCallback() { cancelAnimationFrame(this.frame); this.frame = 0; this.resizeObserver?.disconnect(); this.sourceRequest?.controller.abort(); this.sourceRequest = undefined; this.clipboardController?.abort(); this.clipboardController = undefined; this.sourceUnsubscribe?.(); this.sourceUnsubscribe = undefined; }
212
215
  attributeChangedCallback() { this.renderFilter(); this.renderHeader(); this.initializeColumnWidths(); this.paint(true); }
216
+ localizedMessage(attribute, fallback, values = {}) {
217
+ return Object.entries(values).reduce((message, [key, value]) => message.replaceAll(`{${key}}`, value), this.getAttribute(attribute) ?? fallback);
218
+ }
213
219
  render() {
214
220
  const shadow = this.attachShadow({ mode: "open" });
215
221
  const style = document.createElement("style");
@@ -372,7 +378,7 @@ export function defineDataGrid() {
372
378
  this.failedSourceRange = key;
373
379
  const error = new Error("loadRange resolved before every requested row was available");
374
380
  if (this.reorderStatus)
375
- this.reorderStatus.textContent = error.message;
381
+ this.reorderStatus.textContent = this.localizedMessage("load-error-label", "Data could not be loaded.");
376
382
  this.viewport?.setAttribute("aria-busy", "false");
377
383
  this.dispatchEvent(new CustomEvent("spui-data-load-error", { detail: { error, start, end }, bubbles: true, composed: true }));
378
384
  return;
@@ -389,7 +395,7 @@ export function defineDataGrid() {
389
395
  this.sourceRequest = undefined;
390
396
  this.failedSourceRange = key;
391
397
  if (this.reorderStatus)
392
- this.reorderStatus.textContent = `Data could not be loaded: ${error instanceof Error ? error.message : String(error)}`;
398
+ this.reorderStatus.textContent = this.localizedMessage("load-error-label", "Data could not be loaded.");
393
399
  this.viewport?.setAttribute("aria-busy", "false");
394
400
  this.dispatchEvent(new CustomEvent("spui-data-load-error", { detail: { error, start, end }, bubbles: true, composed: true }));
395
401
  });
@@ -476,7 +482,7 @@ export function defineDataGrid() {
476
482
  grip.dataset.reorderColumn = column.id;
477
483
  grip.draggable = true;
478
484
  grip.setAttribute("aria-label", `${this.getAttribute("reorder-label") || "Reorder column"} ${column.label}`);
479
- grip.title = `${this.getAttribute("reorder-label") || "Reorder column"} ${column.label}; use Alt+Shift+Arrow keys`;
485
+ grip.title = this.localizedMessage("reorder-hint-label", "Reorder {column}; use Alt+Shift+Arrow keys", { column: column.label });
480
486
  grip.textContent = "⠿";
481
487
  cell.append(grip);
482
488
  }
@@ -1024,11 +1030,14 @@ export function defineDataGrid() {
1024
1030
  }
1025
1031
  catch (reason) {
1026
1032
  editing.saving = false;
1027
- editing.error = reason instanceof Error ? reason.message : String(reason || "The value could not be saved.");
1033
+ const message = reason instanceof Error ? reason.message : String(reason || "The value could not be saved.");
1034
+ editing.error = this.getAttribute("edit-error-label") || "The value could not be saved.";
1028
1035
  if (input) {
1029
1036
  input.disabled = false;
1030
1037
  input.removeAttribute("aria-busy");
1031
1038
  }
1039
+ this.editErrorCallback?.({ item: edit.item, rowId: edit.rowId, columnId: edit.columnId, previousValue: edit.previousValue, value: edit.value, error: message });
1040
+ this.dispatchEvent(new CustomEvent("spui-cell-edit-error", { detail: { item: edit.item, rowId: edit.rowId, columnId: edit.columnId, previousValue: edit.previousValue, value: edit.value, error: message }, bubbles: true, composed: true }));
1032
1041
  this.showEditError(editing);
1033
1042
  }
1034
1043
  }
@@ -1049,7 +1058,7 @@ export function defineDataGrid() {
1049
1058
  error.setAttribute("role", "alert");
1050
1059
  cell.append(error);
1051
1060
  }
1052
- error.textContent = editing.error || "The value could not be saved.";
1061
+ error.textContent = editing.error || this.getAttribute("edit-error-label") || "The value could not be saved.";
1053
1062
  requestAnimationFrame(() => input.focus());
1054
1063
  }
1055
1064
  currentEditValue(item, rowId, column) {
@@ -1101,13 +1110,13 @@ export function defineDataGrid() {
1101
1110
  });
1102
1111
  void writeDataGridClipboardText(text).then(() => {
1103
1112
  if (this.clipboardController === controller && this.reorderStatus)
1104
- this.reorderStatus.textContent = "Selection copied.";
1113
+ this.reorderStatus.textContent = this.localizedMessage("selection-copied-label", "Selection copied.");
1105
1114
  }, reason => {
1106
1115
  if (controller.signal.aborted)
1107
1116
  return;
1108
1117
  const message = reason instanceof Error ? reason.message : String(reason);
1109
1118
  if (this.reorderStatus)
1110
- this.reorderStatus.textContent = `Copy failed. ${message}`;
1119
+ this.reorderStatus.textContent = this.localizedMessage("copy-failed-label", "Copy failed.");
1111
1120
  this.dispatchEvent(new CustomEvent("spui-clipboard-error", { detail: { operation: "copy", message }, bubbles: true, composed: true }));
1112
1121
  });
1113
1122
  }
@@ -1194,7 +1203,7 @@ export function defineDataGrid() {
1194
1203
  this.dispatchEvent(new CustomEvent("spui-cell-edit", { detail: edit, bubbles: true, composed: true }));
1195
1204
  }
1196
1205
  if (this.reorderStatus)
1197
- this.reorderStatus.textContent = `Pasted ${edits.length} cell${edits.length === 1 ? "" : "s"}.`;
1206
+ this.reorderStatus.textContent = this.localizedMessage(edits.length === 1 ? "paste-one-label" : "paste-many-label", edits.length === 1 ? "Pasted {count} cell." : "Pasted {count} cells.", { count: String(edits.length) });
1198
1207
  this.paint(true);
1199
1208
  }
1200
1209
  catch (reason) {
@@ -1202,7 +1211,7 @@ export function defineDataGrid() {
1202
1211
  return;
1203
1212
  const message = reason instanceof Error ? reason.message : String(reason);
1204
1213
  if (this.reorderStatus)
1205
- this.reorderStatus.textContent = `Paste failed. ${message}`;
1214
+ this.reorderStatus.textContent = this.localizedMessage("paste-failed-label", "Paste failed.");
1206
1215
  this.dispatchEvent(new CustomEvent("spui-cells-edit-error", { detail: { message, edits }, bubbles: true, composed: true }));
1207
1216
  }
1208
1217
  }
@@ -191,7 +191,7 @@ export function defineDatePicker() {
191
191
  control.append(input, calendarButton);
192
192
  shadow.replaceChildren(document.createElement("style"), label, control, calendar);
193
193
  const style = shadow.querySelector("style");
194
- style.textContent = `${base}:host{position:relative;display:grid;gap:var(--spui-control-gap,6px);min-width:0;color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}.control{display:flex;position:relative;min-width:0}.control input{box-sizing:border-box;width:100%;min-width:0;min-height:var(--spui-control-height,36px);padding-inline:var(--spui-control-padding-inline,12px) 42px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,var(--colorNeutralStroke1,#8a8886))));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,var(--colorNeutralBackground1,#fff))));box-shadow:var(--spui-control-shadow,none);color:inherit;font:inherit}.control input:focus-visible,.calendar-button:focus-visible,.calendar button:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:1px}.control input[aria-invalid=true]{border-color:var(--spui-semantic-danger,var(--colorPaletteRedBorderActive,#d13438))}.calendar-button{position:absolute;inset-block:2px;inset-inline-end:2px;display:grid;place-items:center;width:36px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:var(--spui-ui-muted,var(--colorNeutralForeground2,#616161));cursor:pointer}.calendar-button:hover{background:var(--spui-ui-surface-hover,var(--colorNeutralBackground1Hover,#f5f5f5));color:var(--spui-ui-text,inherit)}label{font-size:14px;font-weight:600;color:var(--spui-ui-muted,var(--spui-semantic-body-text,inherit))}.calendar{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-start:0;z-index:var(--spui-layer-dropdown,20);width:min(320px,calc(100vw - 24px));padding:12px;border:1px solid var(--spui-ui-stroke,var(--colorNeutralStroke1,#d1d1d1));border-radius:var(--spui-card-radius,8px);background:var(--spui-ui-surface,var(--colorNeutralBackground1,#fff));box-shadow:var(--spui-card-shadow,0 4px 16px #0002);color:var(--spui-ui-text,var(--colorNeutralForeground1,#242424));direction:inherit}.calendar[hidden]{display:none}.calendar-header{display:grid;grid-template-columns:36px 1fr 36px;align-items:center;gap:4px;margin-block-end:8px}.month-label{text-align:center;font-weight:600}.calendar button{font:inherit}.month-nav{display:grid;place-items:center;width:36px;height:36px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:inherit;cursor:pointer}.month-nav:hover{background:var(--spui-ui-surface-hover,#f5f5f5)}.weekdays{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}.days{display:grid;gap:2px}.days>[role=row]{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}.weekday{display:grid;place-items:center;height:32px;color:var(--spui-ui-muted,var(--colorNeutralForeground2,#616161));font-size:12px;font-weight:600}.day{display:grid;place-items:center;min-width:0;aspect-ratio:1;border:0;border-radius:50%;background:transparent;color:inherit;cursor:pointer}.day:hover:not(:disabled){background:var(--spui-ui-surface-hover,var(--colorNeutralBackground1Hover,#f5f5f5))}.day[aria-selected=true]{background:var(--spui-ui-accent,var(--colorBrandBackground,#0f6cbd));color:var(--spui-ui-accent-text,var(--colorNeutralForegroundOnBrand,#fff))}.day[aria-current=date]{outline:1px solid var(--spui-ui-accent,var(--colorBrandForeground1,#0f6cbd));outline-offset:-2px}.day.outside-month{color:var(--spui-ui-muted,var(--colorNeutralForeground3,#a19f9d))}.day:disabled{opacity:.42;cursor:default}.calendar[dir=rtl]{direction:rtl}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important}}@media(forced-colors:active){.calendar,.control input{border-color:FieldText}.day[aria-selected=true]{outline:2px solid Highlight}.calendar-button,.month-nav,.day{forced-color-adjust:auto}}`;
194
+ style.textContent = `${base}:host{position:relative;display:grid;gap:var(--spui-control-gap,6px);min-width:0;color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font:inherit}.control{display:flex;position:relative;min-width:0}.control input{box-sizing:border-box;width:100%;min-width:0;min-height:var(--spui-control-height,36px);padding-inline:var(--spui-control-padding-inline,12px) 42px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,var(--colorNeutralStroke1,#8a8886))));border-radius:var(--spui-control-radius,4px);background:var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,var(--colorNeutralBackground1,#fff))));box-shadow:var(--spui-control-shadow,none);color:inherit;font:inherit}.control input:focus-visible{border-width:2px;border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline:0;box-shadow:none}.calendar-button:focus-visible,.calendar button:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:1px}.control input[aria-invalid]:not([aria-invalid=false]){border-color:var(--spui-input-invalid-border,var(--spui-ui-danger,var(--spui-semantic-danger,var(--colorPaletteRedBorderActive,#d13438))))}.control input[aria-invalid]:not([aria-invalid=false]):focus-visible{border-color:var(--spui-input-invalid-border,var(--spui-ui-danger,var(--spui-semantic-danger,var(--colorPaletteRedBorderActive,#d13438))))}.calendar-button{position:absolute;inset-block:2px;inset-inline-end:2px;display:grid;place-items:center;width:36px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:var(--spui-ui-muted,var(--colorNeutralForeground2,#616161));cursor:pointer}.calendar-button:hover{background:var(--spui-ui-surface-hover,var(--colorNeutralBackground1Hover,#f5f5f5));color:var(--spui-ui-text,inherit)}label{font-size:14px;font-weight:600;color:var(--spui-ui-muted,var(--spui-semantic-body-text,inherit))}.calendar{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-start:0;z-index:var(--spui-layer-dropdown,20);width:min(320px,calc(100vw - 24px));padding:12px;border:1px solid var(--spui-ui-stroke,var(--colorNeutralStroke1,#d1d1d1));border-radius:var(--spui-card-radius,8px);background:var(--spui-ui-surface,var(--colorNeutralBackground1,#fff));box-shadow:var(--spui-card-shadow,0 4px 16px #0002);color:var(--spui-ui-text,var(--colorNeutralForeground1,#242424));direction:inherit}.calendar[hidden]{display:none}.calendar-header{display:grid;grid-template-columns:36px 1fr 36px;align-items:center;gap:4px;margin-block-end:8px}.month-label{text-align:center;font-weight:600}.calendar button{font:inherit}.month-nav{display:grid;place-items:center;width:36px;height:36px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:inherit;cursor:pointer}.month-nav:hover{background:var(--spui-ui-surface-hover,#f5f5f5)}.weekdays{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}.days{display:grid;gap:2px}.days>[role=row]{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}.weekday{display:grid;place-items:center;height:32px;color:var(--spui-ui-muted,var(--colorNeutralForeground2,#616161));font-size:12px;font-weight:600}.day{display:grid;place-items:center;min-width:0;aspect-ratio:1;border:0;border-radius:50%;background:transparent;color:inherit;cursor:pointer}.day:hover:not(:disabled){background:var(--spui-ui-surface-hover,var(--colorNeutralBackground1Hover,#f5f5f5))}.day[aria-selected=true]{background:var(--spui-ui-accent,var(--colorBrandBackground,#0f6cbd));color:var(--spui-ui-accent-text,var(--colorNeutralForegroundOnBrand,#fff))}.day[aria-current=date]{outline:1px solid var(--spui-ui-accent,var(--colorBrandForeground1,#0f6cbd));outline-offset:-2px}.day.outside-month{color:var(--spui-ui-muted,var(--colorNeutralForeground3,#a19f9d))}.day:disabled{opacity:.42;cursor:default}.calendar[dir=rtl]{direction:rtl}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important}}@media(forced-colors:active){.calendar,.control input{border-color:FieldText}.control input:focus-visible{border-color:Highlight;outline:0}.control input[aria-invalid]:not([aria-invalid=false]):focus-visible{border-color:Highlight}.day[aria-selected=true]{outline:2px solid Highlight}.calendar-button,.month-nav,.day{forced-color-adjust:auto}}`;
195
195
  style.textContent += `.control input:disabled,.calendar-button:disabled,.month-nav:disabled{cursor:not-allowed;opacity:.5}.calendar-button:disabled:hover,.month-nav:disabled:hover{background:transparent}.day[aria-disabled=true]{opacity:.42;cursor:default}`;
196
196
  this.syncInput();
197
197
  this.syncInputAttributes();
@@ -364,7 +364,7 @@ export function defineDialog() {
364
364
  this.closeDialog("backdropClick", event);
365
365
  });
366
366
  const style = document.createElement("style");
367
- style.textContent = `${base}:host{display:contents}dialog{position:relative;z-index:2147483647;box-sizing:border-box;width:min(520px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);overflow:auto;padding:0;border:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1));border-radius:var(--spui-card-radius,12px);background:var(--spui-card-background,var(--spui-ui-surface,#fff));box-shadow:var(--spui-card-shadow,0 16px 48px #0004);color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424))}dialog::backdrop{background:color-mix(in srgb,var(--spui-ui-text,#242424) 42%,transparent);backdrop-filter:blur(2px)}:host([backdrop-appearance=transparent]) dialog::backdrop{background:transparent;backdrop-filter:none}header{display:flex;align-items:start;justify-content:space-between;gap:16px;padding:20px 20px 0}h2{margin:0;font-size:20px;line-height:1.3;font-weight:650}.close{display:inline-grid;place-items:center;flex:none;width:var(--spui-control-height,32px);height:var(--spui-control-height,32px);margin:-5px -6px 0 0;margin-left:auto;border:0;border-radius:var(--spui-control-radius,6px);background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.close:hover{background:var(--spui-ui-surface-hover,#f5f5f5)}.close:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}.body{padding:16px 20px 20px;line-height:1.5}footer{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px;padding:12px 20px 20px;border-top:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))}footer[hidden]{display:none}@media(forced-colors:active){dialog{border-color:CanvasText;box-shadow:none}dialog::backdrop{background:Canvas} .close:focus-visible{outline-color:Highlight}}`;
367
+ style.textContent = `${base}:host{display:contents}dialog{position:relative;z-index:2147483647;box-sizing:border-box;width:min(520px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);overflow:auto;padding:0;border:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1));border-radius:var(--spui-card-radius,12px);background:var(--spui-card-background,var(--spui-ui-surface,#fff));box-shadow:var(--spui-card-shadow,0 16px 48px #0004);color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424))}dialog::backdrop{background:color-mix(in srgb,var(--spui-ui-text,#242424) 42%,transparent);backdrop-filter:blur(2px)}:host([backdrop-appearance=transparent]) dialog::backdrop{background:transparent;backdrop-filter:none}header{display:flex;align-items:start;justify-content:space-between;gap:16px;padding:20px 20px 0}h2{margin:0;font-size:20px;line-height:1.3;font-weight:650}.close{display:inline-grid;place-items:center;flex:none;width:var(--spui-control-height,32px);height:var(--spui-control-height,32px);margin:-5px 0 0;margin-inline-end:-6px;border:0;border-radius:var(--spui-control-radius,6px);background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.close:hover{background:var(--spui-ui-surface-hover,#f5f5f5)}.close:focus-visible{outline:2px solid var(--spui-focus-ring,#005a9e);outline-offset:2px}.body{padding:16px 20px 20px;line-height:1.5}footer{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px;padding:12px 20px 20px;border-top:1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))}footer[hidden]{display:none}@media(forced-colors:active){dialog{border-color:CanvasText;box-shadow:none}dialog::backdrop{background:Canvas} .close:focus-visible{outline-color:Highlight}}`;
368
368
  const overlayStyle = document.createElement("style");
369
369
  overlayStyle.textContent = ".modal-backdrop{position:fixed;inset:0;z-index:2147483000;background:color-mix(in srgb,var(--spui-ui-text,#242424) 42%,transparent);backdrop-filter:blur(2px)}.modal-backdrop[hidden]{display:none}.modal-backdrop slot{position:absolute;inset:0}:host([data-has-custom-backdrop]) .modal-backdrop{background:transparent;backdrop-filter:none}:host([backdrop-appearance=transparent]) .modal-backdrop{background:transparent;backdrop-filter:none}::slotted([slot=backdrop]){position:absolute;inset:0;display:block;background:color-mix(in srgb,var(--spui-ui-text,#242424) 42%,transparent)}::slotted([slot=backdrop][data-appearance=transparent]){background:transparent}";
370
370
  const backdrop = document.createElement("div");
@@ -33,7 +33,7 @@ export function defineFileUpload() {
33
33
  render() {
34
34
  const shadow = this.attachShadow({ mode: "open" });
35
35
  const style = document.createElement("style");
36
- style.textContent = `${base}:host{display:block;min-width:0;color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424));font-family:var(--spui-font-family,inherit)}.label{display:block;margin-block-end:6px;font-size:14px;font-weight:600}.drop{box-sizing:border-box;display:grid;place-items:center;gap:6px;min-height:104px;padding:16px;border:1px dashed var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886));border-radius:var(--spui-control-radius,6px);background:var(--spui-ui-surface,var(--spui-semantic-input-background,#fff));text-align:center;transition:border-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),background-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}.drop[data-dragging=true]{border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.hint{color:var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161));font-size:12px}.browse{min-height:32px;padding:4px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,#8a8886));border-radius:var(--spui-control-radius,4px);background:var(--spui-ui-surface,#fff);color:inherit;font:inherit;cursor:pointer}.browse:hover:not(:disabled){background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.browse:focus-visible,.remove:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:2px}.browse:disabled,.remove:disabled{opacity:.55;cursor:not-allowed}.input{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.files{display:grid;gap:4px;margin:8px 0 0;padding:0;list-style:none}.files:empty{display:none}.file{display:flex;align-items:center;gap:8px;min-width:0;padding:6px 8px;border:1px solid var(--spui-ui-stroke,#d1d1d1);border-radius:var(--spui-control-radius,4px)}.filename{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.size{flex:none;color:var(--spui-ui-muted,#616161);font-size:12px;font-variant-numeric:tabular-nums}.remove{min-width:32px;min-height:32px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:inherit;font:inherit;cursor:pointer}.status{margin-block-start:6px;color:var(--spui-semantic-error-text,var(--spui-ui-danger,#b10e1c));font-size:12px}.status:empty{display:none}:host([data-spui-appearance=glass]) .drop{backdrop-filter:var(--spui-card-backdrop,blur(12px) saturate(1.2))}@media(prefers-reduced-motion:reduce){.drop{transition:none}}@media(forced-colors:active){.drop,.file{border-color:CanvasText;background:Canvas;color:CanvasText}.drop[data-dragging=true]{outline:2px solid Highlight}.browse{border-color:ButtonText;background:ButtonFace;color:ButtonText}}`;
36
+ style.textContent = `${base}:host{display:block;min-width:0;color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424));font-family:var(--spui-font-family,inherit)}.label{display:block;margin-block-end:6px;font-size:14px;font-weight:600}.drop{box-sizing:border-box;display:grid;place-items:center;gap:6px;min-height:104px;padding:16px;border:1px dashed var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886));border-radius:var(--spui-control-radius,6px);background:var(--spui-ui-surface,var(--spui-semantic-input-background,#fff));text-align:center;transition:border-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),background-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}.drop[data-dragging=true]{border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.hint{color:var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161));font-size:12px}.browse{min-height:32px;padding:4px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,#8a8886));border-radius:var(--spui-control-radius,4px);background:var(--spui-ui-surface,#fff);color:inherit;font:inherit;cursor:pointer}.browse:hover:not(:disabled){background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.browse:focus-visible,.remove:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:2px}.browse:disabled,.remove:disabled{opacity:.55;cursor:not-allowed}.input{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.files{display:grid;gap:4px;margin:8px 0 0;padding:0;list-style:none}.files:empty{display:none}.file{display:flex;align-items:center;gap:8px;min-width:0;padding:6px 8px;border:1px solid var(--spui-ui-stroke,#d1d1d1);border-radius:var(--spui-control-radius,4px)}.filename{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.size{flex:none;color:var(--spui-ui-muted,#616161);font-size:12px;font-variant-numeric:tabular-nums}.remove{min-width:32px;min-height:32px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:inherit;font:inherit;cursor:pointer}.status{margin-block-start:6px;color:var(--spui-semantic-error-text,var(--spui-ui-danger,#b10e1c));font-size:12px}.status:empty{display:none}:host([data-spui-appearance=glass]) .drop,:host-context([data-spui-appearance=glass]) .drop{backdrop-filter:var(--spui-card-backdrop,blur(12px) saturate(1.2))}@media(prefers-reduced-motion:reduce){.drop{transition:none}}@media(forced-colors:active){.drop,.file{border-color:CanvasText;background:Canvas;color:CanvasText}.drop[data-dragging=true]{outline:2px solid Highlight}.browse{border-color:ButtonText;background:ButtonFace;color:ButtonText}}`;
37
37
  const label = document.createElement("label");
38
38
  label.className = "label";
39
39
  label.part.add("label");
@@ -17,6 +17,16 @@ export type FloatingModifiers = {
17
17
  };
18
18
  };
19
19
  export type FloatingAnchorRect = Pick<DOMRectReadOnly, "left" | "top" | "right" | "bottom" | "width" | "height">;
20
+ export type FloatingBoundary = Element | {
21
+ x: number;
22
+ y: number;
23
+ width: number;
24
+ height: number;
25
+ } | readonly Element[] | "clippingParents" | "scrollParent" | "window" | null;
26
+ export declare function getFloatingBoundary(boundary: FloatingBoundary | undefined, context: Element, viewport?: {
27
+ width: number;
28
+ height: number;
29
+ }): Pick<DOMRectReadOnly, "left" | "top" | "right" | "bottom"> | undefined;
20
30
  export declare function getFloatingPosition(anchor: FloatingAnchorRect, surface: Pick<DOMRectReadOnly, "width" | "height">, placement: FloatingPlacement, direction: "ltr" | "rtl", gap?: number, viewport?: {
21
31
  width: number;
22
32
  height: number;
@@ -1,3 +1,56 @@
1
+ export function getFloatingBoundary(boundary, context, viewport = { width: innerWidth, height: innerHeight }) {
2
+ if (boundary === undefined || boundary === null || boundary === "window")
3
+ return undefined;
4
+ const rectEdges = (rect) => {
5
+ const left = rect.left ?? rect.x ?? 0;
6
+ const top = rect.top ?? rect.y ?? 0;
7
+ return { left, top, right: left + rect.width, bottom: top + rect.height };
8
+ };
9
+ const isElement = (value) => Boolean(value && typeof value === "object" && value.nodeType === 1 && typeof value.getBoundingClientRect === "function");
10
+ if (Array.isArray(boundary)) {
11
+ const rects = boundary.map(element => rectEdges(element.getBoundingClientRect()));
12
+ if (!rects.length)
13
+ return undefined;
14
+ const left = Math.max(...rects.map(rect => rect.left));
15
+ const top = Math.max(...rects.map(rect => rect.top));
16
+ 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))) };
17
+ }
18
+ if (isElement(boundary))
19
+ return rectEdges(boundary.getBoundingClientRect());
20
+ if (typeof boundary === "object" && "width" in boundary && "height" in boundary)
21
+ return rectEdges(boundary);
22
+ if (boundary !== "clippingParents" && boundary !== "scrollParent")
23
+ return undefined;
24
+ const bounds = { left: 0, top: 0, right: viewport.width, bottom: viewport.height };
25
+ const view = context.ownerDocument.defaultView;
26
+ const parent = (current) => current.parentElement ?? (current.getRootNode() instanceof ShadowRoot ? current.getRootNode().host : null);
27
+ for (let current = parent(context); current; current = parent(current)) {
28
+ const style = view?.getComputedStyle(current);
29
+ if (!style)
30
+ continue;
31
+ const clipsX = /^(auto|scroll|hidden|clip|overlay)$/.test(style.overflowX);
32
+ const clipsY = /^(auto|scroll|hidden|clip|overlay)$/.test(style.overflowY);
33
+ const scrolls = /^(auto|scroll|hidden|overlay)$/.test(style.overflowX) || /^(auto|scroll|hidden|overlay)$/.test(style.overflowY);
34
+ if (boundary === "scrollParent" && !scrolls)
35
+ continue;
36
+ if (!clipsX && !clipsY)
37
+ continue;
38
+ const rect = current.getBoundingClientRect();
39
+ const left = rect.left + current.clientLeft;
40
+ const top = rect.top + current.clientTop;
41
+ if (boundary === "scrollParent")
42
+ return { left, top, right: left + current.clientWidth, bottom: top + current.clientHeight };
43
+ if (clipsX) {
44
+ bounds.left = Math.max(bounds.left, left);
45
+ bounds.right = Math.min(bounds.right, left + current.clientWidth);
46
+ }
47
+ if (clipsY) {
48
+ bounds.top = Math.max(bounds.top, top);
49
+ bounds.bottom = Math.min(bounds.bottom, top + current.clientHeight);
50
+ }
51
+ }
52
+ return { left: bounds.left, top: bounds.top, right: Math.max(bounds.left, bounds.right), bottom: Math.max(bounds.top, bounds.bottom) };
53
+ }
1
54
  export function getFloatingPosition(anchor, surface, placement, direction, gap = 8, viewport = { width: innerWidth, height: innerHeight }, align = "center", fallbackPlacements = [], pinned = false, flipBoundary, overflowBoundary, modifiers = {}) {
2
55
  const viewportBoundary = { left: 0, top: 0, right: viewport.width, bottom: viewport.height };
3
56
  const flipBounds = flipBoundary ?? viewportBoundary;
@@ -29,7 +29,7 @@ export function defineInfoButton() {
29
29
  render() {
30
30
  const shadow = this.attachShadow({ mode: "open" });
31
31
  const style = document.createElement("style");
32
- style.textContent = `:host{display:inline-flex;vertical-align:middle;line-height:1}:host([hidden]){display:none}button{display:inline-grid;place-items:center;box-sizing:border-box;width:var(--spui-info-button-size,20px);height:var(--spui-info-button-size,20px);padding:2px;border:1px solid transparent;border-radius:50%;background:transparent;color:var(--spui-info-button-color,var(--spui-ui-muted,var(--spui-semantic-body-text,#484644)));cursor:pointer;font:inherit}button:hover:not(:disabled){background:var(--spui-info-button-hover,var(--spui-ui-surface-hover,#f3f2f1));color:var(--spui-ui-accent,var(--spui-semantic-link,#0f6cbd))}button:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#005a9e));outline-offset:2px}button:disabled{opacity:.55;cursor:not-allowed}svg{width:calc(var(--spui-info-button-size,20px) * .8);height:calc(var(--spui-info-button-size,20px) * .8);fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;pointer-events:none}:host([size=small]){--spui-info-button-size:16px}:host([size=large]){--spui-info-button-size:24px}:host([data-spui-appearance=glass]) button{backdrop-filter:blur(8px)}@media(forced-colors:active){button{border-color:ButtonText;color:ButtonText}button:focus-visible{outline-color:Highlight}}`;
32
+ style.textContent = `:host{display:inline-flex;vertical-align:middle;line-height:1}:host([hidden]){display:none}button{display:inline-grid;place-items:center;box-sizing:border-box;width:var(--spui-info-button-size,20px);height:var(--spui-info-button-size,20px);padding:2px;border:1px solid transparent;border-radius:50%;background:transparent;color:var(--spui-info-button-color,var(--spui-ui-muted,var(--spui-semantic-body-text,#484644)));cursor:pointer;font:inherit}button:hover:not(:disabled){background:var(--spui-info-button-hover,var(--spui-ui-surface-hover,#f3f2f1));color:var(--spui-ui-accent,var(--spui-semantic-link,#0f6cbd))}button:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#005a9e));outline-offset:2px}button:disabled{opacity:.55;cursor:not-allowed}svg{width:calc(var(--spui-info-button-size,20px) * .8);height:calc(var(--spui-info-button-size,20px) * .8);fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;pointer-events:none}:host([size=small]){--spui-info-button-size:16px}:host([size=large]){--spui-info-button-size:24px}:host([data-spui-appearance=glass]) button,:host-context([data-spui-appearance=glass]) button{backdrop-filter:blur(8px)}@media(forced-colors:active){button{border-color:ButtonText;color:ButtonText}button:focus-visible{outline-color:Highlight}}`;
33
33
  const popover = document.createElement("spui-popover");
34
34
  this.popoverElement = popover;
35
35
  const trigger = document.createElement("button");