@pstrikez/fluent-winui-theme 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1485,7 +1485,7 @@ var require_prism = __commonJS({
1485
1485
  import * as fluentNamespace from "@fluentui/react-components";
1486
1486
 
1487
1487
  // src/winui/appearance.ts
1488
- import { CheckmarkCircleFilled, ChevronDown12Regular, DismissCircleFilled, ErrorCircleFilled, InfoFilled } from "@fluentui/react-icons";
1488
+ import { CheckmarkCircleFilled, ChevronDown12Regular, ChevronUp12Regular, DismissCircleFilled, ErrorCircleFilled, InfoFilled } from "@fluentui/react-icons";
1489
1489
  import * as React2 from "react";
1490
1490
 
1491
1491
  // src/winui/wrap.ts
@@ -1562,6 +1562,16 @@ var withWinuiAppearance = (components) => {
1562
1562
  ...props,
1563
1563
  expandIcon: props.expandIcon === void 0 ? { children: React2.createElement(ChevronDown12Regular) } : props.expandIcon
1564
1564
  }));
1565
+ const withSpinGlyph = (slot, Glyph) => {
1566
+ if (slot === null) return slot;
1567
+ const slotProps2 = resolveSlotProps(slot);
1568
+ return slotProps2?.children === void 0 ? { ...slotProps2, children: React2.createElement(Glyph) } : slotProps2;
1569
+ };
1570
+ const winuiSpinGlyphs = (component) => wrapFluent(component, (props) => ({
1571
+ ...props,
1572
+ incrementButton: withSpinGlyph(props.incrementButton, ChevronUp12Regular),
1573
+ decrementButton: withSpinGlyph(props.decrementButton, ChevronDown12Regular)
1574
+ }));
1565
1575
  return {
1566
1576
  ...components,
1567
1577
  AccordionHeader: winuiChevron(components.AccordionHeader),
@@ -1578,6 +1588,7 @@ var withWinuiAppearance = (components) => {
1578
1588
  Input: stamp(components.Input, appearance("outline", rootAndPrimary)),
1579
1589
  Textarea: stamp(components.Textarea, appearance("outline", rootAndPrimary)),
1580
1590
  Select: stamp(components.Select, appearance("outline", rootAndPrimary)),
1591
+ SpinButton: winuiSpinGlyphs(stamp(components.SpinButton, appearance("outline", rootAndPrimary))),
1581
1592
  Combobox: stamp(components.Combobox, appearance("outline", rootAndPrimary)),
1582
1593
  Dropdown: stamp(components.Dropdown, appearance("outline", rootAndPrimary)),
1583
1594
  Card: stamp(components.Card, appearance("filled", rootIsPrimary)),
@@ -1743,11 +1754,11 @@ var withWinuiDrag = (components) => {
1743
1754
  const suppressClickRef = React4.useRef(false);
1744
1755
  const settleTimerRef = React4.useRef(void 0);
1745
1756
  React4.useEffect(() => () => clearTimeout(settleTimerRef.current), []);
1746
- const end = (gesture, toggle, fromDrag) => {
1757
+ const end = (gesture, toggle2, fromDrag) => {
1747
1758
  gestureRef.current = null;
1748
1759
  gesture.root.removeAttribute(DRAGGING);
1749
1760
  gesture.root.style.removeProperty(DRAG_X);
1750
- if (toggle) {
1761
+ if (toggle2) {
1751
1762
  if (fromDrag) {
1752
1763
  gesture.root.setAttribute(SETTLING, "");
1753
1764
  clearTimeout(settleTimerRef.current);
@@ -5553,7 +5564,30 @@ var en = {
5553
5564
  "common.discard.discard": "Discard",
5554
5565
  "common.copy.action": "Copy",
5555
5566
  "common.copy.copied": "Copied",
5556
- "common.copy.failed": "Copy failed"
5567
+ "common.copy.failed": "Copy failed",
5568
+ "numberBox.increment": "Increase value",
5569
+ "numberBox.decrement": "Decrease value",
5570
+ "fileDropZone.browse": "Browse files",
5571
+ "fileDropZone.dropHint": "Drop files here",
5572
+ "fileDropZone.remove": "Remove file",
5573
+ "pager.label": "Pagination",
5574
+ "pager.first": "First page",
5575
+ "pager.previous": "Previous page",
5576
+ "pager.next": "Next page",
5577
+ "pager.last": "Last page",
5578
+ "pager.page": "Page {n}",
5579
+ "pager.pageSize": "Items per page",
5580
+ "pager.perPage": "{n} / page",
5581
+ "pager.total": "Total {n} items",
5582
+ "dataTable.empty": "No data",
5583
+ "dataTable.loading": "Loading",
5584
+ "dataTable.selectAll": "Select all rows",
5585
+ "dataTable.selectRow": "Select row",
5586
+ "dataTable.expandRow": "Expand row",
5587
+ "dataTable.collapseRow": "Collapse row",
5588
+ "tabView.close": "Close tab",
5589
+ "tabView.scrollBackward": "Scroll tabs left",
5590
+ "tabView.scrollForward": "Scroll tabs right"
5557
5591
  };
5558
5592
  var zhHans = {
5559
5593
  "common.on": "\u5F00",
@@ -5568,7 +5602,30 @@ var zhHans = {
5568
5602
  "common.discard.discard": "\u653E\u5F03",
5569
5603
  "common.copy.action": "\u590D\u5236",
5570
5604
  "common.copy.copied": "\u5DF2\u590D\u5236",
5571
- "common.copy.failed": "\u590D\u5236\u5931\u8D25"
5605
+ "common.copy.failed": "\u590D\u5236\u5931\u8D25",
5606
+ "numberBox.increment": "\u589E\u5927",
5607
+ "numberBox.decrement": "\u51CF\u5C0F",
5608
+ "fileDropZone.browse": "\u6D4F\u89C8\u6587\u4EF6",
5609
+ "fileDropZone.dropHint": "\u5C06\u6587\u4EF6\u62D6\u653E\u5230\u6B64\u5904",
5610
+ "fileDropZone.remove": "\u79FB\u9664\u6587\u4EF6",
5611
+ "pager.label": "\u5206\u9875",
5612
+ "pager.first": "\u7B2C\u4E00\u9875",
5613
+ "pager.previous": "\u4E0A\u4E00\u9875",
5614
+ "pager.next": "\u4E0B\u4E00\u9875",
5615
+ "pager.last": "\u6700\u540E\u4E00\u9875",
5616
+ "pager.page": "\u7B2C {n} \u9875",
5617
+ "pager.pageSize": "\u6BCF\u9875\u6761\u6570",
5618
+ "pager.perPage": "{n} \u6761/\u9875",
5619
+ "pager.total": "\u5171 {n} \u6761",
5620
+ "dataTable.empty": "\u6682\u65E0\u6570\u636E",
5621
+ "dataTable.loading": "\u52A0\u8F7D\u4E2D",
5622
+ "dataTable.selectAll": "\u9009\u62E9\u5168\u90E8\u884C",
5623
+ "dataTable.selectRow": "\u9009\u62E9\u6B64\u884C",
5624
+ "dataTable.expandRow": "\u5C55\u5F00\u6B64\u884C",
5625
+ "dataTable.collapseRow": "\u6536\u8D77\u6B64\u884C",
5626
+ "tabView.close": "\u5173\u95ED\u6807\u7B7E\u9875",
5627
+ "tabView.scrollBackward": "\u5411\u5DE6\u6EDA\u52A8\u6807\u7B7E\u9875",
5628
+ "tabView.scrollForward": "\u5411\u53F3\u6EDA\u52A8\u6807\u7B7E\u9875"
5572
5629
  };
5573
5630
  var winuiStringsByLocale = { en, "zh-Hans": zhHans };
5574
5631
  var StringsContext = createContext2(en);
@@ -6917,7 +6974,8 @@ import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
6917
6974
  var { Dialog, DialogBody, DialogContent, DialogSurface, mergeClasses: mergeClasses5 } = fluentComponents;
6918
6975
  var surfaceWidthClasses = {
6919
6976
  standard: "",
6920
- editor: "fwt-dialog-shell--editor"
6977
+ editor: "fwt-dialog-shell--editor",
6978
+ wide: "fwt-dialog-shell--wide"
6921
6979
  };
6922
6980
  function DialogShell({ actions, children, onExited, onOpenChange, onSubmit, open, surfaceClassName, title, width = "standard" }) {
6923
6981
  return /* @__PURE__ */ jsx12(
@@ -7028,6 +7086,7 @@ var useStyles5 = makeStyles5({
7028
7086
  }
7029
7087
  }
7030
7088
  });
7089
+ var useDangerFillClass = () => useStyles5().danger;
7031
7090
  function ConfirmDialog({
7032
7091
  actionIntent = "danger",
7033
7092
  actionLabel,
@@ -7078,13 +7137,86 @@ function ConfirmDialog({
7078
7137
  surfaceClassName: "!w-[min(430px,calc(100vw-48px))]",
7079
7138
  title: /* @__PURE__ */ jsx14(DialogTitle, { children: title }),
7080
7139
  children: /* @__PURE__ */ jsxs6("div", { className: "grid gap-3 min-w-0", children: [
7081
- /* @__PURE__ */ jsx14("span", { children: message }),
7140
+ message && /* @__PURE__ */ jsx14("span", { children: message }),
7082
7141
  error && /* @__PURE__ */ jsx14(OutcomeMessageBar, { onDismiss: onDismissError, children: error })
7083
7142
  ] })
7084
7143
  }
7085
7144
  );
7086
7145
  }
7087
7146
 
7147
+ // src/components/ui/confirm-flyout.tsx
7148
+ import { useCallback as useCallback4, useState as useState5 } from "react";
7149
+ import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
7150
+ var { Button: Button5, Popover, PopoverSurface, PopoverTrigger, Spinner, Text, mergeClasses: mergeClasses7 } = fluentComponents;
7151
+ var errorText = (error) => error instanceof Error ? error.message : String(error);
7152
+ function ConfirmFlyout({
7153
+ cancelLabel,
7154
+ children,
7155
+ confirmLabel,
7156
+ disabled = false,
7157
+ intent = "danger",
7158
+ message,
7159
+ onConfirm,
7160
+ positioning,
7161
+ title
7162
+ }) {
7163
+ const { t: t2 } = useTranslation();
7164
+ const dangerFill = useDangerFillClass();
7165
+ const [open, setOpen] = useState5(false);
7166
+ const [busy, setBusy] = useState5(false);
7167
+ const [error, setError] = useState5(null);
7168
+ const changeOpen = useCallback4((next) => {
7169
+ if (busy || next && disabled) return;
7170
+ setError(null);
7171
+ setOpen(next);
7172
+ }, [busy, disabled]);
7173
+ const confirm = async () => {
7174
+ setError(null);
7175
+ setBusy(true);
7176
+ try {
7177
+ await onConfirm();
7178
+ setOpen(false);
7179
+ } catch (caught) {
7180
+ setError(errorText(caught));
7181
+ } finally {
7182
+ setBusy(false);
7183
+ }
7184
+ };
7185
+ return /* @__PURE__ */ jsxs7(
7186
+ Popover,
7187
+ {
7188
+ onOpenChange: (_2, data) => changeOpen(data.open),
7189
+ open: open && !disabled,
7190
+ positioning,
7191
+ trapFocus: true,
7192
+ children: [
7193
+ /* @__PURE__ */ jsx15(PopoverTrigger, { disableButtonEnhancement: true, children }),
7194
+ /* @__PURE__ */ jsx15(PopoverSurface, { "aria-label": title, children: /* @__PURE__ */ jsxs7("div", { className: "grid gap-3 min-w-0 max-w-[min(320px,calc(100vw-48px))]", children: [
7195
+ title && /* @__PURE__ */ jsx15(Text, { weight: "semibold", children: title }),
7196
+ /* @__PURE__ */ jsx15(Text, { children: message }),
7197
+ error && /* @__PURE__ */ jsx15(OutcomeMessageBar, { onDismiss: () => setError(null), children: error }),
7198
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-2", children: [
7199
+ /* @__PURE__ */ jsx15(
7200
+ Button5,
7201
+ {
7202
+ appearance: "primary",
7203
+ className: mergeClasses7("!whitespace-nowrap", intent === "danger" && dangerFill),
7204
+ disabledFocusable: busy,
7205
+ icon: busy ? /* @__PURE__ */ jsx15(Spinner, { size: "tiny" }) : void 0,
7206
+ onClick: () => {
7207
+ void confirm();
7208
+ },
7209
+ children: confirmLabel
7210
+ }
7211
+ ),
7212
+ cancelLabel !== void 0 && /* @__PURE__ */ jsx15(Button5, { className: "!whitespace-nowrap", disabled: busy, onClick: () => changeOpen(false), children: cancelLabel || t2("common.cancel") })
7213
+ ] })
7214
+ ] }) })
7215
+ ]
7216
+ }
7217
+ );
7218
+ }
7219
+
7088
7220
  // src/components/ui/danger.ts
7089
7221
  var { buttonClassNames, makeStyles: makeStyles6 } = fluentComponents;
7090
7222
  var RED = "var(--winui-system-fill-critical) !important";
@@ -7124,6 +7256,10 @@ var useTextStyles = makeStyles6({
7124
7256
  });
7125
7257
  var useDangerTextClass = () => useTextStyles().danger;
7126
7258
 
7259
+ // src/components/ui/data-table.tsx
7260
+ import { ChevronDown16Regular, ChevronRight16Regular } from "@fluentui/react-icons";
7261
+ import { useMemo as useMemo3, useState as useState6 } from "react";
7262
+
7127
7263
  // src/components/ui/layout.ts
7128
7264
  var TIGHT_STACK_CLASS = "grid gap-1";
7129
7265
  var HEADER_ROW_CLASS = "flex items-center justify-between min-w-0 max-[900px]:flex-col max-[900px]:items-stretch";
@@ -7135,19 +7271,6 @@ var SCROLLPORT_FILL_CLASS = "h-full min-h-max";
7135
7271
  var CONTROL_ROW_CLASS = "!min-h-[34px]";
7136
7272
  var CHECKBOX_LIST_CLASS = "gap-x-2 gap-y-1";
7137
7273
 
7138
- // src/components/ui/dashboard-page-header.tsx
7139
- import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
7140
- var { Text, mergeClasses: mergeClasses7 } = fluentComponents;
7141
- function DashboardPageHeader({ actions, className, description, title }) {
7142
- return /* @__PURE__ */ jsxs7("header", { className: mergeClasses7(HEADER_ROW_CLASS, "gap-[18px]", className), children: [
7143
- /* @__PURE__ */ jsxs7("div", { className: "grid gap-1.5 min-w-0", children: [
7144
- /* @__PURE__ */ jsx15(Text, { as: "h1", size: 700, weight: "semibold", className: "m-0", children: title }),
7145
- description !== void 0 && /* @__PURE__ */ jsx15(Text, { size: 200, className: "text-fui-fg2 max-w-[760px]", children: description })
7146
- ] }),
7147
- actions !== void 0 && /* @__PURE__ */ jsx15("div", { className: "flex items-center gap-2 flex-none max-[900px]:justify-start", children: actions })
7148
- ] });
7149
- }
7150
-
7151
7274
  // src/components/ui/empty-state.tsx
7152
7275
  import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
7153
7276
  var { Text: Text2, mergeClasses: mergeClasses8 } = fluentComponents;
@@ -7168,33 +7291,682 @@ function EmptyStateLine({ children, className }) {
7168
7291
  return /* @__PURE__ */ jsx16(Text2, { block: true, size: 300, className: mergeClasses8("text-fui-fg2", className), children });
7169
7292
  }
7170
7293
 
7171
- // src/components/ui/error-shell.tsx
7294
+ // src/components/ui/pager.tsx
7295
+ import {
7296
+ ChevronLeft12Regular,
7297
+ ChevronRight12Regular,
7298
+ MoreHorizontal16Regular,
7299
+ Next16Regular,
7300
+ Previous16Regular
7301
+ } from "@fluentui/react-icons";
7172
7302
  import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
7173
- var { Text: Text3 } = fluentComponents;
7303
+ var { Button: Button6, Option: Option2, Text: Text3, Tooltip: Tooltip2, makeStyles: makeStyles7, mergeClasses: mergeClasses9 } = fluentComponents;
7304
+ function pagerPageCount(total, pageSize) {
7305
+ if (!(pageSize > 0) || !(total > 0)) return 1;
7306
+ return Math.ceil(total / pageSize);
7307
+ }
7308
+ function pagerPageWindow(page, pageCount) {
7309
+ if (pageCount < 8) return Array.from({ length: Math.max(pageCount, 0) }, (_2, index) => index + 1);
7310
+ const selectedIndex = page - 1;
7311
+ if (selectedIndex < 4) return [1, 2, 3, 4, 5, "end-ellipsis", pageCount];
7312
+ if (selectedIndex >= pageCount - 4) return [1, "start-ellipsis", pageCount - 4, pageCount - 3, pageCount - 2, pageCount - 1, pageCount];
7313
+ return [1, "start-ellipsis", page - 1, page, page + 1, "end-ellipsis", pageCount];
7314
+ }
7315
+ var clampPage = (page, pageCount) => Math.min(Math.max(Math.trunc(page) || 1, 1), pageCount);
7316
+ var useStyles7 = makeStyles7({
7317
+ navButton: {
7318
+ height: "40px !important",
7319
+ minWidth: "40px !important",
7320
+ padding: "0 !important",
7321
+ width: "40px !important"
7322
+ },
7323
+ numberButton: {
7324
+ height: "20px !important",
7325
+ minHeight: "20px !important",
7326
+ minWidth: "32px !important",
7327
+ paddingBlock: "0 !important",
7328
+ paddingInline: "0 !important"
7329
+ },
7330
+ selected: {
7331
+ position: "relative",
7332
+ "::after": {
7333
+ backgroundColor: "var(--winui-accent-fill-default)",
7334
+ borderRadius: "1px",
7335
+ bottom: "-10px",
7336
+ content: '""',
7337
+ height: "2px",
7338
+ insetInline: 0,
7339
+ position: "absolute",
7340
+ "@media (forced-colors: active)": { backgroundColor: "Highlight" }
7341
+ }
7342
+ },
7343
+ // The glyphs are mirrored for a right-to-left reading order.
7344
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/PagerControl/PagerControl_themeresources.xaml#L80
7345
+ mirrored: {
7346
+ ':where([dir="rtl"]) &': { transform: "scaleX(-1)" }
7347
+ }
7348
+ });
7349
+ function NavigationButton({ className, disabled, icon, label, onClick }) {
7350
+ return /* @__PURE__ */ jsx17(Tooltip2, { content: label, relationship: "label", children: /* @__PURE__ */ jsx17(Button6, { appearance: "subtle", className, disabled, icon, onClick }) });
7351
+ }
7352
+ function Pager({
7353
+ ariaLabel,
7354
+ className,
7355
+ disabled = false,
7356
+ onPageChange,
7357
+ onPageSizeChange,
7358
+ page,
7359
+ pageCount: pageCountProp,
7360
+ pageSize,
7361
+ pageSizeOptions,
7362
+ showTotal = false,
7363
+ total
7364
+ }) {
7365
+ const { t: t2 } = useTranslation();
7366
+ const styles = useStyles7();
7367
+ const pageCount = Math.max(1, Math.trunc(pageCountProp ?? pagerPageCount(total ?? 0, pageSize ?? 1)));
7368
+ const current = clampPage(page, pageCount);
7369
+ const go = (next) => {
7370
+ const target = clampPage(next, pageCount);
7371
+ if (target !== current) onPageChange(target);
7372
+ };
7373
+ const atStart = current <= 1;
7374
+ const atEnd = current >= pageCount;
7375
+ const mirrored = styles.mirrored;
7376
+ const sizes = pageSize !== void 0 && pageSizeOptions && onPageSizeChange ? [.../* @__PURE__ */ new Set([...pageSizeOptions, pageSize])].sort((a2, b2) => a2 - b2) : null;
7377
+ const sizeLabel = (size) => t2("pager.perPage").replace("{n}", String(size));
7378
+ return /* @__PURE__ */ jsxs9("nav", { "aria-label": ariaLabel ?? t2("pager.label"), className: mergeClasses9("flex flex-wrap items-center justify-end gap-x-4 gap-y-1", className), children: [
7379
+ showTotal && total !== void 0 && (typeof showTotal === "function" ? showTotal(total) : /* @__PURE__ */ jsx17(Text3, { className: "text-fui-fg2", size: 300, children: t2("pager.total").replace("{n}", String(total)) })),
7380
+ sizes && pageSize !== void 0 && /* @__PURE__ */ jsx17(
7381
+ Dropdown,
7382
+ {
7383
+ "aria-label": t2("pager.pageSize"),
7384
+ disabled,
7385
+ onOptionSelect: (_2, data) => {
7386
+ const next = Number(data.optionValue);
7387
+ if (next > 0 && next !== pageSize) onPageSizeChange?.(next);
7388
+ },
7389
+ selectedOptions: [String(pageSize)],
7390
+ style: { "--fwt-select-min-width": "112px" },
7391
+ value: sizeLabel(pageSize),
7392
+ children: sizes.map((size) => /* @__PURE__ */ jsx17(Option2, { text: sizeLabel(size), value: String(size), children: sizeLabel(size) }, size))
7393
+ }
7394
+ ),
7395
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center", children: [
7396
+ /* @__PURE__ */ jsx17(NavigationButton, { className: styles.navButton, disabled: disabled || atStart, icon: /* @__PURE__ */ jsx17(Previous16Regular, { className: mirrored }), label: t2("pager.first"), onClick: () => go(1) }),
7397
+ /* @__PURE__ */ jsx17(NavigationButton, { className: styles.navButton, disabled: disabled || atStart, icon: /* @__PURE__ */ jsx17(ChevronLeft12Regular, { className: mirrored }), label: t2("pager.previous"), onClick: () => go(current - 1) }),
7398
+ /* @__PURE__ */ jsx17("div", { className: "flex items-center h-10", style: { gap: 5 }, children: pagerPageWindow(current, pageCount).map((item) => typeof item === "number" ? /* @__PURE__ */ jsx17("span", { className: mergeClasses9("inline-flex", item === current && styles.selected), children: /* @__PURE__ */ jsx17(
7399
+ Button6,
7400
+ {
7401
+ appearance: "subtle",
7402
+ "aria-current": item === current ? "page" : void 0,
7403
+ "aria-label": t2("pager.page").replace("{n}", String(item)),
7404
+ className: styles.numberButton,
7405
+ disabled,
7406
+ onClick: () => go(item),
7407
+ children: item
7408
+ }
7409
+ ) }, item) : /* @__PURE__ */ jsx17("span", { "aria-hidden": true, className: "grid place-items-center w-5 text-fui-fg2", children: /* @__PURE__ */ jsx17(MoreHorizontal16Regular, {}) }, item)) }),
7410
+ /* @__PURE__ */ jsx17(NavigationButton, { className: styles.navButton, disabled: disabled || atEnd, icon: /* @__PURE__ */ jsx17(ChevronRight12Regular, { className: mirrored }), label: t2("pager.next"), onClick: () => go(current + 1) }),
7411
+ /* @__PURE__ */ jsx17(NavigationButton, { className: styles.navButton, disabled: disabled || atEnd, icon: /* @__PURE__ */ jsx17(Next16Regular, { className: mirrored }), label: t2("pager.last"), onClick: () => go(pageCount) })
7412
+ ] })
7413
+ ] });
7414
+ }
7415
+
7416
+ // src/components/ui/table-actions.tsx
7417
+ import { jsx as jsx18 } from "react/jsx-runtime";
7418
+ var { TableCell, TableHeaderCell, makeStyles: makeStyles8, mergeClasses: mergeClasses10 } = fluentComponents;
7419
+ var useStyles8 = makeStyles8({
7420
+ trailing: {
7421
+ textAlign: "right",
7422
+ "& .fui-TableHeaderCell__button": { justifyContent: "flex-end" }
7423
+ },
7424
+ centred: {
7425
+ textAlign: "center",
7426
+ "& .fui-TableHeaderCell__button": { justifyContent: "center" }
7427
+ }
7428
+ });
7429
+ function TableTrailingHeader({ className, ...props }) {
7430
+ const styles = useStyles8();
7431
+ return /* @__PURE__ */ jsx18(TableHeaderCell, { ...props, className: mergeClasses10(styles.trailing, className) });
7432
+ }
7433
+ function TableTrailingCell({ className, ...props }) {
7434
+ const styles = useStyles8();
7435
+ return /* @__PURE__ */ jsx18(TableCell, { ...props, className: mergeClasses10(styles.trailing, className) });
7436
+ }
7437
+ function TableCentredHeader({ className, ...props }) {
7438
+ const styles = useStyles8();
7439
+ return /* @__PURE__ */ jsx18(TableHeaderCell, { ...props, className: mergeClasses10(styles.centred, className) });
7440
+ }
7441
+ function TableCentredCell({ className, ...props }) {
7442
+ const styles = useStyles8();
7443
+ return /* @__PURE__ */ jsx18(TableCell, { ...props, className: mergeClasses10(styles.centred, className) });
7444
+ }
7445
+ var stopRowSelection = { onClick: (event) => event.stopPropagation() };
7446
+ var ACTION_GAP = "var(--spacingHorizontalXS)";
7447
+ var ACTION_BUTTON_SIZE = "24px";
7448
+ var TABLE_ACTIONS_WIDTH = `calc(3 * ${ACTION_BUTTON_SIZE} + 2 * ${ACTION_GAP} + var(--spacingHorizontalS) + var(--fwt-panel-inset))`;
7449
+ function TableActions({ children }) {
7450
+ return /* @__PURE__ */ jsx18("div", { className: "flex items-center justify-end", style: { gap: ACTION_GAP }, ...stopRowSelection, children });
7451
+ }
7452
+
7453
+ // src/components/ui/table-columns.tsx
7454
+ import { jsx as jsx19 } from "react/jsx-runtime";
7455
+ function TableColumns({ widths }) {
7456
+ return /* @__PURE__ */ jsx19("colgroup", { children: widths.map((width, index) => /* @__PURE__ */ jsx19("col", { style: width === null ? void 0 : { width } }, index)) });
7457
+ }
7458
+
7459
+ // src/components/ui/data-table.tsx
7460
+ import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
7461
+ var {
7462
+ Button: Button7,
7463
+ Spinner: Spinner2,
7464
+ Table,
7465
+ TableBody,
7466
+ TableCell: TableCell2,
7467
+ TableCellLayout,
7468
+ TableHeader,
7469
+ TableHeaderCell: TableHeaderCell2,
7470
+ TableRow,
7471
+ TableSelectionCell,
7472
+ mergeClasses: mergeClasses11
7473
+ } = fluentComponents;
7474
+ var LEADING_COLUMN_WIDTH = "44px";
7475
+ var HEADER_BY_ALIGN = { center: TableCentredHeader, end: TableTrailingHeader, start: TableHeaderCell2 };
7476
+ var CELL_BY_ALIGN = { center: TableCentredCell, end: TableTrailingCell, start: TableCell2 };
7477
+ var toggle = (keys2, key) => keys2.includes(key) ? keys2.filter((candidate) => candidate !== key) : [...keys2, key];
7478
+ function DataTable({
7479
+ ariaLabel,
7480
+ className,
7481
+ columns,
7482
+ defaultSort,
7483
+ empty,
7484
+ expandable,
7485
+ loading = false,
7486
+ minWidth,
7487
+ onRowClick,
7488
+ onSortChange,
7489
+ pagination,
7490
+ rowClassName,
7491
+ rowKey,
7492
+ rows,
7493
+ selection,
7494
+ size = "medium"
7495
+ }) {
7496
+ const { t: t2 } = useTranslation();
7497
+ const [sort, setSort] = useState6(defaultSort ?? null);
7498
+ const [ownPage, setOwnPage] = useState6(1);
7499
+ const [ownPageSize, setOwnPageSize] = useState6(null);
7500
+ const [ownExpanded, setOwnExpanded] = useState6([]);
7501
+ const sortedRows = useMemo3(() => {
7502
+ const column = sort && columns.find((candidate) => candidate.key === sort.key);
7503
+ if (!sort || !column?.sort) return rows;
7504
+ const direction = sort.direction === "ascending" ? 1 : -1;
7505
+ const compare = column.sort;
7506
+ return [...rows].sort((a2, b2) => direction * compare(a2, b2));
7507
+ }, [columns, rows, sort]);
7508
+ const paged = pagination !== void 0 && pagination !== false;
7509
+ const pageSize = !paged ? 0 : pagination.onPageSizeChange ? pagination.pageSize : ownPageSize ?? pagination.pageSize;
7510
+ const pageCount = paged ? Math.max(1, Math.ceil(sortedRows.length / Math.max(pageSize, 1))) : 1;
7511
+ const requestedPage = paged ? pagination.page ?? ownPage : 1;
7512
+ const page = Math.min(Math.max(requestedPage, 1), pageCount);
7513
+ const visibleRows = paged ? sortedRows.slice((page - 1) * pageSize, page * pageSize) : sortedRows;
7514
+ const changePage = (next) => {
7515
+ setOwnPage(next);
7516
+ if (paged) pagination.onPageChange?.(next);
7517
+ };
7518
+ const changePageSize = (next) => {
7519
+ setOwnPageSize(next);
7520
+ setOwnPage(1);
7521
+ if (paged) {
7522
+ pagination.onPageSizeChange?.(next);
7523
+ pagination.onPageChange?.(1);
7524
+ }
7525
+ };
7526
+ const cycleSort = (column) => {
7527
+ const next = sort?.key !== column.key ? { key: column.key, direction: "ascending" } : sort.direction === "ascending" ? { key: column.key, direction: "descending" } : null;
7528
+ setSort(next);
7529
+ onSortChange?.(next);
7530
+ setOwnPage(1);
7531
+ };
7532
+ const selectedKeys = selection?.selectedKeys ?? [];
7533
+ const selectionMode = selection?.mode ?? "multiple";
7534
+ const isSelectable = (row) => selection?.isSelectable?.(row) ?? true;
7535
+ const selectableVisible = visibleRows.filter(isSelectable).map(rowKey);
7536
+ const selectedVisible = selectableVisible.filter((key) => selectedKeys.includes(key));
7537
+ const allChecked = selectedVisible.length === 0 ? false : selectedVisible.length === selectableVisible.length ? true : "mixed";
7538
+ const toggleAll = () => {
7539
+ if (!selection) return;
7540
+ selection.onChange(allChecked === true ? selectedKeys.filter((key) => !selectableVisible.includes(key)) : [...selectedKeys, ...selectableVisible.filter((key) => !selectedKeys.includes(key))]);
7541
+ };
7542
+ const selectRow = (key) => {
7543
+ if (!selection) return;
7544
+ selection.onChange(selectionMode === "single" ? [key] : toggle(selectedKeys, key));
7545
+ };
7546
+ const stop = (event) => event.stopPropagation();
7547
+ const expandedKeys = expandable?.expandedKeys ?? ownExpanded;
7548
+ const toggleExpanded = (key) => {
7549
+ const next = toggle(expandedKeys, key);
7550
+ setOwnExpanded(next);
7551
+ expandable?.onExpandedChange?.(next);
7552
+ };
7553
+ const columnCount = columns.length + (selection ? 1 : 0) + (expandable ? 1 : 0);
7554
+ const widths = [
7555
+ ...selection ? [LEADING_COLUMN_WIDTH] : [],
7556
+ ...expandable ? [LEADING_COLUMN_WIDTH] : [],
7557
+ ...columns.map((column) => column.width ?? null)
7558
+ ];
7559
+ const tableStyle = minWidth === void 0 ? void 0 : { minWidth };
7560
+ return /* @__PURE__ */ jsxs10("div", { className: mergeClasses11("min-w-0", className), children: [
7561
+ /* @__PURE__ */ jsxs10("div", { "aria-busy": loading || void 0, className: "relative min-w-0", children: [
7562
+ /* @__PURE__ */ jsx20(ScrollArea, { axes: "horizontal", className: "min-w-0", children: /* @__PURE__ */ jsxs10(Table, { "aria-label": ariaLabel, size, style: tableStyle, children: [
7563
+ /* @__PURE__ */ jsx20(TableColumns, { widths }),
7564
+ /* @__PURE__ */ jsx20(TableHeader, { children: /* @__PURE__ */ jsxs10(TableRow, { children: [
7565
+ selection && (selectionMode === "multiple" ? /* @__PURE__ */ jsx20(
7566
+ TableSelectionCell,
7567
+ {
7568
+ checkboxIndicator: { "aria-label": t2("dataTable.selectAll"), disabled: selectableVisible.length === 0 },
7569
+ checked: allChecked,
7570
+ onClick: selectableVisible.length === 0 ? void 0 : toggleAll
7571
+ }
7572
+ ) : /* @__PURE__ */ jsx20(TableHeaderCell2, {})),
7573
+ expandable && /* @__PURE__ */ jsx20(TableHeaderCell2, {}),
7574
+ columns.map((column) => {
7575
+ const Header = HEADER_BY_ALIGN[column.align ?? "start"];
7576
+ const sorted = sort?.key === column.key ? sort.direction : void 0;
7577
+ return /* @__PURE__ */ jsx20(
7578
+ Header,
7579
+ {
7580
+ onClick: column.sort ? () => cycleSort(column) : void 0,
7581
+ sortable: column.sort !== void 0,
7582
+ sortDirection: sorted,
7583
+ children: column.title
7584
+ },
7585
+ column.key
7586
+ );
7587
+ })
7588
+ ] }) }),
7589
+ /* @__PURE__ */ jsxs10(TableBody, { children: [
7590
+ visibleRows.length === 0 && /* @__PURE__ */ jsx20(TableRow, { children: /* @__PURE__ */ jsx20(TableCell2, { colSpan: columnCount, children: empty ?? /* @__PURE__ */ jsx20(EmptyStateLine, { className: "py-6 text-center", children: t2("dataTable.empty") }) }) }),
7591
+ visibleRows.flatMap((row, index) => {
7592
+ const key = rowKey(row);
7593
+ const selected = selectedKeys.includes(key);
7594
+ const expanded = expandable !== void 0 && expandedKeys.includes(key);
7595
+ const canExpand = expandable !== void 0 && (expandable.isExpandable?.(row) ?? true);
7596
+ const items = [/* @__PURE__ */ jsxs10(
7597
+ TableRow,
7598
+ {
7599
+ "aria-selected": selection ? selected : void 0,
7600
+ className: mergeClasses11(onRowClick && "cursor-pointer", rowClassName?.(row, index)),
7601
+ onClick: onRowClick ? () => onRowClick(row, index) : void 0,
7602
+ children: [
7603
+ selection && /* @__PURE__ */ jsx20(
7604
+ TableSelectionCell,
7605
+ {
7606
+ checkboxIndicator: { "aria-label": t2("dataTable.selectRow"), disabled: !isSelectable(row) },
7607
+ checked: selected,
7608
+ onClick: (event) => {
7609
+ stop(event);
7610
+ if (isSelectable(row)) selectRow(key);
7611
+ },
7612
+ radioIndicator: { "aria-label": t2("dataTable.selectRow"), disabled: !isSelectable(row) },
7613
+ type: selectionMode === "single" ? "radio" : "checkbox"
7614
+ }
7615
+ ),
7616
+ expandable && /* @__PURE__ */ jsx20(TableCell2, { ...stopRowSelection, children: canExpand && /* @__PURE__ */ jsx20(
7617
+ Button7,
7618
+ {
7619
+ appearance: "subtle",
7620
+ "aria-expanded": expanded,
7621
+ "aria-label": t2(expanded ? "dataTable.collapseRow" : "dataTable.expandRow"),
7622
+ icon: expanded ? /* @__PURE__ */ jsx20(ChevronDown16Regular, {}) : /* @__PURE__ */ jsx20(ChevronRight16Regular, {}),
7623
+ onClick: () => toggleExpanded(key),
7624
+ size: "small"
7625
+ }
7626
+ ) }),
7627
+ columns.map((column) => {
7628
+ const Cell = CELL_BY_ALIGN[column.align ?? "start"];
7629
+ const content = column.render ? column.render(row, index) : column.dataKey === void 0 ? null : row[column.dataKey];
7630
+ return /* @__PURE__ */ jsx20(Cell, { className: column.ellipsis ? "overflow-hidden" : void 0, children: column.ellipsis ? /* @__PURE__ */ jsx20(TableCellLayout, { title: typeof content === "string" || typeof content === "number" ? String(content) : void 0, truncate: true, children: content }) : content }, column.key);
7631
+ })
7632
+ ]
7633
+ },
7634
+ key
7635
+ )];
7636
+ if (expanded && canExpand) {
7637
+ items.push(/* @__PURE__ */ jsx20(TableRow, { children: /* @__PURE__ */ jsx20(TableCell2, { colSpan: columnCount, children: expandable.render(row) }) }, `${key}:expanded`));
7638
+ }
7639
+ return items;
7640
+ })
7641
+ ] })
7642
+ ] }) }),
7643
+ loading && /* @__PURE__ */ jsx20(
7644
+ "div",
7645
+ {
7646
+ className: "absolute inset-0 grid place-items-center",
7647
+ style: { background: "color-mix(in srgb, var(--colorNeutralBackground1) 60%, transparent)" },
7648
+ children: /* @__PURE__ */ jsx20(Spinner2, { label: t2("dataTable.loading"), size: "small" })
7649
+ }
7650
+ )
7651
+ ] }),
7652
+ paged && !(pagination.hideOnSinglePage && pageCount <= 1) && /* @__PURE__ */ jsx20("div", { className: "flex justify-end px-3 py-1", style: { borderTop: "1px solid var(--colorNeutralStroke3)" }, children: /* @__PURE__ */ jsx20(
7653
+ Pager,
7654
+ {
7655
+ onPageChange: changePage,
7656
+ onPageSizeChange: changePageSize,
7657
+ page,
7658
+ pageCount,
7659
+ pageSize,
7660
+ pageSizeOptions: pagination.pageSizeOptions,
7661
+ showTotal: pagination.showTotal,
7662
+ total: sortedRows.length
7663
+ }
7664
+ ) })
7665
+ ] });
7666
+ }
7667
+
7668
+ // src/components/ui/dashboard-page-header.tsx
7669
+ import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
7670
+ var { Text: Text4, mergeClasses: mergeClasses12 } = fluentComponents;
7671
+ function DashboardPageHeader({ actions, className, description, title }) {
7672
+ return /* @__PURE__ */ jsxs11("header", { className: mergeClasses12(HEADER_ROW_CLASS, "gap-[18px]", className), children: [
7673
+ /* @__PURE__ */ jsxs11("div", { className: "grid gap-1.5 min-w-0", children: [
7674
+ /* @__PURE__ */ jsx21(Text4, { as: "h1", size: 700, weight: "semibold", className: "m-0", children: title }),
7675
+ description !== void 0 && /* @__PURE__ */ jsx21(Text4, { size: 200, className: "text-fui-fg2 max-w-[760px]", children: description })
7676
+ ] }),
7677
+ actions !== void 0 && /* @__PURE__ */ jsx21("div", { className: "flex items-center gap-2 flex-none max-[900px]:justify-start", children: actions })
7678
+ ] });
7679
+ }
7680
+
7681
+ // src/components/ui/error-shell.tsx
7682
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
7683
+ var { Text: Text5 } = fluentComponents;
7174
7684
  function ErrorShell({ action, children, message, title }) {
7175
- return /* @__PURE__ */ jsx17(ScrollArea, { axes: "vertical", className: "fwt-error-shell-viewport", contentClassName: "h-full", children: /* @__PURE__ */ jsxs9("main", { className: "fwt-error-shell", children: [
7176
- /* @__PURE__ */ jsxs9("div", { className: "fwt-error-shell-stack", children: [
7177
- /* @__PURE__ */ jsx17(Text3, { align: "center", as: "h1", size: 700, weight: "semibold", children: title }),
7178
- message !== void 0 && /* @__PURE__ */ jsx17(Text3, { align: "center", as: "p", className: "text-fui-fg2", size: 300, children: message })
7685
+ return /* @__PURE__ */ jsx22(ScrollArea, { axes: "vertical", className: "fwt-error-shell-viewport", contentClassName: "h-full", children: /* @__PURE__ */ jsxs12("main", { className: "fwt-error-shell", children: [
7686
+ /* @__PURE__ */ jsxs12("div", { className: "fwt-error-shell-stack", children: [
7687
+ /* @__PURE__ */ jsx22(Text5, { align: "center", as: "h1", size: 700, weight: "semibold", children: title }),
7688
+ message !== void 0 && /* @__PURE__ */ jsx22(Text5, { align: "center", as: "p", className: "text-fui-fg2", size: 300, children: message })
7179
7689
  ] }),
7180
7690
  children,
7181
- action !== void 0 && /* @__PURE__ */ jsx17("div", { className: "fwt-error-shell-actions", children: action })
7691
+ action !== void 0 && /* @__PURE__ */ jsx22("div", { className: "fwt-error-shell-actions", children: action })
7182
7692
  ] }) });
7183
7693
  }
7184
7694
  function ErrorStack({ children }) {
7185
- return /* @__PURE__ */ jsx17(
7695
+ return /* @__PURE__ */ jsx22(
7186
7696
  ScrollArea,
7187
7697
  {
7188
7698
  axes: "horizontal",
7189
7699
  className: "winui-focus-rect-within w-full min-w-0 rounded-[var(--winui-overlay-corner-radius,8px)] border border-solid border-fui-stroke1 bg-fui-bg2 text-left",
7190
- children: /* @__PURE__ */ jsx17("pre", { className: "m-0 w-max min-w-full p-4 font-mono", children: /* @__PURE__ */ jsx17("code", { children }) })
7700
+ children: /* @__PURE__ */ jsx22("pre", { className: "m-0 w-max min-w-full p-4 font-mono", children: /* @__PURE__ */ jsx22("code", { children }) })
7191
7701
  }
7192
7702
  );
7193
7703
  }
7194
7704
 
7705
+ // src/components/ui/file-drop-zone.tsx
7706
+ import { ArrowUploadRegular, DismissRegular as DismissRegular3, DocumentRegular } from "@fluentui/react-icons";
7707
+ import { useId as useId2, useRef as useRef5, useState as useState7 } from "react";
7708
+ import { Fragment as Fragment2, jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
7709
+ var { Button: Button8, Text: Text6, makeStyles: makeStyles9, mergeClasses: mergeClasses13, shorthands } = fluentComponents;
7710
+ var useStyles9 = makeStyles9({
7711
+ root: {
7712
+ display: "grid",
7713
+ rowGap: "8px",
7714
+ minWidth: 0
7715
+ },
7716
+ zone: {
7717
+ alignItems: "center",
7718
+ backgroundColor: "var(--winui-card-background-fill-default)",
7719
+ ...shorthands.border("1px", "dashed", "var(--winui-surface-stroke-default)"),
7720
+ borderRadius: "var(--winui-control-corner-radius)",
7721
+ boxSizing: "border-box",
7722
+ color: "var(--winui-text-fill-primary)",
7723
+ cursor: "pointer",
7724
+ display: "grid",
7725
+ justifyItems: "center",
7726
+ minHeight: "120px",
7727
+ padding: "24px 16px",
7728
+ rowGap: "4px",
7729
+ textAlign: "center",
7730
+ transitionDuration: "var(--winui-control-faster-animation-duration)",
7731
+ transitionProperty: "background-color, border-color",
7732
+ "@media (prefers-reduced-motion: reduce)": { transitionDuration: "0.01ms" },
7733
+ "&:hover": { backgroundColor: "var(--winui-control-fill-secondary)" },
7734
+ "&:active": { backgroundColor: "var(--winui-control-fill-tertiary)" },
7735
+ // The system focus visual, as ./settings-card draws it.
7736
+ "&:focus-visible": {
7737
+ boxShadow: "0 0 0 1px var(--winui-focus-stroke-inner)",
7738
+ outlineColor: "var(--winui-focus-stroke-outer)",
7739
+ outlineOffset: "1px",
7740
+ outlineStyle: "solid",
7741
+ outlineWidth: "2px"
7742
+ }
7743
+ },
7744
+ dragOver: {
7745
+ backgroundColor: "var(--winui-accent-tint-fill-default)",
7746
+ ...shorthands.borderColor("var(--winui-accent-base)"),
7747
+ "&:hover": { backgroundColor: "var(--winui-accent-tint-fill-default)" },
7748
+ "&:active": { backgroundColor: "var(--winui-accent-tint-fill-secondary)" }
7749
+ },
7750
+ disabled: {
7751
+ backgroundColor: "var(--winui-control-fill-disabled)",
7752
+ color: "var(--winui-text-fill-disabled)",
7753
+ cursor: "not-allowed",
7754
+ "&:hover": { backgroundColor: "var(--winui-control-fill-disabled)" },
7755
+ "&:active": { backgroundColor: "var(--winui-control-fill-disabled)" }
7756
+ },
7757
+ icon: {
7758
+ color: "var(--winui-text-fill-secondary)",
7759
+ display: "inline-flex",
7760
+ fontSize: "24px",
7761
+ lineHeight: 0,
7762
+ pointerEvents: "none"
7763
+ },
7764
+ iconDragOver: { color: "var(--winui-accent-base)" },
7765
+ list: {
7766
+ display: "grid",
7767
+ listStyleType: "none",
7768
+ margin: 0,
7769
+ padding: 0,
7770
+ rowGap: "4px"
7771
+ },
7772
+ file: {
7773
+ alignItems: "center",
7774
+ backgroundColor: "var(--winui-card-background-fill-default)",
7775
+ ...shorthands.border("1px", "solid", "var(--winui-card-stroke-default)"),
7776
+ borderRadius: "var(--winui-control-corner-radius)",
7777
+ columnGap: "8px",
7778
+ display: "flex",
7779
+ minHeight: "40px",
7780
+ paddingBlock: "4px",
7781
+ paddingInlineStart: "12px",
7782
+ paddingInlineEnd: "4px"
7783
+ },
7784
+ fileName: {
7785
+ flexGrow: 1,
7786
+ minWidth: 0,
7787
+ overflow: "hidden",
7788
+ textOverflow: "ellipsis",
7789
+ whiteSpace: "nowrap"
7790
+ }
7791
+ });
7792
+ var BYTE_UNITS = ["B", "KB", "MB", "GB", "TB"];
7793
+ var formatFileSize = (bytes) => {
7794
+ let size = bytes;
7795
+ let unit = 0;
7796
+ while (size >= 1024 && unit < BYTE_UNITS.length - 1) {
7797
+ size /= 1024;
7798
+ unit += 1;
7799
+ }
7800
+ const text = new Intl.NumberFormat(void 0, { maximumFractionDigits: unit === 0 ? 0 : 1 }).format(size);
7801
+ return `${text} ${BYTE_UNITS[unit]}`;
7802
+ };
7803
+ var matchesAccept = (file, accept) => {
7804
+ const tokens3 = accept?.split(",").map((token) => token.trim().toLowerCase()).filter(Boolean) ?? [];
7805
+ if (tokens3.length === 0) return true;
7806
+ const name = file.name.toLowerCase();
7807
+ const type = file.type.toLowerCase();
7808
+ return tokens3.some((token) => {
7809
+ if (token.startsWith(".")) return name.endsWith(token);
7810
+ if (token.endsWith("/*")) return type.startsWith(token.slice(0, -1));
7811
+ return type === token;
7812
+ });
7813
+ };
7814
+ var pickFiles = (files, accept, multiple) => {
7815
+ const accepted = [...files].filter((file) => matchesAccept(file, accept));
7816
+ return multiple ? accepted : accepted.slice(0, 1);
7817
+ };
7818
+ function FileDropZone({
7819
+ accept,
7820
+ className,
7821
+ description,
7822
+ disabled,
7823
+ icon,
7824
+ multiple,
7825
+ onFiles,
7826
+ onRemove,
7827
+ selectedFiles,
7828
+ title
7829
+ }) {
7830
+ const styles = useStyles9();
7831
+ const { t: t2 } = useTranslation();
7832
+ const inputRef = useRef5(null);
7833
+ const depth = useRef5(0);
7834
+ const [dragOver, setDragOver] = useState7(false);
7835
+ const titleId = useId2();
7836
+ const reset = () => {
7837
+ depth.current = 0;
7838
+ setDragOver(false);
7839
+ };
7840
+ const emit = (files) => {
7841
+ const picked = pickFiles(files, accept, multiple);
7842
+ if (picked.length > 0) onFiles(picked);
7843
+ };
7844
+ const open = () => {
7845
+ if (!disabled) inputRef.current?.click();
7846
+ };
7847
+ const handleDragEnter = (event) => {
7848
+ if (disabled) return;
7849
+ event.preventDefault();
7850
+ depth.current += 1;
7851
+ setDragOver(true);
7852
+ };
7853
+ const handleDragOver = (event) => {
7854
+ if (disabled) return;
7855
+ event.preventDefault();
7856
+ event.dataTransfer.dropEffect = "copy";
7857
+ };
7858
+ const handleDragLeave = () => {
7859
+ if (disabled) return;
7860
+ depth.current = Math.max(0, depth.current - 1);
7861
+ if (depth.current === 0) setDragOver(false);
7862
+ };
7863
+ const handleDrop = (event) => {
7864
+ if (disabled) return;
7865
+ event.preventDefault();
7866
+ reset();
7867
+ emit(Array.from(event.dataTransfer.files));
7868
+ };
7869
+ const handleKeyDown = (event) => {
7870
+ if (event.target !== event.currentTarget) return;
7871
+ if (event.key === "Enter" || event.key === " ") {
7872
+ event.preventDefault();
7873
+ open();
7874
+ }
7875
+ };
7876
+ const handleInputChange = (event) => {
7877
+ const files = Array.from(event.target.files ?? []);
7878
+ event.target.value = "";
7879
+ emit(files);
7880
+ };
7881
+ return /* @__PURE__ */ jsxs13("div", { className: mergeClasses13(styles.root, className), children: [
7882
+ /* @__PURE__ */ jsxs13(
7883
+ "div",
7884
+ {
7885
+ "aria-disabled": disabled || void 0,
7886
+ "aria-labelledby": titleId,
7887
+ className: mergeClasses13(styles.zone, dragOver && styles.dragOver, disabled && styles.disabled),
7888
+ "data-drag-over": dragOver || void 0,
7889
+ onClick: open,
7890
+ onDragEnter: handleDragEnter,
7891
+ onDragLeave: handleDragLeave,
7892
+ onDragOver: handleDragOver,
7893
+ onDrop: handleDrop,
7894
+ onKeyDown: handleKeyDown,
7895
+ role: "button",
7896
+ tabIndex: disabled ? -1 : 0,
7897
+ children: [
7898
+ /* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: mergeClasses13(styles.icon, dragOver && styles.iconDragOver), children: icon ?? /* @__PURE__ */ jsx23(ArrowUploadRegular, {}) }),
7899
+ /* @__PURE__ */ jsx23(Text6, { id: titleId, size: 300, weight: "semibold", children: dragOver ? t2("fileDropZone.dropHint") : title }),
7900
+ description !== void 0 && /* @__PURE__ */ jsx23(Text6, { size: 200, className: "text-fui-fg2", children: description })
7901
+ ]
7902
+ }
7903
+ ),
7904
+ /* @__PURE__ */ jsx23(
7905
+ "input",
7906
+ {
7907
+ accept,
7908
+ disabled,
7909
+ hidden: true,
7910
+ multiple,
7911
+ onChange: handleInputChange,
7912
+ ref: inputRef,
7913
+ tabIndex: -1,
7914
+ type: "file"
7915
+ }
7916
+ ),
7917
+ selectedFiles !== void 0 && selectedFiles.length > 0 && /* @__PURE__ */ jsx23("ul", { className: styles.list, children: selectedFiles.map((file, index) => /* @__PURE__ */ jsxs13("li", { className: styles.file, children: [
7918
+ /* @__PURE__ */ jsx23(DocumentRegular, { "aria-hidden": true, className: "text-fui-fg2 shrink-0" }),
7919
+ /* @__PURE__ */ jsx23(Text6, { className: styles.fileName, size: 300, title: file.name, children: file.name }),
7920
+ /* @__PURE__ */ jsx23(Text6, { className: "text-fui-fg2 shrink-0", size: 200, children: formatFileSize(file.size) }),
7921
+ onRemove && /* @__PURE__ */ jsx23(
7922
+ Button8,
7923
+ {
7924
+ appearance: "subtle",
7925
+ "aria-label": `${t2("fileDropZone.remove")}: ${file.name}`,
7926
+ icon: /* @__PURE__ */ jsx23(DismissRegular3, {}),
7927
+ onClick: () => onRemove(file, index),
7928
+ size: "small"
7929
+ }
7930
+ )
7931
+ ] }, `${file.name}:${file.size}:${file.lastModified}:${index}`)) })
7932
+ ] });
7933
+ }
7934
+ function FilePickerButton({ accept, children, disabled, multiple, onClick, onFiles, ...rest }) {
7935
+ const { t: t2 } = useTranslation();
7936
+ const inputRef = useRef5(null);
7937
+ const buttonProps = {
7938
+ ...rest,
7939
+ disabled,
7940
+ onClick: (event) => {
7941
+ onClick?.(event);
7942
+ if (!event.defaultPrevented) inputRef.current?.click();
7943
+ }
7944
+ };
7945
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
7946
+ /* @__PURE__ */ jsx23(Button8, { ...buttonProps, children: children ?? t2("fileDropZone.browse") }),
7947
+ /* @__PURE__ */ jsx23(
7948
+ "input",
7949
+ {
7950
+ accept,
7951
+ disabled,
7952
+ hidden: true,
7953
+ multiple,
7954
+ onChange: (event) => {
7955
+ const files = Array.from(event.target.files ?? []);
7956
+ event.target.value = "";
7957
+ if (files.length > 0) onFiles(files);
7958
+ },
7959
+ ref: inputRef,
7960
+ tabIndex: -1,
7961
+ type: "file"
7962
+ }
7963
+ )
7964
+ ] });
7965
+ }
7966
+
7195
7967
  // src/components/ui/status-badge.tsx
7196
- import { jsx as jsx18 } from "react/jsx-runtime";
7197
- var { Badge, makeStyles: makeStyles7, mergeClasses: mergeClasses9 } = fluentComponents;
7968
+ import { jsx as jsx24 } from "react/jsx-runtime";
7969
+ var { Badge, makeStyles: makeStyles10, mergeClasses: mergeClasses14 } = fluentComponents;
7198
7970
  var TONE_HUES = {
7199
7971
  accent: { light: "#0078d4", dark: "#4cc2ff" },
7200
7972
  danger: { light: "#c42b1c", dark: "#ff99a4" },
@@ -7204,7 +7976,7 @@ var TONE_HUES = {
7204
7976
  };
7205
7977
  var CHIP_ROOT_PADDING = "5px";
7206
7978
  var LABEL_INSET = `calc(var(--strokeWidthThin) + ${CHIP_ROOT_PADDING} + var(--spacingHorizontalXXS))`;
7207
- var useStyles7 = makeStyles7({
7979
+ var useStyles10 = makeStyles10({
7208
7980
  root: {
7209
7981
  paddingLeft: LABEL_INSET,
7210
7982
  paddingRight: LABEL_INSET
@@ -7212,14 +7984,14 @@ var useStyles7 = makeStyles7({
7212
7984
  });
7213
7985
  function StatusBadge({ children, className, tone }) {
7214
7986
  const hue = useBadgeHue(TONE_HUES[tone]);
7215
- const styles = useStyles7();
7216
- return /* @__PURE__ */ jsx18(Badge, { appearance: "tint", className: mergeClasses9(styles.root, hue.className, className), size: "large", style: hue.style, children });
7987
+ const styles = useStyles10();
7988
+ return /* @__PURE__ */ jsx24(Badge, { appearance: "tint", className: mergeClasses14(styles.root, hue.className, className), size: "large", style: hue.style, children });
7217
7989
  }
7218
7990
 
7219
7991
  // src/components/ui/http-badge.tsx
7220
- import { jsx as jsx19 } from "react/jsx-runtime";
7221
- var { makeStyles: makeStyles8 } = fluentComponents;
7222
- var useStyles8 = makeStyles8({
7992
+ import { jsx as jsx25 } from "react/jsx-runtime";
7993
+ var { makeStyles: makeStyles11 } = fluentComponents;
7994
+ var useStyles11 = makeStyles11({
7223
7995
  root: {
7224
7996
  fontFamily: "var(--fontFamilyMonospace)",
7225
7997
  minWidth: "48px",
@@ -7227,34 +7999,34 @@ var useStyles8 = makeStyles8({
7227
7999
  }
7228
8000
  });
7229
8001
  function HttpBadge({ children, tone }) {
7230
- const styles = useStyles8();
7231
- return /* @__PURE__ */ jsx19(StatusBadge, { className: styles.root, tone, children: /* @__PURE__ */ jsx19("span", { translate: "no", children }) });
8002
+ const styles = useStyles11();
8003
+ return /* @__PURE__ */ jsx25(StatusBadge, { className: styles.root, tone, children: /* @__PURE__ */ jsx25("span", { translate: "no", children }) });
7232
8004
  }
7233
8005
  function HttpMethodBadge({ method }) {
7234
- return /* @__PURE__ */ jsx19(HttpBadge, { tone: method === "GET" ? "accent" : method === "POST" ? "success" : "neutral", children: method });
8006
+ return /* @__PURE__ */ jsx25(HttpBadge, { tone: method === "GET" ? "accent" : method === "POST" ? "success" : "neutral", children: method });
7235
8007
  }
7236
8008
  function HttpStatusBadge({ children, severity }) {
7237
- return /* @__PURE__ */ jsx19(HttpBadge, { tone: severity === "error" ? "danger" : severity, children });
8009
+ return /* @__PURE__ */ jsx25(HttpBadge, { tone: severity === "error" ? "danger" : severity, children });
7238
8010
  }
7239
8011
 
7240
8012
  // src/components/ui/info-label.tsx
7241
- import { jsx as jsx20 } from "react/jsx-runtime";
8013
+ import { jsx as jsx26 } from "react/jsx-runtime";
7242
8014
  var { InfoLabel } = fluentComponents;
7243
- var infoLabelSlot = (label, info) => (_2, slotProps2) => /* @__PURE__ */ jsx20(InfoLabel, { ...slotProps2, info, children: label });
8015
+ var infoLabelSlot = (label, info) => (_2, slotProps2) => /* @__PURE__ */ jsx26(InfoLabel, { ...slotProps2, info, children: label });
7244
8016
 
7245
8017
  // src/components/ui/loading-screen.tsx
7246
- import { jsx as jsx21 } from "react/jsx-runtime";
7247
- var { Spinner } = fluentComponents;
8018
+ import { jsx as jsx27 } from "react/jsx-runtime";
8019
+ var { Spinner: Spinner3 } = fluentComponents;
7248
8020
  function AppLoadingScreen({ label }) {
7249
- return /* @__PURE__ */ jsx21("main", { className: "fwt-loading fwt-loading-app", children: /* @__PURE__ */ jsx21(Spinner, { label }) });
8021
+ return /* @__PURE__ */ jsx27("main", { className: "fwt-loading fwt-loading-app", children: /* @__PURE__ */ jsx27(Spinner3, { label }) });
7250
8022
  }
7251
8023
  function ContentLoadingScreen({ label }) {
7252
- return /* @__PURE__ */ jsx21("div", { className: "fwt-loading", children: /* @__PURE__ */ jsx21(Spinner, { label }) });
8024
+ return /* @__PURE__ */ jsx27("div", { className: "fwt-loading", children: /* @__PURE__ */ jsx27(Spinner3, { label }) });
7253
8025
  }
7254
8026
 
7255
8027
  // src/components/ui/masked-icon.tsx
7256
- import { jsx as jsx22 } from "react/jsx-runtime";
7257
- var { mergeClasses: mergeClasses10 } = fluentComponents;
8028
+ import { jsx as jsx28 } from "react/jsx-runtime";
8029
+ var { mergeClasses: mergeClasses15 } = fluentComponents;
7258
8030
  function MaskedIcon({ className, maskSize = "contain", url }) {
7259
8031
  const style = {
7260
8032
  backgroundColor: "currentColor",
@@ -7267,13 +8039,96 @@ function MaskedIcon({ className, maskSize = "contain", url }) {
7267
8039
  maskPosition: "center",
7268
8040
  WebkitMaskPosition: "center"
7269
8041
  };
7270
- return /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: mergeClasses10("block flex-none", className), style });
8042
+ return /* @__PURE__ */ jsx28("span", { "aria-hidden": true, className: mergeClasses15("block flex-none", className), style });
7271
8043
  }
7272
8044
 
7273
- // src/components/ui/multiselect-combobox.tsx
7274
- import { useState as useState5 } from "react";
7275
- import { jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
7276
- var { Option: Option2 } = fluentComponents;
8045
+ // src/components/ui/metric.tsx
8046
+ import { jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
8047
+ var { makeStyles: makeStyles12, mergeClasses: mergeClasses16 } = fluentComponents;
8048
+ var useStyles12 = makeStyles12({
8049
+ root: {
8050
+ display: "grid",
8051
+ minWidth: 0,
8052
+ rowGap: "4px"
8053
+ },
8054
+ label: {
8055
+ color: "var(--winui-text-fill-secondary)",
8056
+ fontSize: "var(--fontSizeBase200)",
8057
+ lineHeight: "var(--lineHeightBase200)"
8058
+ },
8059
+ value: {
8060
+ alignItems: "baseline",
8061
+ color: "var(--winui-text-fill-primary)",
8062
+ columnGap: "4px",
8063
+ display: "flex",
8064
+ fontVariantNumeric: "tabular-nums",
8065
+ fontWeight: "var(--fontWeightSemibold)",
8066
+ minWidth: 0
8067
+ },
8068
+ title: {
8069
+ fontSize: "var(--fontSizeHero700)",
8070
+ lineHeight: "var(--lineHeightHero700)"
8071
+ },
8072
+ subtitle: {
8073
+ fontSize: "var(--fontSizeBase500)",
8074
+ lineHeight: "var(--lineHeightBase500)"
8075
+ },
8076
+ // A prefix or suffix is a unit or a sign, not part of the figure: one step
8077
+ // down the ramp and the secondary fill, so the figure stays the loudest thing.
8078
+ affix: {
8079
+ color: "var(--winui-text-fill-secondary)",
8080
+ fontSize: "var(--fontSizeBase300)",
8081
+ fontWeight: "var(--fontWeightRegular)",
8082
+ lineHeight: "var(--lineHeightBase300)"
8083
+ },
8084
+ accent: { color: "var(--winui-accent-text-fill-tertiary)" },
8085
+ success: { color: "var(--winui-system-fill-success)" },
8086
+ warning: { color: "var(--winui-system-fill-caution)" },
8087
+ danger: { color: "var(--winui-system-fill-critical)" },
8088
+ grid: {
8089
+ display: "grid",
8090
+ gap: "var(--fwt-metric-gap, 16px)",
8091
+ gridTemplateColumns: "repeat(auto-fit, minmax(min(var(--fwt-metric-min-width, 160px), 100%), 1fr))"
8092
+ }
8093
+ });
8094
+ var formatMetricValue = (value, precision, locale) => typeof value === "number" ? new Intl.NumberFormat(locale, precision === void 0 ? void 0 : { minimumFractionDigits: precision, maximumFractionDigits: precision }).format(value) : value;
8095
+ function Metric({
8096
+ className,
8097
+ formatter,
8098
+ label,
8099
+ locale,
8100
+ precision,
8101
+ prefix,
8102
+ size = "title",
8103
+ suffix,
8104
+ tone = "default",
8105
+ value
8106
+ }) {
8107
+ const styles = useStyles12();
8108
+ const hasValue = value !== null && value !== void 0;
8109
+ const text = hasValue ? formatter ? formatter(value) : formatMetricValue(value, precision, locale) : "\u2014";
8110
+ return /* @__PURE__ */ jsxs14("div", { className: mergeClasses16(styles.root, className), children: [
8111
+ /* @__PURE__ */ jsx29("span", { className: styles.label, children: label }),
8112
+ /* @__PURE__ */ jsxs14("div", { className: mergeClasses16(styles.value, styles[size], tone !== "default" && styles[tone]), children: [
8113
+ prefix !== void 0 && /* @__PURE__ */ jsx29("span", { className: styles.affix, children: prefix }),
8114
+ /* @__PURE__ */ jsx29("span", { children: text }),
8115
+ suffix !== void 0 && /* @__PURE__ */ jsx29("span", { className: styles.affix, children: suffix })
8116
+ ] })
8117
+ ] });
8118
+ }
8119
+ function MetricGrid({ children, className, gap, minItemWidth }) {
8120
+ const styles = useStyles12();
8121
+ const style = {
8122
+ ...minItemWidth !== void 0 && { "--fwt-metric-min-width": typeof minItemWidth === "number" ? `${minItemWidth}px` : minItemWidth },
8123
+ ...gap !== void 0 && { "--fwt-metric-gap": typeof gap === "number" ? `${gap}px` : gap }
8124
+ };
8125
+ return /* @__PURE__ */ jsx29("div", { className: mergeClasses16(styles.grid, className), style, children });
8126
+ }
8127
+
8128
+ // src/components/ui/multiselect-combobox.tsx
8129
+ import { useState as useState8 } from "react";
8130
+ import { jsx as jsx30, jsxs as jsxs15 } from "react/jsx-runtime";
8131
+ var { Option: Option3 } = fluentComponents;
7277
8132
  var sameValues = (left, right) => left.length === right.length && new Set(right).size === right.length && left.every((entry) => right.includes(entry));
7278
8133
  function MultiselectCombobox({
7279
8134
  ariaLabel,
@@ -7290,8 +8145,8 @@ function MultiselectCombobox({
7290
8145
  renderOption,
7291
8146
  value
7292
8147
  }) {
7293
- const [open, setOpen] = useState5(false);
7294
- const [query, setQuery] = useState5("");
8148
+ const [open, setOpen] = useState8(false);
8149
+ const [query, setQuery] = useState8("");
7295
8150
  const needle = query.trim().toLowerCase();
7296
8151
  const optionValues = new Set(options.map((option) => option.value));
7297
8152
  const completeOptions = [
@@ -7304,7 +8159,7 @@ function MultiselectCombobox({
7304
8159
  if (!sameValues(normalized, value)) onChange(normalized);
7305
8160
  setQuery("");
7306
8161
  };
7307
- return /* @__PURE__ */ jsxs10(
8162
+ return /* @__PURE__ */ jsxs15(
7308
8163
  Combobox,
7309
8164
  {
7310
8165
  "aria-label": ariaLabel,
@@ -7328,41 +8183,102 @@ function MultiselectCombobox({
7328
8183
  selectedOptions: clearLabel && value.length === 0 ? [""] : [...value],
7329
8184
  value: open ? query : closedLabel,
7330
8185
  children: [
7331
- clearLabel && needle === "" && /* @__PURE__ */ jsx23(Option2, { text: clearLabel, value: "", children: clearLabel }),
7332
- visible.map((option) => /* @__PURE__ */ jsx23(Option2, { text: option.label, value: option.value, children: renderOption ? renderOption(option) : option.label }, option.value))
8186
+ clearLabel && needle === "" && /* @__PURE__ */ jsx30(Option3, { text: clearLabel, value: "", children: clearLabel }),
8187
+ visible.map((option) => /* @__PURE__ */ jsx30(Option3, { text: option.label, value: option.value, children: renderOption ? renderOption(option) : option.label }, option.value))
7333
8188
  ]
7334
8189
  }
7335
8190
  );
7336
8191
  }
7337
8192
  var valuesAsOptions = (values) => values.map((value) => ({ value, label: value }));
7338
8193
 
8194
+ // src/components/ui/number-box.tsx
8195
+ import { forwardRef as forwardRef4, isValidElement } from "react";
8196
+ import { jsx as jsx31 } from "react/jsx-runtime";
8197
+ var { SpinButton } = fluentComponents;
8198
+ var stepPrecision = (step) => {
8199
+ const text = String(step);
8200
+ const exponent = /e-(\d+)$/.exec(text);
8201
+ if (exponent) return Number(exponent[1]);
8202
+ return text.split(".")[1]?.length ?? 0;
8203
+ };
8204
+ var THOUSANDS_GROUPED = /^-?\d{1,3}(,\d{3})+(\.\d+)?$/;
8205
+ var parseNumberText = (text) => {
8206
+ const trimmed = text.trim().replace(/−/g, "-").replace(/\s/g, "");
8207
+ if (trimmed === "") return null;
8208
+ const normalized = THOUSANDS_GROUPED.test(trimmed) ? trimmed.replace(/,/g, "") : /^-?\d*,\d+$/.test(trimmed) ? trimmed.replace(",", ".") : trimmed;
8209
+ const parsed = Number(normalized);
8210
+ return Number.isFinite(parsed) ? parsed : void 0;
8211
+ };
8212
+ var clampNumber = (value, { min, max, precision }) => {
8213
+ let next = value;
8214
+ if (max !== void 0 && next > max) next = max;
8215
+ if (min !== void 0 && next < min) next = min;
8216
+ return precision === void 0 ? next : Number(next.toFixed(Math.min(Math.max(precision, 0), 100)));
8217
+ };
8218
+ var resolveNumberChange = (data, bounds) => {
8219
+ const raw = data.value !== void 0 ? data.value : data.displayValue !== void 0 ? parseNumberText(data.displayValue) : void 0;
8220
+ return typeof raw === "number" ? clampNumber(raw, bounds) : raw;
8221
+ };
8222
+ var labelSlot = (slot, label) => {
8223
+ if (slot === void 0) return { "aria-label": label };
8224
+ if (slot === null || typeof slot !== "object" || isValidElement(slot) || Symbol.iterator in slot) return slot;
8225
+ return { "aria-label": label, ...slot };
8226
+ };
8227
+ var NumberBox = forwardRef4(function NumberBox2({ value, onChange, min, max, step, precision, decrementButton, incrementButton, ...rest }, ref) {
8228
+ const { t: t2 } = useTranslation();
8229
+ const bounds = { min, max, precision: precision ?? stepPrecision(step ?? 1) };
8230
+ const handleChange = (_event, data) => {
8231
+ const next = resolveNumberChange(data, bounds);
8232
+ if (next !== void 0) onChange(next);
8233
+ };
8234
+ return /* @__PURE__ */ jsx31(
8235
+ SpinButton,
8236
+ {
8237
+ ...rest,
8238
+ decrementButton: labelSlot(decrementButton, t2("numberBox.decrement")),
8239
+ incrementButton: labelSlot(incrementButton, t2("numberBox.increment")),
8240
+ max,
8241
+ min,
8242
+ onChange: handleChange,
8243
+ precision,
8244
+ ref,
8245
+ step,
8246
+ value
8247
+ }
8248
+ );
8249
+ });
8250
+
7339
8251
  // src/components/ui/open-link-label.tsx
7340
8252
  import { Open16Regular } from "@fluentui/react-icons";
7341
- import { jsx as jsx24, jsxs as jsxs11 } from "react/jsx-runtime";
8253
+ import { jsx as jsx32, jsxs as jsxs16 } from "react/jsx-runtime";
7342
8254
  function OpenLinkLabel({ children }) {
7343
- return /* @__PURE__ */ jsxs11("span", { className: "inline-flex items-center gap-1", children: [
8255
+ return /* @__PURE__ */ jsxs16("span", { className: "inline-flex items-center gap-1", children: [
7344
8256
  children,
7345
- /* @__PURE__ */ jsx24(Open16Regular, { "aria-hidden": true, className: "block flex-none" })
8257
+ /* @__PURE__ */ jsx32(Open16Regular, { "aria-hidden": true, className: "block flex-none" })
7346
8258
  ] });
7347
8259
  }
7348
8260
 
7349
8261
  // src/components/ui/outcome-toast.tsx
7350
- import { createContext as createContext3, useCallback as useCallback4, useContext as useContext3, useId as useId2, useMemo as useMemo3, useRef as useRef5 } from "react";
7351
- import { jsx as jsx25, jsxs as jsxs12 } from "react/jsx-runtime";
7352
- var { Spinner: Spinner2, Toast, Toaster, ToastTitle, useToastController } = fluentComponents;
8262
+ import { createContext as createContext3, useCallback as useCallback5, useContext as useContext3, useId as useId3, useMemo as useMemo4, useRef as useRef6 } from "react";
8263
+ import { jsx as jsx33, jsxs as jsxs17 } from "react/jsx-runtime";
8264
+ var { Spinner: Spinner4, Toast, Toaster, ToastTitle, useToastController } = fluentComponents;
7353
8265
  var TOAST_DISMISS_MS = 3e3;
7354
8266
  var OutcomeToastContext = createContext3(null);
8267
+ var ToastApiContext = createContext3(null);
7355
8268
  function OutcomeToastProvider({ children }) {
7356
- const toasterId = useId2();
7357
- const sequence = useRef5(0);
8269
+ return useContext3(OutcomeToastContext) ? children : /* @__PURE__ */ jsx33(ToasterHost, { children });
8270
+ }
8271
+ function ToasterHost({ children }) {
8272
+ const toasterId = useId3();
8273
+ const sequence = useRef6(0);
7358
8274
  const { dispatchToast, dismissToast, updateToast } = useToastController(toasterId);
7359
- const toastFor = useCallback4((toastId, message, pending) => /* @__PURE__ */ jsx25(Toast, { className: "cursor-pointer", onClick: () => dismissToast(toastId), children: /* @__PURE__ */ jsx25(ToastTitle, { media: pending ? /* @__PURE__ */ jsx25(Spinner2, { size: "tiny" }) : void 0, children: message }) }), [dismissToast]);
7360
- const nextToastId = useCallback4(() => `${toasterId}-${sequence.current++}`, [toasterId]);
7361
- const succeed = useCallback4((message) => {
8275
+ const toastFor = useCallback5((toastId, message, pending) => /* @__PURE__ */ jsx33(Toast, { className: "cursor-pointer", onClick: () => dismissToast(toastId), children: /* @__PURE__ */ jsx33(ToastTitle, { media: pending ? /* @__PURE__ */ jsx33(Spinner4, { size: "tiny" }) : void 0, children: message }) }), [dismissToast]);
8276
+ const nextToastId = useCallback5(() => `${toasterId}-${sequence.current++}`, [toasterId]);
8277
+ const succeed = useCallback5((message) => {
7362
8278
  const toastId = nextToastId();
7363
8279
  dispatchToast(toastFor(toastId, message, false), { intent: "success", toastId, timeout: TOAST_DISMISS_MS });
7364
8280
  }, [dispatchToast, nextToastId, toastFor]);
7365
- const start = useCallback4((pending) => {
8281
+ const start = useCallback5((pending) => {
7366
8282
  const toastId = nextToastId();
7367
8283
  dispatchToast(toastFor(toastId, pending, true), { toastId, timeout: -1 });
7368
8284
  return {
@@ -7375,21 +8291,37 @@ function OutcomeToastProvider({ children }) {
7375
8291
  settle: () => dismissToast(toastId)
7376
8292
  };
7377
8293
  }, [dismissToast, dispatchToast, nextToastId, toastFor, updateToast]);
7378
- const value = useMemo3(() => ({ start, succeed }), [start, succeed]);
7379
- return /* @__PURE__ */ jsxs12(OutcomeToastContext.Provider, { value, children: [
7380
- /* @__PURE__ */ jsx25(Toaster, { toasterId, position: "top-end" }),
8294
+ const value = useMemo4(() => ({ start, succeed }), [start, succeed]);
8295
+ const notify = useCallback5((intent, text, options) => {
8296
+ const toastId = nextToastId();
8297
+ dispatchToast(toastFor(toastId, text, false), { intent, toastId, timeout: options?.timeout ?? TOAST_DISMISS_MS });
8298
+ return () => dismissToast(toastId);
8299
+ }, [dismissToast, dispatchToast, nextToastId, toastFor]);
8300
+ const api = useMemo4(() => ({
8301
+ success: (text, options) => notify("success", text, options),
8302
+ error: (text, options) => notify("error", text, options),
8303
+ warning: (text, options) => notify("warning", text, options),
8304
+ info: (text, options) => notify("info", text, options)
8305
+ }), [notify]);
8306
+ return /* @__PURE__ */ jsx33(OutcomeToastContext.Provider, { value, children: /* @__PURE__ */ jsxs17(ToastApiContext.Provider, { value: api, children: [
8307
+ /* @__PURE__ */ jsx33(Toaster, { toasterId, position: "top-end" }),
7381
8308
  children
7382
- ] });
8309
+ ] }) });
7383
8310
  }
7384
8311
  var useOutcomeToasts = () => {
7385
8312
  const value = useContext3(OutcomeToastContext);
7386
8313
  if (!value) throw new Error("useOutcomeToasts requires an OutcomeToastProvider above it");
7387
8314
  return value;
7388
8315
  };
8316
+ var useToast = () => {
8317
+ const value = useContext3(ToastApiContext);
8318
+ if (!value) throw new Error("useToast requires an OutcomeToastProvider above it");
8319
+ return value;
8320
+ };
7389
8321
 
7390
8322
  // src/components/ui/panel.tsx
7391
- import { jsx as jsx26 } from "react/jsx-runtime";
7392
- var { Card, mergeClasses: mergeClasses11 } = fluentComponents;
8323
+ import { jsx as jsx34 } from "react/jsx-runtime";
8324
+ var { Card, mergeClasses: mergeClasses17 } = fluentComponents;
7393
8325
  var PANEL_INSET_CLASS = "p-[var(--fwt-panel-inset)]";
7394
8326
  var PANEL_BAND_CLASS = "px-[var(--fwt-panel-inset)] py-[var(--spacingVerticalSNudge)]";
7395
8327
  var PADDING_CLASS = {
@@ -7397,12 +8329,127 @@ var PADDING_CLASS = {
7397
8329
  flush: "!p-0"
7398
8330
  };
7399
8331
  function Panel({ className, padding = "content", ...props }) {
7400
- return /* @__PURE__ */ jsx26(Card, { ...props, className: mergeClasses11(PADDING_CLASS[padding], className) });
8332
+ return /* @__PURE__ */ jsx34(Card, { ...props, className: mergeClasses17(PADDING_CLASS[padding], className) });
8333
+ }
8334
+
8335
+ // src/components/ui/property-list.tsx
8336
+ import { jsx as jsx35, jsxs as jsxs18 } from "react/jsx-runtime";
8337
+ var { makeStyles: makeStyles13, mergeClasses: mergeClasses18, shorthands: shorthands2 } = fluentComponents;
8338
+ var NARROW = "@container fwt-property-list (width < 480px)";
8339
+ var MEDIUM = "@container fwt-property-list (480px <= width < 720px)";
8340
+ var useStyles13 = makeStyles13({
8341
+ container: {
8342
+ containerName: "fwt-property-list",
8343
+ containerType: "inline-size",
8344
+ minWidth: 0
8345
+ },
8346
+ // Cell lines are each cell's own right and bottom edge. The list is pulled
8347
+ // 1px past the frame on those two sides so the last column's and last row's
8348
+ // lines fall under the frame's clip and the frame's own border stands in.
8349
+ frame: {
8350
+ ...shorthands2.border("1px", "solid", "var(--winui-divider-stroke-default)"),
8351
+ borderRadius: "var(--winui-control-corner-radius)",
8352
+ overflow: "hidden"
8353
+ },
8354
+ list: {
8355
+ display: "grid",
8356
+ gridTemplateColumns: "repeat(var(--fwt-property-columns, 2), minmax(0, 1fr))",
8357
+ margin: 0,
8358
+ columnGap: "24px",
8359
+ rowGap: "12px",
8360
+ [NARROW]: { gridTemplateColumns: "minmax(0, 1fr)" }
8361
+ },
8362
+ listWrapsToTwo: {
8363
+ [MEDIUM]: { gridTemplateColumns: "repeat(2, minmax(0, 1fr))" }
8364
+ },
8365
+ listBordered: {
8366
+ columnGap: 0,
8367
+ rowGap: 0,
8368
+ marginRight: "-1px",
8369
+ marginBottom: "-1px"
8370
+ },
8371
+ item: {
8372
+ display: "grid",
8373
+ gridColumn: "span var(--fwt-span, 1)",
8374
+ minWidth: 0,
8375
+ rowGap: "2px",
8376
+ [NARROW]: { "&[data-wide]": { gridColumn: "1 / -1" } }
8377
+ },
8378
+ itemWrapsToTwo: {
8379
+ [MEDIUM]: { "&[data-wide]": { gridColumn: "1 / -1" } }
8380
+ },
8381
+ itemBordered: {
8382
+ borderBottom: "1px solid var(--winui-divider-stroke-default)",
8383
+ borderRight: "1px solid var(--winui-divider-stroke-default)",
8384
+ gridTemplateColumns: "var(--fwt-property-label-width, 120px) minmax(0, 1fr)",
8385
+ rowGap: 0
8386
+ },
8387
+ label: {
8388
+ color: "var(--winui-text-fill-secondary)",
8389
+ fontSize: "var(--fontSizeBase200)",
8390
+ lineHeight: "var(--lineHeightBase200)",
8391
+ margin: 0,
8392
+ minWidth: 0
8393
+ },
8394
+ value: {
8395
+ color: "var(--winui-text-fill-primary)",
8396
+ fontSize: "var(--fontSizeBase300)",
8397
+ lineHeight: "var(--lineHeightBase300)",
8398
+ margin: 0,
8399
+ minWidth: 0,
8400
+ overflowWrap: "anywhere"
8401
+ },
8402
+ labelBordered: {
8403
+ backgroundColor: "var(--winui-card-background-fill-secondary)",
8404
+ borderRight: "1px solid var(--winui-divider-stroke-default)",
8405
+ fontSize: "var(--fontSizeBase300)",
8406
+ lineHeight: "var(--lineHeightBase300)",
8407
+ padding: "8px 12px"
8408
+ },
8409
+ valueBordered: {
8410
+ backgroundColor: "var(--winui-card-background-fill-default)",
8411
+ padding: "8px 12px"
8412
+ }
8413
+ });
8414
+ function PropertyList({ bordered, className, columns = 2, items }) {
8415
+ const styles = useStyles13();
8416
+ const columnCount = Math.max(1, Math.floor(columns));
8417
+ const stepsDown = columnCount > 2;
8418
+ const list = /* @__PURE__ */ jsx35(
8419
+ "dl",
8420
+ {
8421
+ className: mergeClasses18(styles.list, stepsDown && styles.listWrapsToTwo, bordered && styles.listBordered),
8422
+ children: items.map((item, index) => {
8423
+ const span = Math.min(Math.max(1, Math.floor(item.span ?? 1)), columnCount);
8424
+ return /* @__PURE__ */ jsxs18(
8425
+ "div",
8426
+ {
8427
+ className: mergeClasses18(styles.item, stepsDown && styles.itemWrapsToTwo, bordered && styles.itemBordered),
8428
+ "data-wide": span > 1 ? "" : void 0,
8429
+ style: { "--fwt-span": span },
8430
+ children: [
8431
+ /* @__PURE__ */ jsx35("dt", { className: mergeClasses18(styles.label, bordered && styles.labelBordered), children: item.label }),
8432
+ /* @__PURE__ */ jsx35("dd", { className: mergeClasses18(styles.value, bordered && styles.valueBordered), children: item.value })
8433
+ ]
8434
+ },
8435
+ item.key ?? index
8436
+ );
8437
+ })
8438
+ }
8439
+ );
8440
+ return /* @__PURE__ */ jsx35(
8441
+ "div",
8442
+ {
8443
+ className: mergeClasses18(styles.container, bordered && styles.frame, className),
8444
+ style: { "--fwt-property-columns": columnCount },
8445
+ children: list
8446
+ }
8447
+ );
7401
8448
  }
7402
8449
 
7403
8450
  // src/components/ui/progress-ring.tsx
7404
- import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
7405
- var { makeStyles: makeStyles9, mergeClasses: mergeClasses12 } = fluentComponents;
8451
+ import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
8452
+ var { makeStyles: makeStyles14, mergeClasses: mergeClasses19 } = fluentComponents;
7406
8453
  var DIAMETER = 32;
7407
8454
  var STROKE = 4;
7408
8455
  var RADIUS = (DIAMETER - STROKE) / 2;
@@ -7413,7 +8460,7 @@ var TONE_STROKE = {
7413
8460
  caution: "var(--winui-system-fill-caution)",
7414
8461
  critical: "var(--winui-system-fill-critical)"
7415
8462
  };
7416
- var useStyles9 = makeStyles9({
8463
+ var useStyles14 = makeStyles14({
7417
8464
  // A forced-colours palette repaints background and border colours but not an
7418
8465
  // SVG stroke, so each ring names its system colour itself: Highlight is what
7419
8466
  // HighContrast gives ProgressRingForegroundThemeBrush through
@@ -7432,19 +8479,19 @@ var useStyles9 = makeStyles9({
7432
8479
  }
7433
8480
  });
7434
8481
  function ProgressRing({ className, percent, size = 16, tone }) {
7435
- const styles = useStyles9();
8482
+ const styles = useStyles14();
7436
8483
  const filled = Math.max(0, Math.min(100, percent)) / 100;
7437
- return /* @__PURE__ */ jsxs13(
8484
+ return /* @__PURE__ */ jsxs19(
7438
8485
  "svg",
7439
8486
  {
7440
8487
  "aria-hidden": true,
7441
- className: mergeClasses12("block flex-none", className),
8488
+ className: mergeClasses19("block flex-none", className),
7442
8489
  height: size,
7443
8490
  style: { transform: "translateY(calc(50% - 0.5cap))" },
7444
8491
  viewBox: `0 0 ${DIAMETER} ${DIAMETER}`,
7445
8492
  width: size,
7446
8493
  children: [
7447
- /* @__PURE__ */ jsx27(
8494
+ /* @__PURE__ */ jsx36(
7448
8495
  "circle",
7449
8496
  {
7450
8497
  className: styles.track,
@@ -7456,7 +8503,7 @@ function ProgressRing({ className, percent, size = 16, tone }) {
7456
8503
  strokeWidth: TRACK_STROKE
7457
8504
  }
7458
8505
  ),
7459
- /* @__PURE__ */ jsx27(
8506
+ /* @__PURE__ */ jsx36(
7460
8507
  "circle",
7461
8508
  {
7462
8509
  className: styles.arc,
@@ -7478,9 +8525,9 @@ function ProgressRing({ className, percent, size = 16, tone }) {
7478
8525
 
7479
8526
  // src/components/ui/reorder-list.tsx
7480
8527
  import { ReOrderDotsVerticalRegular } from "@fluentui/react-icons";
7481
- import { useEffect as useEffect5, useMemo as useMemo4, useRef as useRef6, useState as useState6 } from "react";
7482
- import { jsx as jsx28 } from "react/jsx-runtime";
7483
- var { Button: Button5, makeStyles: makeStyles10, mergeClasses: mergeClasses13 } = fluentComponents;
8528
+ import { useEffect as useEffect5, useMemo as useMemo5, useRef as useRef7, useState as useState9 } from "react";
8529
+ import { jsx as jsx37 } from "react/jsx-runtime";
8530
+ var { Button: Button9, makeStyles: makeStyles15, mergeClasses: mergeClasses20 } = fluentComponents;
7484
8531
  var REORDER_OPACITY = 0.8;
7485
8532
  var DRAG_RETURN_MS = 200;
7486
8533
  var LIST_ATTRIBUTE = "data-reorder-list";
@@ -7490,7 +8537,7 @@ var EDGE_ATTRIBUTE = "data-reorder-edge";
7490
8537
  var HANDLE_ATTRIBUTE = "data-reorder-handle";
7491
8538
  var DRAG_Y = "--fwt-reorder-drag-y";
7492
8539
  var TRACKING_TRANSFORM = { transform: `translateY(var(${DRAG_Y}, 0px))` };
7493
- var useStyles10 = makeStyles10({
8540
+ var useStyles15 = makeStyles15({
7494
8541
  // A drag that starts on the handle travels over the rows, and without this
7495
8542
  // the browser reads that travel as a text selection across them.
7496
8543
  list: { [`&[${REORDERING_ATTRIBUTE}]`]: { userSelect: "none" } },
@@ -7579,11 +8626,11 @@ var siblingHandles = (handle) => {
7579
8626
  return [...list.querySelectorAll(`[${HANDLE_ATTRIBUTE}]`)].filter((element) => element.closest(`[${LIST_ATTRIBUTE}]`) === list && !element.hasAttribute("disabled"));
7580
8627
  };
7581
8628
  function useReorderList({ busy = false, disabled = false, length, onDrop, onDropError, onReorder }) {
7582
- const styles = useStyles10();
7583
- const gestureRef = useRef6(null);
7584
- const settleRef = useRef6(void 0);
7585
- const mountedRef = useRef6(true);
7586
- const [preview, setPreview] = useState6(null);
8629
+ const styles = useStyles15();
8630
+ const gestureRef = useRef7(null);
8631
+ const settleRef = useRef7(void 0);
8632
+ const mountedRef = useRef7(true);
8633
+ const [preview, setPreview] = useState9(null);
7587
8634
  const locked = busy || disabled || length < 2;
7588
8635
  const live = preview !== null && preview.from < length && preview.to < length ? preview : null;
7589
8636
  useEffect5(() => {
@@ -7593,8 +8640,8 @@ function useReorderList({ busy = false, disabled = false, length, onDrop, onDrop
7593
8640
  clearTimeout(settleRef.current);
7594
8641
  };
7595
8642
  }, []);
7596
- const offsets = useMemo4(() => live && slotOffsets(live.items, live.from, live.to), [live]);
7597
- const ranks = useMemo4(
8643
+ const offsets = useMemo5(() => live && slotOffsets(live.items, live.from, live.to), [live]);
8644
+ const ranks = useMemo5(
7598
8645
  () => live && moveItem(Array.from({ length }, (_2, index) => index), live.from, live.to),
7599
8646
  [length, live]
7600
8647
  );
@@ -7723,7 +8770,7 @@ function useReorderList({ busy = false, disabled = false, length, onDrop, onDrop
7723
8770
  return {
7724
8771
  [ITEM_ATTRIBUTE]: String(index),
7725
8772
  [EDGE_ATTRIBUTE]: !live ? void 0 : rank === 0 ? "first" : rank === length - 1 ? "last" : void 0,
7726
- className: mergeClasses13(
8773
+ className: mergeClasses20(
7727
8774
  grabbed && styles.lifted,
7728
8775
  // The row under the pointer is not travelling toward anything -- it is
7729
8776
  // where the pointer put it -- so it wears the drag opacity flat, and
@@ -7735,20 +8782,20 @@ function useReorderList({ busy = false, disabled = false, length, onDrop, onDrop
7735
8782
  style: !live ? void 0 : grabbed ? TRACKING_TRANSFORM : { transform: `translateY(${offsets?.get(index) ?? 0}px)` }
7736
8783
  };
7737
8784
  },
7738
- listProps: (className) => ({ [LIST_ATTRIBUTE]: "", className: mergeClasses13(styles.list, className), onKeyDown }),
8785
+ listProps: (className) => ({ [LIST_ATTRIBUTE]: "", className: mergeClasses20(styles.list, className), onKeyDown }),
7739
8786
  position
7740
8787
  };
7741
8788
  }
7742
8789
  function ReorderHandle({ label, ...gesture }) {
7743
- const styles = useStyles10();
7744
- return /* @__PURE__ */ jsx28(
7745
- Button5,
8790
+ const styles = useStyles15();
8791
+ return /* @__PURE__ */ jsx37(
8792
+ Button9,
7746
8793
  {
7747
8794
  appearance: "subtle",
7748
8795
  "aria-keyshortcuts": `${REORDER_CHORD}+ArrowUp ${REORDER_CHORD}+ArrowDown`,
7749
8796
  "aria-label": label,
7750
8797
  className: styles.handle,
7751
- icon: /* @__PURE__ */ jsx28(ReOrderDotsVerticalRegular, {}),
8798
+ icon: /* @__PURE__ */ jsx37(ReOrderDotsVerticalRegular, {}),
7752
8799
  size: "small",
7753
8800
  ...gesture
7754
8801
  }
@@ -7757,12 +8804,12 @@ function ReorderHandle({ label, ...gesture }) {
7757
8804
 
7758
8805
  // src/components/ui/resource-list.tsx
7759
8806
  import { AddRegular, ArrowClockwiseRegular } from "@fluentui/react-icons";
7760
- import { jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
7761
- var { Button: Button6, Spinner: Spinner3, Tooltip: Tooltip2, makeStyles: makeStyles11, mergeClasses: mergeClasses14 } = fluentComponents;
8807
+ import { jsx as jsx38, jsxs as jsxs20 } from "react/jsx-runtime";
8808
+ var { Button: Button10, Spinner: Spinner5, Tooltip: Tooltip3, makeStyles: makeStyles16, mergeClasses: mergeClasses21 } = fluentComponents;
7762
8809
  var DEFAULT_ROW_HEIGHT = "44px";
7763
8810
  var ROW_HEIGHT = "--fwt-resource-row-height";
7764
8811
  var EDGE_INSET = "var(--fwt-panel-inset)";
7765
- var useStyles11 = makeStyles11({
8812
+ var useStyles16 = makeStyles16({
7766
8813
  table: {
7767
8814
  "& .fui-TableRow": { height: `var(${ROW_HEIGHT})` },
7768
8815
  // By type rather than by position: a DataGrid row carries Tabster's focus
@@ -7795,12 +8842,12 @@ var useStyles11 = makeStyles11({
7795
8842
  emptyState: { padding: EDGE_INSET }
7796
8843
  });
7797
8844
  function ResourceListPanel({ className, rowHeight = DEFAULT_ROW_HEIGHT, style, ...props }) {
7798
- const styles = useStyles11();
7799
- return /* @__PURE__ */ jsx29(
8845
+ const styles = useStyles16();
8846
+ return /* @__PURE__ */ jsx38(
7800
8847
  Panel,
7801
8848
  {
7802
8849
  ...props,
7803
- className: mergeClasses14("grid min-w-0 !gap-0 overflow-hidden", styles.table, className),
8850
+ className: mergeClasses21("grid min-w-0 !gap-0 overflow-hidden", styles.table, className),
7804
8851
  padding: "flush",
7805
8852
  style: { ...style, [ROW_HEIGHT]: rowHeight }
7806
8853
  }
@@ -7809,12 +8856,12 @@ function ResourceListPanel({ className, rowHeight = DEFAULT_ROW_HEIGHT, style, .
7809
8856
  function ResourceListActions(props) {
7810
8857
  const { appearance, createDisabled = false, createLabel, createTrailingIcon, disabled = false, onRefresh, refreshLabel, refreshing = false } = props;
7811
8858
  const busy = disabled || createDisabled || refreshing;
7812
- const createButton = createLabel !== void 0 && /* @__PURE__ */ jsxs14(
7813
- Button6,
8859
+ const createButton = createLabel !== void 0 && /* @__PURE__ */ jsxs20(
8860
+ Button10,
7814
8861
  {
7815
8862
  appearance: "primary",
7816
8863
  disabled: busy,
7817
- icon: /* @__PURE__ */ jsx29(AddRegular, {}),
8864
+ icon: /* @__PURE__ */ jsx38(AddRegular, {}),
7818
8865
  onClick: "onCreate" in props ? props.onCreate : void 0,
7819
8866
  children: [
7820
8867
  createLabel,
@@ -7822,43 +8869,43 @@ function ResourceListActions(props) {
7822
8869
  ]
7823
8870
  }
7824
8871
  );
7825
- return /* @__PURE__ */ jsxs14("div", { "aria-busy": refreshing, className: "flex items-center gap-2 flex-none", children: [
7826
- /* @__PURE__ */ jsx29(Tooltip2, { content: refreshLabel, relationship: "label", children: /* @__PURE__ */ jsx29(
7827
- Button6,
8872
+ return /* @__PURE__ */ jsxs20("div", { "aria-busy": refreshing, className: "flex items-center gap-2 flex-none", children: [
8873
+ /* @__PURE__ */ jsx38(Tooltip3, { content: refreshLabel, relationship: "label", children: /* @__PURE__ */ jsx38(
8874
+ Button10,
7828
8875
  {
7829
8876
  appearance,
7830
8877
  "aria-label": refreshLabel,
7831
8878
  disabled,
7832
8879
  disabledFocusable: refreshing,
7833
- icon: refreshing ? /* @__PURE__ */ jsx29(Spinner3, { size: "tiny" }) : /* @__PURE__ */ jsx29(ArrowClockwiseRegular, {}),
8880
+ icon: refreshing ? /* @__PURE__ */ jsx38(Spinner5, { size: "tiny" }) : /* @__PURE__ */ jsx38(ArrowClockwiseRegular, {}),
7834
8881
  onClick: onRefresh
7835
8882
  }
7836
8883
  ) }),
7837
8884
  createButton && (props.createTrigger === void 0 ? createButton : props.createTrigger(createButton)),
7838
- /* @__PURE__ */ jsx29("span", { "aria-live": "polite", className: "sr-only", children: refreshing ? `${refreshLabel}\u2026` : "" })
8885
+ /* @__PURE__ */ jsx38("span", { "aria-live": "polite", className: "sr-only", children: refreshing ? `${refreshLabel}\u2026` : "" })
7839
8886
  ] });
7840
8887
  }
7841
8888
  function ResourceListEmptyState({ children }) {
7842
- const styles = useStyles11();
7843
- return /* @__PURE__ */ jsx29(EmptyStateLine, { className: styles.emptyState, children });
8889
+ const styles = useStyles16();
8890
+ return /* @__PURE__ */ jsx38(EmptyStateLine, { className: styles.emptyState, children });
7844
8891
  }
7845
8892
 
7846
8893
  // src/components/ui/row-title.tsx
7847
- import { jsx as jsx30 } from "react/jsx-runtime";
7848
- var { mergeClasses: mergeClasses15 } = fluentComponents;
8894
+ import { jsx as jsx39 } from "react/jsx-runtime";
8895
+ var { mergeClasses: mergeClasses22 } = fluentComponents;
7849
8896
  var rowTitleClass = "winui-focus-rect text-fui-fg1 no-underline hover:underline";
7850
8897
  function RowTitleButton({ children, onClick, ...trigger }) {
7851
- return /* @__PURE__ */ jsx30("button", { className: mergeClasses15(rowTitleClass, "block bg-transparent border-0 cursor-pointer leading-[var(--lineHeightBase300)] min-w-0 max-w-full truncate p-0 text-fui-base300 text-left"), onClick, type: "button", ...trigger, children });
8898
+ return /* @__PURE__ */ jsx39("button", { className: mergeClasses22(rowTitleClass, "block bg-transparent border-0 cursor-pointer leading-[var(--lineHeightBase300)] min-w-0 max-w-full truncate p-0 text-fui-base300 text-left"), onClick, type: "button", ...trigger, children });
7852
8899
  }
7853
8900
 
7854
8901
  // src/components/ui/secret-input.tsx
7855
- import { useState as useState7 } from "react";
7856
- import { jsx as jsx31 } from "react/jsx-runtime";
8902
+ import { useState as useState10 } from "react";
8903
+ import { jsx as jsx40 } from "react/jsx-runtime";
7857
8904
  function SecretInput({ onChange, revealed = false, value, ...rest }) {
7858
- const [guardLocked, setGuardLocked] = useState7(true);
8905
+ const [guardLocked, setGuardLocked] = useState10(true);
7859
8906
  const hasValue = String(value ?? "").length > 0;
7860
8907
  const unlock = () => setGuardLocked(false);
7861
- return /* @__PURE__ */ jsx31(
8908
+ return /* @__PURE__ */ jsx40(
7862
8909
  Input,
7863
8910
  {
7864
8911
  ...rest,
@@ -7899,12 +8946,12 @@ function SecretInput({ onChange, revealed = false, value, ...rest }) {
7899
8946
  }
7900
8947
 
7901
8948
  // src/components/ui/section-header.tsx
7902
- import { jsx as jsx32, jsxs as jsxs15 } from "react/jsx-runtime";
7903
- var { InfoButton, Text: Text4, mergeClasses: mergeClasses16 } = fluentComponents;
8949
+ import { jsx as jsx41, jsxs as jsxs21 } from "react/jsx-runtime";
8950
+ var { InfoButton, Text: Text7, mergeClasses: mergeClasses23 } = fluentComponents;
7904
8951
  var TITLE_SIZE = { 2: 500, 3: 400, 4: 300 };
7905
8952
  function SectionHeader({ actions, description, info, level, title, titleId, truncate = false }) {
7906
- const headingText = /* @__PURE__ */ jsx32(
7907
- Text4,
8953
+ const headingText = /* @__PURE__ */ jsx41(
8954
+ Text7,
7908
8955
  {
7909
8956
  as: `h${level}`,
7910
8957
  className: description === void 0 ? "m-0 min-w-0" : "m-0",
@@ -7916,25 +8963,25 @@ function SectionHeader({ actions, description, info, level, title, titleId, trun
7916
8963
  children: title
7917
8964
  }
7918
8965
  );
7919
- const heading = info === void 0 ? headingText : /* @__PURE__ */ jsxs15("div", { className: "inline-flex items-center gap-1 min-w-0", children: [
8966
+ const heading = info === void 0 ? headingText : /* @__PURE__ */ jsxs21("div", { className: "inline-flex items-center gap-1 min-w-0", children: [
7920
8967
  headingText,
7921
- /* @__PURE__ */ jsx32(InfoButton, { info })
8968
+ /* @__PURE__ */ jsx41(InfoButton, { info })
7922
8969
  ] });
7923
- const block = description === void 0 ? heading : /* @__PURE__ */ jsxs15("div", { className: mergeClasses16(TIGHT_STACK_CLASS, "min-w-0"), children: [
8970
+ const block = description === void 0 ? heading : /* @__PURE__ */ jsxs21("div", { className: mergeClasses23(TIGHT_STACK_CLASS, "min-w-0"), children: [
7924
8971
  heading,
7925
- /* @__PURE__ */ jsx32(Text4, { className: "text-fui-fg2", size: 200, children: description })
8972
+ /* @__PURE__ */ jsx41(Text7, { className: "text-fui-fg2", size: 200, children: description })
7926
8973
  ] });
7927
8974
  if (actions === void 0) return block;
7928
- return /* @__PURE__ */ jsxs15("div", { className: mergeClasses16(HEADER_ROW_CLASS, "gap-3"), children: [
8975
+ return /* @__PURE__ */ jsxs21("div", { className: mergeClasses23(HEADER_ROW_CLASS, "gap-3"), children: [
7929
8976
  block,
7930
- /* @__PURE__ */ jsx32("div", { className: "flex items-center gap-2 flex-none", children: actions })
8977
+ /* @__PURE__ */ jsx41("div", { className: "flex items-center gap-2 flex-none", children: actions })
7931
8978
  ] });
7932
8979
  }
7933
8980
 
7934
8981
  // src/components/ui/settings-card.tsx
7935
- import { useId as useId3, useState as useState8 } from "react";
7936
- import { Fragment as Fragment2, jsx as jsx33, jsxs as jsxs16 } from "react/jsx-runtime";
7937
- var { Text: Text5, makeStyles: makeStyles12, mergeClasses: mergeClasses17, shorthands } = fluentComponents;
8982
+ import { useId as useId4, useState as useState11 } from "react";
8983
+ import { Fragment as Fragment3, jsx as jsx42, jsxs as jsxs22 } from "react/jsx-runtime";
8984
+ var { Text: Text8, makeStyles: makeStyles17, mergeClasses: mergeClasses24, shorthands: shorthands3 } = fluentComponents;
7938
8985
  var ICON_MARGIN_START = "2px";
7939
8986
  var ICON_MARGIN_END = "20px";
7940
8987
  var ICON_SIZE = "24px";
@@ -7944,7 +8991,7 @@ var ICON_COLUMN_VAR = "var(--fwt-settings-icon-column, 0px)";
7944
8991
  var WRAPPED = "@container fwt-settings-row (width < 476px)";
7945
8992
  var WRAPPED_WITH_ICON = "@container fwt-settings-row (286px <= width < 476px)";
7946
8993
  var WRAPPED_NO_ICON = "@container fwt-settings-row (width < 286px)";
7947
- var useStyles12 = makeStyles12({
8994
+ var useStyles17 = makeStyles17({
7948
8995
  // Containment sits one level out of the row so the query measures the same
7949
8996
  // box the toolkit's trigger reads (this element carries no padding or
7950
8997
  // border), and so the wrapped state can style the row itself -- a container
@@ -7973,7 +9020,7 @@ var useStyles12 = makeStyles12({
7973
9020
  borderRightWidth: "1px",
7974
9021
  borderBottomWidth: "1px",
7975
9022
  borderLeftWidth: "1px",
7976
- ...shorthands.borderColor("var(--winui-card-stroke-default)"),
9023
+ ...shorthands3.borderColor("var(--winui-card-stroke-default)"),
7977
9024
  borderRadius: "var(--winui-control-corner-radius)",
7978
9025
  boxSizing: "border-box",
7979
9026
  color: "var(--winui-text-fill-primary)",
@@ -8028,7 +9075,7 @@ var useStyles12 = makeStyles12({
8028
9075
  // would hold its rest fill while the reader is holding it down.
8029
9076
  "&:active, &:has(> :active)": {
8030
9077
  backgroundColor: "var(--winui-control-fill-tertiary)",
8031
- ...shorthands.borderColor("var(--winui-control-stroke-default)")
9078
+ ...shorthands3.borderColor("var(--winui-control-stroke-default)")
8032
9079
  },
8033
9080
  // The system focus visual: a 2px FocusStrokeColorOuter ring with a 1px
8034
9081
  // FocusStrokeColorInner ring immediately inside it, around the border box
@@ -8116,7 +9163,7 @@ var useStyles12 = makeStyles12({
8116
9163
  expanderHeader: {
8117
9164
  position: "relative",
8118
9165
  backgroundColor: "var(--winui-card-background-fill-default)",
8119
- ...shorthands.borderColor("var(--winui-card-stroke-default)"),
9166
+ ...shorthands3.borderColor("var(--winui-card-stroke-default)"),
8120
9167
  fontFamily: "inherit",
8121
9168
  fontSize: "inherit",
8122
9169
  paddingInlineEnd: "4px",
@@ -8166,7 +9213,7 @@ var useStyles12 = makeStyles12({
8166
9213
  // The row paints the ring; see the interactive style above.
8167
9214
  ":focus-visible": { outline: "none" },
8168
9215
  background: "none",
8169
- ...shorthands.borderWidth(0),
9216
+ ...shorthands3.borderWidth(0),
8170
9217
  cursor: "pointer",
8171
9218
  "&:disabled": { cursor: "not-allowed" },
8172
9219
  inset: 0,
@@ -8301,48 +9348,48 @@ var useStyles12 = makeStyles12({
8301
9348
  readoutDisabled: { color: "var(--winui-text-fill-disabled)" }
8302
9349
  });
8303
9350
  function CardText({ description, header, icon, id }) {
8304
- const styles = useStyles12();
8305
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
8306
- icon !== void 0 && /* @__PURE__ */ jsx33("span", { "aria-hidden": true, className: styles.icon, ...{ [ICON_MARKER]: "" }, children: icon }),
8307
- /* @__PURE__ */ jsxs16("span", { className: styles.text, children: [
8308
- /* @__PURE__ */ jsx33(Text5, { block: true, id, children: header }),
8309
- description !== void 0 && /* @__PURE__ */ jsx33(Text5, { block: true, size: 200, className: styles.description, children: description })
9351
+ const styles = useStyles17();
9352
+ return /* @__PURE__ */ jsxs22(Fragment3, { children: [
9353
+ icon !== void 0 && /* @__PURE__ */ jsx42("span", { "aria-hidden": true, className: styles.icon, ...{ [ICON_MARKER]: "" }, children: icon }),
9354
+ /* @__PURE__ */ jsxs22("span", { className: styles.text, children: [
9355
+ /* @__PURE__ */ jsx42(Text8, { block: true, id, children: header }),
9356
+ description !== void 0 && /* @__PURE__ */ jsx42(Text8, { block: true, size: 200, className: styles.description, children: description })
8310
9357
  ] })
8311
9358
  ] });
8312
9359
  }
8313
9360
  function SettingsSwitch({ checked, disabled, label, onChange }) {
8314
- const styles = useStyles12();
9361
+ const styles = useStyles17();
8315
9362
  const { t: t2 } = useTranslation();
8316
- return /* @__PURE__ */ jsxs16("span", { className: styles.switchRow, children: [
8317
- /* @__PURE__ */ jsx33(Text5, { className: disabled === true ? styles.readoutDisabled : void 0, children: t2(checked ? "common.on" : "common.off") }),
8318
- /* @__PURE__ */ jsx33(Switch, { "aria-label": label, checked, disabled, onChange: (_2, data) => onChange(data.checked) })
9363
+ return /* @__PURE__ */ jsxs22("span", { className: styles.switchRow, children: [
9364
+ /* @__PURE__ */ jsx42(Text8, { className: disabled === true ? styles.readoutDisabled : void 0, children: t2(checked ? "common.on" : "common.off") }),
9365
+ /* @__PURE__ */ jsx42(Switch, { "aria-label": label, checked, disabled, onChange: (_2, data) => onChange(data.checked) })
8319
9366
  ] });
8320
9367
  }
8321
9368
  function SettingsCard({ action, description, header, icon }) {
8322
- const styles = useStyles12();
8323
- return /* @__PURE__ */ jsx33("div", { className: styles.row, children: /* @__PURE__ */ jsxs16("div", { className: styles.card, children: [
8324
- /* @__PURE__ */ jsx33(CardText, { description, header, icon }),
8325
- action !== void 0 && /* @__PURE__ */ jsx33("span", { className: styles.action, children: action })
9369
+ const styles = useStyles17();
9370
+ return /* @__PURE__ */ jsx42("div", { className: styles.row, children: /* @__PURE__ */ jsxs22("div", { className: styles.card, children: [
9371
+ /* @__PURE__ */ jsx42(CardText, { description, header, icon }),
9372
+ action !== void 0 && /* @__PURE__ */ jsx42("span", { className: styles.action, children: action })
8326
9373
  ] }) });
8327
9374
  }
8328
9375
  function SettingsExpander({ action, children, defaultOpen = false, description, disclosureDisabled = false, header, icon, revealOn, toggledOn }) {
8329
- const styles = useStyles12();
8330
- const [open, setOpen] = useState8(defaultOpen);
8331
- const [toggleWas, setToggleWas] = useState8(toggledOn);
9376
+ const styles = useStyles17();
9377
+ const [open, setOpen] = useState11(defaultOpen);
9378
+ const [toggleWas, setToggleWas] = useState11(toggledOn);
8332
9379
  if (toggledOn !== void 0 && toggledOn !== toggleWas) {
8333
9380
  setToggleWas(toggledOn);
8334
9381
  setOpen(toggledOn);
8335
9382
  }
8336
- const [revealWas, setRevealWas] = useState8(revealOn);
9383
+ const [revealWas, setRevealWas] = useState11(revealOn);
8337
9384
  if (revealOn !== revealWas) {
8338
9385
  setRevealWas(revealOn);
8339
9386
  if (revealOn === true) setOpen(true);
8340
9387
  }
8341
- const contentId = useId3();
8342
- const headerId = useId3();
8343
- return /* @__PURE__ */ jsxs16("div", { className: styles.row, children: [
8344
- /* @__PURE__ */ jsxs16("div", { className: mergeClasses17(styles.card, !disclosureDisabled && styles.interactive, styles.expanderHeader, open && styles.expanderHeaderOpen), children: [
8345
- /* @__PURE__ */ jsx33(
9388
+ const contentId = useId4();
9389
+ const headerId = useId4();
9390
+ return /* @__PURE__ */ jsxs22("div", { className: styles.row, children: [
9391
+ /* @__PURE__ */ jsxs22("div", { className: mergeClasses24(styles.card, !disclosureDisabled && styles.interactive, styles.expanderHeader, open && styles.expanderHeaderOpen), children: [
9392
+ /* @__PURE__ */ jsx42(
8346
9393
  "button",
8347
9394
  {
8348
9395
  "aria-controls": contentId,
@@ -8354,112 +9401,48 @@ function SettingsExpander({ action, children, defaultOpen = false, description,
8354
9401
  type: "button"
8355
9402
  }
8356
9403
  ),
8357
- /* @__PURE__ */ jsx33(CardText, { description, header, icon, id: headerId }),
8358
- action !== void 0 && /* @__PURE__ */ jsx33("span", { className: styles.action, children: action }),
8359
- /* @__PURE__ */ jsx33("span", { "aria-hidden": true, className: styles.chevron, children: /* @__PURE__ */ jsx33("svg", { className: mergeClasses17(styles.chevronGlyph, open && styles.chevronOpen), width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx33("path", { d: "M3.15 5.65c.2-.2.5-.2.7 0L8 9.79l4.15-4.14a.5.5 0 0 1 .7.7l-4.5 4.5a.5.5 0 0 1-.7 0l-4.5-4.5a.5.5 0 0 1 0-.7Z" }) }) })
9404
+ /* @__PURE__ */ jsx42(CardText, { description, header, icon, id: headerId }),
9405
+ action !== void 0 && /* @__PURE__ */ jsx42("span", { className: styles.action, children: action }),
9406
+ /* @__PURE__ */ jsx42("span", { "aria-hidden": true, className: styles.chevron, children: /* @__PURE__ */ jsx42("svg", { className: mergeClasses24(styles.chevronGlyph, open && styles.chevronOpen), width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx42("path", { d: "M3.15 5.65c.2-.2.5-.2.7 0L8 9.79l4.15-4.14a.5.5 0 0 1 .7.7l-4.5 4.5a.5.5 0 0 1-.7 0l-4.5-4.5a.5.5 0 0 1 0-.7Z" }) }) })
8360
9407
  ] }),
8361
- /* @__PURE__ */ jsx33("div", { className: mergeClasses17(styles.contentFrame, open && styles.contentFrameOpen), children: /* @__PURE__ */ jsx33("div", { className: styles.contentClip, children: /* @__PURE__ */ jsx33("div", { "aria-labelledby": headerId, className: styles.content, id: contentId, inert: !open, role: "group", children }) }) })
9408
+ /* @__PURE__ */ jsx42("div", { className: mergeClasses24(styles.contentFrame, open && styles.contentFrameOpen), children: /* @__PURE__ */ jsx42("div", { className: styles.contentClip, children: /* @__PURE__ */ jsx42("div", { "aria-labelledby": headerId, className: styles.content, id: contentId, inert: !open, role: "group", children }) }) })
8362
9409
  ] });
8363
9410
  }
8364
9411
 
8365
9412
  // src/components/ui/switch-setting.tsx
8366
- import { jsx as jsx34, jsxs as jsxs17 } from "react/jsx-runtime";
9413
+ import { jsx as jsx43, jsxs as jsxs23 } from "react/jsx-runtime";
8367
9414
  var { InfoButton: InfoButton2 } = fluentComponents;
8368
9415
  function SwitchSetting({ checked, description, label, onChange }) {
8369
- return /* @__PURE__ */ jsxs17("span", { className: "inline-flex items-center gap-1", children: [
8370
- /* @__PURE__ */ jsx34(Switch, { checked, label, onChange: (_2, data) => onChange(data.checked) }),
8371
- /* @__PURE__ */ jsx34(InfoButton2, { info: description })
9416
+ return /* @__PURE__ */ jsxs23("span", { className: "inline-flex items-center gap-1", children: [
9417
+ /* @__PURE__ */ jsx43(Switch, { checked, label, onChange: (_2, data) => onChange(data.checked) }),
9418
+ /* @__PURE__ */ jsx43(InfoButton2, { info: description })
8372
9419
  ] });
8373
9420
  }
8374
9421
 
8375
- // src/components/ui/table-actions.tsx
8376
- import { jsx as jsx35 } from "react/jsx-runtime";
8377
- var { TableCell, TableHeaderCell, makeStyles: makeStyles13, mergeClasses: mergeClasses18 } = fluentComponents;
8378
- var useStyles13 = makeStyles13({
8379
- trailing: {
8380
- textAlign: "right",
8381
- "& .fui-TableHeaderCell__button": { justifyContent: "flex-end" }
8382
- },
8383
- centred: {
8384
- textAlign: "center",
8385
- "& .fui-TableHeaderCell__button": { justifyContent: "center" }
8386
- }
8387
- });
8388
- function TableTrailingHeader({ className, ...props }) {
8389
- const styles = useStyles13();
8390
- return /* @__PURE__ */ jsx35(TableHeaderCell, { ...props, className: mergeClasses18(styles.trailing, className) });
8391
- }
8392
- function TableTrailingCell({ className, ...props }) {
8393
- const styles = useStyles13();
8394
- return /* @__PURE__ */ jsx35(TableCell, { ...props, className: mergeClasses18(styles.trailing, className) });
8395
- }
8396
- function TableCentredHeader({ className, ...props }) {
8397
- const styles = useStyles13();
8398
- return /* @__PURE__ */ jsx35(TableHeaderCell, { ...props, className: mergeClasses18(styles.centred, className) });
8399
- }
8400
- function TableCentredCell({ className, ...props }) {
8401
- const styles = useStyles13();
8402
- return /* @__PURE__ */ jsx35(TableCell, { ...props, className: mergeClasses18(styles.centred, className) });
8403
- }
8404
- var stopRowSelection = { onClick: (event) => event.stopPropagation() };
8405
- var ACTION_GAP = "var(--spacingHorizontalXS)";
8406
- var ACTION_BUTTON_SIZE = "24px";
8407
- var TABLE_ACTIONS_WIDTH = `calc(3 * ${ACTION_BUTTON_SIZE} + 2 * ${ACTION_GAP} + var(--spacingHorizontalS) + var(--fwt-panel-inset))`;
8408
- function TableActions({ children }) {
8409
- return /* @__PURE__ */ jsx35("div", { className: "flex items-center justify-end", style: { gap: ACTION_GAP }, ...stopRowSelection, children });
8410
- }
8411
-
8412
- // src/components/ui/table-columns.tsx
8413
- import { jsx as jsx36 } from "react/jsx-runtime";
8414
- function TableColumns({ widths }) {
8415
- return /* @__PURE__ */ jsx36("colgroup", { children: widths.map((width, index) => /* @__PURE__ */ jsx36("col", { style: width === null ? void 0 : { width } }, index)) });
8416
- }
8417
-
8418
- // src/components/ui/tooltip-icon-button.tsx
8419
- import { jsx as jsx37 } from "react/jsx-runtime";
8420
- var { Button: Button7, Tooltip: Tooltip3, mergeClasses: mergeClasses19 } = fluentComponents;
8421
- function TooltipIconButton(props) {
8422
- return props.to === void 0 ? /* @__PURE__ */ jsx37(IconButton, { ...props }) : /* @__PURE__ */ jsx37(AddressedIconButton, { ...props, to: props.to });
8423
- }
8424
- function AddressedIconButton({ to, ...props }) {
8425
- const address = useRouteAddress(to);
8426
- return /* @__PURE__ */ jsx37(IconButton, { ...props, ...address });
8427
- }
8428
- function IconButton({ className, danger = false, disabled = false, disabledFocusable = false, href, icon, label, onClick }) {
8429
- const dangerClasses = useDangerActionClasses();
8430
- const shared = {
8431
- appearance: "subtle",
8432
- "aria-label": label,
8433
- className: mergeClasses19(danger && dangerClasses.button, className),
8434
- disabled,
8435
- disabledFocusable,
8436
- icon,
8437
- onClick,
8438
- size: "small"
8439
- };
8440
- return /* @__PURE__ */ jsx37(Tooltip3, { content: label, relationship: "label", children: href === void 0 ? /* @__PURE__ */ jsx37(Button7, { ...shared }) : /* @__PURE__ */ jsx37(Button7, { ...shared, as: "a", href }) });
8441
- }
9422
+ // src/components/ui/tab-view.tsx
9423
+ import { CaretLeft12Filled, CaretRight12Filled, Dismiss12Regular } from "@fluentui/react-icons";
9424
+ import { useCallback as useCallback7, useEffect as useEffect7, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState13 } from "react";
8442
9425
 
8443
9426
  // src/components/ui/truncation-tooltip.tsx
8444
- import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef7, useState as useState9 } from "react";
8445
- import { jsx as jsx38 } from "react/jsx-runtime";
9427
+ import { useCallback as useCallback6, useEffect as useEffect6, useRef as useRef8, useState as useState12 } from "react";
9428
+ import { jsx as jsx44 } from "react/jsx-runtime";
8446
9429
  var { Tooltip: Tooltip4 } = fluentComponents;
8447
9430
  var OVERFLOW_TOLERANCE_PX = 1;
8448
9431
  var collapseWhitespace = (text) => text.replace(/\s+/gu, " ").trim();
8449
9432
  var hidesContent = (node, content) => node.scrollWidth - node.clientWidth > OVERFLOW_TOLERANCE_PX || collapseWhitespace(node.textContent ?? "") !== collapseWhitespace(content);
8450
9433
  var useTruncation = (content, relationship) => {
8451
- const [truncated, setTruncated] = useState9(false);
8452
- const [visible, setVisible] = useState9(false);
8453
- const nodeRef = useRef7(null);
8454
- const contentRef = useRef7(content);
8455
- const measure2 = useCallback5(() => {
9434
+ const [truncated, setTruncated] = useState12(false);
9435
+ const [visible, setVisible] = useState12(false);
9436
+ const nodeRef = useRef8(null);
9437
+ const contentRef = useRef8(content);
9438
+ const measure2 = useCallback6(() => {
8456
9439
  const node = nodeRef.current;
8457
9440
  if (!node) return;
8458
9441
  const hides = hidesContent(node, contentRef.current);
8459
9442
  setTruncated(hides);
8460
9443
  if (!hides) setVisible(false);
8461
9444
  }, []);
8462
- const measureRef = useCallback5((node) => {
9445
+ const measureRef = useCallback6((node) => {
8463
9446
  nodeRef.current = node;
8464
9447
  if (!node) return;
8465
9448
  measure2();
@@ -8498,37 +9481,549 @@ var useTruncation = (content, relationship) => {
8498
9481
  };
8499
9482
  function TruncationTooltip({ children, content, relationship }) {
8500
9483
  const { measureRef, tooltipProps } = useTruncation(content, relationship);
8501
- return /* @__PURE__ */ jsx38(Tooltip4, { ...tooltipProps, children: children(measureRef) });
9484
+ return /* @__PURE__ */ jsx44(Tooltip4, { ...tooltipProps, children: children(measureRef) });
9485
+ }
9486
+
9487
+ // src/components/ui/tab-view.tsx
9488
+ import { jsx as jsx45, jsxs as jsxs24 } from "react/jsx-runtime";
9489
+ var { makeStyles: makeStyles18, mergeClasses: mergeClasses25 } = fluentComponents;
9490
+ var useStyles18 = makeStyles18({
9491
+ // TabViewHeaderPadding: 8px above the tabs.
9492
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L239
9493
+ // The strip's bottom line is TabViewBorderBrush (CardStrokeColorDefault),
9494
+ // drawn here under the scroller so that the selected tab, which reaches the
9495
+ // strip's last pixel row, paints over it and interrupts it.
9496
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView.xaml#L36-L37
9497
+ root: {
9498
+ alignItems: "flex-end",
9499
+ display: "flex",
9500
+ maxWidth: "100%",
9501
+ minWidth: 0,
9502
+ paddingTop: "8px",
9503
+ position: "relative",
9504
+ "&::after": {
9505
+ backgroundColor: "var(--winui-card-stroke-default)",
9506
+ bottom: 0,
9507
+ content: '""',
9508
+ height: "1px",
9509
+ left: 0,
9510
+ pointerEvents: "none",
9511
+ position: "absolute",
9512
+ right: 0,
9513
+ zIndex: 0
9514
+ }
9515
+ },
9516
+ scroller: {
9517
+ alignSelf: "stretch",
9518
+ display: "flex",
9519
+ flexGrow: 0,
9520
+ flexShrink: 1,
9521
+ minWidth: 0,
9522
+ overflowX: "auto",
9523
+ overflowY: "hidden",
9524
+ position: "relative",
9525
+ scrollbarWidth: "none",
9526
+ zIndex: 1,
9527
+ "&::-webkit-scrollbar": { display: "none" },
9528
+ "@media (prefers-reduced-motion: no-preference)": { scrollBehavior: "smooth" }
9529
+ },
9530
+ tablist: {
9531
+ alignItems: "flex-end",
9532
+ display: "flex",
9533
+ flexWrap: "nowrap",
9534
+ minWidth: "min-content"
9535
+ },
9536
+ // TabViewItemMinHeight 32, MinWidth 100, MaxWidth 240; the item's own
9537
+ // corners are OverlayCornerRadius on top only (TopCornerRadiusFilterConverter).
9538
+ // Every item holds a 1px border (TabViewItemBorderThickness) so selecting
9539
+ // one, which paints it, moves nothing.
9540
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L242-L244
9541
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView.xaml#L296-L297
9542
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView.xaml#L560-L562
9543
+ item: {
9544
+ alignItems: "stretch",
9545
+ borderBottomWidth: 0,
9546
+ borderLeft: "1px solid transparent",
9547
+ borderRight: "1px solid transparent",
9548
+ borderTop: "1px solid transparent",
9549
+ borderTopLeftRadius: "var(--winui-overlay-corner-radius)",
9550
+ borderTopRightRadius: "var(--winui-overlay-corner-radius)",
9551
+ boxSizing: "border-box",
9552
+ display: "flex",
9553
+ flexGrow: 0,
9554
+ flexShrink: 1,
9555
+ maxWidth: "240px",
9556
+ minHeight: "32px",
9557
+ minWidth: "100px",
9558
+ position: "relative",
9559
+ // TabSeparator: 1px DividerStrokeColorDefault inset 8px top and bottom,
9560
+ // gone under the pointer, on the selected tab and on the tab before it.
9561
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView.xaml#L553
9562
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L266
9563
+ "&::after": {
9564
+ backgroundColor: "var(--winui-divider-stroke-default)",
9565
+ bottom: "8px",
9566
+ content: '""',
9567
+ pointerEvents: "none",
9568
+ position: "absolute",
9569
+ right: "-1px",
9570
+ top: "8px",
9571
+ width: "1px"
9572
+ },
9573
+ "&:last-child::after": { display: "none" },
9574
+ "&:hover::after": { opacity: 0 },
9575
+ "&:has(+ [data-selected])::after": { opacity: 0 },
9576
+ "&:hover": { backgroundColor: "var(--winui-subtle-fill-secondary)" },
9577
+ "&:active": { backgroundColor: "var(--winui-subtle-fill-tertiary)" },
9578
+ // The selected tab: TabViewItemHeaderBackgroundSelected, a stroke on top
9579
+ // and sides in CardStrokeColorDefault, no bottom edge. It holds its fill
9580
+ // through the pointer states.
9581
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView.xaml#L325-L345
9582
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L72-L80
9583
+ "&[data-selected]": {
9584
+ backgroundColor: "var(--winui-solid-background-fill-tertiary)",
9585
+ borderLeftColor: "var(--winui-card-stroke-default)",
9586
+ borderRightColor: "var(--winui-card-stroke-default)",
9587
+ borderTopColor: "var(--winui-card-stroke-default)",
9588
+ zIndex: 1
9589
+ },
9590
+ "&[data-selected]::after": { opacity: 0 },
9591
+ "&[data-disabled]": { backgroundColor: "transparent" },
9592
+ // WinUI's CloseButtonOverlayMode Auto: the close button shows on the
9593
+ // selected tab and under the pointer, or always where there is no hover.
9594
+ "&:hover [data-tab-close], &:focus-within [data-tab-close]": { opacity: 1, pointerEvents: "auto" },
9595
+ "@media (hover: none)": { "& [data-tab-close]": { opacity: 1, pointerEvents: "auto" } }
9596
+ },
9597
+ // TabViewItemHeaderPaddingWithCloseButton 8,3,4,3 / WithoutCloseButton
9598
+ // 8,3,8,3; the close button's 4px margin supplies the right-hand 4.
9599
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L253-L254
9600
+ tab: {
9601
+ alignItems: "center",
9602
+ appearance: "none",
9603
+ backgroundColor: "transparent",
9604
+ borderRadius: "inherit",
9605
+ border: "none",
9606
+ // The foreground ramp: rest and pointer-over TextFillColorSecondary,
9607
+ // pressed Tertiary, selected Primary.
9608
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L12-L21
9609
+ color: "var(--winui-text-fill-secondary)",
9610
+ columnGap: "10px",
9611
+ cursor: "pointer",
9612
+ display: "flex",
9613
+ flexBasis: 0,
9614
+ flexGrow: 1,
9615
+ flexShrink: 1,
9616
+ // TabViewItemHeaderFontSize 12.
9617
+ fontFamily: "inherit",
9618
+ fontSize: "12px",
9619
+ lineHeight: "16px",
9620
+ minWidth: 0,
9621
+ padding: "3px 8px 3px 8px",
9622
+ textAlign: "start",
9623
+ "&:active:not(:disabled)": { color: "var(--winui-text-fill-tertiary)" },
9624
+ '&[aria-selected="true"], &[aria-selected="true"]:active': { color: "var(--winui-text-fill-primary)" },
9625
+ "&:disabled": { color: "var(--winui-text-fill-disabled)", cursor: "not-allowed" },
9626
+ // The system focus visual, as the library's other selectors draw it.
9627
+ "&:focus-visible": {
9628
+ boxShadow: "inset 0 0 0 1px var(--winui-focus-stroke-inner)",
9629
+ outline: "2px solid var(--winui-focus-stroke-outer)",
9630
+ outlineOffset: "-2px"
9631
+ }
9632
+ },
9633
+ tabWithClose: { paddingRight: 0 },
9634
+ // The icon sits in a 16px box with a 10px gap before the label.
9635
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L246-L247
9636
+ icon: {
9637
+ alignItems: "center",
9638
+ display: "inline-flex",
9639
+ flexShrink: 0,
9640
+ fontSize: "16px",
9641
+ height: "16px",
9642
+ justifyContent: "center",
9643
+ width: "16px"
9644
+ },
9645
+ label: {
9646
+ flexBasis: 0,
9647
+ flexGrow: 1,
9648
+ minWidth: 0,
9649
+ overflow: "hidden",
9650
+ textOverflow: "ellipsis",
9651
+ whiteSpace: "nowrap"
9652
+ },
9653
+ // TabViewItemHeaderCloseButtonWidth 32, Height 24, glyph 12, margin 4,0,0,0,
9654
+ // ControlCornerRadius; the fills are the subtle ramp, the glyph Primary
9655
+ // (Secondary while pressed).
9656
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L248-L252
9657
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView.xaml#L172-L187
9658
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L47-L60
9659
+ close: {
9660
+ alignItems: "center",
9661
+ alignSelf: "center",
9662
+ appearance: "none",
9663
+ backgroundColor: "transparent",
9664
+ borderRadius: "var(--winui-control-corner-radius)",
9665
+ border: "none",
9666
+ color: "var(--winui-text-fill-primary)",
9667
+ cursor: "pointer",
9668
+ display: "inline-flex",
9669
+ flexShrink: 0,
9670
+ fontSize: "12px",
9671
+ height: "24px",
9672
+ justifyContent: "center",
9673
+ margin: "0 4px",
9674
+ opacity: 0,
9675
+ padding: 0,
9676
+ pointerEvents: "none",
9677
+ width: "32px",
9678
+ "&:hover": { backgroundColor: "var(--winui-subtle-fill-secondary)" },
9679
+ "&:active": {
9680
+ backgroundColor: "var(--winui-subtle-fill-tertiary)",
9681
+ color: "var(--winui-text-fill-secondary)"
9682
+ },
9683
+ "&:focus-visible": {
9684
+ boxShadow: "inset 0 0 0 1px var(--winui-focus-stroke-inner)",
9685
+ outline: "2px solid var(--winui-focus-stroke-outer)",
9686
+ outlineOffset: "0",
9687
+ opacity: 1,
9688
+ pointerEvents: "auto"
9689
+ },
9690
+ "&:disabled": { color: "var(--winui-text-fill-disabled)", cursor: "not-allowed" }
9691
+ },
9692
+ closeShown: { opacity: 1, pointerEvents: "auto" },
9693
+ // Scroll buttons: 32x24, glyph 8, ControlCornerRadius, the subtle ramp, with
9694
+ // 8,0,3,3 / 3,0,8,3 container padding.
9695
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L255-L260
9696
+ // https://github.com/microsoft/microsoft-ui-xaml/blob/188f602b27cdb47572b28c380e9c087b02e1ccee/controls/dev/TabView/TabView_themeresources.xaml#L34-L41
9697
+ scrollButtonBox: {
9698
+ alignSelf: "flex-end",
9699
+ flexShrink: 0,
9700
+ position: "relative",
9701
+ zIndex: 1
9702
+ },
9703
+ scrollBoxLeft: { padding: "0 3px 3px 8px" },
9704
+ scrollBoxRight: { padding: "0 8px 3px 3px" },
9705
+ scrollButton: {
9706
+ alignItems: "center",
9707
+ appearance: "none",
9708
+ backgroundColor: "transparent",
9709
+ borderRadius: "var(--winui-control-corner-radius)",
9710
+ border: "none",
9711
+ color: "var(--winui-text-fill-secondary)",
9712
+ cursor: "pointer",
9713
+ display: "inline-flex",
9714
+ fontSize: "8px",
9715
+ height: "24px",
9716
+ justifyContent: "center",
9717
+ padding: "3px 7px",
9718
+ width: "32px",
9719
+ "&:hover:not(:disabled)": { backgroundColor: "var(--winui-subtle-fill-secondary)" },
9720
+ "&:active:not(:disabled)": { backgroundColor: "var(--winui-subtle-fill-tertiary)" },
9721
+ "&:disabled": { color: "var(--winui-text-fill-disabled)", cursor: "default" },
9722
+ "&:focus-visible": {
9723
+ boxShadow: "inset 0 0 0 1px var(--winui-focus-stroke-inner)",
9724
+ outline: "2px solid var(--winui-focus-stroke-outer)",
9725
+ outlineOffset: "0"
9726
+ }
9727
+ },
9728
+ // TabStripFooter: beside the tabs, after them, on the strip's baseline.
9729
+ footer: {
9730
+ alignItems: "center",
9731
+ alignSelf: "stretch",
9732
+ display: "flex",
9733
+ flexShrink: 0,
9734
+ minHeight: "32px",
9735
+ paddingBottom: "3px",
9736
+ paddingInline: "4px",
9737
+ position: "relative",
9738
+ zIndex: 1
9739
+ }
9740
+ });
9741
+ var SCROLL_STEP_PX = 200;
9742
+ function TabView({ ariaLabel, className, footer, items, onClose, onSelect, selectedValue }) {
9743
+ const styles = useStyles18();
9744
+ const { t: t2 } = useTranslation();
9745
+ const scrollerRef = useRef9(null);
9746
+ const [overflow, setOverflow] = useState13({ backward: false, forward: false, scrollable: false });
9747
+ const enabledValues = items.filter((item) => item.disabled !== true).map((item) => item.value);
9748
+ const tabStop = selectedValue !== null && enabledValues.includes(selectedValue) ? selectedValue : enabledValues[0];
9749
+ const measure2 = useCallback7(() => {
9750
+ const scroller = scrollerRef.current;
9751
+ if (!scroller) return;
9752
+ const scrollable = scroller.scrollWidth - scroller.clientWidth > 1;
9753
+ const backward = scrollable && scroller.scrollLeft > 0;
9754
+ const forward = scrollable && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth - 1;
9755
+ setOverflow((previous) => previous.scrollable === scrollable && previous.backward === backward && previous.forward === forward ? previous : { backward, forward, scrollable });
9756
+ }, []);
9757
+ useLayoutEffect4(() => {
9758
+ measure2();
9759
+ const scroller = scrollerRef.current;
9760
+ if (!scroller || typeof ResizeObserver === "undefined") return;
9761
+ const observer = new ResizeObserver(measure2);
9762
+ observer.observe(scroller);
9763
+ const list = scroller.firstElementChild;
9764
+ if (list) observer.observe(list);
9765
+ return () => observer.disconnect();
9766
+ }, [measure2, items]);
9767
+ useEffect7(() => {
9768
+ const selected = scrollerRef.current?.querySelector('[role="tab"][aria-selected="true"]');
9769
+ selected?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
9770
+ }, [selectedValue]);
9771
+ const scrollBy = (direction) => scrollerRef.current?.scrollBy?.({ left: direction * SCROLL_STEP_PX });
9772
+ const closeIfClosable = (value) => {
9773
+ const item = items.find((candidate) => candidate.value === value);
9774
+ if (item?.closable !== true || item.disabled === true) return false;
9775
+ onClose?.(value);
9776
+ return true;
9777
+ };
9778
+ const handleKeyDown = (event) => {
9779
+ const target = event.target;
9780
+ const owner = target.closest("[data-tab-value]");
9781
+ if (!owner) return;
9782
+ const value = owner.dataset.tabValue;
9783
+ if (event.key === "F4" && event.ctrlKey || event.key === "Delete") {
9784
+ if (closeIfClosable(value)) event.preventDefault();
9785
+ return;
9786
+ }
9787
+ if (!target.matches('[role="tab"]') || enabledValues.length === 0) return;
9788
+ const current = enabledValues.indexOf(value);
9789
+ let next;
9790
+ switch (event.key) {
9791
+ case "ArrowRight":
9792
+ next = enabledValues[(current + 1) % enabledValues.length];
9793
+ break;
9794
+ case "ArrowLeft":
9795
+ next = enabledValues[(current - 1 + enabledValues.length) % enabledValues.length];
9796
+ break;
9797
+ case "Home":
9798
+ next = enabledValues[0];
9799
+ break;
9800
+ case "End":
9801
+ next = enabledValues[enabledValues.length - 1];
9802
+ break;
9803
+ default:
9804
+ return;
9805
+ }
9806
+ event.preventDefault();
9807
+ const nextTab = event.currentTarget.querySelector(`[data-tab-value="${CSS.escape(next)}"] [role="tab"]`);
9808
+ nextTab?.focus();
9809
+ if (next !== selectedValue) onSelect(next);
9810
+ };
9811
+ return /* @__PURE__ */ jsxs24("div", { className: mergeClasses25(styles.root, className), children: [
9812
+ overflow.scrollable ? /* @__PURE__ */ jsx45("div", { className: mergeClasses25(styles.scrollButtonBox, styles.scrollBoxLeft), children: /* @__PURE__ */ jsx45(
9813
+ "button",
9814
+ {
9815
+ "aria-label": t2("tabView.scrollBackward"),
9816
+ className: styles.scrollButton,
9817
+ disabled: !overflow.backward,
9818
+ onClick: () => scrollBy(-1),
9819
+ tabIndex: -1,
9820
+ type: "button",
9821
+ children: /* @__PURE__ */ jsx45(CaretLeft12Filled, { fontSize: 8 })
9822
+ }
9823
+ ) }) : null,
9824
+ /* @__PURE__ */ jsx45("div", { className: styles.scroller, onScroll: measure2, ref: scrollerRef, children: /* @__PURE__ */ jsx45("div", { "aria-label": ariaLabel, "aria-orientation": "horizontal", className: styles.tablist, onKeyDown: handleKeyDown, role: "tablist", children: items.map((item) => {
9825
+ const selected = item.value === selectedValue;
9826
+ const disabled = item.disabled === true;
9827
+ const closable = item.closable === true;
9828
+ const closeLabel = item.closeLabel ?? t2("tabView.close");
9829
+ return /* @__PURE__ */ jsxs24(
9830
+ "div",
9831
+ {
9832
+ className: styles.item,
9833
+ "data-disabled": disabled ? "" : void 0,
9834
+ "data-selected": selected ? "" : void 0,
9835
+ "data-tab-value": item.value,
9836
+ onAuxClick: (event) => {
9837
+ if (event.button !== 1 || !closable) return;
9838
+ event.preventDefault();
9839
+ closeIfClosable(item.value);
9840
+ },
9841
+ onMouseDown: (event) => {
9842
+ if (event.button === 1) event.preventDefault();
9843
+ },
9844
+ role: "presentation",
9845
+ children: [
9846
+ /* @__PURE__ */ jsxs24(
9847
+ "button",
9848
+ {
9849
+ "aria-selected": selected,
9850
+ className: mergeClasses25(styles.tab, closable && styles.tabWithClose),
9851
+ disabled,
9852
+ onClick: () => {
9853
+ if (!selected) onSelect(item.value);
9854
+ },
9855
+ role: "tab",
9856
+ tabIndex: item.value === tabStop ? 0 : -1,
9857
+ type: "button",
9858
+ children: [
9859
+ item.icon === void 0 ? null : /* @__PURE__ */ jsx45("span", { "aria-hidden": "true", className: styles.icon, children: item.icon }),
9860
+ typeof item.header === "string" ? /* @__PURE__ */ jsx45(TruncationTooltip, { content: item.header, relationship: "description", children: (measureRef) => /* @__PURE__ */ jsx45("span", { className: styles.label, ref: measureRef, children: item.header }) }) : /* @__PURE__ */ jsx45("span", { className: styles.label, children: item.header })
9861
+ ]
9862
+ }
9863
+ ),
9864
+ closable ? /* @__PURE__ */ jsx45(
9865
+ "button",
9866
+ {
9867
+ "aria-label": closeLabel,
9868
+ className: mergeClasses25(styles.close, selected && styles.closeShown),
9869
+ "data-tab-close": "",
9870
+ disabled,
9871
+ onClick: () => closeIfClosable(item.value),
9872
+ tabIndex: -1,
9873
+ type: "button",
9874
+ children: /* @__PURE__ */ jsx45(Dismiss12Regular, { fontSize: 12 })
9875
+ }
9876
+ ) : null
9877
+ ]
9878
+ },
9879
+ item.value
9880
+ );
9881
+ }) }) }),
9882
+ overflow.scrollable ? /* @__PURE__ */ jsx45("div", { className: mergeClasses25(styles.scrollButtonBox, styles.scrollBoxRight), children: /* @__PURE__ */ jsx45(
9883
+ "button",
9884
+ {
9885
+ "aria-label": t2("tabView.scrollForward"),
9886
+ className: styles.scrollButton,
9887
+ disabled: !overflow.forward,
9888
+ onClick: () => scrollBy(1),
9889
+ tabIndex: -1,
9890
+ type: "button",
9891
+ children: /* @__PURE__ */ jsx45(CaretRight12Filled, { fontSize: 8 })
9892
+ }
9893
+ ) }) : null,
9894
+ footer === void 0 ? null : /* @__PURE__ */ jsx45("div", { className: styles.footer, children: footer })
9895
+ ] });
8502
9896
  }
8503
9897
 
9898
+ // src/components/ui/tooltip-icon-button.tsx
9899
+ import { jsx as jsx46 } from "react/jsx-runtime";
9900
+ var { Button: Button11, Tooltip: Tooltip5, mergeClasses: mergeClasses26 } = fluentComponents;
9901
+ function TooltipIconButton(props) {
9902
+ return props.to === void 0 ? /* @__PURE__ */ jsx46(IconButton, { ...props }) : /* @__PURE__ */ jsx46(AddressedIconButton, { ...props, to: props.to });
9903
+ }
9904
+ function AddressedIconButton({ to, ...props }) {
9905
+ const address = useRouteAddress(to);
9906
+ return /* @__PURE__ */ jsx46(IconButton, { ...props, ...address });
9907
+ }
9908
+ function IconButton({ className, danger = false, disabled = false, disabledFocusable = false, href, icon, label, onClick, ...trigger }) {
9909
+ const dangerClasses = useDangerActionClasses();
9910
+ const shared = {
9911
+ ...trigger,
9912
+ appearance: "subtle",
9913
+ "aria-label": label,
9914
+ className: mergeClasses26(danger && dangerClasses.button, className),
9915
+ disabled,
9916
+ disabledFocusable,
9917
+ icon,
9918
+ onClick,
9919
+ size: "small"
9920
+ };
9921
+ return /* @__PURE__ */ jsx46(Tooltip5, { content: label, relationship: "label", children: href === void 0 ? /* @__PURE__ */ jsx46(Button11, { ...shared }) : /* @__PURE__ */ jsx46(Button11, { ...shared, as: "a", href }) });
9922
+ }
9923
+
9924
+ // src/components/ui/use-confirm.tsx
9925
+ import { createContext as createContext4, useCallback as useCallback8, useContext as useContext4, useRef as useRef10, useState as useState14 } from "react";
9926
+ import { jsx as jsx47, jsxs as jsxs25 } from "react/jsx-runtime";
9927
+ var ConfirmContext = createContext4(null);
9928
+ var errorText2 = (error) => error instanceof Error ? error.message : String(error);
9929
+ function ConfirmDialogProvider({ children }) {
9930
+ const nextId = useRef10(0);
9931
+ const [queue, setQueue] = useState14([]);
9932
+ const [open, setOpen] = useState14(true);
9933
+ const [busy, setBusy] = useState14(false);
9934
+ const [error, setError] = useState14(null);
9935
+ const head = queue[0];
9936
+ const confirm = useCallback8((options) => new Promise((resolve) => {
9937
+ setQueue((current) => [...current, { id: nextId.current++, options, resolve }]);
9938
+ }), []);
9939
+ const finish = (confirmed) => {
9940
+ if (!open) return;
9941
+ head?.resolve(confirmed);
9942
+ setOpen(false);
9943
+ };
9944
+ const accept = async () => {
9945
+ if (!head) return;
9946
+ const { onConfirm } = head.options;
9947
+ if (!onConfirm) {
9948
+ finish(true);
9949
+ return;
9950
+ }
9951
+ setError(null);
9952
+ setBusy(true);
9953
+ try {
9954
+ await onConfirm();
9955
+ setBusy(false);
9956
+ finish(true);
9957
+ } catch (caught) {
9958
+ setBusy(false);
9959
+ setError(errorText2(caught));
9960
+ }
9961
+ };
9962
+ const advance = () => {
9963
+ setQueue((current) => current.slice(1));
9964
+ setError(null);
9965
+ setOpen(true);
9966
+ };
9967
+ return /* @__PURE__ */ jsxs25(ConfirmContext.Provider, { value: confirm, children: [
9968
+ children,
9969
+ head && /* @__PURE__ */ jsx47(
9970
+ ConfirmDialog,
9971
+ {
9972
+ actionIntent: head.options.intent,
9973
+ actionLabel: head.options.actionLabel,
9974
+ busy,
9975
+ cancelLabel: head.options.cancelLabel,
9976
+ error,
9977
+ message: head.options.message,
9978
+ onConfirm: () => {
9979
+ void accept();
9980
+ },
9981
+ onDismissError: () => setError(null),
9982
+ onExited: advance,
9983
+ onOpenChange: (next) => {
9984
+ if (!next) finish(false);
9985
+ },
9986
+ open,
9987
+ title: head.options.title
9988
+ },
9989
+ head.id
9990
+ )
9991
+ ] });
9992
+ }
9993
+ var useConfirm = () => {
9994
+ const value = useContext4(ConfirmContext);
9995
+ if (!value) throw new Error("useConfirm requires a ConfirmDialogProvider above it");
9996
+ return value;
9997
+ };
9998
+
8504
9999
  // src/components/ui/use-dialog-invocation.ts
8505
- import { useCallback as useCallback6, useMemo as useMemo5, useRef as useRef8, useState as useState10 } from "react";
10000
+ import { useCallback as useCallback9, useMemo as useMemo6, useRef as useRef11, useState as useState15 } from "react";
8506
10001
  var useDialogInvocation = () => {
8507
- const nextKey = useRef8(0);
8508
- const [invocation, setInvocation] = useState10(null);
8509
- const [isOpen, setIsOpen] = useState10(false);
8510
- const open = useCallback6((value) => {
10002
+ const nextKey = useRef11(0);
10003
+ const [invocation, setInvocation] = useState15(null);
10004
+ const [isOpen, setIsOpen] = useState15(false);
10005
+ const open = useCallback9((value) => {
8511
10006
  setInvocation({ key: nextKey.current++, value });
8512
10007
  setIsOpen(true);
8513
10008
  }, []);
8514
- const close = useCallback6(() => setIsOpen(false), []);
8515
- return useMemo5(() => ({ close, invocation, isOpen, open }), [close, invocation, isOpen, open]);
10009
+ const close = useCallback9(() => setIsOpen(false), []);
10010
+ return useMemo6(() => ({ close, invocation, isOpen, open }), [close, invocation, isOpen, open]);
8516
10011
  };
8517
10012
 
8518
10013
  // src/components/ui/use-discard-guard.tsx
8519
- import { useCallback as useCallback7, useRef as useRef9, useState as useState11 } from "react";
8520
- import { jsx as jsx39 } from "react/jsx-runtime";
10014
+ import { useCallback as useCallback10, useRef as useRef12, useState as useState16 } from "react";
10015
+ import { jsx as jsx48 } from "react/jsx-runtime";
8521
10016
  var useDiscardGuard = ({ onClose, values }) => {
8522
10017
  const { t: t2 } = useTranslation();
8523
10018
  const prompt = useDialogInvocation();
8524
- const discarding = useRef9(false);
8525
- const [openedWith] = useState11(() => JSON.stringify(values));
10019
+ const discarding = useRef12(false);
10020
+ const [openedWith] = useState16(() => JSON.stringify(values));
8526
10021
  const dirty = JSON.stringify(values) !== openedWith;
8527
- const requestClose = useCallback7(() => {
10022
+ const requestClose = useCallback10(() => {
8528
10023
  if (dirty) prompt.open();
8529
10024
  else onClose();
8530
10025
  }, [dirty, onClose, prompt]);
8531
- const discardConfirmation = prompt.invocation && /* @__PURE__ */ jsx39(
10026
+ const discardConfirmation = prompt.invocation && /* @__PURE__ */ jsx48(
8532
10027
  ConfirmDialog,
8533
10028
  {
8534
10029
  actionLabel: t2("common.discard.discard"),
@@ -8556,13 +10051,13 @@ var useDiscardGuard = ({ onClose, values }) => {
8556
10051
 
8557
10052
  // src/shell/app-shell.tsx
8558
10053
  import { NavigationRegular } from "@fluentui/react-icons";
8559
- import { useLayoutEffect as useLayoutEffect4, useRef as useRef10, useState as useState13 } from "react";
10054
+ import { useLayoutEffect as useLayoutEffect5, useRef as useRef13, useState as useState18 } from "react";
8560
10055
 
8561
10056
  // src/shell/page-frames.tsx
8562
- import { useState as useState12 } from "react";
10057
+ import { useState as useState17 } from "react";
8563
10058
  var usePageFrames = (page, pageKey) => {
8564
- const [current, setCurrent] = useState12({ id: 0, key: pageKey, node: page });
8565
- const [leaving, setLeaving] = useState12(null);
10059
+ const [current, setCurrent] = useState17({ id: 0, key: pageKey, node: page });
10060
+ const [leaving, setLeaving] = useState17(null);
8566
10061
  if (current.key !== pageKey) {
8567
10062
  setLeaving({ id: current.id, node: current.node });
8568
10063
  setCurrent({ id: current.id + 1, key: pageKey, node: page });
@@ -8578,14 +10073,14 @@ var usePageFrames = (page, pageKey) => {
8578
10073
  var pageFrameClassName = (frame) => frame.leaving ? "fwt-page-leaving" : frame.id > 0 ? "fwt-page-entering" : "";
8579
10074
 
8580
10075
  // src/shell/app-shell.tsx
8581
- import { jsx as jsx40, jsxs as jsxs18 } from "react/jsx-runtime";
8582
- var { Button: Button8, DrawerBody, OverlayDrawer } = fluentComponents;
10076
+ import { jsx as jsx49, jsxs as jsxs26 } from "react/jsx-runtime";
10077
+ var { Button: Button12, DrawerBody, OverlayDrawer } = fluentComponents;
8583
10078
  var MAIN_ID = "fwt-main";
8584
10079
  function AppShell({ children, labels, narrowHeader, narrowHeaderActions, navigation, pageKey, workspace = false }) {
8585
- const [navigationOpen, setNavigationOpen] = useState13(false);
8586
- const firstFrameRef = useRef10(null);
8587
- const entranceStarted = useRef10(false);
8588
- useLayoutEffect4(() => {
10080
+ const [navigationOpen, setNavigationOpen] = useState18(false);
10081
+ const firstFrameRef = useRef13(null);
10082
+ const entranceStarted = useRef13(false);
10083
+ useLayoutEffect5(() => {
8589
10084
  if (entranceStarted.current) return;
8590
10085
  if (prefersReducedMotion()) return;
8591
10086
  const frame = firstFrameRef.current;
@@ -8597,19 +10092,19 @@ function AppShell({ children, labels, narrowHeader, narrowHeaderActions, navigat
8597
10092
  { duration: PAGE_ENTER_MS, easing: PAGE_ENTER_EASING, fill: "forwards" }
8598
10093
  );
8599
10094
  }, []);
8600
- const page = /* @__PURE__ */ jsx40(
10095
+ const page = /* @__PURE__ */ jsx49(
8601
10096
  ScrollArea,
8602
10097
  {
8603
10098
  axes: "vertical",
8604
10099
  className: "h-full min-h-0",
8605
10100
  contentClassName: workspace ? "h-full" : "min-h-full",
8606
10101
  noTabIndex: true,
8607
- children: /* @__PURE__ */ jsx40("div", { className: `${workspace ? SCROLLPORT_FILL_CLASS : ""} p-[22px_var(--fwt-page-inset)_var(--fwt-page-inset)] max-[680px]:p-4`, children })
10102
+ children: /* @__PURE__ */ jsx49("div", { className: `${workspace ? SCROLLPORT_FILL_CLASS : ""} p-[22px_var(--fwt-page-inset)_var(--fwt-page-inset)] max-[680px]:p-4`, children })
8608
10103
  }
8609
10104
  );
8610
10105
  const frames = usePageFrames(page, pageKey);
8611
- return /* @__PURE__ */ jsxs18(OutcomeToastProvider, { children: [
8612
- /* @__PURE__ */ jsx40(
10106
+ return /* @__PURE__ */ jsxs26(OutcomeToastProvider, { children: [
10107
+ /* @__PURE__ */ jsx49(
8613
10108
  "a",
8614
10109
  {
8615
10110
  className: "fixed left-3 top-3 z-[100000] -translate-y-20 rounded-md bg-fui-bg1 px-3 py-2 text-fui-fg1 shadow-lg focus:translate-y-0",
@@ -8617,22 +10112,22 @@ function AppShell({ children, labels, narrowHeader, narrowHeaderActions, navigat
8617
10112
  children: labels.skipToContent
8618
10113
  }
8619
10114
  ),
8620
- /* @__PURE__ */ jsxs18("div", { className: "grid grid-cols-[clamp(240px,18vw,290px)_minmax(0,1fr)] grid-rows-[minmax(0,1fr)] h-[100dvh] min-h-0 max-[900px]:grid-cols-1 max-[900px]:grid-rows-[58px_minmax(0,1fr)]", children: [
8621
- /* @__PURE__ */ jsx40("div", { className: "min-h-0 max-[900px]:hidden", children: navigation({}) }),
8622
- /* @__PURE__ */ jsxs18("header", { className: "hidden max-[900px]:flex items-center gap-3 border-b border-b-solid border-fui-divider px-4", children: [
8623
- /* @__PURE__ */ jsx40(
8624
- Button8,
10115
+ /* @__PURE__ */ jsxs26("div", { className: "grid grid-cols-[clamp(240px,18vw,290px)_minmax(0,1fr)] grid-rows-[minmax(0,1fr)] h-[100dvh] min-h-0 max-[900px]:grid-cols-1 max-[900px]:grid-rows-[58px_minmax(0,1fr)]", children: [
10116
+ /* @__PURE__ */ jsx49("div", { className: "min-h-0 max-[900px]:hidden", children: navigation({}) }),
10117
+ /* @__PURE__ */ jsxs26("header", { className: "hidden max-[900px]:flex items-center gap-3 border-b border-b-solid border-fui-divider px-4", children: [
10118
+ /* @__PURE__ */ jsx49(
10119
+ Button12,
8625
10120
  {
8626
10121
  appearance: "subtle",
8627
10122
  "aria-label": labels.openNavigation,
8628
- icon: /* @__PURE__ */ jsx40(NavigationRegular, {}),
10123
+ icon: /* @__PURE__ */ jsx49(NavigationRegular, {}),
8629
10124
  onClick: () => setNavigationOpen(true)
8630
10125
  }
8631
10126
  ),
8632
10127
  narrowHeader,
8633
- narrowHeaderActions !== void 0 && /* @__PURE__ */ jsx40("div", { className: "ml-auto flex items-center gap-2", children: narrowHeaderActions })
10128
+ narrowHeaderActions !== void 0 && /* @__PURE__ */ jsx49("div", { className: "ml-auto flex items-center gap-2", children: narrowHeaderActions })
8634
10129
  ] }),
8635
- /* @__PURE__ */ jsx40("div", { className: "grid grid-cols-[minmax(0,1fr)] grid-rows-[minmax(0,1fr)] min-h-0", children: frames.map((frame) => /* @__PURE__ */ jsx40(
10130
+ /* @__PURE__ */ jsx49("div", { className: "grid grid-cols-[minmax(0,1fr)] grid-rows-[minmax(0,1fr)] min-h-0", children: frames.map((frame) => /* @__PURE__ */ jsx49(
8636
10131
  "div",
8637
10132
  {
8638
10133
  "aria-hidden": frame.leaving || void 0,
@@ -8648,7 +10143,7 @@ function AppShell({ children, labels, narrowHeader, narrowHeaderActions, navigat
8648
10143
  frame.id
8649
10144
  )) })
8650
10145
  ] }),
8651
- /* @__PURE__ */ jsx40(
10146
+ /* @__PURE__ */ jsx49(
8652
10147
  OverlayDrawer,
8653
10148
  {
8654
10149
  "aria-label": labels.navigation,
@@ -8656,33 +10151,33 @@ function AppShell({ children, labels, narrowHeader, narrowHeaderActions, navigat
8656
10151
  onOpenChange: (_2, data) => setNavigationOpen(data.open),
8657
10152
  open: navigationOpen,
8658
10153
  position: "start",
8659
- children: /* @__PURE__ */ jsx40(DrawerBody, { className: "!p-0", children: navigation({ onNavigate: () => setNavigationOpen(false) }) })
10154
+ children: /* @__PURE__ */ jsx49(DrawerBody, { className: "!p-0", children: navigation({ onNavigate: () => setNavigationOpen(false) }) })
8660
10155
  }
8661
10156
  )
8662
10157
  ] });
8663
10158
  }
8664
10159
 
8665
10160
  // src/shell/gradient-background.tsx
8666
- import { jsx as jsx41 } from "react/jsx-runtime";
10161
+ import { jsx as jsx50 } from "react/jsx-runtime";
8667
10162
  function GradientBackground({ children }) {
8668
- return /* @__PURE__ */ jsx41("div", { className: "fwt-gradient-background", children });
10163
+ return /* @__PURE__ */ jsx50("div", { className: "fwt-gradient-background", children });
8669
10164
  }
8670
10165
 
8671
10166
  // src/shell/navigation-pane.tsx
8672
- import { DismissRegular as DismissRegular3 } from "@fluentui/react-icons";
8673
- import { useRef as useRef11 } from "react";
8674
- import { jsx as jsx42, jsxs as jsxs19 } from "react/jsx-runtime";
10167
+ import { DismissRegular as DismissRegular4 } from "@fluentui/react-icons";
10168
+ import { useRef as useRef14 } from "react";
10169
+ import { jsx as jsx51, jsxs as jsxs27 } from "react/jsx-runtime";
8675
10170
  var {
8676
- Button: Button9,
10171
+ Button: Button13,
8677
10172
  NavDrawer,
8678
10173
  NavDrawerBody,
8679
10174
  NavDrawerFooter,
8680
10175
  NavDrawerHeader,
8681
10176
  NavItem,
8682
10177
  NavSectionHeader,
8683
- makeStyles: makeStyles14
10178
+ makeStyles: makeStyles19
8684
10179
  } = fluentComponents;
8685
- var useStyles14 = makeStyles14({
10180
+ var useStyles19 = makeStyles19({
8686
10181
  // 36px is a floor rather than a fixed height, so a two-line label lengthens
8687
10182
  // the row instead of being cut. The left-pane template's 40px icon column
8688
10183
  // plus the presenter's 4 puts the label at 44; Fluent's icon slot is 20px
@@ -8704,14 +10199,14 @@ var useStyles14 = makeStyles14({
8704
10199
  });
8705
10200
  var NAV_INDICATOR_INSET = 0;
8706
10201
  function PaneLink({ item, onNavigate, pending, href }) {
8707
- const styles = useStyles14();
10202
+ const styles = useStyles19();
8708
10203
  const address = useRouteAddress(href);
8709
10204
  const handleClick = (event) => {
8710
10205
  const followsInThisView = event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;
8711
10206
  address.onClick(event);
8712
10207
  if (followsInThisView) onNavigate?.();
8713
10208
  };
8714
- return /* @__PURE__ */ jsx42(
10209
+ return /* @__PURE__ */ jsx51(
8715
10210
  NavItem,
8716
10211
  {
8717
10212
  as: "a",
@@ -8727,11 +10222,11 @@ function PaneLink({ item, onNavigate, pending, href }) {
8727
10222
  );
8728
10223
  }
8729
10224
  function PaneItem({ item, onNavigate, pendingValue }) {
8730
- const styles = useStyles14();
10225
+ const styles = useStyles19();
8731
10226
  if (item.href !== void 0) {
8732
- return /* @__PURE__ */ jsx42(PaneLink, { href: item.href, item, onNavigate, pending: pendingValue === item.value });
10227
+ return /* @__PURE__ */ jsx51(PaneLink, { href: item.href, item, onNavigate, pending: pendingValue === item.value });
8733
10228
  }
8734
- return /* @__PURE__ */ jsx42(NavItem, { className: styles.item, "data-nav-value": item.value, icon: item.icon, value: item.value, children: item.label });
10229
+ return /* @__PURE__ */ jsx51(NavItem, { className: styles.item, "data-nav-value": item.value, icon: item.icon, value: item.value, children: item.label });
8735
10230
  }
8736
10231
  function NavigationPane({
8737
10232
  closeLabel = "Close navigation",
@@ -8744,10 +10239,10 @@ function NavigationPane({
8744
10239
  pendingValue,
8745
10240
  selectedValue
8746
10241
  }) {
8747
- const bodyRef = useRef11(null);
8748
- const footerRef = useRef11(null);
10242
+ const bodyRef = useRef14(null);
10243
+ const footerRef = useRef14(null);
8749
10244
  const allItems = [...groups.flatMap((group) => group.items), ...footerItems];
8750
- return /* @__PURE__ */ jsxs19(
10245
+ return /* @__PURE__ */ jsxs27(
8751
10246
  NavDrawer,
8752
10247
  {
8753
10248
  "aria-label": label,
@@ -8762,21 +10257,21 @@ function NavigationPane({
8762
10257
  surfaceMotion: null,
8763
10258
  type: "inline",
8764
10259
  children: [
8765
- /* @__PURE__ */ jsx42(NavDrawerHeader, { className: "!bg-transparent !px-5 !py-4", children: /* @__PURE__ */ jsxs19("div", { className: "flex items-center min-h-10", children: [
10260
+ /* @__PURE__ */ jsx51(NavDrawerHeader, { className: "!bg-transparent !px-5 !py-4", children: /* @__PURE__ */ jsxs27("div", { className: "flex items-center min-h-10", children: [
8766
10261
  header,
8767
- !onNavigate && headerActions !== void 0 && /* @__PURE__ */ jsx42("div", { className: "ml-auto flex items-center gap-2", children: headerActions }),
8768
- onNavigate && /* @__PURE__ */ jsx42(Button9, { appearance: "subtle", "aria-label": closeLabel, className: "!ml-auto", icon: /* @__PURE__ */ jsx42(DismissRegular3, {}), onClick: onNavigate })
10262
+ !onNavigate && headerActions !== void 0 && /* @__PURE__ */ jsx51("div", { className: "ml-auto flex items-center gap-2", children: headerActions }),
10263
+ onNavigate && /* @__PURE__ */ jsx51(Button13, { appearance: "subtle", "aria-label": closeLabel, className: "!ml-auto", icon: /* @__PURE__ */ jsx51(DismissRegular4, {}), onClick: onNavigate })
8769
10264
  ] }) }),
8770
- /* @__PURE__ */ jsx42(NavDrawerBody, { className: "!bg-transparent overflow-hidden !p-0", children: /* @__PURE__ */ jsx42(ScrollArea, { axes: "vertical", className: "h-full min-h-0", contentClassName: "px-[10px]", noTabIndex: true, children: /* @__PURE__ */ jsxs19("div", { className: "relative", ref: bodyRef, children: [
8771
- /* @__PURE__ */ jsx42(NavSelectionIndicator, { containerRef: bodyRef, inset: NAV_INDICATOR_INSET, otherListIs: "below", selectedValue }),
8772
- groups.map((group, groupIndex) => group.items.length === 0 ? null : /* @__PURE__ */ jsxs19("div", { children: [
8773
- group.label !== void 0 && /* @__PURE__ */ jsx42(NavSectionHeader, { children: group.label }),
8774
- /* @__PURE__ */ jsx42("div", { className: "grid gap-1", children: group.items.map((item) => /* @__PURE__ */ jsx42(PaneItem, { item, onNavigate, pendingValue }, item.value)) })
10265
+ /* @__PURE__ */ jsx51(NavDrawerBody, { className: "!bg-transparent overflow-hidden !p-0", children: /* @__PURE__ */ jsx51(ScrollArea, { axes: "vertical", className: "h-full min-h-0", contentClassName: "px-[10px]", noTabIndex: true, children: /* @__PURE__ */ jsxs27("div", { className: "relative", ref: bodyRef, children: [
10266
+ /* @__PURE__ */ jsx51(NavSelectionIndicator, { containerRef: bodyRef, inset: NAV_INDICATOR_INSET, otherListIs: "below", selectedValue }),
10267
+ groups.map((group, groupIndex) => group.items.length === 0 ? null : /* @__PURE__ */ jsxs27("div", { children: [
10268
+ group.label !== void 0 && /* @__PURE__ */ jsx51(NavSectionHeader, { children: group.label }),
10269
+ /* @__PURE__ */ jsx51("div", { className: "grid gap-1", children: group.items.map((item) => /* @__PURE__ */ jsx51(PaneItem, { item, onNavigate, pendingValue }, item.value)) })
8775
10270
  ] }, groupIndex))
8776
10271
  ] }) }) }),
8777
- footerItems.length > 0 && /* @__PURE__ */ jsx42(NavDrawerFooter, { className: "!bg-transparent !gap-y-1 !px-[10px] !py-3", children: /* @__PURE__ */ jsxs19("div", { className: "grid gap-y-1 relative w-full", ref: footerRef, children: [
8778
- /* @__PURE__ */ jsx42(NavSelectionIndicator, { containerRef: footerRef, inset: NAV_INDICATOR_INSET, otherListIs: "above", selectedValue }),
8779
- footerItems.map((item) => /* @__PURE__ */ jsx42(PaneItem, { item, onNavigate, pendingValue }, item.value))
10272
+ footerItems.length > 0 && /* @__PURE__ */ jsx51(NavDrawerFooter, { className: "!bg-transparent !gap-y-1 !px-[10px] !py-3", children: /* @__PURE__ */ jsxs27("div", { className: "grid gap-y-1 relative w-full", ref: footerRef, children: [
10273
+ /* @__PURE__ */ jsx51(NavSelectionIndicator, { containerRef: footerRef, inset: NAV_INDICATOR_INSET, otherListIs: "above", selectedValue }),
10274
+ footerItems.map((item) => /* @__PURE__ */ jsx51(PaneItem, { item, onNavigate, pendingValue }, item.value))
8780
10275
  ] }) })
8781
10276
  ]
8782
10277
  }
@@ -8784,9 +10279,9 @@ function NavigationPane({
8784
10279
  }
8785
10280
 
8786
10281
  // src/shell/navigation-progress.tsx
8787
- import { jsx as jsx43 } from "react/jsx-runtime";
10282
+ import { jsx as jsx52 } from "react/jsx-runtime";
8788
10283
  function NavigationProgress({ active }) {
8789
- return /* @__PURE__ */ jsx43("div", { "aria-hidden": "true", className: "fwt-navigation-progress", "data-active": active });
10284
+ return /* @__PURE__ */ jsx52("div", { "aria-hidden": "true", className: "fwt-navigation-progress", "data-active": active });
8790
10285
  }
8791
10286
  export {
8792
10287
  AppLoadingScreen,
@@ -8807,8 +10302,11 @@ export {
8807
10302
  CodeBlock,
8808
10303
  Combobox,
8809
10304
  ConfirmDialog,
10305
+ ConfirmDialogProvider,
10306
+ ConfirmFlyout,
8810
10307
  ContentLoadingScreen,
8811
10308
  DashboardPageHeader,
10309
+ DataTable,
8812
10310
  DialogShell,
8813
10311
  Dropdown,
8814
10312
  EXPAND_ANIMATION_MS,
@@ -8816,6 +10314,8 @@ export {
8816
10314
  EmptyStateLine,
8817
10315
  ErrorShell,
8818
10316
  ErrorStack,
10317
+ FileDropZone,
10318
+ FilePickerButton,
8819
10319
  GradientBackground,
8820
10320
  HEADER_ROW_CLASS,
8821
10321
  HttpMethodBadge,
@@ -8827,10 +10327,13 @@ export {
8827
10327
  Input,
8828
10328
  LISTBOX_POSITIONING,
8829
10329
  MaskedIcon,
10330
+ Metric,
10331
+ MetricGrid,
8830
10332
  MultiselectCombobox,
8831
10333
  NavSelectionIndicator,
8832
10334
  NavigationPane,
8833
10335
  NavigationProgress,
10336
+ NumberBox,
8834
10337
  OpenLinkLabel,
8835
10338
  OutcomeMessageBar,
8836
10339
  OutcomeToastProvider,
@@ -8853,8 +10356,10 @@ export {
8853
10356
  POPUP_SLIDE_EASING,
8854
10357
  POPUP_SLIDE_MS,
8855
10358
  POP_IN_OFFSET_PX,
10359
+ Pager,
8856
10360
  Panel,
8857
10361
  ProgressRing,
10362
+ PropertyList,
8858
10363
  REPOSITION_ANIMATION_MS,
8859
10364
  REPOSITION_DELETE_DELAY_MS,
8860
10365
  REPOSITION_EASING,
@@ -8879,6 +10384,7 @@ export {
8879
10384
  THEME_MODE_ATTRIBUTE,
8880
10385
  TIGHT_STACK_CLASS,
8881
10386
  TWO_COLUMN_FORM_CLASS,
10387
+ TabView,
8882
10388
  TableActions,
8883
10389
  TableCentredCell,
8884
10390
  TableCentredHeader,
@@ -8892,21 +10398,32 @@ export {
8892
10398
  WinuiStringsProvider,
8893
10399
  applyThemeMode,
8894
10400
  baseFontStack,
10401
+ clampNumber,
8895
10402
  copyOutcomeIcon,
8896
10403
  copyToClipboard,
8897
10404
  fluentComponents,
10405
+ formatFileSize,
10406
+ formatMetricValue,
8898
10407
  infoLabelSlot,
10408
+ matchesAccept,
8899
10409
  monospaceStack,
8900
10410
  moveItem,
8901
10411
  pageFrameClassName,
10412
+ pagerPageCount,
10413
+ pagerPageWindow,
10414
+ parseNumberText,
8902
10415
  progressIndeterminateCss,
8903
10416
  refuseToggle,
10417
+ resolveNumberChange,
8904
10418
  resolveThemeMode,
10419
+ stepPrecision,
8905
10420
  stopRowSelection,
8906
10421
  useBadgeHue,
10422
+ useConfirm,
8907
10423
  useCopyLabel,
8908
10424
  useCopyToClipboard,
8909
10425
  useDangerActionClasses,
10426
+ useDangerFillClass,
8910
10427
  useDangerTextClass,
8911
10428
  useDialogInvocation,
8912
10429
  useDiscardGuard,
@@ -8915,6 +10432,7 @@ export {
8915
10432
  useReorderList,
8916
10433
  useRouteAddress,
8917
10434
  useScrollAreaHost,
10435
+ useToast,
8918
10436
  useTruncation,
8919
10437
  useWinuiTheme,
8920
10438
  valuesAsOptions,