@spfx-fast/sharepoint-ui 0.4.0 → 0.4.2

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.
package/dist/react.js CHANGED
@@ -51,7 +51,7 @@ import { defineTooltip } from "./elements/tooltip.js";
51
51
  import { definePopover } from "./elements/popover.js";
52
52
  import { defineTeachingPopover as defineNativeTeachingPopover } from "./elements/teaching-popover.js";
53
53
  import { defineMenu, defineMenuItem, defineMenuItemLink, defineMenuDivider, defineMenuGroup, defineMenuGroupHeader, defineMenuList, defineMenuPopover, defineMenuSplitGroup, defineMenuTrigger, defineMenuBar as defineNativeMenuBar, defineMenuBarItem } from "./elements/menu.js";
54
- import { defineText } from "./elements/text.js";
54
+ import { getTextSizeStyles } from "./elements/text.js";
55
55
  import { defineToast, defineToastBody, defineToastFooter, defineToastTitle } from "./elements/toast.js";
56
56
  import { defineToaster } from "./elements/toaster.js";
57
57
  import { defineSearchBox } from "./elements/search.js";
@@ -208,24 +208,33 @@ function isComposedDescendant(root, target) {
208
208
  }
209
209
  return false;
210
210
  }
211
+ const nativeResourceEventNames = [
212
+ ["abort", "onAbort"], ["canplay", "onCanPlay"], ["canplaythrough", "onCanPlayThrough"], ["durationchange", "onDurationChange"], ["emptied", "onEmptied"], ["encrypted", "onEncrypted"], ["ended", "onEnded"], ["error", "onError"], ["loadeddata", "onLoadedData"], ["loadedmetadata", "onLoadedMetadata"], ["load", "onLoad"], ["loadstart", "onLoadStart"], ["pause", "onPause"], ["play", "onPlay"], ["playing", "onPlaying"], ["progress", "onProgress"], ["ratechange", "onRateChange"], ["seeked", "onSeeked"], ["seeking", "onSeeking"], ["stalled", "onStalled"], ["suspend", "onSuspend"], ["timeupdate", "onTimeUpdate"], ["volumechange", "onVolumeChange"], ["waiting", "onWaiting"],
213
+ ].flatMap(([eventName, prop]) => [
214
+ { eventName, prop: `${prop}Capture`, capture: true, kind: "resource" },
215
+ { eventName, prop, capture: false, kind: "resource" },
216
+ ]);
211
217
  const nativeEventBindings = [
212
- ["click", "onClick", false, "mouse"], ["click", "onClickCapture", true, "mouse"],
213
- ["keydown", "onKeyDown", false, "keyboard"], ["keydown", "onKeyDownCapture", true, "keyboard"], ["keyup", "onKeyUp", false, "keyboard"], ["keyup", "onKeyUpCapture", true, "keyboard"], ["keypress", "onKeyPress", false, "keyboard"], ["keypress", "onKeyPressCapture", true, "keyboard"],
214
- ["focusin", "onFocus", false, "focus"], ["focusin", "onFocusCapture", true, "focus"], ["focusout", "onBlur", false, "focus"], ["focusout", "onBlurCapture", true, "focus"],
215
- ["auxclick", "onAuxClick", false, "mouse"], ["auxclick", "onAuxClickCapture", true, "mouse"], ["contextmenu", "onContextMenu", false, "mouse"], ["contextmenu", "onContextMenuCapture", true, "mouse"], ["dblclick", "onDoubleClick", false, "mouse"], ["dblclick", "onDoubleClickCapture", true, "mouse"], ["mousedown", "onMouseDown", false, "mouse"], ["mousedown", "onMouseDownCapture", true, "mouse"], ["mousemove", "onMouseMove", false, "mouse"], ["mousemove", "onMouseMoveCapture", true, "mouse"], ["mouseout", "onMouseOut", false, "mouse"], ["mouseout", "onMouseOutCapture", true, "mouse"], ["mouseover", "onMouseOver", false, "mouse"], ["mouseover", "onMouseOverCapture", true, "mouse"], ["mouseup", "onMouseUp", false, "mouse"], ["mouseup", "onMouseUpCapture", true, "mouse"],
216
- ["gotpointercapture", "onGotPointerCapture", false, "pointer"], ["gotpointercapture", "onGotPointerCaptureCapture", true, "pointer"], ["lostpointercapture", "onLostPointerCapture", false, "pointer"], ["lostpointercapture", "onLostPointerCaptureCapture", true, "pointer"], ["pointercancel", "onPointerCancel", false, "pointer"], ["pointercancel", "onPointerCancelCapture", true, "pointer"], ["pointerdown", "onPointerDown", false, "pointer"], ["pointerdown", "onPointerDownCapture", true, "pointer"], ["pointermove", "onPointerMove", false, "pointer"], ["pointermove", "onPointerMoveCapture", true, "pointer"], ["pointerout", "onPointerOut", false, "pointer"], ["pointerout", "onPointerOutCapture", true, "pointer"], ["pointerover", "onPointerOver", false, "pointer"], ["pointerover", "onPointerOverCapture", true, "pointer"], ["pointerup", "onPointerUp", false, "pointer"], ["pointerup", "onPointerUpCapture", true, "pointer"],
217
- ["drag", "onDrag", false, "drag"], ["drag", "onDragCapture", true, "drag"], ["dragend", "onDragEnd", false, "drag"], ["dragend", "onDragEndCapture", true, "drag"], ["dragenter", "onDragEnter", false, "drag"], ["dragenter", "onDragEnterCapture", true, "drag"], ["dragexit", "onDragExit", false, "drag"], ["dragexit", "onDragExitCapture", true, "drag"], ["dragleave", "onDragLeave", false, "drag"], ["dragleave", "onDragLeaveCapture", true, "drag"], ["dragover", "onDragOver", false, "drag"], ["dragover", "onDragOverCapture", true, "drag"], ["dragstart", "onDragStart", false, "drag"], ["dragstart", "onDragStartCapture", true, "drag"], ["drop", "onDrop", false, "drag"], ["drop", "onDropCapture", true, "drag"],
218
- ["copy", "onCopy", false, "clipboard"], ["copy", "onCopyCapture", true, "clipboard"], ["cut", "onCut", false, "clipboard"], ["cut", "onCutCapture", true, "clipboard"], ["paste", "onPaste", false, "clipboard"], ["paste", "onPasteCapture", true, "clipboard"],
219
- ["compositionend", "onCompositionEnd", false, "composition"], ["compositionend", "onCompositionEndCapture", true, "composition"], ["compositionstart", "onCompositionStart", false, "composition"], ["compositionstart", "onCompositionStartCapture", true, "composition"], ["compositionupdate", "onCompositionUpdate", false, "composition"], ["compositionupdate", "onCompositionUpdateCapture", true, "composition"],
220
- ["beforeinput", "onBeforeInput", false, "input"], ["beforeinput", "onBeforeInputCapture", true, "input"], ["input", "onInput", false, "input"], ["input", "onInputCapture", true, "input"],
221
- ["input", "onChange", false, "change"], ["input", "onChangeCapture", true, "change"],
222
- ["scroll", "onScroll", false, "scroll"], ["scroll", "onScrollCapture", true, "scroll"],
223
- ["invalid", "onInvalid", false, "invalid"], ["invalid", "onInvalidCapture", true, "invalid"],
224
- ["touchcancel", "onTouchCancel", false, "touch"], ["touchcancel", "onTouchCancelCapture", true, "touch"], ["touchend", "onTouchEnd", false, "touch"], ["touchend", "onTouchEndCapture", true, "touch"], ["touchmove", "onTouchMove", false, "touch"], ["touchmove", "onTouchMoveCapture", true, "touch"], ["touchstart", "onTouchStart", false, "touch"], ["touchstart", "onTouchStartCapture", true, "touch"],
225
- ["wheel", "onWheel", false, "wheel"], ["wheel", "onWheelCapture", true, "wheel"],
226
- ["animationstart", "onAnimationStart", false, "animation"], ["animationstart", "onAnimationStartCapture", true, "animation"], ["animationend", "onAnimationEnd", false, "animation"], ["animationend", "onAnimationEndCapture", true, "animation"], ["animationiteration", "onAnimationIteration", false, "animation"], ["animationiteration", "onAnimationIterationCapture", true, "animation"],
227
- ["transitionend", "onTransitionEnd", false, "transition"], ["transitionend", "onTransitionEndCapture", true, "transition"],
228
- ].map(([eventName, prop, capture, kind]) => ({ eventName, prop, capture, kind }));
218
+ ...nativeResourceEventNames,
219
+ ...[
220
+ ["click", "onClick", false, "mouse"], ["click", "onClickCapture", true, "mouse"],
221
+ ["keydown", "onKeyDown", false, "keyboard"], ["keydown", "onKeyDownCapture", true, "keyboard"], ["keyup", "onKeyUp", false, "keyboard"], ["keyup", "onKeyUpCapture", true, "keyboard"], ["keypress", "onKeyPress", false, "keyboard"], ["keypress", "onKeyPressCapture", true, "keyboard"],
222
+ ["focusin", "onFocus", false, "focus"], ["focusin", "onFocusCapture", true, "focus"], ["focusout", "onBlur", false, "focus"], ["focusout", "onBlurCapture", true, "focus"],
223
+ ["auxclick", "onAuxClick", false, "mouse"], ["auxclick", "onAuxClickCapture", true, "mouse"], ["contextmenu", "onContextMenu", false, "mouse"], ["contextmenu", "onContextMenuCapture", true, "mouse"], ["dblclick", "onDoubleClick", false, "mouse"], ["dblclick", "onDoubleClickCapture", true, "mouse"], ["mousedown", "onMouseDown", false, "mouse"], ["mousedown", "onMouseDownCapture", true, "mouse"], ["mousemove", "onMouseMove", false, "mouse"], ["mousemove", "onMouseMoveCapture", true, "mouse"], ["mouseout", "onMouseOut", false, "mouse"], ["mouseout", "onMouseOutCapture", true, "mouse"], ["mouseover", "onMouseOver", false, "mouse"], ["mouseover", "onMouseOverCapture", true, "mouse"], ["mouseup", "onMouseUp", false, "mouse"], ["mouseup", "onMouseUpCapture", true, "mouse"],
224
+ ["gotpointercapture", "onGotPointerCapture", false, "pointer"], ["gotpointercapture", "onGotPointerCaptureCapture", true, "pointer"], ["lostpointercapture", "onLostPointerCapture", false, "pointer"], ["lostpointercapture", "onLostPointerCaptureCapture", true, "pointer"], ["pointercancel", "onPointerCancel", false, "pointer"], ["pointercancel", "onPointerCancelCapture", true, "pointer"], ["pointerdown", "onPointerDown", false, "pointer"], ["pointerdown", "onPointerDownCapture", true, "pointer"], ["pointermove", "onPointerMove", false, "pointer"], ["pointermove", "onPointerMoveCapture", true, "pointer"], ["pointerout", "onPointerOut", false, "pointer"], ["pointerout", "onPointerOutCapture", true, "pointer"], ["pointerover", "onPointerOver", false, "pointer"], ["pointerover", "onPointerOverCapture", true, "pointer"], ["pointerup", "onPointerUp", false, "pointer"], ["pointerup", "onPointerUpCapture", true, "pointer"],
225
+ ["drag", "onDrag", false, "drag"], ["drag", "onDragCapture", true, "drag"], ["dragend", "onDragEnd", false, "drag"], ["dragend", "onDragEndCapture", true, "drag"], ["dragenter", "onDragEnter", false, "drag"], ["dragenter", "onDragEnterCapture", true, "drag"], ["dragexit", "onDragExit", false, "drag"], ["dragexit", "onDragExitCapture", true, "drag"], ["dragleave", "onDragLeave", false, "drag"], ["dragleave", "onDragLeaveCapture", true, "drag"], ["dragover", "onDragOver", false, "drag"], ["dragover", "onDragOverCapture", true, "drag"], ["dragstart", "onDragStart", false, "drag"], ["dragstart", "onDragStartCapture", true, "drag"], ["drop", "onDrop", false, "drag"], ["drop", "onDropCapture", true, "drag"],
226
+ ["copy", "onCopy", false, "clipboard"], ["copy", "onCopyCapture", true, "clipboard"], ["cut", "onCut", false, "clipboard"], ["cut", "onCutCapture", true, "clipboard"], ["paste", "onPaste", false, "clipboard"], ["paste", "onPasteCapture", true, "clipboard"],
227
+ ["compositionend", "onCompositionEnd", false, "composition"], ["compositionend", "onCompositionEndCapture", true, "composition"], ["compositionstart", "onCompositionStart", false, "composition"], ["compositionstart", "onCompositionStartCapture", true, "composition"], ["compositionupdate", "onCompositionUpdate", false, "composition"], ["compositionupdate", "onCompositionUpdateCapture", true, "composition"],
228
+ ["beforeinput", "onBeforeInput", false, "input"], ["beforeinput", "onBeforeInputCapture", true, "input"], ["input", "onInput", false, "input"], ["input", "onInputCapture", true, "input"],
229
+ ["input", "onChange", false, "change"], ["input", "onChangeCapture", true, "change"],
230
+ ["scroll", "onScroll", false, "scroll"], ["scroll", "onScrollCapture", true, "scroll"],
231
+ ["invalid", "onInvalid", false, "invalid"], ["invalid", "onInvalidCapture", true, "invalid"],
232
+ ["touchcancel", "onTouchCancel", false, "touch"], ["touchcancel", "onTouchCancelCapture", true, "touch"], ["touchend", "onTouchEnd", false, "touch"], ["touchend", "onTouchEndCapture", true, "touch"], ["touchmove", "onTouchMove", false, "touch"], ["touchmove", "onTouchMoveCapture", true, "touch"], ["touchstart", "onTouchStart", false, "touch"], ["touchstart", "onTouchStartCapture", true, "touch"],
233
+ ["wheel", "onWheel", false, "wheel"], ["wheel", "onWheelCapture", true, "wheel"],
234
+ ["animationstart", "onAnimationStart", false, "animation"], ["animationstart", "onAnimationStartCapture", true, "animation"], ["animationend", "onAnimationEnd", false, "animation"], ["animationend", "onAnimationEndCapture", true, "animation"], ["animationiteration", "onAnimationIteration", false, "animation"], ["animationiteration", "onAnimationIterationCapture", true, "animation"],
235
+ ["transitionend", "onTransitionEnd", false, "transition"], ["transitionend", "onTransitionEndCapture", true, "transition"],
236
+ ].map(([eventName, prop, capture, kind]) => ({ eventName, prop, capture, kind })),
237
+ ];
229
238
  const nativeEventPropNames = new Set(nativeEventBindings.map(binding => binding.prop));
230
239
  function withoutNativeControlEventProps(props) {
231
240
  const hostProps = { ...props };
@@ -270,8 +279,8 @@ function useNativeControlEvents(ref, selector, onClick, onClickCapture, events,
270
279
  const handler = handlersRef.current[binding.prop];
271
280
  handler?.(bridged);
272
281
  };
273
- const listenerRoot = binding.kind === "scroll" ? (binding.capture ? shadowRoot : scrollControl ?? shadowRoot) : host;
274
- const listenerCapture = binding.capture;
282
+ const listenerRoot = binding.kind === "resource" ? shadowRoot : binding.kind === "scroll" ? (binding.capture ? shadowRoot : scrollControl ?? shadowRoot) : host;
283
+ const listenerCapture = binding.kind === "resource" || binding.capture;
275
284
  listenerRoot.addEventListener(binding.eventName, listener, listenerCapture);
276
285
  removeListeners.push(() => listenerRoot.removeEventListener(binding.eventName, listener, listenerCapture));
277
286
  }
@@ -504,9 +513,29 @@ export function SharePointUIProvider({ children, lang, dir, appearance, baseAppe
504
513
  const value = { lang: lang ?? parent.lang, dir: dir ?? parent.dir, appearance: resolvedAppearance, baseAppearance: resolvedBaseAppearance, density: resolvedDensity, theme: mergedTheme, hasThemeValues, tokens: mergedTokens, fluentTokens: mergedFluentTokens, styleTokens, fluentTokenStyles, hostStyle, providesCssInheritance: true, strings: { ...parent.strings, ...strings } };
505
514
  return _jsx(UIContext.Provider, { value: value, children: _jsx("div", { "data-spui-provider": "", "data-spui-appearance": resolvedAppearance, "data-spui-base-appearance": resolvedBaseAppearance, lang: lang ?? parent.lang, dir: dir ?? parent.dir, style: { ...hostStyle, display: "contents" }, children: children }) });
506
515
  }
507
- export const Text = /* @__PURE__ */ React.forwardRef(function Text({ as = "span", size = 300, weight, font = "base", align = "start", italic = false, underline = false, strikethrough = false, truncate = false, wrap = true, block = false, children, ...props }, forwardedRef) {
508
- ensureDefined(defineText);
509
- return React.createElement("spui-text", useCustomElementProps({ ...props, ref: forwardedRef, as, size, weight, font, align, italic: italic || undefined, underline: underline || undefined, strikethrough: strikethrough || undefined, truncate: truncate || undefined, wrap: wrap ? undefined : "false", block: block || undefined }), children);
516
+ export const Text = /* @__PURE__ */ React.forwardRef(function Text({ as = "span", size = 300, weight, font = "base", align = "start", italic = false, underline = false, strikethrough = false, truncate = false, wrap = true, block = false, children, style, ...props }, forwardedRef) {
517
+ const defaultBold = as === "strong" || as === "b";
518
+ const defaultItalic = as === "em" || as === "i";
519
+ const sizeStyles = getTextSizeStyles(size);
520
+ const textStyle = {
521
+ boxSizing: "border-box",
522
+ margin: 0,
523
+ color: "inherit",
524
+ ...sizeStyles,
525
+ fontFamily: font === "monospace" ? "var(--spui-font-family-mono,var(--fontFamilyMonospace,ui-monospace,monospace))" : font === "numeric" ? "var(--fontFamilyNumeric,var(--fontFamilyBase,inherit))" : "var(--spui-font-family,var(--fontFamilyBase,inherit))",
526
+ fontWeight: `var(--fontWeight${weight ? weight[0].toUpperCase() + weight.slice(1) : defaultBold ? "Bold" : "Regular"},${weight === "medium" ? 500 : weight === "semibold" ? 600 : weight === "bold" || (!weight && defaultBold) ? 700 : 400})`,
527
+ fontVariantNumeric: font === "numeric" ? "tabular-nums" : undefined,
528
+ textAlign: align,
529
+ fontStyle: italic || defaultItalic ? "italic" : "normal",
530
+ textDecorationLine: [underline && "underline", strikethrough && "line-through"].filter(Boolean).join(" ") || "none",
531
+ textUnderlineOffset: underline ? ".15em" : undefined,
532
+ whiteSpace: wrap ? as === "pre" ? "pre-wrap" : "normal" : "nowrap",
533
+ overflowWrap: wrap ? "anywhere" : "normal",
534
+ display: block ? "block" : undefined,
535
+ ...(truncate ? { display: "inline-block", maxWidth: "100%", verticalAlign: "bottom", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", overflowWrap: "normal" } : {}),
536
+ ...style,
537
+ };
538
+ return React.createElement(as, useHostProps({ ...props, ref: forwardedRef, style: textStyle }), children);
510
539
  });
511
540
  const textPreset = (props, size, weight = "regular") => React.createElement(Text, { ...props, size, weight, font: "base" });
512
541
  export function Body1(props) { return textPreset(props, 300); }
@@ -526,17 +555,17 @@ export function Subtitle2Stronger(props) { return textPreset(props, 400, "bold")
526
555
  export function Title1(props) { return textPreset(props, 800, "semibold"); }
527
556
  export function Title2(props) { return textPreset(props, 700, "semibold"); }
528
557
  export function Title3(props) { return textPreset(props, 600, "semibold"); }
529
- export function Label({ htmlFor, size = "medium", weight = "regular", required = false, disabled = false, children, style, ...props }) {
558
+ export const Label = /* @__PURE__ */ React.forwardRef(function Label({ htmlFor, size = "medium", weight = "regular", required = false, disabled = false, children, style, ...props }, forwardedRef) {
530
559
  if (typeof document !== "undefined")
531
560
  ensureLabelStyles(document);
532
561
  const labelStyle = { ...getLabelStyle(size, disabled, weight), ...style };
533
- const hostProps = useHostProps({ ...props, className: ["spui-label", props.className].filter(Boolean).join(" "), htmlFor, style: labelStyle, "data-size": size, "data-disabled": String(disabled) });
562
+ const hostProps = useHostProps({ ...props, ref: forwardedRef, className: ["spui-label", props.className].filter(Boolean).join(" "), htmlFor, style: labelStyle, "data-size": size, "data-disabled": String(disabled) });
534
563
  const requiredStyle = { color: disabled ? "var(--spui-ui-foreground-disabled,var(--spui-semantic-disabled-text,var(--colorNeutralForegroundDisabled,#bdbdbd)))" : "var(--spui-label-required-color,var(--colorPaletteRedForeground3,var(--spui-semantic-error-text,#c50f1f)))", paddingInlineStart: "var(--spui-label-required-gap,var(--spacingHorizontalXS,4px))" };
535
564
  const slotProps = required && typeof required === "object" && !Array.isArray(required) && !React.isValidElement(required) && !("$$typeof" in required) ? required : undefined;
536
565
  const requiredContent = required === true ? "*" : slotProps ? slotProps.children : required;
537
566
  const requiredMarker = !required ? null : React.createElement("span", { ...slotProps, "aria-hidden": slotProps?.["aria-hidden"] ?? true, className: ["spui-label-required", slotProps?.className].filter(Boolean).join(" "), style: { ...requiredStyle, ...slotProps?.style } }, requiredContent);
538
567
  return React.createElement("label", hostProps, children, requiredMarker);
539
- }
568
+ });
540
569
  export const InfoButton = /* @__PURE__ */ React.forwardRef(function InfoButton({ info, children, label, placement = "top", size = "medium", inline = true, popover, open, onOpenChange, ...props }, forwardedRef) {
541
570
  const context = React.useContext(UIContext);
542
571
  const ref = React.useRef(null);
@@ -949,8 +978,11 @@ export const Card = /* @__PURE__ */ React.forwardRef(function Card({ children, a
949
978
  export const SharePointCard = Card;
950
979
  export const CardHeader = /* @__PURE__ */ React.forwardRef(function CardHeader({ image, header, description, action, children, ...props }, forwardedRef) {
951
980
  ensureDefined(defineCardHeader);
981
+ const ref = React.useRef(null);
982
+ useExposeHostRef(ref, forwardedRef);
983
+ useNativeControlEvents(ref, ".layout", props.onClick, props.onClickCapture, props);
952
984
  const headerContent = header ?? children;
953
- return React.createElement("spui-card-header", useCustomElementProps({ ...props, ref: forwardedRef }), image == null ? null : React.createElement("span", { slot: "image" }, image), headerContent == null ? null : React.createElement("span", { slot: "header" }, headerContent), description == null ? null : React.createElement("span", { slot: "description" }, description), action == null ? null : React.createElement("span", { slot: "action" }, action));
985
+ return React.createElement("spui-card-header", nativeControlHostProps({ ...props, ref }), image == null ? null : React.createElement("span", { slot: "image" }, image), headerContent == null ? null : React.createElement("span", { slot: "header" }, headerContent), description == null ? null : React.createElement("span", { slot: "description" }, description), action == null ? null : React.createElement("span", { slot: "action" }, action));
954
986
  });
955
987
  export const CardFooter = /* @__PURE__ */ React.forwardRef(function CardFooter({ action, children, ...props }, forwardedRef) {
956
988
  ensureDefined(defineCardFooter);
@@ -958,7 +990,10 @@ export const CardFooter = /* @__PURE__ */ React.forwardRef(function CardFooter({
958
990
  });
959
991
  export const CardPreview = /* @__PURE__ */ React.forwardRef(function CardPreview({ logo, children, ...props }, forwardedRef) {
960
992
  ensureDefined(defineCardPreview);
961
- return React.createElement("spui-card-preview", useCustomElementProps({ ...props, ref: forwardedRef }), children, logo == null ? null : React.createElement("span", { slot: "logo" }, logo));
993
+ const ref = React.useRef(null);
994
+ useExposeHostRef(ref, forwardedRef);
995
+ useNativeControlEvents(ref, ".preview", props.onClick, props.onClickCapture, props);
996
+ return React.createElement("spui-card-preview", nativeControlHostProps({ ...props, ref }), children, logo == null ? null : React.createElement("span", { slot: "logo" }, logo));
962
997
  });
963
998
  export const ViewCard = /* @__PURE__ */ React.forwardRef(function ViewCard({ kind, title, subtitle, description, children, ...props }, forwardedRef) {
964
999
  ensureDefined(defineViewCard);
@@ -1275,10 +1310,10 @@ export const Drawer = /* @__PURE__ */ React.forwardRef(function Drawer({ type =
1275
1310
  export function DrawerHeader({ children }) {
1276
1311
  return React.createElement(React.Fragment, null, children);
1277
1312
  }
1278
- export function DrawerHeaderNavigation({ children, label, ...props }) {
1313
+ export const DrawerHeaderNavigation = /* @__PURE__ */ React.forwardRef(function DrawerHeaderNavigation({ children, label, ...props }, forwardedRef) {
1279
1314
  const context = React.useContext(UIContext);
1280
- return React.createElement("nav", useHostProps({ ...props, slot: "header-navigation", "aria-label": props["aria-label"] ?? label ?? context.strings.drawerNavigation ?? "Drawer navigation", style: { display: "flex", alignItems: "center", gap: 8, ...props.style } }), children);
1281
- }
1315
+ return React.createElement("nav", useHostProps({ ...props, ref: forwardedRef, slot: "header-navigation", "aria-label": props["aria-label"] ?? label ?? context.strings.drawerNavigation ?? "Drawer navigation", style: { display: "flex", alignItems: "center", gap: 8, ...props.style } }), children);
1316
+ });
1282
1317
  export function DrawerHeaderTitle({ children, action, heading, ...props }) {
1283
1318
  const headingElement = heading;
1284
1319
  const title = React.isValidElement(headingElement)
@@ -1286,12 +1321,12 @@ export function DrawerHeaderTitle({ children, action, heading, ...props }) {
1286
1321
  : React.createElement("h2", { slot: "title", "data-spui-drawer-title": "", style: { margin: 0 }, ...(heading ?? {}) }, children);
1287
1322
  return React.createElement(React.Fragment, null, React.createElement("div", useHostProps({ ...props, slot: "title", "data-spui-drawer-title": "", style: { display: "flex", alignItems: "center", ...props.style } }), title), action == null ? null : React.createElement("span", { slot: "header-action", style: { display: "inline-flex", alignItems: "center" } }, action));
1288
1323
  }
1289
- export function DrawerBody({ children, ...props }) {
1290
- return React.createElement("div", useHostProps({ ...props, style: { minWidth: 0, ...props.style } }), children);
1291
- }
1292
- export function DrawerFooter({ children, ...props }) {
1293
- return React.createElement("div", useHostProps({ ...props, slot: "actions", style: { display: "flex", alignItems: "center", justifyContent: "flex-end", flexWrap: "wrap", gap: 8, ...props.style } }), children);
1294
- }
1324
+ export const DrawerBody = /* @__PURE__ */ React.forwardRef(function DrawerBody({ children, ...props }, forwardedRef) {
1325
+ return React.createElement("div", useHostProps({ ...props, ref: forwardedRef, style: { minWidth: 0, ...props.style } }), children);
1326
+ });
1327
+ export const DrawerFooter = /* @__PURE__ */ React.forwardRef(function DrawerFooter({ children, ...props }, forwardedRef) {
1328
+ return React.createElement("div", useHostProps({ ...props, ref: forwardedRef, slot: "actions", style: { display: "flex", alignItems: "center", justifyContent: "flex-end", flexWrap: "wrap", gap: 8, ...props.style } }), children);
1329
+ });
1295
1330
  export const InlineDrawer = /* @__PURE__ */ React.forwardRef(function InlineDrawer({ open = false, title, position = "start", size = "small", separator = false, unmountOnClose = true, surfaceMotion, actions, children, ...props }, forwardedRef) {
1296
1331
  const context = React.useContext(UIContext);
1297
1332
  ensureDefined(defineInlineDrawer);
@@ -1927,9 +1962,9 @@ export const TagPickerInput = /* @__PURE__ */ React.forwardRef(function TagPicke
1927
1962
  export function TagPickerList({ children }) {
1928
1963
  return React.createElement(React.Fragment, null, children);
1929
1964
  }
1930
- export function TagPickerButton({ children, appearance = "outline", size = "medium", disabled = false, ...props }) {
1931
- return React.createElement("button", useCustomElementProps({ ...props, slot: "button", type: "button", "data-appearance": appearance, "data-size": size, disabled: disabled || undefined }), children);
1932
- }
1965
+ export const TagPickerButton = /* @__PURE__ */ React.forwardRef(function TagPickerButton({ children, appearance = "outline", size = "medium", disabled = false, ...props }, forwardedRef) {
1966
+ return React.createElement("button", useHostProps({ ...props, ref: forwardedRef, slot: "button", type: "button", "data-appearance": appearance, "data-size": size, disabled: disabled || undefined }), children);
1967
+ });
1933
1968
  export const TagPickerOption = /* @__PURE__ */ React.forwardRef(function TagPickerOption({ value, text, label, group, media, secondaryContent, disabled = false, children, ...props }, forwardedRef) {
1934
1969
  return React.createElement("spui-tag-picker-option", useCustomElementProps({ ref: forwardedRef, ...props, value, text, label, group, disabled: disabled || undefined }), media == null ? null : React.createElement("span", { slot: "media" }, media), React.createElement("span", { slot: "label" }, children), secondaryContent == null ? null : React.createElement("span", { slot: "secondary-content" }, secondaryContent));
1935
1970
  });
@@ -2995,7 +3030,10 @@ export const MenuGroupHeader = /* @__PURE__ */ React.forwardRef(function MenuGro
2995
3030
  });
2996
3031
  export const Avatar = /* @__PURE__ */ React.forwardRef(function Avatar({ name, image, initials, size = 32, shape = "circular", color = "neutral", active, activeAppearance = "ring", idForColor, decorative = false, icon, badge, children, ...props }, forwardedRef) {
2997
3032
  ensureDefined(defineAvatar);
2998
- return React.createElement("spui-avatar", useCustomElementProps({ ...props, ref: forwardedRef, name, image, initials, size, shape, color, active: active === "unset" ? undefined : active, "active-appearance": activeAppearance, "id-for-color": idForColor, decorative: decorative || undefined }), icon || children ? React.createElement("span", { slot: "icon" }, icon ?? children) : null, badge ? React.createElement("span", { slot: "badge" }, badge) : null);
3033
+ const ref = React.useRef(null);
3034
+ useExposeHostRef(ref, forwardedRef);
3035
+ useNativeControlEvents(ref, ".surface", props.onClick, props.onClickCapture, props);
3036
+ return React.createElement("spui-avatar", nativeControlHostProps({ ...props, ref, name, image, initials, size, shape, color, active: active === "unset" ? undefined : active, "active-appearance": activeAppearance, "id-for-color": idForColor, decorative: decorative || undefined }), icon || children ? React.createElement("span", { slot: "icon" }, icon ?? children) : null, badge ? React.createElement("span", { slot: "badge" }, badge) : null);
2999
3037
  });
3000
3038
  export function AvatarGroupProvider({ value, children }) {
3001
3039
  return React.createElement(AvatarGroupContext.Provider, { value }, React.createElement(AvatarGroupSizeContext.Provider, { value: value.size }, React.createElement(AvatarGroupOverflowContext.Provider, { value: Boolean(value.isOverflow) }, children)));
@@ -3008,13 +3046,14 @@ export const AvatarGroup = /* @__PURE__ */ React.forwardRef(function AvatarGroup
3008
3046
  const ref = React.useRef(null);
3009
3047
  useExposeHostRef(ref, forwardedRef);
3010
3048
  ;
3049
+ useNativeControlEvents(ref, ".group", props.onClick, props.onClickCapture, props);
3011
3050
  ensureDefined(defineAvatarGroup);
3012
3051
  useSpuiEvent(ref, "spui-avatar-group-expanded-change", detail => onExpandedChange?.(Boolean(detail.expanded)));
3013
3052
  React.useLayoutEffect(() => {
3014
3053
  if (ref.current && expanded !== undefined)
3015
3054
  ref.current.expanded = expanded;
3016
3055
  }, [expanded]);
3017
- return React.createElement(AvatarGroupSizeContext.Provider, { value: resolvedSize }, React.createElement("spui-avatar-group", useCustomElementProps({
3056
+ return React.createElement(AvatarGroupSizeContext.Provider, { value: resolvedSize }, React.createElement("spui-avatar-group", nativeControlHostProps({
3018
3057
  ...props,
3019
3058
  ref,
3020
3059
  label: label ?? context.strings.people ?? "People",
@@ -3086,10 +3125,13 @@ export function AvatarGroupPopover({ children, count, indicator, label, triggerL
3086
3125
  }
3087
3126
  export const Persona = /* @__PURE__ */ React.forwardRef(function Persona({ name, image, initials, primaryText, secondaryText, tertiaryText, quaternaryText, presence, presenceLabel, size = "medium", color = "neutral", textPosition = "after", textAlignment = "start", presenceOnly = false, avatar, children, ...props }, forwardedRef) {
3088
3127
  ensureDefined(definePersona);
3128
+ const ref = React.useRef(null);
3129
+ useExposeHostRef(ref, forwardedRef);
3130
+ useNativeControlEvents(ref, ".layout", props.onClick, props.onClickCapture, props);
3089
3131
  const textSlot = (node, slot) => node == null ? null : React.isValidElement(node)
3090
3132
  ? React.cloneElement(node, { slot })
3091
3133
  : React.createElement("span", { slot }, node);
3092
- return React.createElement("spui-persona", useCustomElementProps({ ref: forwardedRef, ...props, name, image, initials, "secondary-text": typeof secondaryText === "string" ? secondaryText : undefined, "tertiary-text": typeof tertiaryText === "string" ? tertiaryText : undefined, presence, "presence-label": presenceLabel, size, color, "text-position": textPosition, "text-alignment": textAlignment, "presence-only": presenceOnly || undefined }), textSlot(primaryText, "primary-text"), textSlot(secondaryText, "secondary-text"), textSlot(tertiaryText, "tertiary-text"), textSlot(quaternaryText, "quaternary-text"), avatar === undefined ? null : React.createElement("span", { slot: "avatar" }, avatar), children === undefined ? null : React.createElement("span", { slot: "details" }, children));
3134
+ return React.createElement("spui-persona", nativeControlHostProps({ ref, ...props, name, image, initials, "secondary-text": typeof secondaryText === "string" ? secondaryText : undefined, "tertiary-text": typeof tertiaryText === "string" ? tertiaryText : undefined, presence, "presence-label": presenceLabel, size, color, "text-position": textPosition, "text-alignment": textAlignment, "presence-only": presenceOnly || undefined }), textSlot(primaryText, "primary-text"), textSlot(secondaryText, "secondary-text"), textSlot(tertiaryText, "tertiary-text"), textSlot(quaternaryText, "quaternary-text"), avatar === undefined ? null : React.createElement("span", { slot: "avatar" }, avatar), children === undefined ? null : React.createElement("span", { slot: "details" }, children));
3093
3135
  });
3094
3136
  const VirtualizerScrollViewRootContext = React.createContext(null);
3095
3137
  function mergeVirtualizerRootProps(slotProps, rootProps) {
@@ -5554,7 +5596,7 @@ export const TextField = /* @__PURE__ */ React.forwardRef(function TextField(inp
5554
5596
  return React.createElement("spui-field", useCustomElementProps({ ...props, ref, label, value }));
5555
5597
  });
5556
5598
  /** Pair one form control with a theme-aware label, hint, and validation message. */
5557
- export function Field({ children, label, hint, validationMessage, validationMessageIcon, validationState, required, disabled, orientation = "vertical", size = "medium", className, style, ...props }) {
5599
+ export const Field = /* @__PURE__ */ React.forwardRef(function Field({ children, label, hint, validationMessage, validationMessageIcon, validationState, required, disabled, orientation = "vertical", size = "medium", className, style, ...props }, forwardedRef) {
5558
5600
  const generatedId = React.useId();
5559
5601
  const initialControl = React.isValidElement(children) && children.type !== React.Fragment ? children : undefined;
5560
5602
  const initialControlProps = initialControl?.props ?? {};
@@ -5636,8 +5678,8 @@ export function Field({ children, label, hint, validationMessage, validationMess
5636
5678
  hintId,
5637
5679
  disabled: Boolean(disabled || controlProps.disabled),
5638
5680
  };
5639
- return _jsxs("div", { ...useHostProps({ ...props, className: ["spui-form-field", className].filter(Boolean).join(" "), style: gridStyle, "data-orientation": orientation, "data-size": size, "data-validation-state": state }), children: [label == null ? null : _jsx(Label, { id: labelId, htmlFor: controlId, size: size, required: requiredValue, disabled: Boolean(disabled || controlProps.disabled), style: { gridArea: orientation === "horizontal" ? "1 / 1 / span 3 / 2" : undefined }, children: label }), _jsx("div", { style: { gridArea: orientation === "horizontal" ? "1 / 2 / span 3 / 3" : undefined, minWidth: 0 }, children: _jsx(FieldContext.Provider, { value: fieldContextValue, children: enhancedControl }) }), hint == null ? null : _jsx("div", { id: hintId, style: { gridArea: orientation === "horizontal" ? "2 / 2" : undefined, color: "var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161))", fontSize: "var(--spui-field-hint-size,12px)" }, children: hint }), !hasValidationMessage ? null : _jsxs("div", { id: messageId, "data-field-validation": state, role: state === "error" || state === "warning" ? "alert" : undefined, style: { gridArea: orientation === "horizontal" ? "3 / 2" : undefined, display: "flex", alignItems: "baseline", gap: 6, color: tokens?.foreground, fontSize: "var(--spui-field-message-size,12px)" }, children: [state === "none" ? null : _jsx("span", { "data-slot": "validationMessageIcon", "aria-hidden": "true", children: validationMessageIcon ?? (state === "success" ? "✓" : "!") }), validationMessage] })] });
5640
- }
5681
+ return _jsxs("div", { ...useHostProps({ ...props, ref: forwardedRef, className: ["spui-form-field", className].filter(Boolean).join(" "), style: gridStyle, "data-orientation": orientation, "data-size": size, "data-validation-state": state }), children: [label == null ? null : _jsx(Label, { id: labelId, htmlFor: controlId, size: size, required: requiredValue, disabled: Boolean(disabled || controlProps.disabled), style: { gridArea: orientation === "horizontal" ? "1 / 1 / span 3 / 2" : undefined }, children: label }), _jsx("div", { style: { gridArea: orientation === "horizontal" ? "1 / 2 / span 3 / 3" : undefined, minWidth: 0 }, children: _jsx(FieldContext.Provider, { value: fieldContextValue, children: enhancedControl }) }), hint == null ? null : _jsx("div", { id: hintId, style: { gridArea: orientation === "horizontal" ? "2 / 2" : undefined, color: "var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161))", fontSize: "var(--spui-field-hint-size,12px)" }, children: hint }), !hasValidationMessage ? null : _jsxs("div", { id: messageId, "data-field-validation": state, role: state === "error" || state === "warning" ? "alert" : undefined, style: { gridArea: orientation === "horizontal" ? "3 / 2" : undefined, display: "flex", alignItems: "baseline", gap: 6, color: tokens?.foreground, fontSize: "var(--spui-field-message-size,12px)" }, children: [state === "none" ? null : _jsx("span", { "data-slot": "validationMessageIcon", "aria-hidden": "true", children: validationMessageIcon ?? (state === "success" ? "✓" : "!") }), validationMessage] })] });
5682
+ });
5641
5683
  /** Bare input primitive. Supply aria-label or aria-labelledby; use TextField when a shadow-safe visible label is needed. */
5642
5684
  export const Input = /* @__PURE__ */ React.forwardRef(function Input(inputProps, forwardedRef) {
5643
5685
  const { type = "text", value, defaultValue, checked, defaultChecked, input: inputControl, onValueChange, onChange, contentBefore, contentAfter, size = "medium", appearance = "outline", disabled, required, readOnly, placeholder, capture, formNoValidate, ...props } = useFieldControlProps_unstable(inputProps, { supportsRequired: true, supportsSize: true });
@@ -6773,23 +6815,19 @@ export const AccordionHeader = /* @__PURE__ */ React.forwardRef(function Accordi
6773
6815
  const ref = React.useRef(null);
6774
6816
  useExposeHostRef(ref, forwardedRef);
6775
6817
  ;
6818
+ useNativeControlEvents(ref, ".header", props.onClick, props.onClickCapture, props);
6776
6819
  const buttonProps = React.isValidElement(button) ? button.props : button;
6777
6820
  React.useLayoutEffect(() => {
6778
6821
  const header = ref.current;
6779
6822
  if (!header)
6780
6823
  return;
6781
- const root = header.shadowRoot?.querySelector(".header");
6782
- const bridge = (callback, event) => {
6783
- if (callback && root)
6784
- callback(createReactEventBridge(event, event, root, event.target));
6785
- };
6786
6824
  header.button = {
6787
6825
  ...buttonProps,
6788
- onClickCapture: event => { bridge(props.onClickCapture, event); buttonProps?.onClickCapture?.(event); },
6789
- onClick: event => { buttonProps?.onClick?.(event); bridge(props.onClick, event); },
6826
+ onClickCapture: buttonProps?.onClickCapture,
6827
+ onClick: buttonProps?.onClick,
6790
6828
  };
6791
6829
  header.dispatchEvent(new CustomEvent("spui-header-slots-change", { bubbles: true, composed: true }));
6792
- }, [buttonProps, props.onClick, props.onClickCapture]);
6830
+ }, [buttonProps]);
6793
6831
  return React.createElement("spui-accordion-header", nativeControlHostProps({ ...props, ref, slot: "heading", "expand-icon-position": expandIconPosition, inline: inline || undefined, size }), icon == null ? null : React.createElement("span", { slot: "icon" }, icon), children, expandIcon == null ? null : React.createElement("span", { slot: "expand-icon" }, expandIcon));
6794
6832
  });
6795
6833
  export const AccordionPanel = /* @__PURE__ */ React.forwardRef(function AccordionPanel({ children, collapseMotion, ...props }, forwardedRef) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfx-fast/sharepoint-ui",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "license": "MIT",
5
5
  "description": "Host-aware, framework-independent UI elements for SharePoint Framework",
6
6
  "homepage": "https://vystartasv.github.io/sharepoint-ui-docs/",
@@ -1,2 +0,0 @@
1
- /** Applies a theme token map once per document and returns the class inherited by shadow roots. */
2
- export declare function getReactThemeClass(document: Document, styles: object): string | undefined;
@@ -1,75 +0,0 @@
1
- const registries = new WeakMap();
2
- const maxThemeRulesPerDocument = 256;
3
- function hash(value) {
4
- let result = 2166136261;
5
- for (let index = 0; index < value.length; index++) {
6
- result ^= value.charCodeAt(index);
7
- result = Math.imul(result, 16777619);
8
- }
9
- return (result >>> 0).toString(36);
10
- }
11
- function createSheet(document) {
12
- const Sheet = document.defaultView?.CSSStyleSheet;
13
- if (!Sheet)
14
- return undefined;
15
- try {
16
- const sheet = new Sheet();
17
- sheet.insertRule(".spui-theme-empty{}", 0);
18
- if (!("adoptedStyleSheets" in document))
19
- return undefined;
20
- document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
21
- sheet.deleteRule(0);
22
- return sheet;
23
- }
24
- catch {
25
- return undefined;
26
- }
27
- }
28
- function getRegistry(document) {
29
- const existing = registries.get(document);
30
- if (existing)
31
- return existing;
32
- const sheet = createSheet(document);
33
- if (!sheet)
34
- return undefined;
35
- const registry = { sheet, records: new Map(), classes: new WeakMap() };
36
- registries.set(document, registry);
37
- return registry;
38
- }
39
- function entriesOf(styles) {
40
- return Object.entries(styles).filter(([, value]) => typeof value === "string" || typeof value === "number");
41
- }
42
- function serialize(styles) {
43
- return JSON.stringify(entriesOf(styles).sort(([left], [right]) => left.localeCompare(right)));
44
- }
45
- function cssPropertyName(name) {
46
- return name.startsWith("--") ? name : name.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
47
- }
48
- /** Applies a theme token map once per document and returns the class inherited by shadow roots. */
49
- export function getReactThemeClass(document, styles) {
50
- const registry = getRegistry(document);
51
- if (!registry)
52
- return undefined;
53
- const cachedClass = registry.classes.get(styles);
54
- if (cachedClass)
55
- return cachedClass;
56
- const serialized = serialize(styles);
57
- const existing = registry.records.get(serialized);
58
- if (existing)
59
- return existing.className;
60
- if (registry.records.size >= maxThemeRulesPerDocument)
61
- return undefined;
62
- const baseName = `spui-theme-${hash(serialized)}`;
63
- let className = baseName;
64
- let suffix = 0;
65
- while ([...registry.records.values()].some(record => record.className === className && record.serialized !== serialized))
66
- className = `${baseName}-${++suffix}`;
67
- const index = registry.sheet.cssRules.length;
68
- registry.sheet.insertRule(`.${className}{}`, index);
69
- const rule = registry.sheet.cssRules[index];
70
- for (const [name, value] of entriesOf(styles))
71
- rule.style.setProperty(cssPropertyName(name), String(value));
72
- registry.records.set(serialized, { className, rule, serialized });
73
- registry.classes.set(styles, className);
74
- return className;
75
- }