@spfx-fast/sharepoint-ui 0.4.1 → 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 +21 -878
  4. package/components.json +178 -33
  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 +188 -19
  50. package/dist/react.js +321 -61
  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
package/dist/react.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { createPortal } from "react-dom";
4
- import { observeAccessibleTextFromIdRefs, resolveAccessibleTextFromIdRefs } from "./elements/shared.js";
4
+ import { getDirectionFromLanguage, observeAccessibleTextFromIdRefs, resolveAccessibleTextFromIdRefs } from "./elements/shared.js";
5
5
  import { defineButton } from "./elements/button.js";
6
6
  import { defineButtonGroup } from "./elements/button-group.js";
7
7
  import { defineCompoundButton, defineMenuButton, defineSplitButton, defineToggleButton } from "./elements/button-variants.js";
@@ -27,7 +27,9 @@ import { defineSpinButton } from "./elements/spin-button.js";
27
27
  import { defineSlider } from "./elements/slider.js";
28
28
  import { defineDatePicker } from "./elements/date-picker.js";
29
29
  import { defineCombobox } from "./elements/combobox.js";
30
- import { defineRichTextEditor } from "./elements/rich-text-editor.js";
30
+ import { defineRichTextEditor, getRichTextEditorFieldOptions } from "./elements/rich-text-editor.js";
31
+ export { getRichTextEditorFieldOptions } from "./elements/rich-text-editor.js";
32
+ import { getSharePointFieldAdapter } from "./sharepoint-fields.js";
31
33
  import { defineAlert } from "./elements/alert.js";
32
34
  import { defineSkeleton, defineSkeletonItem } from "./elements/skeleton.js";
33
35
  import { defineLink } from "./elements/link.js";
@@ -70,7 +72,8 @@ import { defineOverflow, defineOverflowItem, defineOverflowDivider } from "./ele
70
72
  import { defineSwatchPicker as defineNativeSwatchPicker } from "./elements/swatch-picker.js";
71
73
  import { createTableColumn as createNativeTableColumn, defineTable as defineNativeTable } from "./elements/table.js";
72
74
  import { getSharePointUIStyleTokens } from "./appearance.js";
73
- import { getSharePointUIDesignTokens } from "./theme.js";
75
+ import { getSharePointThemeColorPresets, getSharePointUIDesignTokens } from "./theme.js";
76
+ export { getSharePointThemeColorPresets } from "./theme.js";
74
77
  export { createResizeObserverFromDocument, getRTLRootMargin, scrollToItemDynamic, scrollToItemStatic, useDynamicVirtualizerMeasure, useIntersectionObserver, useMeasureList, useResizeObserverRef_unstable, useStaticVirtualizerMeasure } from "./virtualizer-hooks.js";
75
78
  export { composeSharePointUIDesignThemes } from "./theme.js";
76
79
  const FieldContext = React.createContext(undefined);
@@ -105,9 +108,9 @@ export function useFieldControlProps_unstable(props, options = {}) {
105
108
  next.style = { ...next.style, "--spui-control-border": tokens.border, "--spui-input-border": tokens.border, "--spui-focus-ring": tokens.border };
106
109
  return next;
107
110
  }
108
- const defaultStrings = { loading: "Loading", close: "Close", dialogLabel: "Dialog", richTextEditorLabel: "Rich text", dismiss: "Dismiss", notifications: "Notifications", clear: "Clear", spinButtonIncrement: "Increment value", spinButtonDecrement: "Decrement value", remove: "Remove", noResults: "No results", selectedOptionsLabel: "Selected options", required: "Required", invalidValue: "Enter a valid value", moreInformation: "More information", people: "People", showMorePeople: "Show more people ({count})", showFewerPeople: "Show fewer people", navigationMenu: "Open navigation", navigationClose: "Close navigation", navigationExpand: "Expand navigation", navigationCollapse: "Collapse navigation", treeLabel: "Tree", treeToggleLabel: "Expand or collapse", treeEmptyMessage: "No items", splitButtonMenuLabel: "More options", navigationToggle: "Toggle navigation", splitNavItemActionLabel: "More actions", virtualizerLabel: "Items", dataGridLabel: "Data grid", dataGridFilterLabel: "Search rows", dataGridSelectRow: "Select row", dataGridSelectAll: "Select all rows", dataGridRowLabel: "row", dataGridLoadingLabel: "Loading…", dataGridEmptyLabel: "No items", dataGridSortPriority: "Sort priority {priority}", dataGridResizeLabel: "Resize column", dataGridReorderLabel: "Reorder column", dataGridEmptyGroupLabel: "No value", dataGridExpandGroupLabel: "Expand group", dataGridCollapseGroupLabel: "Collapse group", dataGridGroupCountLabel: "{count} items", dataGridEditHint: "Press Enter or F2 to edit", tableResizeHandle: "Resize column", dataGridSelectionCopied: "Selection copied.", dataGridCopyFailed: "Copy failed. {message}", dataGridPasteOne: "Pasted {count} cell.", dataGridPasteMany: "Pasted {count} cells.", dataGridPasteFailed: "Paste failed. {message}", dataGridColumnReordered: "{label}, {position} of {count}", toolbarLabel: "Toolbar", breadcrumbLabel: "Breadcrumb", menuBarLabel: "Menu bar", drawerExpand: "Expand drawer to full screen", drawerRestore: "Restore drawer size", drawerLabel: "Supplementary content", drawerNavigation: "Drawer navigation", tableResizeColumn: "Resize {column} column", ratingValue: "{value} of {max}", colorChoose: "Choose color", colorHex: "Hex color", colorHue: "Hue", colorArea: "Saturation and brightness", colorAreaValue: "{saturation}% saturation, {brightness}% brightness", colorSaturation: "Saturation", colorValue: "Brightness", colorFormat: "Color format", colorRgb: "RGB color values", colorRed: "Red", colorGreen: "Green", colorBlue: "Blue", colorOpacity: "Opacity", colorSwatches: "Color swatches", colorAdd: "Add color", colorSwatch: "Select {color}", colorInvalid: "Enter a 3 or 6 digit hex color, for example #336699.", richTextBold: "Bold", richTextItalic: "Italic", richTextUnderline: "Underline", richTextBulletList: "Bulleted list", richTextNumberList: "Numbered list", richTextLink: "Link", richTextToolbar: "Rich text formatting", richTextLinkPrompt: "Link URL", richTextRequired: "Enter some text.", richTextChooseImage: "Choose image", richTextUndo: "Undo", richTextRedo: "Redo", richTextInsertTable: "Insert table", richTextInsertImage: "Insert image", richTextInsertRowAbove: "Insert row above", richTextInsertRowBelow: "Insert row below", richTextInsertColumnBefore: "Insert column before", richTextInsertColumnAfter: "Insert column after", richTextDeleteRow: "Delete row", richTextDeleteColumn: "Delete column", richTextDeleteTable: "Delete table", fileUploadBrowse: "Browse files", fileUploadDrop: "Drag files here or browse to select", fileUploadRemove: "Remove", fileUploadSelected: "Selected files", fileUploadRequired: "Select at least one file.", fileUploadTypeError: "The selected file type is not accepted.", fileUploadSizeError: "The selected file exceeds the allowed size.", fileUploadLimitError: "The maximum number of files has been reached.", carouselDescription: "Carousel", carouselPrevious: "Previous slide", carouselNext: "Next slide", carouselSlide: "Slide {index} of {count}", carouselRoleDescription: "carousel", carouselSlides: "Carousel slides", carouselNavigation: "Slide navigation", carouselPlay: "Play", carouselPause: "Pause", teachingPopoverLabel: "Guided steps", teachingPopoverDismiss: "Dismiss", teachingPopoverPrevious: "Previous step", teachingPopoverNext: "Next step", teachingPopoverFinish: "Finish tour", teachingPopoverSteps: "Tour steps", teachingPopoverPageCount: "{current} of {total}", teachingPopoverPageLabel: "Step {current} of {total}", overflowDescription: "Overflow actions", overflowMenuLabel: "More actions ({count})" };
111
+ const defaultStrings = { loading: "Loading", close: "Close", dialogLabel: "Dialog", richTextEditorLabel: "Rich text", dismiss: "Dismiss", notifications: "Notifications", clear: "Clear", spinButtonIncrement: "Increment value", spinButtonDecrement: "Decrement value", remove: "Remove", noResults: "No results", selectedOptionsLabel: "Selected options", required: "Required", invalidValue: "Enter a valid value", moreInformation: "More information", people: "People", presenceAvailable: "Available", presenceBusy: "Busy", presenceDoNotDisturb: "Do not disturb", presenceAway: "Away", presenceOffline: "Offline", presenceUnknown: "Presence unknown", presenceOutOfOffice: "Out of office", presenceBlocked: "Blocked", presenceOutOfOfficeLabel: "{status}, out of office", showMorePeople: "Show more people ({count})", showFewerPeople: "Show fewer people", navigationMenu: "Open navigation", navigationClose: "Close navigation", navigationExpand: "Expand navigation", navigationCollapse: "Collapse navigation", treeLabel: "Tree", treeToggleLabel: "Expand or collapse", treeEmptyMessage: "No items", splitButtonMenuLabel: "More options", navigationToggle: "Toggle navigation", splitNavItemActionLabel: "More actions", virtualizerLabel: "Items", dataGridLabel: "Data grid", dataGridFilterLabel: "Search rows", dataGridSelectRow: "Select row", dataGridSelectAll: "Select all rows", dataGridRowLabel: "row", dataGridLoadingLabel: "Loading…", dataGridEmptyLabel: "No items", dataGridSortPriority: "Sort priority {priority}", dataGridResizeLabel: "Resize column", dataGridReorderLabel: "Reorder column", dataGridReorderHint: "Reorder {column}; use Alt+Shift+Arrow keys", dataGridLoadError: "Data could not be loaded.", dataGridEditError: "The value could not be saved.", dataGridEmptyGroupLabel: "No value", dataGridExpandGroupLabel: "Expand group", dataGridCollapseGroupLabel: "Collapse group", dataGridGroupCountLabel: "{count} items", dataGridEditHint: "Press Enter or F2 to edit", tableResizeHandle: "Resize column", dataGridSelectionCopied: "Selection copied.", dataGridCopyFailed: "Copy failed.", dataGridPasteOne: "Pasted {count} cell.", dataGridPasteMany: "Pasted {count} cells.", dataGridPasteFailed: "Paste failed.", dataGridColumnReordered: "{label}, {position} of {count}", toolbarLabel: "Toolbar", breadcrumbLabel: "Breadcrumb", menuBarLabel: "Menu bar", drawerExpand: "Expand drawer to full screen", drawerRestore: "Restore drawer size", drawerLabel: "Supplementary content", drawerNavigation: "Drawer navigation", tableResizeColumn: "Resize {column} column", ratingValue: "{value} of {max}", colorChoose: "Choose color", colorHex: "Hex color", colorHue: "Hue", colorArea: "Saturation and brightness", colorAreaValue: "{saturation}% saturation, {brightness}% brightness", colorSaturation: "Saturation", colorValue: "Brightness", colorFormat: "Color format", colorRgb: "RGB color values", colorRed: "Red", colorGreen: "Green", colorBlue: "Blue", colorOpacity: "Opacity", colorSwatches: "Color swatches", colorAdd: "Add color", colorSwatch: "Select {color}", colorInvalid: "Enter a 3 or 6 digit hex color, for example #336699.", richTextBold: "Bold", richTextTextColor: "Text color", richTextHighlightColor: "Highlight color", richTextCustomColor: "Custom color", richTextThemeAccent: "SharePoint theme accent", richTextFontFamily: "Font family", richTextFontSize: "Font size", richTextItalic: "Italic", richTextUnderline: "Underline", richTextStrike: "Strikethrough", richTextClearFormatting: "Clear formatting", richTextFormatBlock: "Text style", richTextParagraph: "Paragraph", richTextHeading1: "Heading 1", richTextHeading2: "Heading 2", richTextHeading3: "Heading 3", richTextBlockquote: "Quote", richTextPreformatted: "Preformatted", richTextBulletList: "Bulleted list", richTextNumberList: "Numbered list", richTextLink: "Link", richTextToolbar: "Rich text formatting", richTextLinkPrompt: "Link URL", richTextRequired: "Enter some text.", richTextChooseImage: "Choose image", richTextUndo: "Undo", richTextRedo: "Redo", richTextInsertTable: "Insert table", richTextInsertImage: "Insert image", richTextInsertRowAbove: "Insert row above", richTextInsertRowBelow: "Insert row below", richTextInsertColumnBefore: "Insert column before", richTextInsertColumnAfter: "Insert column after", richTextDeleteRow: "Delete row", richTextDeleteColumn: "Delete column", richTextDeleteTable: "Delete table", fileUploadBrowse: "Browse files", fileUploadDrop: "Drag files here or browse to select", fileUploadRemove: "Remove", fileUploadSelected: "Selected files", fileUploadRequired: "Select at least one file.", fileUploadTypeError: "The selected file type is not accepted.", fileUploadSizeError: "The selected file exceeds the allowed size.", fileUploadLimitError: "The maximum number of files has been reached.", carouselDescription: "Carousel", carouselPrevious: "Previous slide", carouselNext: "Next slide", carouselSlide: "Slide {index} of {count}", carouselRoleDescription: "carousel", carouselSlides: "Carousel slides", carouselNavigation: "Slide navigation", carouselPlay: "Play", carouselPause: "Pause", teachingPopoverLabel: "Guided steps", teachingPopoverDismiss: "Dismiss", teachingPopoverPrevious: "Previous step", teachingPopoverNext: "Next step", teachingPopoverFinish: "Finish tour", teachingPopoverSteps: "Tour steps", teachingPopoverPageCount: "{current} of {total}", teachingPopoverPageLabel: "Step {current} of {total}", overflowDescription: "Overflow actions", overflowMenuLabel: "More actions ({count})" };
109
112
  const defaultHostStyle = Object.freeze({ "--spui-font-family": '"Segoe UI", sans-serif', "--spui-color-scheme": "light", colorScheme: "light" });
110
- const UIContext = React.createContext({ appearance: "fluent", baseAppearance: "fluent", density: "comfortable", hasThemeValues: false, styleTokens: getSharePointUIStyleTokens(), fluentTokenStyles: {}, hostStyle: defaultHostStyle, providesCssInheritance: false, strings: defaultStrings });
113
+ const UIContext = React.createContext({ dirIsExplicit: false, appearance: "fluent", baseAppearance: "fluent", density: "comfortable", hasThemeValues: false, styleTokens: getSharePointUIStyleTokens(), fluentTokenStyles: {}, hostStyle: defaultHostStyle, providesCssInheritance: false, strings: defaultStrings });
111
114
  const AvatarGroupSizeContext = React.createContext(32);
112
115
  const AvatarGroupContext = React.createContext(undefined);
113
116
  const BreadcrumbSizeContext = React.createContext("medium");
@@ -138,7 +141,9 @@ function hasDesignThemeValues(theme) {
138
141
  function useHostProps(props) {
139
142
  const context = React.useContext(UIContext);
140
143
  const lang = context.lang || (typeof document === "undefined" ? undefined : document.documentElement.lang || undefined);
141
- const dir = context.dir || (typeof document === "undefined" ? undefined : document.documentElement.dir || undefined);
144
+ const documentDir = typeof document === "undefined" ? undefined : document.documentElement.dir || undefined;
145
+ const localLang = typeof props.lang === "string" ? props.lang : undefined;
146
+ const dir = props.dir ?? (context.dirIsExplicit ? context.dir : localLang ? getDirectionFromLanguage(localLang) ?? context.dir ?? documentDir : context.dir ?? documentDir ?? getDirectionFromLanguage(lang));
142
147
  const style = context.providesCssInheritance ? props.style : props.style ? { ...context.hostStyle, ...props.style } : context.hostStyle;
143
148
  const className = props.className;
144
149
  return { ...props, className, "data-spui-appearance": props["data-spui-appearance"] ?? context.appearance, "data-spui-base-appearance": props["data-spui-base-appearance"] ?? context.baseAppearance, style, ...(props.lang === undefined && lang ? { lang } : {}), ...(props.dir === undefined && dir ? { dir } : {}) };
@@ -235,12 +240,25 @@ const nativeEventBindings = [
235
240
  ["transitionend", "onTransitionEnd", false, "transition"], ["transitionend", "onTransitionEndCapture", true, "transition"],
236
241
  ].map(([eventName, prop, capture, kind]) => ({ eventName, prop, capture, kind })),
237
242
  ];
243
+ const nativeEventBindingsByProp = new Map();
244
+ const nativeEventBindingOrder = new Map(nativeEventBindings.map((binding, index) => [binding, index]));
245
+ for (const binding of nativeEventBindings) {
246
+ const bindings = nativeEventBindingsByProp.get(binding.prop);
247
+ if (bindings)
248
+ bindings.push(binding);
249
+ else
250
+ nativeEventBindingsByProp.set(binding.prop, [binding]);
251
+ }
238
252
  const nativeEventPropNames = new Set(nativeEventBindings.map(binding => binding.prop));
239
253
  function withoutNativeControlEventProps(props) {
240
- const hostProps = { ...props };
241
- for (const prop of nativeEventPropNames)
254
+ let hostProps;
255
+ for (const prop in props) {
256
+ if (!Object.prototype.hasOwnProperty.call(props, prop) || !nativeEventPropNames.has(prop))
257
+ continue;
258
+ hostProps ??= { ...props };
242
259
  delete hostProps[prop];
243
- return hostProps;
260
+ }
261
+ return hostProps ?? props;
244
262
  }
245
263
  function nativeControlHostProps(props) {
246
264
  return useCustomElementProps(withoutNativeControlEventProps(props));
@@ -249,7 +267,12 @@ function useNativeControlEvents(ref, selector, onClick, onClickCapture, events,
249
267
  const handlers = { ...events, onClick, onClickCapture };
250
268
  const handlersRef = React.useRef(handlers);
251
269
  React.useLayoutEffect(() => { handlersRef.current = handlers; });
252
- const activeBindings = nativeEventBindings.filter(binding => typeof handlers[binding.prop] === "function");
270
+ const activeBindings = [];
271
+ for (const prop of Object.keys(handlers)) {
272
+ if (typeof handlers[prop] === "function")
273
+ activeBindings.push(...(nativeEventBindingsByProp.get(prop) ?? []));
274
+ }
275
+ activeBindings.sort((a, b) => nativeEventBindingOrder.get(a) - nativeEventBindingOrder.get(b));
253
276
  const subscriptionKey = activeBindings.map(binding => binding.eventName + ":" + binding.prop + ":" + (binding.capture ? 1 : 0)).join("|");
254
277
  const hasMouseTransitions = typeof handlers.onMouseEnter === "function" || typeof handlers.onMouseLeave === "function";
255
278
  const hasPointerTransitions = typeof handlers.onPointerEnter === "function" || typeof handlers.onPointerLeave === "function";
@@ -499,6 +522,10 @@ function useNativeMotionPresence(ref, visible, enabled, animationRoot = ref, ref
499
522
  }
500
523
  export function SharePointUIProvider({ children, lang, dir, appearance, baseAppearance, density, theme, tokens, fluentTokens, strings }) {
501
524
  const parent = React.useContext(UIContext);
525
+ const resolvedLang = lang ?? parent.lang ?? (typeof document === "undefined" ? undefined : document.documentElement.lang || undefined);
526
+ const documentDir = typeof document === "undefined" ? undefined : document.documentElement.dir || undefined;
527
+ const resolvedDir = dir ?? (parent.dirIsExplicit ? parent.dir : lang !== undefined ? getDirectionFromLanguage(lang) ?? parent.dir ?? documentDir : parent.dir ?? documentDir ?? getDirectionFromLanguage(resolvedLang));
528
+ const dirIsExplicit = dir !== undefined || parent.dirIsExplicit;
502
529
  const mergedTheme = { ...parent.theme, ...theme, palette: { ...parent.theme?.palette, ...theme?.palette }, fluentTokens: { ...parent.theme?.fluentTokens, ...theme?.fluentTokens }, colors: { ...parent.theme?.colors, ...theme?.colors }, typography: { ...parent.theme?.typography, ...theme?.typography }, spacing: { ...parent.theme?.spacing, ...theme?.spacing }, shape: { ...parent.theme?.shape, ...theme?.shape }, elevation: { ...parent.theme?.elevation, ...theme?.elevation }, materials: { ...parent.theme?.materials, ...theme?.materials }, motion: { ...parent.theme?.motion, ...theme?.motion }, layers: { ...parent.theme?.layers, ...theme?.layers }, customProperties: { ...parent.theme?.customProperties, ...theme?.customProperties } };
503
530
  const mergedTokens = { ...parent.tokens, ...tokens };
504
531
  const mergedFluentTokens = { ...parent.fluentTokens, ...fluentTokens };
@@ -510,8 +537,8 @@ export function SharePointUIProvider({ children, lang, dir, appearance, baseAppe
510
537
  const hasThemeValues = hasDesignThemeValues(mergedTheme);
511
538
  const inheritsDefaultTokens = resolvedAppearance === "fluent" && resolvedBaseAppearance === "fluent" && resolvedDensity === "comfortable" && !hasThemeValues && !Object.keys(mergedTokens).length && !Object.keys(mergedFluentTokens).length;
512
539
  const hostStyle = inheritsDefaultTokens ? defaultHostStyle : Object.freeze({ ...fluentTokenStyles, ...styleTokens, colorScheme: styleTokens["--spui-color-scheme"] });
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 } };
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 }) });
540
+ const value = { lang: resolvedLang, dir: resolvedDir, dirIsExplicit, appearance: resolvedAppearance, baseAppearance: resolvedBaseAppearance, density: resolvedDensity, theme: mergedTheme, hasThemeValues, tokens: mergedTokens, fluentTokens: mergedFluentTokens, styleTokens, fluentTokenStyles, hostStyle, providesCssInheritance: true, strings: { ...parent.strings, ...strings } };
541
+ return _jsx(UIContext.Provider, { value: value, children: _jsx("div", { "data-spui-provider": "", "data-spui-appearance": resolvedAppearance, "data-spui-base-appearance": resolvedBaseAppearance, lang: resolvedLang, dir: resolvedDir, style: { ...hostStyle, display: "contents" }, children: children }) });
515
542
  }
516
543
  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
544
  const defaultBold = as === "strong" || as === "b";
@@ -836,7 +863,7 @@ export function useOverflowMenu(id) {
836
863
  }, [registerOverflowMenu, id]);
837
864
  return { ref, overflowCount, isOverflowing: hasOverflow };
838
865
  }
839
- export function Overflow({ children, label, minimumVisible = 0, overflowDirection = "end", overflowAxis = "horizontal", hasHiddenItems = false, overflowContent, padding = 10, onOverflowChange, onOverflowItemSelect, ...props }) {
866
+ export function Overflow({ children, label, minimumVisible = 0, overflowDirection = "end", overflowAxis = "horizontal", density = "comfortable", hasHiddenItems = false, overflowContent, padding = 10, onOverflowChange, onOverflowItemSelect, ...props }) {
840
867
  const ref = React.useRef(null);
841
868
  const [overflowIds, setOverflowIds] = React.useState([]);
842
869
  const [overflowState, setOverflowState] = React.useState(emptyOverflowContext);
@@ -941,7 +968,7 @@ export function Overflow({ children, label, minimumVisible = 0, overflowDirectio
941
968
  });
942
969
  const trigger = React.createElement(Button, { appearance: "subtle", size: "small", iconOnly: true, "aria-label": menuLabel }, React.createElement("span", { "aria-hidden": true }, "⋯"));
943
970
  const menu = React.createElement(Menu, { label: label || strings.overflowDescription, trigger, onSelect: value => onOverflowItemSelect?.(value) }, ...menuItems, overflowContent);
944
- const host = React.createElement("spui-overflow", useCustomElementProps({ ...props, ref, "aria-label": label || strings.overflowDescription, "minimum-visible": minimumVisible, "overflow-direction": overflowDirection, "overflow-axis": overflowAxis, "has-hidden-items": hasHiddenItems || undefined, padding }), children, React.createElement("div", { slot: "overflow-trigger", hidden: overflowIds.length === 0 && !hasHiddenItems }, menu));
971
+ const host = React.createElement("spui-overflow", useCustomElementProps({ ...props, ref, "aria-label": label || strings.overflowDescription, "minimum-visible": minimumVisible, "overflow-direction": overflowDirection, "overflow-axis": overflowAxis, density, "has-hidden-items": hasHiddenItems || undefined, padding }), children, React.createElement("div", { slot: "overflow-trigger", hidden: overflowIds.length === 0 && !hasHiddenItems }, menu));
945
972
  return React.createElement(OverflowProvider, { value: contextValue }, host);
946
973
  }
947
974
  export const Card = /* @__PURE__ */ React.forwardRef(function Card({ children, appearance = "filled", orientation = "vertical", size = "medium", focusMode, selected, defaultSelected, disabled = false, selectionLabel, checkbox, floatingAction, onSelectionChange, ...props }, forwardedRef) {
@@ -1310,10 +1337,10 @@ export const Drawer = /* @__PURE__ */ React.forwardRef(function Drawer({ type =
1310
1337
  export function DrawerHeader({ children }) {
1311
1338
  return React.createElement(React.Fragment, null, children);
1312
1339
  }
1313
- export function DrawerHeaderNavigation({ children, label, ...props }) {
1340
+ export const DrawerHeaderNavigation = /* @__PURE__ */ React.forwardRef(function DrawerHeaderNavigation({ children, label, ...props }, forwardedRef) {
1314
1341
  const context = React.useContext(UIContext);
1315
- 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);
1316
- }
1342
+ 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);
1343
+ });
1317
1344
  export function DrawerHeaderTitle({ children, action, heading, ...props }) {
1318
1345
  const headingElement = heading;
1319
1346
  const title = React.isValidElement(headingElement)
@@ -1321,12 +1348,12 @@ export function DrawerHeaderTitle({ children, action, heading, ...props }) {
1321
1348
  : React.createElement("h2", { slot: "title", "data-spui-drawer-title": "", style: { margin: 0 }, ...(heading ?? {}) }, children);
1322
1349
  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));
1323
1350
  }
1324
- export function DrawerBody({ children, ...props }) {
1325
- return React.createElement("div", useHostProps({ ...props, style: { minWidth: 0, ...props.style } }), children);
1326
- }
1327
- export function DrawerFooter({ children, ...props }) {
1328
- return React.createElement("div", useHostProps({ ...props, slot: "actions", style: { display: "flex", alignItems: "center", justifyContent: "flex-end", flexWrap: "wrap", gap: 8, ...props.style } }), children);
1329
- }
1351
+ export const DrawerBody = /* @__PURE__ */ React.forwardRef(function DrawerBody({ children, ...props }, forwardedRef) {
1352
+ return React.createElement("div", useHostProps({ ...props, ref: forwardedRef, style: { minWidth: 0, ...props.style } }), children);
1353
+ });
1354
+ export const DrawerFooter = /* @__PURE__ */ React.forwardRef(function DrawerFooter({ children, ...props }, forwardedRef) {
1355
+ 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);
1356
+ });
1330
1357
  export const InlineDrawer = /* @__PURE__ */ React.forwardRef(function InlineDrawer({ open = false, title, position = "start", size = "small", separator = false, unmountOnClose = true, surfaceMotion, actions, children, ...props }, forwardedRef) {
1331
1358
  const context = React.useContext(UIContext);
1332
1359
  ensureDefined(defineInlineDrawer);
@@ -1521,7 +1548,7 @@ export const DatePicker = /* @__PURE__ */ React.forwardRef(function DatePicker(i
1521
1548
  return React.createElement("spui-date-picker", nativeControlHostProps({ ...props, ref, label, min, max, name, placeholder, required, disabled, "read-only": readOnly, "calendar-label": calendarLabel ?? context.strings.datePickerCalendar, "previous-month-label": previousMonthLabel ?? context.strings.datePickerPreviousMonth, "next-month-label": nextMonthLabel ?? context.strings.datePickerNextMonth, "invalid-date-message": invalidDateMessage ?? context.strings.datePickerInvalid, "required-message": requiredMessage ?? context.strings.datePickerRequired }));
1522
1549
  });
1523
1550
  export const ComboBox = /* @__PURE__ */ React.forwardRef(function ComboBox(inputProps, forwardedRef) {
1524
- const { label, selectedLabel, value, defaultValue, selectedValue, selectedOptions, defaultSelectedOptions, multiselect = false, name, input, listbox, mountNode, placeholder, required, disabled, freeform, allowFreeform, noResults, clearable, clearIcon, expandIcon, defaultOpen, disableAutoFocus, inlinePopup, open, appearance, size, positioning, onValueChange, onOptionSelect, onSelectedOptionsChange, onOpenChange, onActiveOptionChange, children, ...props } = useFieldControlProps_unstable(inputProps, { supportsRequired: true, supportsSize: true });
1551
+ const { label, selectedLabel, requiredMessage, value, defaultValue, selectedValue, selectedOptions, defaultSelectedOptions, multiselect = false, name, input, listbox, mountNode, placeholder, required, disabled, freeform, allowFreeform, noResults, clearable, clearIcon, expandIcon, defaultOpen, disableAutoFocus, inlinePopup, open, appearance, size, positioning, onValueChange, onOptionSelect, onSelectedOptionsChange, onOpenChange, onActiveOptionChange, children, ...props } = useFieldControlProps_unstable(inputProps, { supportsRequired: true, supportsSize: true });
1525
1552
  const ref = React.useRef(null);
1526
1553
  useExposeHostRef(ref, forwardedRef);
1527
1554
  ;
@@ -1609,7 +1636,7 @@ export const ComboBox = /* @__PURE__ */ React.forwardRef(function ComboBox(input
1609
1636
  const expandIconSlot = expandIcon == null ? null : React.isValidElement(expandIcon)
1610
1637
  ? React.cloneElement(expandIcon, { slot: "expand-icon" })
1611
1638
  : React.createElement("span", { slot: "expand-icon", "aria-hidden": true }, expandIcon);
1612
- return React.createElement(CompoundComboboxContext.Provider, { value: { ...provider, mode: "combobox", value: value ?? provider?.value, selectedOptions: selectedOptions ?? provider?.selectedOptions, multiselect } }, React.createElement(React.Fragment, null, React.createElement("spui-combobox", nativeControlHostProps({ ...props, ref, label, "selected-label": selectedLabel ?? context.strings.selectedOptionsLabel, value: value ?? defaultValue ?? provider?.value, "selected-value": selectedValue, multiselect: multiselect || undefined, name, placeholder, required, disabled, "allow-freeform": freeform ?? allowFreeform, "no-results": noResults ?? context.strings.noResults, clearable, "default-open": open === undefined && provider?.open === undefined ? defaultOpen : undefined, open: open ?? provider?.open ? "" : undefined, "disable-auto-focus": disableAutoFocus, appearance: appearance ?? provider?.appearance, size: size ?? provider?.size, positioning: typeof positioning === "string" ? positioning : positioning?.position ? `${positioning.position}${positioning.align && positioning.align !== "center" ? `-${positioning.align}` : ""}` : undefined, "inline-popup": inlinePopup }), children, inputSlot, clearIconSlot, expandIconSlot, listboxSlot), listboxPortal));
1639
+ return React.createElement(CompoundComboboxContext.Provider, { value: { ...provider, mode: "combobox", value: value ?? provider?.value, selectedOptions: selectedOptions ?? provider?.selectedOptions, multiselect } }, React.createElement(React.Fragment, null, React.createElement("spui-combobox", nativeControlHostProps({ ...props, ref, label, "selected-label": selectedLabel ?? context.strings.selectedOptionsLabel, "required-message": requiredMessage ?? context.strings.required, value: value ?? defaultValue ?? provider?.value, "selected-value": selectedValue, multiselect: multiselect || undefined, name, placeholder, required, disabled, "allow-freeform": freeform ?? allowFreeform, "no-results": noResults ?? context.strings.noResults, clearable, "default-open": open === undefined && provider?.open === undefined ? defaultOpen : undefined, open: open ?? provider?.open ? "" : undefined, "disable-auto-focus": disableAutoFocus, appearance: appearance ?? provider?.appearance, size: size ?? provider?.size, positioning: typeof positioning === "string" ? positioning : positioning?.position ? `${positioning.position}${positioning.align && positioning.align !== "center" ? `-${positioning.align}` : ""}` : undefined, "inline-popup": inlinePopup }), children, inputSlot, clearIconSlot, expandIconSlot, listboxSlot), listboxPortal));
1613
1640
  });
1614
1641
  export const ComboOption = /* @__PURE__ */ React.forwardRef(function ComboOption({ value, label, disabled, children }, forwardedRef) {
1615
1642
  ensureDefined(defineCombobox);
@@ -1801,8 +1828,14 @@ export const OptionGroup = /* @__PURE__ */ React.forwardRef(function OptionGroup
1801
1828
  return React.createElement("spui-combobox-option-group", useCustomElementProps({ ref: forwardedRef, ...props, label }), children);
1802
1829
  return _jsxs("div", { ...props, ref: forwardedRef, role: "group", "aria-label": label, children: [label ? _jsx("div", { children: label }) : null, children] });
1803
1830
  });
1831
+ const richTextEditorModeRank = { plain: 0, restricted: 1, rich: 2, html: 3 };
1804
1832
  export const RichTextEditor = /* @__PURE__ */ React.forwardRef(function RichTextEditor(inputProps, forwardedRef) {
1805
- const { label, editorLabel, value, defaultValue, placeholder, disabled, readOnly, required, name, onValueChange, onImageUpload, ...props } = useFieldControlProps_unstable(inputProps, { supportsRequired: true });
1833
+ const { label, editorLabel, value, defaultValue, placeholder, field, contentMode, allowHyperlink, disabled, readOnly, required, name, onValueChange, onImageUpload, onImageUploadError, linkPicker, onLinkPickerError, ...props } = useFieldControlProps_unstable(inputProps, { supportsRequired: true });
1834
+ const fieldOptions = field ? getRichTextEditorFieldOptions(field) : undefined;
1835
+ const effectiveContentMode = fieldOptions && contentMode
1836
+ ? richTextEditorModeRank[contentMode] < richTextEditorModeRank[fieldOptions.contentMode] ? contentMode : fieldOptions.contentMode
1837
+ : contentMode ?? fieldOptions?.contentMode;
1838
+ const effectiveAllowHyperlink = fieldOptions?.allowHyperlink === false ? false : allowHyperlink ?? fieldOptions?.allowHyperlink;
1806
1839
  const ref = React.useRef(null);
1807
1840
  useExposeHostRef(ref, forwardedRef);
1808
1841
  ;
@@ -1812,10 +1845,18 @@ export const RichTextEditor = /* @__PURE__ */ React.forwardRef(function RichText
1812
1845
  React.useEffect(() => { const element = ref.current; if (element)
1813
1846
  element.uploadImage = onImageUpload; return () => { if (element)
1814
1847
  delete element.uploadImage; }; }, [onImageUpload]);
1848
+ React.useEffect(() => { const element = ref.current; if (element)
1849
+ element.linkPicker = linkPicker; return () => { if (element)
1850
+ delete element.linkPicker; }; }, [linkPicker]);
1815
1851
  useSpuiEvent(ref, "spui-input", value !== undefined || onValueChange ? detail => {
1816
1852
  onValueChange?.(String(detail.value ?? ""));
1817
- if (value !== undefined && ref.current)
1818
- ref.current.value = value;
1853
+ } : undefined);
1854
+ useSpuiEvent(ref, "spui-image-upload-error", onImageUploadError ? detail => {
1855
+ const data = detail;
1856
+ onImageUploadError({ fileName: String(data.fileName ?? ""), error: data.error });
1857
+ } : undefined);
1858
+ useSpuiEvent(ref, "spui-link-picker-error", onLinkPickerError ? detail => {
1859
+ onLinkPickerError(detail.error);
1819
1860
  } : undefined);
1820
1861
  React.useLayoutEffect(() => {
1821
1862
  const element = ref.current;
@@ -1831,7 +1872,7 @@ export const RichTextEditor = /* @__PURE__ */ React.forwardRef(function RichText
1831
1872
  element.value = defaultValue;
1832
1873
  }
1833
1874
  }, [value, defaultValue]);
1834
- return React.createElement("spui-rich-text-editor", nativeControlHostProps({ ...props, ref, label, placeholder, disabled, "read-only": readOnly, required, name, "required-message": strings.richTextRequired, "editor-label": editorLabel ?? strings.richTextEditorLabel, "bold-label": strings.richTextBold, "italic-label": strings.richTextItalic, "underline-label": strings.richTextUnderline, "bullet-list-label": strings.richTextBulletList, "number-list-label": strings.richTextNumberList, "link-label": strings.richTextLink, "undo-label": strings.richTextUndo, "redo-label": strings.richTextRedo, "insert-table-label": strings.richTextInsertTable, "insert-image-label": strings.richTextInsertImage, "image-input-label": strings.richTextChooseImage, "insert-row-above-label": strings.richTextInsertRowAbove, "insert-row-below-label": strings.richTextInsertRowBelow, "insert-column-before-label": strings.richTextInsertColumnBefore, "insert-column-after-label": strings.richTextInsertColumnAfter, "delete-row-label": strings.richTextDeleteRow, "delete-column-label": strings.richTextDeleteColumn, "delete-table-label": strings.richTextDeleteTable, "toolbar-label": strings.richTextToolbar, "link-prompt": strings.richTextLinkPrompt }));
1875
+ return React.createElement("spui-rich-text-editor", nativeControlHostProps({ ...props, ref, label, placeholder, "content-mode": effectiveContentMode, "allow-hyperlink": effectiveAllowHyperlink === false ? "false" : undefined, disabled, "read-only": readOnly, required, name, "required-message": strings.richTextRequired, "editor-label": editorLabel ?? strings.richTextEditorLabel, "bold-label": strings.richTextBold, "italic-label": strings.richTextItalic, "underline-label": strings.richTextUnderline, "strike-label": strings.richTextStrike ?? "Strikethrough", "subscript-label": strings.richTextSubscript ?? "Subscript", "superscript-label": strings.richTextSuperscript ?? "Superscript", "align-left-label": strings.richTextAlignLeft ?? "Align left", "align-center-label": strings.richTextAlignCenter ?? "Align center", "align-right-label": strings.richTextAlignRight ?? "Align right", "align-justify-label": strings.richTextAlignJustify ?? "Justify text", "clear-formatting-label": strings.richTextClearFormatting ?? "Clear formatting", "format-block-label": strings.richTextFormatBlock ?? "Text style", "font-family-label": strings.richTextFontFamily ?? "Font family", "font-size-label": strings.richTextFontSize ?? "Font size", "paragraph-label": strings.richTextParagraph ?? "Paragraph", "heading-1-label": strings.richTextHeading1 ?? "Heading 1", "heading-2-label": strings.richTextHeading2 ?? "Heading 2", "heading-3-label": strings.richTextHeading3 ?? "Heading 3", "blockquote-label": strings.richTextBlockquote ?? "Quote", "preformatted-label": strings.richTextPreformatted ?? "Preformatted", "bullet-list-label": strings.richTextBulletList, "number-list-label": strings.richTextNumberList, "link-label": strings.richTextLink, "text-color-label": strings.richTextTextColor ?? "Text color", "highlight-color-label": strings.richTextHighlightColor ?? "Highlight color", "custom-color-label": strings.richTextCustomColor ?? "Custom color", "theme-accent-label": strings.richTextThemeAccent ?? "SharePoint theme accent", "color-swatch-label": strings.colorSwatch, "undo-label": strings.richTextUndo, "redo-label": strings.richTextRedo, "insert-table-label": strings.richTextInsertTable, "insert-image-label": strings.richTextInsertImage, "image-input-label": strings.richTextChooseImage, "insert-row-above-label": strings.richTextInsertRowAbove, "insert-row-below-label": strings.richTextInsertRowBelow, "insert-column-before-label": strings.richTextInsertColumnBefore, "insert-column-after-label": strings.richTextInsertColumnAfter, "delete-row-label": strings.richTextDeleteRow, "delete-column-label": strings.richTextDeleteColumn, "delete-table-label": strings.richTextDeleteTable, "toolbar-label": strings.richTextToolbar, "link-prompt": strings.richTextLinkPrompt, "link-dialog-label": strings.richTextLinkDialog ?? "Edit link", "link-text-label": strings.richTextLinkText ?? "Display text", "link-title-label": strings.richTextLinkTitle ?? "Title", "link-apply-label": strings.richTextLinkApply ?? "Apply link", "link-remove-label": strings.richTextLinkRemove ?? "Remove link", "link-cancel-label": strings.richTextLinkCancel ?? strings.close, "link-new-tab-label": strings.richTextLinkNewTab ?? "Open in new tab", "link-invalid-message": strings.richTextLinkInvalid ?? "Enter a valid HTTP, HTTPS, or mailto link.", "link-picker-label": strings.richTextLinkBrowse ?? "Browse SharePoint", "link-picker-loading-label": strings.richTextLinkBrowsing ?? "Opening picker…", "link-picker-error-message": strings.richTextLinkPickerError ?? "Unable to open the SharePoint link picker." }));
1835
1876
  });
1836
1877
  export const Badge = /* @__PURE__ */ React.forwardRef(function Badge({ children, icon, appearance = "filled", color = "brand", iconPosition = "before", shape = "circular", size = "medium", ...props }, forwardedRef) {
1837
1878
  ensureDefined(defineBadge);
@@ -1843,7 +1884,10 @@ export const CounterBadge = /* @__PURE__ */ React.forwardRef(function CounterBad
1843
1884
  });
1844
1885
  export const PresenceBadge = /* @__PURE__ */ React.forwardRef(function PresenceBadge({ status = "available", outOfOffice = false, size = "medium", icon, ...props }, forwardedRef) {
1845
1886
  ensureDefined(definePresenceBadge);
1846
- return React.createElement("spui-presence-badge", useCustomElementProps({ ref: forwardedRef, ...props, status, "out-of-office": outOfOffice || undefined, size }), icon == null ? null : React.createElement("span", { slot: "icon", "aria-hidden": true }, icon));
1887
+ const strings = React.useContext(UIContext).strings;
1888
+ const statusLabel = strings[presenceStringKeys[status]] ?? status.replaceAll("-", " ");
1889
+ const presenceLabel = outOfOffice && status !== "out-of-office" ? (strings.presenceOutOfOfficeLabel ?? "{status}, out of office").replace("{status}", statusLabel) : statusLabel;
1890
+ return React.createElement("spui-presence-badge", useCustomElementProps({ ref: forwardedRef, ...props, status, "aria-label": props["aria-label"] ?? presenceLabel, "out-of-office": outOfOffice || undefined, size }), icon == null ? null : React.createElement("span", { slot: "icon", "aria-hidden": true }, icon));
1847
1891
  });
1848
1892
  export const Tag = /* @__PURE__ */ React.forwardRef(function Tag({ children, appearance, size, shape = "rounded", color, value, label, disabled = false, selected = false, dismissible = false, dismissLabel, onDismiss, media, icon, primaryText, secondaryText, dismissIcon, ...props }, forwardedRef) {
1849
1893
  const ref = React.useRef(null);
@@ -1897,7 +1941,7 @@ export const TagGroup = /* @__PURE__ */ React.forwardRef(function TagGroup({ chi
1897
1941
  }, [selectedValues]);
1898
1942
  return React.createElement("spui-tag-group", useCustomElementProps({ ...props, ref, role: props.role ?? "toolbar", orientation, label, appearance, size, disabled: disabled || undefined, dismissible: dismissible || undefined, "default-selected-values": defaultSelectedValues === undefined ? undefined : JSON.stringify(defaultSelectedValues), "aria-label": props["aria-label"] ?? label }), children);
1899
1943
  });
1900
- export const TagPicker = /* @__PURE__ */ React.forwardRef(function TagPicker({ children, label, selectedLabel, selectedOptions, defaultSelectedOptions, selectedValues, defaultSelectedValues, inputValue, open, defaultOpen, positioning, disableAutoFocus = false, inline = false, noPopover = false, disabled, onOpenChange, onOptionSelect, onInputValueChange, onChange, ...props }, forwardedRef) {
1944
+ export const TagPicker = /* @__PURE__ */ React.forwardRef(function TagPicker({ children, label, selectedLabel, requiredMessage, selectedOptions, defaultSelectedOptions, selectedValues, defaultSelectedValues, inputValue, open, defaultOpen, positioning, disableAutoFocus = false, inline = false, noPopover = false, disabled, onOpenChange, onOptionSelect, onInputValueChange, onChange, ...props }, forwardedRef) {
1901
1945
  const ref = React.useRef(null);
1902
1946
  useExposeHostRef(ref, forwardedRef);
1903
1947
  ;
@@ -1937,7 +1981,7 @@ export const TagPicker = /* @__PURE__ */ React.forwardRef(function TagPicker({ c
1937
1981
  }, [selected, inputValue, open, defaultOpen]);
1938
1982
  React.useLayoutEffect(() => { const element = ref.current; if (element)
1939
1983
  element.positioning = positioning; }, [positioning]);
1940
- return React.createElement("spui-tag-picker", useCustomElementProps({ ...props, ref, label, disabled, "disable-auto-focus": disableAutoFocus || undefined, "selected-label": selectedLabel ?? strings.selectedOptionsLabel, "default-selected-options": defaultSelected === undefined ? undefined : JSON.stringify(defaultSelected), "input-value": inputValue, inline: inline || undefined, "no-popover": noPopover || undefined, "no-results": strings.noResults, "remove-label": strings.remove }), children);
1984
+ return React.createElement("spui-tag-picker", useCustomElementProps({ ...props, ref, label, disabled, "disable-auto-focus": disableAutoFocus || undefined, "selected-label": selectedLabel ?? strings.selectedOptionsLabel, "required-message": requiredMessage ?? strings.required, "default-selected-options": defaultSelected === undefined ? undefined : JSON.stringify(defaultSelected), "input-value": inputValue, inline: inline || undefined, "no-popover": noPopover || undefined, "no-results": strings.noResults, "remove-label": strings.remove }), children);
1941
1985
  });
1942
1986
  export function TagPickerControl({ children, secondaryAction, expandIcon }) {
1943
1987
  return React.createElement(React.Fragment, null, children, secondaryAction == null ? null : React.createElement("span", { slot: "secondary-action" }, secondaryAction), expandIcon == null ? null : React.createElement("span", { slot: "expand-icon", "aria-hidden": true }, expandIcon));
@@ -1962,16 +2006,16 @@ export const TagPickerInput = /* @__PURE__ */ React.forwardRef(function TagPicke
1962
2006
  export function TagPickerList({ children }) {
1963
2007
  return React.createElement(React.Fragment, null, children);
1964
2008
  }
1965
- export function TagPickerButton({ children, appearance = "outline", size = "medium", disabled = false, ...props }) {
1966
- return React.createElement("button", useCustomElementProps({ ...props, slot: "button", type: "button", "data-appearance": appearance, "data-size": size, disabled: disabled || undefined }), children);
1967
- }
2009
+ export const TagPickerButton = /* @__PURE__ */ React.forwardRef(function TagPickerButton({ children, appearance = "outline", size = "medium", disabled = false, ...props }, forwardedRef) {
2010
+ return React.createElement("button", useHostProps({ ...props, ref: forwardedRef, slot: "button", type: "button", "data-appearance": appearance, "data-size": size, disabled: disabled || undefined }), children);
2011
+ });
1968
2012
  export const TagPickerOption = /* @__PURE__ */ React.forwardRef(function TagPickerOption({ value, text, label, group, media, secondaryContent, disabled = false, children, ...props }, forwardedRef) {
1969
2013
  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));
1970
2014
  });
1971
2015
  export const TagPickerOptionGroup = /* @__PURE__ */ React.forwardRef(function TagPickerOptionGroup({ children, label, disabled = false }, forwardedRef) {
1972
2016
  return React.createElement("spui-tag-picker-option-group", useCustomElementProps({ ref: forwardedRef, label, disabled: disabled || undefined }), children);
1973
2017
  });
1974
- export const Rating = /* @__PURE__ */ React.forwardRef(function Rating({ value, defaultValue = 0, max = 5, step = 1, size = "extra-large", color = "neutral", label, itemLabel, iconFilled, iconOutline, fullValueInput, halfValueInput, name, disabled = false, readOnly = false, required = false, onChange, ...props }, forwardedRef) {
2018
+ export const Rating = /* @__PURE__ */ React.forwardRef(function Rating({ value, defaultValue = 0, max = 5, step = 1, size = "extra-large", color = "neutral", label, requiredMessage, itemLabel, iconFilled, iconOutline, fullValueInput, halfValueInput, name, disabled = false, readOnly = false, required = false, onChange, ...props }, forwardedRef) {
1975
2019
  const ref = React.useRef(null);
1976
2020
  useExposeHostRef(ref, forwardedRef);
1977
2021
  ;
@@ -1995,7 +2039,7 @@ export const Rating = /* @__PURE__ */ React.forwardRef(function Rating({ value,
1995
2039
  ? React.cloneElement(slot, { slot: name, hidden: true, "aria-hidden": true, tabIndex: -1 })
1996
2040
  : React.createElement("input", { ...slot, slot: name, hidden: true, "aria-hidden": true, tabIndex: -1 });
1997
2041
  };
1998
- return React.createElement("spui-rating", useCustomElementProps({ ...props, ref, value, "default-value": defaultValue, max, step, size, color, label, name, disabled: disabled || undefined, readonly: readOnly || undefined, required: required || undefined, "item-label": strings.ratingValue }), iconOutline == null ? null : React.createElement("span", { slot: "icon-outline", hidden: true }, React.createElement(iconOutline, { "aria-hidden": true, focusable: "false" })), iconFilled == null ? null : React.createElement("span", { slot: "icon-filled", hidden: true }, React.createElement(iconFilled, { "aria-hidden": true, focusable: "false" })), inputSlot(fullValueInput, "full-value-input"), inputSlot(halfValueInput, "half-value-input"));
2042
+ return React.createElement("spui-rating", useCustomElementProps({ ...props, ref, value, "default-value": defaultValue, max, step, size, color, label, name, disabled: disabled || undefined, readonly: readOnly || undefined, required: required || undefined, "required-message": requiredMessage ?? strings.required, "item-label": strings.ratingValue }), iconOutline == null ? null : React.createElement("span", { slot: "icon-outline", hidden: true }, React.createElement(iconOutline, { "aria-hidden": true, focusable: "false" })), iconFilled == null ? null : React.createElement("span", { slot: "icon-filled", hidden: true }, React.createElement(iconFilled, { "aria-hidden": true, focusable: "false" })), inputSlot(fullValueInput, "full-value-input"), inputSlot(halfValueInput, "half-value-input"));
1999
2043
  });
2000
2044
  export const RatingItem = /* @__PURE__ */ React.forwardRef(function RatingItem({ value = 1, selectedIcon, unselectedIcon, ...props }, forwardedRef) {
2001
2045
  ensureDefined(defineRatingItem);
@@ -2208,7 +2252,7 @@ export const BreadcrumbDivider = /* @__PURE__ */ React.forwardRef(function Bread
2208
2252
  ensureDefined(defineBreadcrumbDivider);
2209
2253
  return React.createElement("spui-breadcrumb-divider", useCustomElementProps({ ...props, ref: forwardedRef }), children);
2210
2254
  });
2211
- export const Nav = /* @__PURE__ */ React.forwardRef(function Nav({ children, label = "Navigation", selectedValue, defaultSelectedValue, selectedCategoryValue, defaultSelectedCategoryValue, openCategories, defaultOpenCategories = [], open, defaultOpen, collapsed, defaultCollapsed, collapsible = false, multiple = true, density = "medium", openLabel, closeLabel, onItemSelect, onCategoryToggle, onNavItemSelect, onNavCategoryItemToggle, onOpenChange, onCollapsedChange, onClick, onClickCapture, onKeyDown, onKeyDownCapture, onKeyUp, onKeyUpCapture, onKeyPress, onKeyPressCapture, onFocus, onFocusCapture, onBlur, onBlurCapture, onAuxClick, onAuxClickCapture, onContextMenu, onContextMenuCapture, onDoubleClick, onDoubleClickCapture, onMouseDown, onMouseDownCapture, onMouseMove, onMouseMoveCapture, onMouseOut, onMouseOutCapture, onMouseOver, onMouseOverCapture, onMouseUp, onMouseUpCapture, onGotPointerCapture, onGotPointerCaptureCapture, onLostPointerCapture, onLostPointerCaptureCapture, onPointerCancel, onPointerCancelCapture, onPointerDown, onPointerDownCapture, onPointerMove, onPointerMoveCapture, onPointerOut, onPointerOutCapture, onPointerOver, onPointerOverCapture, onPointerUp, onPointerUpCapture, onMouseEnter, onMouseLeave, onPointerEnter, onPointerLeave, ...props }, forwardedRef) {
2255
+ export const Nav = /* @__PURE__ */ React.forwardRef(function Nav({ children, label = "Navigation", selectedValue, defaultSelectedValue, selectedCategoryValue, defaultSelectedCategoryValue, openCategories, defaultOpenCategories = [], open, defaultOpen, collapsed, defaultCollapsed, fullWidth = false, collapsible = false, multiple = true, density = "medium", openLabel, closeLabel, onItemSelect, onCategoryToggle, onNavItemSelect, onNavCategoryItemToggle, onOpenChange, onCollapsedChange, onClick, onClickCapture, onKeyDown, onKeyDownCapture, onKeyUp, onKeyUpCapture, onKeyPress, onKeyPressCapture, onFocus, onFocusCapture, onBlur, onBlurCapture, onAuxClick, onAuxClickCapture, onContextMenu, onContextMenuCapture, onDoubleClick, onDoubleClickCapture, onMouseDown, onMouseDownCapture, onMouseMove, onMouseMoveCapture, onMouseOut, onMouseOutCapture, onMouseOver, onMouseOverCapture, onMouseUp, onMouseUpCapture, onGotPointerCapture, onGotPointerCaptureCapture, onLostPointerCapture, onLostPointerCaptureCapture, onPointerCancel, onPointerCancelCapture, onPointerDown, onPointerDownCapture, onPointerMove, onPointerMoveCapture, onPointerOut, onPointerOutCapture, onPointerOver, onPointerOverCapture, onPointerUp, onPointerUpCapture, onMouseEnter, onMouseLeave, onPointerEnter, onPointerLeave, ...props }, forwardedRef) {
2212
2256
  const ref = React.useRef(null);
2213
2257
  useExposeHostRef(ref, forwardedRef);
2214
2258
  ;
@@ -2246,7 +2290,7 @@ export const Nav = /* @__PURE__ */ React.forwardRef(function Nav({ children, lab
2246
2290
  element.defaultCollapsed = defaultCollapsed;
2247
2291
  defaultsApplied.current = true;
2248
2292
  }, [selectedValue, defaultSelectedValue, selectedCategoryValue, defaultSelectedCategoryValue, openCategories, defaultOpenCategories, open, defaultOpen, collapsed, defaultCollapsed]);
2249
- return React.createElement("spui-nav", nativeControlHostProps({ ...props, ref, label, multiple: multiple ? "" : "false", density, collapsible: collapsible || undefined, "open-label": openLabel ?? strings.navigationMenu ?? "Open navigation", "close-label": closeLabel ?? strings.navigationClose ?? strings.close, "expand-label": strings.navigationExpand ?? "Expand navigation", "collapse-label": strings.navigationCollapse ?? "Collapse navigation" }), children);
2293
+ return React.createElement("spui-nav", nativeControlHostProps({ ...props, ref, label, multiple: multiple ? "" : "false", density, "full-width": fullWidth || undefined, collapsible: collapsible || undefined, "open-label": openLabel ?? strings.navigationMenu ?? "Open navigation", "close-label": closeLabel ?? strings.navigationClose ?? strings.close, "expand-label": strings.navigationExpand ?? "Expand navigation", "collapse-label": strings.navigationCollapse ?? "Collapse navigation" }), children);
2250
2294
  });
2251
2295
  function renderNavAvatar(avatar) {
2252
2296
  return avatar ? React.cloneElement(avatar, { slot: "avatar", ...(avatar.type === Avatar ? { decorative: true } : {}) }) : null;
@@ -3087,6 +3131,7 @@ export function AvatarGroupPopover({ children, count, indicator, label, triggerL
3087
3131
  const context = React.useContext(UIContext);
3088
3132
  const size = React.useContext(AvatarGroupSizeContext);
3089
3133
  const itemCount = count ?? React.Children.count(children);
3134
+ const resolvedLabel = label ?? context.strings.people ?? "More people";
3090
3135
  const triggerText = (triggerLabel ?? context.strings.showMorePeople ?? "Show more people ({count})").replace("{count}", String(itemCount));
3091
3136
  const showCount = indicator ?? (size < 24 ? "icon" : "count");
3092
3137
  const defaultTriggerContent = showCount === "icon"
@@ -3110,12 +3155,13 @@ export function AvatarGroupPopover({ children, count, indicator, label, triggerL
3110
3155
  : React.createElement("ul", { ...contentProps, role: contentProps.role ?? "list" }, React.createElement(AvatarGroupOverflowContext.Provider, { value: true }, listChildren));
3111
3156
  const surfaceElement = React.isValidElement(popoverSurface) ? popoverSurface : undefined;
3112
3157
  const surfaceProps = (surfaceElement ? surfaceElement.props : popoverSurface ?? {});
3158
+ const surfaceLabel = surfaceProps["aria-label"] ?? resolvedLabel;
3113
3159
  const surfaceContent = surfaceElement
3114
- ? React.cloneElement(surfaceElement, { "aria-label": surfaceProps["aria-label"] ?? "Overflow", tabIndex: surfaceProps.tabIndex ?? 0, children: listContent })
3115
- : React.createElement(PopoverSurface, { ...surfaceProps, "aria-label": surfaceProps["aria-label"] ?? "Overflow", tabIndex: surfaceProps.tabIndex ?? 0 }, listContent);
3160
+ ? React.cloneElement(surfaceElement, { "aria-label": surfaceLabel, tabIndex: surfaceProps.tabIndex ?? 0, children: listContent })
3161
+ : React.createElement(PopoverSurface, { ...surfaceProps, "aria-label": surfaceLabel, tabIndex: surfaceProps.tabIndex ?? 0 }, listContent);
3116
3162
  return React.createElement(Popover, {
3117
3163
  ...props,
3118
- label: label ?? context.strings.people ?? "More people",
3164
+ label: resolvedLabel,
3119
3165
  placement,
3120
3166
  open,
3121
3167
  trapFocus: true,
@@ -3123,15 +3169,18 @@ export function AvatarGroupPopover({ children, count, indicator, label, triggerL
3123
3169
  onOpenChange: (_event, data) => onOpenChange?.(data.open),
3124
3170
  }, surfaceContent);
3125
3171
  }
3172
+ const presenceStringKeys = { available: "presenceAvailable", busy: "presenceBusy", "do-not-disturb": "presenceDoNotDisturb", away: "presenceAway", offline: "presenceOffline", unknown: "presenceUnknown", "out-of-office": "presenceOutOfOffice", blocked: "presenceBlocked" };
3126
3173
  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) {
3127
3174
  ensureDefined(definePersona);
3128
3175
  const ref = React.useRef(null);
3129
3176
  useExposeHostRef(ref, forwardedRef);
3130
3177
  useNativeControlEvents(ref, ".layout", props.onClick, props.onClickCapture, props);
3178
+ const strings = React.useContext(UIContext).strings;
3179
+ const presenceLabelFromProvider = presence ? strings[presenceStringKeys[presence]] : undefined;
3131
3180
  const textSlot = (node, slot) => node == null ? null : React.isValidElement(node)
3132
3181
  ? React.cloneElement(node, { slot })
3133
3182
  : React.createElement("span", { slot }, node);
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));
3183
+ 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 ?? presenceLabelFromProvider, 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));
3135
3184
  });
3136
3185
  const VirtualizerScrollViewRootContext = React.createContext(null);
3137
3186
  function mergeVirtualizerRootProps(slotProps, rootProps) {
@@ -3660,7 +3709,7 @@ const EMPTY_DATA_GRID_ITEMS = [];
3660
3709
  const EMPTY_DATA_GRID_COLUMN_WIDTHS = Object.freeze({});
3661
3710
  const EMPTY_DATA_GRID_COLUMN_SIZING_OPTIONS = Object.freeze({});
3662
3711
  const DEFAULT_DATA_GRID_RESIZABLE_COLUMNS_OPTIONS = Object.freeze({ autoFitColumns: true });
3663
- function VirtualDataGrid({ items, dataSource, onDataLoadError, onDataSourceGroupToggle, columns, getRowId, label: labelProp, height = 400, rowHeight = 40, getRowHeight, overscan = 4, virtualize, virtualizeColumns, focusMode = "cell", subtleSelection = false, selectionAppearance = "brand", selectionMode = "none", selectedKeys, defaultSelectedKeys = [], selectionModel, defaultSelectionModel, onDataSourceSelectionChange, onSelectionChange, sort, defaultSort, onSortChange, multiSort, defaultMultiSort = [], onMultiSortChange, sortPriorityLabel: sortPriorityLabelProp, filterable = false, filterValue, defaultFilterValue = "", onFilterValueChange, filterLabel: filterLabelProp, renderCell, onCellEdit, onCellsEdit, validateCellEdit, rowLabel: rowLabelProp, editHint: editHintProp, emptyMessage: emptyMessageProp, loadingLabel: loadingLabelProp, selectLabel: selectLabelProp, selectAllLabel: selectAllLabelProp, resizableColumns = false, columnWidths, defaultColumnWidths = EMPTY_DATA_GRID_COLUMN_WIDTHS, columnSizingOptions = EMPTY_DATA_GRID_COLUMN_SIZING_OPTIONS, resizableColumnsOptions = DEFAULT_DATA_GRID_RESIZABLE_COLUMNS_OPTIONS, containerWidthOffset = 0, onColumnResize, resizeLabel: resizeLabelProp, reorderableColumns = false, columnOrder, defaultColumnOrder, onColumnOrderChange, reorderLabel: reorderLabelProp, groupBy, collapsedGroupKeys, defaultCollapsedGroupKeys = [], onCollapsedGroupKeysChange, emptyGroupLabel: emptyGroupLabelProp, expandGroupLabel: expandGroupLabelProp, collapseGroupLabel: collapseGroupLabelProp, onRenderedRange, ...props }) {
3712
+ function VirtualDataGrid({ items, dataSource, onDataLoadError, onDataSourceGroupToggle, columns, getRowId, label: labelProp, height = 400, rowHeight = 40, getRowHeight, overscan = 4, virtualize, virtualizeColumns, focusMode = "cell", subtleSelection = false, selectionAppearance = "brand", selectionMode = "none", selectedKeys, defaultSelectedKeys = [], selectionModel, defaultSelectionModel, onDataSourceSelectionChange, onSelectionChange, sort, defaultSort, onSortChange, multiSort, defaultMultiSort = [], onMultiSortChange, sortPriorityLabel: sortPriorityLabelProp, filterable = false, filterValue, defaultFilterValue = "", onFilterValueChange, filterLabel: filterLabelProp, renderCell, onCellEdit, onCellEditError, onCellsEdit, validateCellEdit, rowLabel: rowLabelProp, editHint: editHintProp, emptyMessage: emptyMessageProp, loadingLabel: loadingLabelProp, selectLabel: selectLabelProp, selectAllLabel: selectAllLabelProp, resizableColumns = false, columnWidths, defaultColumnWidths = EMPTY_DATA_GRID_COLUMN_WIDTHS, columnSizingOptions = EMPTY_DATA_GRID_COLUMN_SIZING_OPTIONS, resizableColumnsOptions = DEFAULT_DATA_GRID_RESIZABLE_COLUMNS_OPTIONS, containerWidthOffset = 0, onColumnResize, resizeLabel: resizeLabelProp, reorderableColumns = false, columnOrder, defaultColumnOrder, onColumnOrderChange, reorderLabel: reorderLabelProp, groupBy, collapsedGroupKeys, defaultCollapsedGroupKeys = [], onCollapsedGroupKeysChange, emptyGroupLabel: emptyGroupLabelProp, expandGroupLabel: expandGroupLabelProp, collapseGroupLabel: collapseGroupLabelProp, onRenderedRange, ...props }) {
3664
3713
  selectionMode = selectionMode === "multiselect" ? "multiple" : selectionMode;
3665
3714
  const [scrollTop, setScrollTop] = React.useState(0);
3666
3715
  const [viewportHeight, setViewportHeight] = React.useState(typeof height === "number" ? height : 400);
@@ -3996,7 +4045,9 @@ function VirtualDataGrid({ items, dataSource, onDataLoadError, onDataSourceGroup
3996
4045
  }
3997
4046
  catch (reason) {
3998
4047
  const message = reason instanceof Error ? reason.message : String(reason || "The value could not be saved.");
3999
- updateEditingCell({ ...current, draft, saving: false, error: message });
4048
+ updateEditingCell({ ...current, draft, saving: false, error: uiStrings.dataGridEditError ?? defaultStrings.dataGridEditError });
4049
+ onCellEditError?.({ item: edit.item, rowId: edit.rowId, columnId: edit.columnId, previousValue: edit.previousValue, value: edit.value, error: message });
4050
+ viewport.current?.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 }));
4000
4051
  requestAnimationFrame(() => viewport.current?.querySelector("[data-testid='spui-data-grid-editor']")?.focus());
4001
4052
  }
4002
4053
  };
@@ -4093,7 +4144,7 @@ function VirtualDataGrid({ items, dataSource, onDataLoadError, onDataSourceGroup
4093
4144
  if (controller.signal.aborted)
4094
4145
  return;
4095
4146
  const message = reason instanceof Error ? reason.message : String(reason);
4096
- setReorderAnnouncement((uiStrings.dataGridCopyFailed ?? defaultStrings.dataGridCopyFailed).replace("{message}", message));
4147
+ setReorderAnnouncement(uiStrings.dataGridCopyFailed ?? defaultStrings.dataGridCopyFailed);
4097
4148
  viewport.current?.dispatchEvent(new CustomEvent("spui-clipboard-error", { detail: { operation: "copy", message }, bubbles: true, composed: true }));
4098
4149
  });
4099
4150
  };
@@ -4177,7 +4228,7 @@ function VirtualDataGrid({ items, dataSource, onDataLoadError, onDataSourceGroup
4177
4228
  if (clipboardController.current?.signal.aborted)
4178
4229
  return;
4179
4230
  const message = reason instanceof Error ? reason.message : String(reason);
4180
- setReorderAnnouncement((uiStrings.dataGridPasteFailed ?? defaultStrings.dataGridPasteFailed).replace("{message}", message));
4231
+ setReorderAnnouncement(uiStrings.dataGridPasteFailed ?? defaultStrings.dataGridPasteFailed);
4181
4232
  viewport.current?.dispatchEvent(new CustomEvent("spui-cells-edit-error", { detail: { message, edits }, bubbles: true, composed: true }));
4182
4233
  }
4183
4234
  };
@@ -4416,7 +4467,7 @@ function VirtualDataGrid({ items, dataSource, onDataLoadError, onDataSourceGroup
4416
4467
  else
4417
4468
  setSelection(event.currentTarget.checked ? sortedItems.map(getRowId).map(String) : []); } }) }), orderedColumns.map((column, columnIndex) => _jsxs("div", { role: "columnheader", "data-column-id": column.id, "data-column-index": columnIndex, "aria-colindex": columnIndex + (selectionMode === "none" ? 1 : 2), "aria-sort": column.sortable === false ? undefined : activeSorts[0]?.columnId === column.id ? activeSorts[0].direction : "none", className: "spui-grid-cell spui-grid-header-cell", onDragOver: event => { if (reorderableColumns && draggedColumn.current)
4418
4469
  event.preventDefault(); }, onDrop: event => { event.preventDefault(); const rect = event.currentTarget.getBoundingClientRect(); const rtl = getComputedStyle(viewport.current).direction === "rtl"; const after = rtl ? event.clientX < rect.left + rect.width / 2 : event.clientX > rect.left + rect.width / 2; if (reorderableColumns)
4419
- moveColumn(draggedColumn.current ?? "", column.id, after); draggedColumn.current = undefined; }, children: [reorderableColumns && _jsx("button", { type: "button", className: "spui-grid-reorder-handle", "data-reorder-column": column.id, draggable: true, "aria-label": `${reorderLabel} ${column.label}`, title: `${reorderLabel} ${column.label}; use Alt+Shift+Arrow keys`, onDragStart: event => { draggedColumn.current = column.id; event.dataTransfer.effectAllowed = "move"; event.dataTransfer.setData("text/plain", column.id); }, onDragEnd: () => { draggedColumn.current = undefined; }, children: "\u283F" }), column.sortable === false ? column.label : _jsxs("button", { type: "button", "aria-label": activeSorts.some(entry => entry.columnId === column.id) ? `${column.label}, ${sortPriorityLabel.replace("{priority}", String(activeSorts.findIndex(entry => entry.columnId === column.id) + 1))}` : column.label, onClick: event => changeSort(column.id, event.shiftKey), children: [column.label, activeSorts.some(entry => entry.columnId === column.id) ? ` ${activeSorts.findIndex(entry => entry.columnId === column.id) + 1}${activeSorts.find(entry => entry.columnId === column.id)?.direction === "ascending" ? "▲" : "▼"}` : ""] }), resizableColumns && column.resizable !== false && _jsx("div", { ref: element => { if (element && activeColumnWidths[column.id] === undefined)
4470
+ moveColumn(draggedColumn.current ?? "", column.id, after); draggedColumn.current = undefined; }, children: [reorderableColumns && _jsx("button", { type: "button", className: "spui-grid-reorder-handle", "data-reorder-column": column.id, draggable: true, "aria-label": `${reorderLabel} ${column.label}`, title: (uiStrings.dataGridReorderHint ?? defaultStrings.dataGridReorderHint).replace("{column}", column.label), onDragStart: event => { draggedColumn.current = column.id; event.dataTransfer.effectAllowed = "move"; event.dataTransfer.setData("text/plain", column.id); }, onDragEnd: () => { draggedColumn.current = undefined; }, children: "\u283F" }), column.sortable === false ? column.label : _jsxs("button", { type: "button", "aria-label": activeSorts.some(entry => entry.columnId === column.id) ? `${column.label}, ${sortPriorityLabel.replace("{priority}", String(activeSorts.findIndex(entry => entry.columnId === column.id) + 1))}` : column.label, onClick: event => changeSort(column.id, event.shiftKey), children: [column.label, activeSorts.some(entry => entry.columnId === column.id) ? ` ${activeSorts.findIndex(entry => entry.columnId === column.id) + 1}${activeSorts.find(entry => entry.columnId === column.id)?.direction === "ascending" ? "▲" : "▼"}` : ""] }), resizableColumns && column.resizable !== false && _jsx("div", { ref: element => { if (element && activeColumnWidths[column.id] === undefined)
4420
4471
  element.setAttribute("aria-valuenow", String(Math.round(element.parentElement?.getBoundingClientRect().width ?? 120))); }, className: "spui-grid-resize-handle", "data-resize-column": column.id, role: "separator", "aria-orientation": "vertical", "aria-label": `${resizeLabel} ${column.label}`, "aria-valuemin": getDataGridColumnSizing(column, columnSizingOptions).minWidth, "aria-valuemax": column.maxWidth ?? 1600, "aria-valuenow": activeColumnWidths[column.id] ?? getDataGridColumnSizing(column, columnSizingOptions).defaultWidth, tabIndex: 0, onDoubleClick: event => autoFitResize(column, event), onPointerDown: event => startResize(column, event), onPointerMove: moveResize, onPointerUp: event => endResize(event), onPointerCancel: event => endResize(event, true), onLostPointerCapture: event => endResize(event, true) })] }, column.id))] }) }), _jsx("div", { role: "rowgroup", style: { position: "relative" }, children: (dataSource ? sourceLength : sortedItems.length) === 0 ? _jsx("div", { role: "row", "aria-rowindex": 2, className: "spui-grid-row", style: { gridTemplateColumns: gridColumns }, children: _jsx("div", { role: "gridcell", className: "spui-grid-cell", style: { gridColumn: `1 / span ${columns.length + (selectionMode === "none" ? 0 : 1)}` }, children: shownEmptyMessage }) }) : _jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", role: "presentation", style: { height: shouldVirtualize ? rowSizes.offset(first) : 0 } }), Array.from({ length: last - first }, (_, offset) => {
4421
4472
  const rowIndex = first + offset;
4422
4473
  const sourceRow = dataSource ? getDataGridDataSourceRow(dataSource, rowIndex) : undefined;
@@ -4448,9 +4499,9 @@ function VirtualDataGrid({ items, dataSource, onDataLoadError, onDataSourceGroup
4448
4499
  else if (event.key === "Enter") {
4449
4500
  event.preventDefault();
4450
4501
  event.currentTarget.blur();
4451
- } }, style: { boxSizing: "border-box", width: "100%", minWidth: 0, minHeight: 30, padding: "3px 6px", border: `1px solid var(${editingCell.error ? "--spui-semantic-danger" : "--spui-ui-accent"},${editingCell.error ? "#d13438" : "#78716c"})`, borderRadius: "var(--spui-control-radius,4px)", background: "var(--spui-base-surface,var(--spui-ui-surface,#fff))", color: "var(--spui-ui-text,var(--spui-semantic-body-text,#242424))", font: "inherit" } })] }) : Object.hasOwn(editedCells, editedKey) ? String(displayValue ?? "") : renderCell ? renderCell(item, column, itemIndex) : String(displayValue ?? "") }, column.id);
4502
+ } }, style: { boxSizing: "border-box", width: "100%", minWidth: 0, minHeight: 30, padding: "3px 6px", border: `2px solid var(${editingCell.error ? "--spui-semantic-danger" : "--spui-ui-accent"},${editingCell.error ? "#d13438" : "#78716c"})`, outline: "none", borderRadius: "var(--spui-control-radius,4px)", background: "var(--spui-base-surface,var(--spui-ui-surface,#fff))", color: "var(--spui-ui-text,var(--spui-semantic-body-text,#242424))", font: "inherit" } })] }) : Object.hasOwn(editedCells, editedKey) ? String(displayValue ?? "") : renderCell ? renderCell(item, column, itemIndex) : String(displayValue ?? "") }, column.id);
4452
4503
  })] }, key);
4453
- }), _jsx("div", { "aria-hidden": "true", role: "presentation", style: { height: shouldVirtualize ? Math.max(0, rowSizes.totalSize - rowSizes.offset(last)) : 0 } })] }) })] }), _jsx("div", { className: "spui-grid-reorder-status", role: "status", "aria-live": "polite", children: sourceError ? `Data could not be loaded: ${sourceError}` : reorderAnnouncement })] });
4504
+ }), _jsx("div", { "aria-hidden": "true", role: "presentation", style: { height: shouldVirtualize ? Math.max(0, rowSizes.totalSize - rowSizes.offset(last)) : 0 } })] }) })] }), _jsx("div", { className: "spui-grid-reorder-status", role: "status", "aria-live": "polite", children: sourceError ? uiStrings.dataGridLoadError ?? defaultStrings.dataGridLoadError : reorderAnnouncement })] });
4454
4505
  }
4455
4506
  const defaultDataGridContextValue = {
4456
4507
  items: [], totalRows: 0, firstRow: 0, lastRow: 0, rowHeight: 40, sourceBusy: false, sourceError: "",
@@ -4523,7 +4574,7 @@ function useDataGridContextSelector(selector) {
4523
4574
  export function useDataGridContext_unstable(selector) {
4524
4575
  return useDataGridContextSelector(context => selector(context ?? defaultDataGridContextValue));
4525
4576
  }
4526
- function ComposedDataGrid({ items = [], dataSource, onDataLoadError, onDataSourceSelectionChange, onDataSourceGroupToggle, onRenderedRange, rowHeight: requestedRowHeight = 40, overscan = 4, virtualize, loadingLabel: loadingLabelProp, expandGroupLabel: expandGroupLabelProp, collapseGroupLabel: collapseGroupLabelProp, groupCountLabel: groupCountLabelProp, columns, getRowId, selectionMode = "none", selectionAppearance = "brand", subtleSelection = false, focusMode = "cell", selectedItems, defaultSelectedItems = new Set(), selectionModel, defaultSelectionModel, onSelectionChange, sortState, defaultSortState, onSortChange, onCellEdit, validateCellEdit, rowLabel: rowLabelProp, editHint: editHintProp, label: labelProp, resizableColumns = false, columnWidths, defaultColumnWidths = EMPTY_DATA_GRID_COLUMN_WIDTHS, columnSizingOptions = EMPTY_DATA_GRID_COLUMN_SIZING_OPTIONS, resizableColumnsOptions = DEFAULT_DATA_GRID_RESIZABLE_COLUMNS_OPTIONS, containerWidthOffset = 0, onColumnResize, resizeLabel: resizeLabelProp, reorderableColumns = false, columnOrder, defaultColumnOrder, onColumnOrderChange, reorderLabel: reorderLabelProp, children, onKeyDown: onGridKeyDown, ...props }) {
4577
+ function ComposedDataGrid({ items = [], dataSource, onDataLoadError, onDataSourceSelectionChange, onDataSourceGroupToggle, onRenderedRange, rowHeight: requestedRowHeight = 40, overscan = 4, virtualize, loadingLabel: loadingLabelProp, expandGroupLabel: expandGroupLabelProp, collapseGroupLabel: collapseGroupLabelProp, groupCountLabel: groupCountLabelProp, columns, getRowId, selectionMode = "none", selectionAppearance = "brand", subtleSelection = false, focusMode = "cell", selectedItems, defaultSelectedItems = new Set(), selectionModel, defaultSelectionModel, onSelectionChange, sortState, defaultSortState, onSortChange, onCellEdit, onCellEditError, validateCellEdit, rowLabel: rowLabelProp, editHint: editHintProp, label: labelProp, resizableColumns = false, columnWidths, defaultColumnWidths = EMPTY_DATA_GRID_COLUMN_WIDTHS, columnSizingOptions = EMPTY_DATA_GRID_COLUMN_SIZING_OPTIONS, resizableColumnsOptions = DEFAULT_DATA_GRID_RESIZABLE_COLUMNS_OPTIONS, containerWidthOffset = 0, onColumnResize, resizeLabel: resizeLabelProp, reorderableColumns = false, columnOrder, defaultColumnOrder, onColumnOrderChange, reorderLabel: reorderLabelProp, children, onKeyDown: onGridKeyDown, ...props }) {
4527
4578
  const compositionStrings = React.useContext(UIContext).strings;
4528
4579
  const label = labelProp ?? (typeof props["aria-label"] === "string" ? props["aria-label"] : compositionStrings.dataGridLabel ?? defaultStrings.dataGridLabel);
4529
4580
  const loadingLabel = loadingLabelProp ?? compositionStrings.dataGridLoadingLabel ?? defaultStrings.dataGridLoadingLabel;
@@ -4878,7 +4929,7 @@ function ComposedDataGrid({ items = [], dataSource, onDataLoadError, onDataSourc
4878
4929
  },
4879
4930
  };
4880
4931
  }, [orderedColumns, columnSizingOptions, activeWidths, resizeColumn, resizableColumns, resizeLabel, keyboardSizingColumns]);
4881
- const context = React.useMemo(() => ({ items: contextItems, dataSource, totalRows, firstRow, lastRow, rowHeight: safeRowHeight, sourceBusy, sourceError, expandGroupLabel, collapseGroupLabel, groupCountLabel, toggleGroup, columns: contextColumns, getRowId, selectionMode, selectionAppearance, subtleSelection, focusMode, selectedItems: selected, selectionModel: activeSelectionModel, setSelectionModel, isItemSelected, isRowSelected, setSelectedItems, sortState: activeSort, setSortState: setSort, activeCell, setActiveCell, columnWidths: activeWidths, resizeColumn, columnSizingOptions, resizableColumns, autoFitColumns, resizeLabel, orderedColumns, reorderColumn: moveColumn, reorderableColumns, reorderLabel, draggedColumn, editHint, rowLabel, editedCells, onCellEdit, validateCellEdit, setEditedCell, getRows: fluentRows, selection: fluentSelection, sort: fluentSort, tableRef: gridRoot, columnSizing_unstable: fluentSizing, selectableRows: selectionMode !== "none", compositeRowTabsterAttribute: tableRowNavigationAttribute }), [contextItems, contextColumns, dataSource, totalRows, firstRow, lastRow, safeRowHeight, sourceBusy, sourceError, expandGroupLabel, collapseGroupLabel, groupCountLabel, onDataSourceGroupToggle, columns, getRowId, selectionMode, selectionAppearance, subtleSelection, focusMode, selected, selectionModel, activeSelectionModel, setSelectionModel, isItemSelected, isRowSelected, setSelectedItems, onSelectionChange, onDataSourceSelectionChange, activeSort, sortState, onSortChange, activeCell, activeWidths, columnWidths, columnSizingOptions, onColumnResize, resizableColumns, autoFitColumns, resizeLabel, orderedColumns, columnOrder, onColumnOrderChange, reorderableColumns, reorderLabel, editHint, rowLabel, editedCells, onCellEdit, validateCellEdit, fluentRows, fluentSelection, fluentSort, fluentSizing]);
4932
+ const context = React.useMemo(() => ({ items: contextItems, dataSource, totalRows, firstRow, lastRow, rowHeight: safeRowHeight, sourceBusy, sourceError, expandGroupLabel, collapseGroupLabel, groupCountLabel, toggleGroup, columns: contextColumns, getRowId, selectionMode, selectionAppearance, subtleSelection, focusMode, selectedItems: selected, selectionModel: activeSelectionModel, setSelectionModel, isItemSelected, isRowSelected, setSelectedItems, sortState: activeSort, setSortState: setSort, activeCell, setActiveCell, columnWidths: activeWidths, resizeColumn, columnSizingOptions, resizableColumns, autoFitColumns, resizeLabel, orderedColumns, reorderColumn: moveColumn, reorderableColumns, reorderLabel, draggedColumn, editHint, rowLabel, editedCells, onCellEdit, onCellEditError, validateCellEdit, setEditedCell, getRows: fluentRows, selection: fluentSelection, sort: fluentSort, tableRef: gridRoot, columnSizing_unstable: fluentSizing, selectableRows: selectionMode !== "none", compositeRowTabsterAttribute: tableRowNavigationAttribute }), [contextItems, contextColumns, dataSource, totalRows, firstRow, lastRow, safeRowHeight, sourceBusy, sourceError, expandGroupLabel, collapseGroupLabel, groupCountLabel, onDataSourceGroupToggle, columns, getRowId, selectionMode, selectionAppearance, subtleSelection, focusMode, selected, selectionModel, activeSelectionModel, setSelectionModel, isItemSelected, isRowSelected, setSelectedItems, onSelectionChange, onDataSourceSelectionChange, activeSort, sortState, onSortChange, activeCell, activeWidths, columnWidths, columnSizingOptions, onColumnResize, resizableColumns, autoFitColumns, resizeLabel, orderedColumns, columnOrder, onColumnOrderChange, reorderableColumns, reorderLabel, editHint, rowLabel, editedCells, onCellEdit, onCellEditError, validateCellEdit, fluentRows, fluentSelection, fluentSort, fluentSizing]);
4882
4933
  const focusBy = (event) => {
4883
4934
  if (event.ctrlKey && (event.key === "Home" || event.key === "End")) {
4884
4935
  event.preventDefault();
@@ -4950,7 +5001,7 @@ function ComposedDataGrid({ items = [], dataSource, onDataLoadError, onDataSourc
4950
5001
  const rtl = getComputedStyle(event.currentTarget).direction === "rtl";
4951
5002
  moveColumn(from, to, rtl ? event.clientX < rect.left + rect.width / 2 : event.clientX > rect.left + rect.width / 2);
4952
5003
  draggedColumn.current = undefined;
4953
- } props.onDrop?.(event); }, "data-selection-appearance": selectionAppearance, "data-spui-composed-grid": "", style: { boxSizing: "border-box", width: "100%", overflow: "auto", border: "1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))", borderRadius: "var(--spui-control-radius,6px)", background: "var(--spui-base-surface,var(--spui-ui-surface,#fff))", color: "var(--spui-ui-text,var(--spui-semantic-body-text,#242424))", fontFamily: "var(--spui-font-family,inherit)", "--spui-composed-grid-columns": tracks, ...props.style } }), children: children }), sourceBusy && _jsx("div", { role: "status", "aria-live": "polite", className: "spui-sr-only", children: loadingLabel }), sourceError && _jsx("div", { role: "alert", children: sourceError }), _jsx("div", { className: "spui-grid-reorder-status", role: "status", "aria-live": "polite", style: { position: "absolute", width: 1, height: 1, overflow: "hidden", clipPath: "inset(50%)" }, children: reorderAnnouncement })] }) });
5004
+ } props.onDrop?.(event); }, "data-selection-appearance": selectionAppearance, "data-spui-composed-grid": "", style: { boxSizing: "border-box", width: "100%", overflow: "auto", border: "1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))", borderRadius: "var(--spui-control-radius,6px)", background: "var(--spui-base-surface,var(--spui-ui-surface,#fff))", color: "var(--spui-ui-text,var(--spui-semantic-body-text,#242424))", fontFamily: "var(--spui-font-family,inherit)", "--spui-composed-grid-columns": tracks, ...props.style } }), children: children }), sourceBusy && _jsx("div", { role: "status", "aria-live": "polite", className: "spui-sr-only", children: loadingLabel }), sourceError && _jsx("div", { role: "alert", children: compositionStrings.dataGridLoadError ?? defaultStrings.dataGridLoadError }), _jsx("div", { className: "spui-grid-reorder-status", role: "status", "aria-live": "polite", style: { position: "absolute", width: 1, height: 1, overflow: "hidden", clipPath: "inset(50%)" }, children: reorderAnnouncement })] }) });
4954
5005
  }
4955
5006
  export function DataGrid(props) {
4956
5007
  if ("children" in props && props.children !== undefined)
@@ -5077,6 +5128,7 @@ export function DataGridCell({ children, columnId, rowIndex = 1, columnIndex = 0
5077
5128
  return _jsx(ComposedDataGridCell, { ...props, item: item, context: context, cellKey: cellKey, rowIndex: rowIndex, columnIndex: effectiveColumnIndex, columnId: id, focusMode: focusMode, editable: editable, value: value, editType: editType, editLabel: editLabel, children: children });
5078
5129
  }
5079
5130
  function ComposedDataGridCell({ children, item, context, cellKey, rowIndex = 1, columnIndex, columnId, focusMode, editable, value, editType, editLabel, ...props }) {
5131
+ const uiStrings = React.useContext(UIContext).strings;
5080
5132
  const [editing, setEditing] = React.useState(false);
5081
5133
  const [draft, setDraft] = React.useState("");
5082
5134
  const [error, setError] = React.useState("");
@@ -5131,8 +5183,9 @@ function ComposedDataGridCell({ children, item, context, cellKey, rowIndex = 1,
5131
5183
  }
5132
5184
  catch (reason) {
5133
5185
  const message = reason instanceof Error ? reason.message : String(reason || "The value could not be saved.");
5134
- setError(message);
5135
- cell.current?.dispatchEvent(new CustomEvent("spui-cell-edit-error", { bubbles: true, detail: { ...edit, error: message } }));
5186
+ setError(uiStrings.dataGridEditError ?? defaultStrings.dataGridEditError);
5187
+ context.onCellEditError?.({ item: edit.item, rowId: edit.rowId, columnId: edit.columnId, previousValue: edit.previousValue, value: edit.value, error: message });
5188
+ cell.current?.dispatchEvent(new CustomEvent("spui-cell-edit-error", { bubbles: true, composed: true, detail: { item: edit.item, rowId: edit.rowId, columnId: edit.columnId, previousValue: edit.previousValue, value: edit.value, error: message } }));
5136
5189
  requestAnimationFrame(() => input.current?.focus());
5137
5190
  }
5138
5191
  finally {
@@ -5171,10 +5224,11 @@ function ComposedDataGridCell({ children, item, context, cellKey, rowIndex = 1,
5171
5224
  }
5172
5225
  else if (event.key.startsWith("Arrow"))
5173
5226
  event.stopPropagation(); }, onBlur: () => { if (!savingRef.current && !cancelledRef.current)
5174
- void commit(); }, style: { width: "100%", minWidth: 0, boxSizing: "border-box", font: "inherit", color: "inherit", background: "var(--spui-base-surface,var(--spui-ui-surface,#fff))", border: "1px solid var(--spui-ui-accent,var(--spui-semantic-primary-button-background,#0078d4))", borderRadius: "var(--spui-control-radius,4px)", padding: "4px 6px", outline: "2px solid color-mix(in srgb,var(--spui-ui-accent,#0078d4) 22%,transparent)" } }), error && _jsx("span", { id: `${cellKey}-error`, role: "alert", className: "spui-sr-only", children: error })] }) : rendered });
5227
+ void commit(); }, style: { width: "100%", minWidth: 0, boxSizing: "border-box", font: "inherit", color: "inherit", background: "var(--spui-base-surface,var(--spui-ui-surface,#fff))", border: error ? "2px solid var(--spui-semantic-danger,var(--spui-ui-danger,#d13438))" : "2px solid var(--spui-ui-accent,var(--spui-semantic-primary-button-background,#0078d4))", outline: "none", borderRadius: "var(--spui-control-radius,4px)", padding: "4px 6px" } }), error && _jsx("span", { id: `${cellKey}-error`, role: "alert", className: "spui-sr-only", children: error })] }) : rendered });
5175
5228
  }
5176
5229
  export function DataGridHeaderCell({ children, columnId, rowIndex = 0, columnIndex = 0, sortable = true, sortDirection: explicitSortDirection, focusMode = "cell", aside, sortIcon, button, ...props }) {
5177
5230
  const context = useDataGridComposition();
5231
+ const uiStrings = React.useContext(UIContext).strings;
5178
5232
  const contextualColumnId = React.useContext(DataGridColumnIdContext);
5179
5233
  const grid = useDataGridComposition();
5180
5234
  const id = contextualColumnId ?? columnId;
@@ -5239,7 +5293,7 @@ export function DataGridHeaderCell({ children, columnId, rowIndex = 0, columnInd
5239
5293
  event.stopPropagation();
5240
5294
  grid.reorderColumn(String(id), ids[nextIndex], nextIndex > index);
5241
5295
  };
5242
- return _jsxs("div", { ...props, role: "columnheader", "aria-sort": sortDirection, "data-column-id": id == null ? undefined : String(id), style: { boxSizing: "border-box", position: "relative", display: "flex", gridColumn: effectiveColumnIndex + 1, width: "100%", minWidth: 0, borderBlockEnd: "1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))", fontWeight: 600, ...props.style }, children: [grid?.reorderableColumns && id !== undefined && _jsx("button", { type: "button", draggable: true, "aria-label": `${grid.reorderLabel ?? "Reorder column"} ${headerLabel}`, title: `${grid.reorderLabel ?? "Reorder column"} ${headerLabel}; use Alt+Shift+Arrow keys`, "data-reorder-column": String(id), "data-testid": `data-grid-reorder-${String(id)}`, onKeyDown: reorderKey, onDragStart: event => { event.dataTransfer.effectAllowed = "move"; event.dataTransfer.setData("text/plain", String(id)); }, style: { flex: "none", width: 26, minHeight: 40, padding: 0, border: 0, background: "transparent", color: "var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161))", cursor: "grab" }, children: "\u283F" }), headerControl, renderSpanSlot(aside), grid?.resizableColumns && id !== undefined && _jsx("div", { ref: handleRef, role: "separator", "aria-orientation": "vertical", "aria-label": `${grid.resizeLabel} ${headerLabel}`, "aria-valuemin": getDataGridColumnSizing({ id: String(id), label: String(id) }, grid.columnSizingOptions).minWidth, "aria-valuemax": 1600, "aria-valuenow": width, tabIndex: 0, "data-testid": `data-grid-resize-${String(id)}`, onKeyDown: resizeKey, onDoubleClick: fit, onPointerDown: event => { if (event.button !== 0)
5296
+ return _jsxs("div", { ...props, role: "columnheader", "aria-sort": sortDirection, "data-column-id": id == null ? undefined : String(id), style: { boxSizing: "border-box", position: "relative", display: "flex", gridColumn: effectiveColumnIndex + 1, width: "100%", minWidth: 0, borderBlockEnd: "1px solid var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1))", fontWeight: 600, ...props.style }, children: [grid?.reorderableColumns && id !== undefined && _jsx("button", { type: "button", draggable: true, "aria-label": `${grid.reorderLabel ?? "Reorder column"} ${headerLabel}`, title: (uiStrings.dataGridReorderHint ?? defaultStrings.dataGridReorderHint).replace("{column}", headerLabel), "data-reorder-column": String(id), "data-testid": `data-grid-reorder-${String(id)}`, onKeyDown: reorderKey, onDragStart: event => { event.dataTransfer.effectAllowed = "move"; event.dataTransfer.setData("text/plain", String(id)); }, style: { flex: "none", width: 26, minHeight: 40, padding: 0, border: 0, background: "transparent", color: "var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161))", cursor: "grab" }, children: "\u283F" }), headerControl, renderSpanSlot(aside), grid?.resizableColumns && id !== undefined && _jsx("div", { ref: handleRef, role: "separator", "aria-orientation": "vertical", "aria-label": `${grid.resizeLabel} ${headerLabel}`, "aria-valuemin": getDataGridColumnSizing({ id: String(id), label: String(id) }, grid.columnSizingOptions).minWidth, "aria-valuemax": 1600, "aria-valuenow": width, tabIndex: 0, "data-testid": `data-grid-resize-${String(id)}`, onKeyDown: resizeKey, onDoubleClick: fit, onPointerDown: event => { if (event.button !== 0)
5243
5297
  return; resizeStart.current = { x: event.clientX, width: width ?? getDataGridColumnSizing({ id: String(id), label: String(id) }, grid.columnSizingOptions).defaultWidth }; event.currentTarget.setPointerCapture(event.pointerId); event.preventDefault(); }, onPointerMove: event => { if (!resizeStart.current)
5244
5298
  return; const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1; grid.resizeColumn(String(id), resizeStart.current.width + (event.clientX - resizeStart.current.x) * direction, event.nativeEvent); }, onPointerUp: event => { resizeStart.current = null; if (event.currentTarget.hasPointerCapture(event.pointerId))
5245
5299
  event.currentTarget.releasePointerCapture(event.pointerId); }, style: { position: "absolute", zIndex: 1, insetBlock: 0, insetInlineEnd: 0, width: 10, cursor: "col-resize", touchAction: "none", outline: "none" } })] });
@@ -5399,7 +5453,7 @@ export function Tree({ items, children, label, selectionMode = "none", selectedK
5399
5453
  const allEntries = React.useMemo(() => flattenAllTree(treeItems), [treeItems]);
5400
5454
  const currentActiveKey = visible.some(entry => entry.key === activeKey) ? activeKey : visible[0]?.key ?? "";
5401
5455
  const lang = String(props.lang ?? context.lang ?? (typeof document === "undefined" ? "" : document.documentElement.lang)).toLowerCase();
5402
- const languageIsRtl = /^(ar|fa|he|ur|ps|sd|ug|yi)(-|$)/.test(lang);
5456
+ const languageIsRtl = getDirectionFromLanguage(lang) === "rtl";
5403
5457
  const direction = props.dir ?? context.dir;
5404
5458
  const isRtl = direction === "rtl" || (direction === "auto" && languageIsRtl) || (direction === undefined && (languageIsRtl || (typeof document !== "undefined" && getComputedStyle(document.documentElement).direction === "rtl")));
5405
5459
  const updateSelected = (node, event) => {
@@ -5596,7 +5650,7 @@ export const TextField = /* @__PURE__ */ React.forwardRef(function TextField(inp
5596
5650
  return React.createElement("spui-field", useCustomElementProps({ ...props, ref, label, value }));
5597
5651
  });
5598
5652
  /** Pair one form control with a theme-aware label, hint, and validation message. */
5599
- export function Field({ children, label, hint, validationMessage, validationMessageIcon, validationState, required, disabled, orientation = "vertical", size = "medium", className, style, ...props }) {
5653
+ export const Field = /* @__PURE__ */ React.forwardRef(function Field({ children, label, hint, validationMessage, validationMessageIcon, validationState, required, disabled, orientation = "vertical", size = "medium", className, style, ...props }, forwardedRef) {
5600
5654
  const generatedId = React.useId();
5601
5655
  const initialControl = React.isValidElement(children) && children.type !== React.Fragment ? children : undefined;
5602
5656
  const initialControlProps = initialControl?.props ?? {};
@@ -5678,8 +5732,8 @@ export function Field({ children, label, hint, validationMessage, validationMess
5678
5732
  hintId,
5679
5733
  disabled: Boolean(disabled || controlProps.disabled),
5680
5734
  };
5681
- 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] })] });
5682
- }
5735
+ 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] })] });
5736
+ });
5683
5737
  /** Bare input primitive. Supply aria-label or aria-labelledby; use TextField when a shadow-safe visible label is needed. */
5684
5738
  export const Input = /* @__PURE__ */ React.forwardRef(function Input(inputProps, forwardedRef) {
5685
5739
  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 });
@@ -5889,6 +5943,95 @@ export const AlphaSlider = /* @__PURE__ */ React.forwardRef(function AlphaSlider
5889
5943
  element.defaultColor = defaultColor; }, [color, defaultColor]);
5890
5944
  return React.createElement("spui-alpha-slider", nativeControlHostProps({ ...props, ref, color: undefined, defaultColor: undefined, shape, transparency: transparency || undefined, vertical: vertical || undefined, slot: "alpha", "aria-label": props["aria-label"] || context.strings.colorOpacity }));
5891
5945
  });
5946
+ /** Load and persist a user's compact command-shelf choice in this browser. Use a site/app-scoped key. */
5947
+ export function useStoredOverflowCompactMode(storageKey, defaultCompact = false) {
5948
+ const key = `spfx-fast:overflow-compact:${storageKey}`;
5949
+ const [compact, setCompactState] = React.useState(defaultCompact);
5950
+ const [ready, setReady] = React.useState(false);
5951
+ React.useEffect(() => {
5952
+ const read = (value) => {
5953
+ if (value === "true" || value === "false")
5954
+ setCompactState(value === "true");
5955
+ else
5956
+ setCompactState(defaultCompact);
5957
+ };
5958
+ try {
5959
+ read(globalThis.localStorage?.getItem(key) ?? null);
5960
+ }
5961
+ catch {
5962
+ setCompactState(defaultCompact);
5963
+ }
5964
+ setReady(true);
5965
+ const onStorage = (event) => { if (event.key === key)
5966
+ read(event.newValue); };
5967
+ globalThis.addEventListener?.("storage", onStorage);
5968
+ return () => globalThis.removeEventListener?.("storage", onStorage);
5969
+ }, [key, defaultCompact]);
5970
+ const setCompact = React.useCallback((value) => {
5971
+ setCompactState(value);
5972
+ try {
5973
+ globalThis.localStorage?.setItem(key, String(value));
5974
+ }
5975
+ catch { /* Keep the current-session choice if storage is unavailable. */ }
5976
+ }, [key]);
5977
+ const toggleCompact = React.useCallback(() => setCompact(!compact), [compact, setCompact]);
5978
+ return { compact, ready, setCompact, toggleCompact };
5979
+ }
5980
+ export function useSavedSwatchPalettes(store) {
5981
+ const [palettes, setPalettes] = React.useState([]);
5982
+ const [loading, setLoading] = React.useState(true);
5983
+ const [error, setError] = React.useState(null);
5984
+ const request = React.useRef(0);
5985
+ const mounted = React.useRef(false);
5986
+ const reload = React.useCallback(async () => {
5987
+ const current = ++request.current;
5988
+ setLoading(true);
5989
+ setError(null);
5990
+ try {
5991
+ const result = await store.list();
5992
+ if (mounted.current && request.current === current)
5993
+ setPalettes(result);
5994
+ return result;
5995
+ }
5996
+ catch (cause) {
5997
+ if (mounted.current && request.current === current)
5998
+ setError(cause);
5999
+ throw cause;
6000
+ }
6001
+ finally {
6002
+ if (mounted.current && request.current === current)
6003
+ setLoading(false);
6004
+ }
6005
+ }, [store]);
6006
+ React.useEffect(() => { mounted.current = true; void reload().catch(() => { }); return () => { mounted.current = false; request.current++; }; }, [reload]);
6007
+ const save = React.useCallback(async (palette) => {
6008
+ if (mounted.current)
6009
+ setError(null);
6010
+ try {
6011
+ await store.save(palette);
6012
+ await reload();
6013
+ }
6014
+ catch (cause) {
6015
+ if (mounted.current)
6016
+ setError(cause);
6017
+ throw cause;
6018
+ }
6019
+ }, [store, reload]);
6020
+ const remove = React.useCallback(async (id) => {
6021
+ if (mounted.current)
6022
+ setError(null);
6023
+ try {
6024
+ await store.remove(id);
6025
+ await reload();
6026
+ }
6027
+ catch (cause) {
6028
+ if (mounted.current)
6029
+ setError(cause);
6030
+ throw cause;
6031
+ }
6032
+ }, [store, reload]);
6033
+ return { palettes, loading, error, reload, save, remove };
6034
+ }
5892
6035
  export const SwatchPicker = /* @__PURE__ */ React.forwardRef(function SwatchPicker({ children, selectedValue, defaultSelectedValue, selectedValues, defaultSelectedValues, selectionMode = "single", layout = "grid", size = "medium", shape = "square", spacing = "medium", focusMode = "arrow", columns = 6, onSelectionChange, ...props }, forwardedRef) {
5893
6036
  const strings = React.useContext(UIContext).strings;
5894
6037
  const ref = React.useRef(null);
@@ -5907,6 +6050,12 @@ export const ColorSwatch = /* @__PURE__ */ React.forwardRef(function ColorSwatch
5907
6050
  ensureDefined(defineNativeSwatchPicker);
5908
6051
  return React.createElement("spui-color-swatch", useCustomElementProps({ ref: forwardedRef, ...props, color, value, disabled: disabled || undefined, size, shape, "border-color": borderColor }), children, icon == null ? null : React.createElement("span", { slot: "icon" }, icon), disabledIcon == null ? null : React.createElement("span", { slot: "disabled-icon" }, disabledIcon));
5909
6052
  });
6053
+ export function SharePointThemeSwatches({ palette, labelForColor }) {
6054
+ const themePalette = React.useContext(UIContext).theme?.palette;
6055
+ const presets = getSharePointThemeColorPresets(palette ?? themePalette, labelForColor);
6056
+ ensureDefined(defineNativeSwatchPicker);
6057
+ return React.createElement(React.Fragment, null, presets.map(preset => React.createElement(ColorSwatch, { key: preset.name, color: preset.color, value: preset.value, "aria-label": preset.label })));
6058
+ }
5910
6059
  export const ImageSwatch = /* @__PURE__ */ React.forwardRef(function ImageSwatch({ src, value, disabled, size, shape, children, ...props }, forwardedRef) {
5911
6060
  ensureDefined(defineNativeSwatchPicker);
5912
6061
  return React.createElement("spui-image-swatch", useCustomElementProps({ ref: forwardedRef, ...props, src, value, disabled: disabled || undefined, size, shape }), children);
@@ -6835,3 +6984,114 @@ export const AccordionPanel = /* @__PURE__ */ React.forwardRef(function Accordio
6835
6984
  const open = React.useContext(AccordionItemOpenContext);
6836
6985
  return React.createElement("spui-accordion-panel", useCustomElementProps({ ref: forwardedRef, ...props, slot: "panel", motion: collapseMotion ? true : undefined }), collapseMotion ? React.createElement(collapseMotion, { visible: open, appear: true, unmountOnExit: true }, children) : children);
6837
6986
  });
6987
+ /** Render a SharePoint field recipe using the library's matching form control. */
6988
+ export function SharePointField({ field, value, defaultValue, options: providedOptions, onValueChange, disabled = false, hint, validationMessage, renderUnsupported, addChoiceLabel = "Add another choice", emptyOptionLabel = "Select an option", className, style, ...hostProps }) {
6989
+ const adapter = getSharePointFieldAdapter(field);
6990
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
6991
+ const [fillInValue, setFillInValue] = React.useState("");
6992
+ if (adapter.hidden)
6993
+ return null;
6994
+ const currentValue = value === undefined ? internalValue : value;
6995
+ const updateValue = (next) => {
6996
+ if (value === undefined)
6997
+ setInternalValue(next);
6998
+ onValueChange?.(next);
6999
+ };
7000
+ const label = adapter.label || adapter.name || adapter.fieldType;
7001
+ const name = adapter.name || undefined;
7002
+ const stringValue = adapter.control === "date-picker" ? toSharePointDateControlString(currentValue) : toSharePointControlString(currentValue);
7003
+ const choices = providedOptions ?? (adapter.choices ?? []).map(choice => ({ value: choice, label: choice }));
7004
+ const controlDisabled = disabled || (adapter.readOnly && !["input", "textarea", "rich-text-editor"].includes(adapter.control));
7005
+ let control;
7006
+ switch (adapter.control) {
7007
+ case "input":
7008
+ control = _jsx(Input, { type: adapter.inputType ?? "text", name: name, value: stringValue, min: adapter.min, max: adapter.max, step: adapter.step, maxLength: adapter.maxLength, required: adapter.required, disabled: disabled, readOnly: adapter.readOnly, onValueChange: next => updateValue(next) });
7009
+ break;
7010
+ case "textarea":
7011
+ control = _jsx(TextArea, { name: name, value: stringValue, maxLength: adapter.maxLength, required: adapter.required, disabled: disabled, readOnly: adapter.readOnly, onValueChange: next => updateValue(next) });
7012
+ break;
7013
+ case "rich-text-editor":
7014
+ control = _jsx(RichTextEditor, { name: name, value: stringValue, field: field, required: adapter.required, disabled: disabled, readOnly: adapter.readOnly, onValueChange: next => updateValue(next) });
7015
+ break;
7016
+ case "select":
7017
+ control = adapter.allowFillIn
7018
+ ? _jsx(ComboBox, { name: name, value: stringValue, selectedValue: stringValue, placeholder: emptyOptionLabel, freeform: true, allowFreeform: true, required: adapter.required, disabled: controlDisabled, onValueChange: next => updateValue(next), onOptionSelect: (_, data) => updateValue(data.optionValue ?? null), children: choices.map(option => _jsx(Option, { value: String(option.value), text: option.label, disabled: option.disabled, children: option.label }, String(option.value))) })
7019
+ : _jsxs(Select, { name: name, value: stringValue, required: adapter.required, disabled: controlDisabled, onValueChange: next => updateValue(next), children: [_jsx("option", { value: "", disabled: adapter.required, children: emptyOptionLabel }), choices.map(option => _jsx("option", { value: String(option.value), disabled: option.disabled, children: option.label }, String(option.value)))] });
7020
+ break;
7021
+ case "radio-group":
7022
+ control = _jsx(RadioGroup, { name: name, value: stringValue, required: adapter.required, disabled: controlDisabled, onValueChange: next => updateValue(next), children: choices.map(option => _jsx(Radio, { value: String(option.value), label: option.label, disabled: option.disabled }, String(option.value))) });
7023
+ break;
7024
+ case "checkbox":
7025
+ control = _jsx(Checkbox, { name: name, checked: currentValue === true || currentValue === "true", disabled: controlDisabled, onCheckedChange: next => updateValue(next) });
7026
+ break;
7027
+ case "multi-choice": {
7028
+ const selected = Array.isArray(currentValue) ? currentValue.map(String) : [];
7029
+ const visibleOptions = [...choices];
7030
+ for (const selectedValue of selected) {
7031
+ if (!visibleOptions.some(option => String(option.value) === selectedValue))
7032
+ visibleOptions.push({ value: selectedValue, label: selectedValue });
7033
+ }
7034
+ const setSelected = (choice, checked) => {
7035
+ const next = checked ? [...new Set([...selected, choice])] : selected.filter(item => item !== choice);
7036
+ updateValue(next);
7037
+ };
7038
+ const addFillIn = () => {
7039
+ const next = fillInValue.trim();
7040
+ if (!next || selected.includes(next))
7041
+ return;
7042
+ updateValue([...selected, next]);
7043
+ setFillInValue("");
7044
+ };
7045
+ control = _jsxs(_Fragment, { children: [visibleOptions.map(option => _jsx(Checkbox, { label: option.label, checked: selected.includes(String(option.value)), disabled: controlDisabled || option.disabled, onCheckedChange: checked => setSelected(String(option.value), checked) }, String(option.value))), adapter.allowFillIn ? _jsxs("div", { style: { display: "flex", alignItems: "end", gap: 8, marginBlockStart: 8 }, children: [_jsx(Input, { type: "text", value: fillInValue, "aria-label": addChoiceLabel, disabled: controlDisabled, onValueChange: setFillInValue, onKeyDown: event => { if (event.key === "Enter") {
7046
+ event.preventDefault();
7047
+ addFillIn();
7048
+ } } }), _jsx(Button, { type: "button", appearance: "outline", disabled: controlDisabled || !fillInValue.trim(), onClick: addFillIn, children: addChoiceLabel })] }) : null] });
7049
+ break;
7050
+ }
7051
+ case "date-picker":
7052
+ control = _jsx(DatePicker, { name: name, value: stringValue, required: adapter.required, disabled: controlDisabled, readOnly: adapter.readOnly, onValueChange: next => updateValue(next) });
7053
+ break;
7054
+ case "combobox":
7055
+ control = _jsx(ComboBox, { name: name, multiselect: adapter.multiple, selectedValue: adapter.multiple ? undefined : stringValue, selectedOptions: adapter.multiple && Array.isArray(currentValue) ? currentValue.map(String) : undefined, required: adapter.required, disabled: controlDisabled, placeholder: emptyOptionLabel, onOptionSelect: (_, data) => { if (!adapter.multiple)
7056
+ updateValue(data.optionValue ?? null); }, onSelectedOptionsChange: next => { if (adapter.multiple)
7057
+ updateValue(next); }, children: choices.map(option => _jsx(Option, { value: String(option.value), text: option.label, disabled: option.disabled, children: option.label }, String(option.value))) });
7058
+ break;
7059
+ case "read-only":
7060
+ control = _jsx(TextField, { name: name, value: stringValue, readOnly: true });
7061
+ break;
7062
+ case "unsupported": {
7063
+ const fallback = renderUnsupported?.(field, adapter.unsupportedReason ?? "No renderer is registered for this SharePoint field type.");
7064
+ control = fallback ?? _jsxs("div", { role: "note", children: ["This SharePoint field type needs a custom renderer (", adapter.fieldType, ")."] });
7065
+ break;
7066
+ }
7067
+ }
7068
+ if (adapter.control === "multi-choice") {
7069
+ return _jsx(Field, { ...hostProps, hint: hint ?? adapter.description, validationMessage: validationMessage, disabled: disabled, className: className, style: style, children: _jsx(SharePointMultiChoiceGroup, { label: label, required: adapter.required, disabled: disabled, children: control }) });
7070
+ }
7071
+ return _jsx(Field, { ...hostProps, label: label, hint: hint ?? adapter.description, validationMessage: validationMessage, required: adapter.required, disabled: disabled, className: className, style: style, children: control });
7072
+ }
7073
+ function toSharePointControlString(value) {
7074
+ if (value == null)
7075
+ return "";
7076
+ if (typeof value === "string" || typeof value === "number")
7077
+ return String(value);
7078
+ if (value instanceof Date) {
7079
+ const pad = (part) => String(part).padStart(2, "0");
7080
+ return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;
7081
+ }
7082
+ if (typeof value === "object" && "url" in value)
7083
+ return value.url;
7084
+ return "";
7085
+ }
7086
+ function SharePointMultiChoiceGroup({ label, required, disabled, children }) {
7087
+ const fieldProps = useFieldControlProps_unstable({ role: "group", "aria-label": label }, { supportsRequired: false });
7088
+ return _jsxs("fieldset", { ...fieldProps, "aria-required": required || undefined, disabled: disabled, style: { minWidth: 0, margin: 0, padding: 0, border: 0 }, children: [_jsxs("legend", { children: [label, required ? _jsx("span", { "aria-hidden": "true", children: " *" }) : null] }), children] });
7089
+ }
7090
+ function toSharePointDateControlString(value) {
7091
+ if (value instanceof Date) {
7092
+ const pad = (part) => String(part).padStart(2, "0");
7093
+ return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
7094
+ }
7095
+ const text = toSharePointControlString(value);
7096
+ return /^\d{4}-\d{2}-\d{2}/.exec(text)?.[0] ?? text;
7097
+ }