@flytedan/flytebot-design-system 0.65.0 → 0.66.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.d.cts CHANGED
@@ -1521,8 +1521,9 @@ declare function StatGrid({ columns, className, children, ...rest }: StatGridPro
1521
1521
 
1522
1522
  /**
1523
1523
  * A flat figure tile — no shadow, no background color, never more than four in a row.
1524
+ * Given `onPress` it becomes a button that can filter a list (MP-311).
1524
1525
  */
1525
- interface StatTileProps extends React.HTMLAttributes<HTMLDivElement> {
1526
+ interface StatTileBaseProps {
1526
1527
  label: string;
1527
1528
  value?: React.ReactNode;
1528
1529
  sub?: React.ReactNode;
@@ -1541,7 +1542,24 @@ interface StatTileProps extends React.HTMLAttributes<HTMLDivElement> {
1541
1542
  compact?: boolean;
1542
1543
  className?: string;
1543
1544
  }
1544
- declare function StatTile({ label, value, sub, delta, invert, loading, compact, className, ...rest }: StatTileProps): React.JSX.Element;
1545
+ /** Display mode: a `div`, exactly as before. `pressed` and `disabled` mean nothing without `onPress`. */
1546
+ interface StatTileDisplayProps extends StatTileBaseProps, React.HTMLAttributes<HTMLDivElement> {
1547
+ onPress?: undefined;
1548
+ pressed?: never;
1549
+ disabled?: never;
1550
+ }
1551
+ /** Press mode: the tile is a real `<button>` with an `aria-pressed` state, so a dashboard's tiles
1552
+ * can filter the list below them. Enter and Space press it (native button behaviour); a pressed
1553
+ * tile wears the brand border and fill. */
1554
+ interface StatTilePressProps extends StatTileBaseProps, Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick" | "type" | "disabled" | "value"> {
1555
+ onPress: () => void;
1556
+ /** Whether the list is currently filtered by this tile. Default false. */
1557
+ pressed?: boolean;
1558
+ /** Shown but cannot be pressed (nothing to go to). A `loading` tile is never pressable either. */
1559
+ disabled?: boolean;
1560
+ }
1561
+ type StatTileProps = StatTileDisplayProps | StatTilePressProps;
1562
+ declare function StatTile(props: StatTileProps): React.JSX.Element;
1545
1563
 
1546
1564
  declare function languageLabel(lang?: string): string;
1547
1565
  /** Tokenise source into [{t, c}] where c is a token class or null for plain text. */
package/dist/index.d.ts CHANGED
@@ -1521,8 +1521,9 @@ declare function StatGrid({ columns, className, children, ...rest }: StatGridPro
1521
1521
 
1522
1522
  /**
1523
1523
  * A flat figure tile — no shadow, no background color, never more than four in a row.
1524
+ * Given `onPress` it becomes a button that can filter a list (MP-311).
1524
1525
  */
1525
- interface StatTileProps extends React.HTMLAttributes<HTMLDivElement> {
1526
+ interface StatTileBaseProps {
1526
1527
  label: string;
1527
1528
  value?: React.ReactNode;
1528
1529
  sub?: React.ReactNode;
@@ -1541,7 +1542,24 @@ interface StatTileProps extends React.HTMLAttributes<HTMLDivElement> {
1541
1542
  compact?: boolean;
1542
1543
  className?: string;
1543
1544
  }
1544
- declare function StatTile({ label, value, sub, delta, invert, loading, compact, className, ...rest }: StatTileProps): React.JSX.Element;
1545
+ /** Display mode: a `div`, exactly as before. `pressed` and `disabled` mean nothing without `onPress`. */
1546
+ interface StatTileDisplayProps extends StatTileBaseProps, React.HTMLAttributes<HTMLDivElement> {
1547
+ onPress?: undefined;
1548
+ pressed?: never;
1549
+ disabled?: never;
1550
+ }
1551
+ /** Press mode: the tile is a real `<button>` with an `aria-pressed` state, so a dashboard's tiles
1552
+ * can filter the list below them. Enter and Space press it (native button behaviour); a pressed
1553
+ * tile wears the brand border and fill. */
1554
+ interface StatTilePressProps extends StatTileBaseProps, Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick" | "type" | "disabled" | "value"> {
1555
+ onPress: () => void;
1556
+ /** Whether the list is currently filtered by this tile. Default false. */
1557
+ pressed?: boolean;
1558
+ /** Shown but cannot be pressed (nothing to go to). A `loading` tile is never pressable either. */
1559
+ disabled?: boolean;
1560
+ }
1561
+ type StatTileProps = StatTileDisplayProps | StatTilePressProps;
1562
+ declare function StatTile(props: StatTileProps): React.JSX.Element;
1545
1563
 
1546
1564
  declare function languageLabel(lang?: string): string;
1547
1565
  /** Tokenise source into [{t, c}] where c is a token class or null for plain text. */
package/dist/index.js CHANGED
@@ -4815,18 +4815,19 @@ function StatGrid({ columns, className = "", children, ...rest }) {
4815
4815
  }
4816
4816
 
4817
4817
  // src/components/data/StatTile.tsx
4818
- import { jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
4818
+ import { Fragment as Fragment8, jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
4819
4819
  function isZeroDelta(delta) {
4820
4820
  if (!delta) return false;
4821
4821
  const match = delta.match(/[\d.]+/);
4822
4822
  return match !== null && parseFloat(match[0]) === 0;
4823
4823
  }
4824
- function StatTile({ label, value, sub, delta, invert = false, loading = false, compact: compact3 = false, className = "", ...rest }) {
4824
+ function StatTile(props) {
4825
+ const { label, value, sub, delta, invert = false, loading = false, compact: compact3 = false, className = "", ...rest } = props;
4825
4826
  const isDecrease = delta?.startsWith("-") ?? false;
4826
4827
  const isZero = isZeroDelta(delta);
4827
4828
  const isGood = invert ? isDecrease : !isDecrease;
4828
4829
  const deltaToneClass = isZero ? "fd-stat-delta-neutral" : isGood ? "fd-stat-delta-up" : "fd-stat-delta-down";
4829
- return /* @__PURE__ */ jsxs42("div", { className: ["fd-stat", compact3 ? "fd-stat-compact" : "", className].filter(Boolean).join(" "), ...rest, children: [
4830
+ const content = /* @__PURE__ */ jsxs42(Fragment8, { children: [
4830
4831
  loading ? /* @__PURE__ */ jsx52("span", { className: "fd-skel fd-skel-text", style: { display: "block", height: compact3 ? 20 : 28, width: "62%" } }) : /* @__PURE__ */ jsxs42("span", { className: "fd-stat-top", children: [
4831
4832
  /* @__PURE__ */ jsx52("span", { className: "fd-stat-figure", children: value }),
4832
4833
  delta ? /* @__PURE__ */ jsxs42("span", { className: "fd-stat-delta " + deltaToneClass, children: [
@@ -4838,6 +4839,12 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
4838
4839
  !loading && sub ? /* @__PURE__ */ jsx52("span", { className: "fd-stat-sub", children: sub }) : null,
4839
4840
  loading ? /* @__PURE__ */ jsx52("span", { className: "fd-skel fd-skel-text", style: { display: "block", height: 10, width: "40%", marginTop: 8 } }) : /* @__PURE__ */ jsx52("span", { className: "fd-stat-label", style: { display: "block" }, children: label })
4840
4841
  ] });
4842
+ const classes = (...extra) => ["fd-stat", ...extra, compact3 ? "fd-stat-compact" : "", className].filter(Boolean).join(" ");
4843
+ if (rest.onPress) {
4844
+ const { onPress, pressed = false, disabled = false, ...buttonRest } = rest;
4845
+ return /* @__PURE__ */ jsx52("button", { type: "button", className: classes("fd-stat-pressable"), "aria-pressed": pressed, disabled: disabled || loading, onClick: onPress, ...buttonRest, children: content });
4846
+ }
4847
+ return /* @__PURE__ */ jsx52("div", { className: classes(), ...rest, children: content });
4841
4848
  }
4842
4849
 
4843
4850
  // src/components/data/CodeBlock.tsx
@@ -4897,7 +4904,7 @@ function useCopyToClipboard() {
4897
4904
  }
4898
4905
 
4899
4906
  // src/components/data/CodeBlock.tsx
4900
- import { Fragment as Fragment8, jsx as jsx53, jsxs as jsxs43 } from "react/jsx-runtime";
4907
+ import { Fragment as Fragment9, jsx as jsx53, jsxs as jsxs43 } from "react/jsx-runtime";
4901
4908
  var JS_KW = /^(?:const|let|var|function|return|if|else|for|while|do|new|class|extends|import|from|export|default|await|async|try|catch|finally|throw|typeof|instanceof|of|in|switch|case|break|continue|delete|void|yield|static|get|set|this|super|interface|type|enum|implements|public|private|protected|readonly|abstract|as|satisfies|declare|namespace)$/;
4902
4909
  var RULES = {
4903
4910
  js: [
@@ -5053,7 +5060,7 @@ function tokenize(src, lang) {
5053
5060
  }
5054
5061
  function Highlighted({ code, lang }) {
5055
5062
  const toks = React34.useMemo(() => tokenize(code, lang), [code, lang]);
5056
- return /* @__PURE__ */ jsx53(Fragment8, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx53("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
5063
+ return /* @__PURE__ */ jsx53(Fragment9, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx53("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
5057
5064
  }
5058
5065
  function CodeBlock({
5059
5066
  code = "",
@@ -5389,7 +5396,7 @@ function Meter({ segments = [], unallocated = 0, height = 8, label, legend = fal
5389
5396
  }
5390
5397
 
5391
5398
  // src/components/data/Pagination.tsx
5392
- import { Fragment as Fragment10, jsx as jsx56, jsxs as jsxs46 } from "react/jsx-runtime";
5399
+ import { Fragment as Fragment11, jsx as jsx56, jsxs as jsxs46 } from "react/jsx-runtime";
5393
5400
  var unitPluralRules = new Intl.PluralRules("en-US");
5394
5401
  function pluralizeUnit(n, singular, irregularPlural) {
5395
5402
  return unitPluralRules.select(n) === "one" ? singular : irregularPlural ?? `${singular}s`;
@@ -5421,10 +5428,10 @@ function Pagination({
5421
5428
  else if (nums[nums.length - 1] !== "\u2026") nums.push("\u2026");
5422
5429
  }
5423
5430
  return /* @__PURE__ */ jsxs46("div", { className: ["fd-pag", className].filter(Boolean).join(" "), ...rest, children: [
5424
- /* @__PURE__ */ jsx56("span", { className: "fd-pag-count", children: loading ? /* @__PURE__ */ jsx56("span", { className: "fd-skel fd-skel-text", style: { display: "inline-block", height: 12, width: 108 } }) : total === 0 ? /* @__PURE__ */ jsxs46(Fragment10, { children: [
5431
+ /* @__PURE__ */ jsx56("span", { className: "fd-pag-count", children: loading ? /* @__PURE__ */ jsx56("span", { className: "fd-skel fd-skel-text", style: { display: "inline-block", height: 12, width: 108 } }) : total === 0 ? /* @__PURE__ */ jsxs46(Fragment11, { children: [
5425
5432
  "No ",
5426
5433
  unitLabel
5427
- ] }) : /* @__PURE__ */ jsxs46(Fragment10, { children: [
5434
+ ] }) : /* @__PURE__ */ jsxs46(Fragment11, { children: [
5428
5435
  /* @__PURE__ */ jsxs46("strong", { children: [
5429
5436
  from.toLocaleString(),
5430
5437
  "\u2013",
@@ -5619,7 +5626,7 @@ function InlinePanelSurface({ panel, align = "right", ...popover }) {
5619
5626
  }
5620
5627
 
5621
5628
  // src/components/data/SortMenu.tsx
5622
- import { Fragment as Fragment12, jsx as jsx59, jsxs as jsxs49 } from "react/jsx-runtime";
5629
+ import { Fragment as Fragment13, jsx as jsx59, jsxs as jsxs49 } from "react/jsx-runtime";
5623
5630
  var directionWord = (field, dir) => dir === "asc" ? field.numeric ? "lowest first" : "A to Z" : field.numeric ? "highest first" : "Z to A";
5624
5631
  function moved(sort, from, to) {
5625
5632
  const next = [...sort];
@@ -5692,7 +5699,7 @@ function SortMenu({
5692
5699
  ] }, f.key);
5693
5700
  });
5694
5701
  const unused = fields.filter((f) => !active.some((entry) => entry.key === f.key));
5695
- const multipleBody = /* @__PURE__ */ jsxs49(Fragment12, { children: [
5702
+ const multipleBody = /* @__PURE__ */ jsxs49(Fragment13, { children: [
5696
5703
  /* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Sorted by" }),
5697
5704
  active.length === 0 ? /* @__PURE__ */ jsx59("span", { className: "fd-body-sm fd-muted", style: { padding: "4px 8px" }, children: "Unsorted" }) : /* @__PURE__ */ jsx59("ol", { className: "fd-stack", style: { gap: 2, margin: 0, padding: 0, listStyle: "none" }, "aria-label": "Sort order", children: active.map((entry, index) => {
5698
5705
  const f = fieldOf(entry.key);
@@ -5741,7 +5748,7 @@ function SortMenu({
5741
5748
  )
5742
5749
  ] }, entry.key);
5743
5750
  }) }),
5744
- unused.length > 0 ? /* @__PURE__ */ jsxs49(Fragment12, { children: [
5751
+ unused.length > 0 ? /* @__PURE__ */ jsxs49(Fragment13, { children: [
5745
5752
  /* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", style: { padding: "10px 8px 6px" }, children: "Add a sort" }),
5746
5753
  unused.map((f) => /* @__PURE__ */ jsxs49("span", { className: "fd-row", style: rowStyle(false), children: [
5747
5754
  /* @__PURE__ */ jsx59("span", { className: "fd-body-sm", style: labelStyle(false), children: f.label }),
@@ -5765,7 +5772,7 @@ function SortMenu({
5765
5772
  ]
5766
5773
  }
5767
5774
  ),
5768
- /* @__PURE__ */ jsx59(InlinePanelSurface, { panel, align, offset: 6, width: multiple ? 340 : 280, label: "Sort by", children: /* @__PURE__ */ jsx59("span", { className: "fd-stack", style: { gap: 2, padding: 8 }, children: multiple ? multipleBody : /* @__PURE__ */ jsxs49(Fragment12, { children: [
5775
+ /* @__PURE__ */ jsx59(InlinePanelSurface, { panel, align, offset: 6, width: multiple ? 340 : 280, label: "Sort by", children: /* @__PURE__ */ jsx59("span", { className: "fd-stack", style: { gap: 2, padding: 8 }, children: multiple ? multipleBody : /* @__PURE__ */ jsxs49(Fragment13, { children: [
5769
5776
  /* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Sort by" }),
5770
5777
  singleBody
5771
5778
  ] }) }) })
@@ -8233,7 +8240,7 @@ function useSessionContext() {
8233
8240
  }
8234
8241
 
8235
8242
  // src/components/platform/AccountMenu.tsx
8236
- import { Fragment as Fragment18, jsx as jsx79, jsxs as jsxs68 } from "react/jsx-runtime";
8243
+ import { Fragment as Fragment19, jsx as jsx79, jsxs as jsxs68 } from "react/jsx-runtime";
8237
8244
  var DEFAULT_LINKS = [];
8238
8245
  var DEFAULT_GROUPS = [];
8239
8246
  function Item({ item, onPick }) {
@@ -8295,7 +8302,7 @@ function AccountMenu({
8295
8302
  }
8296
8303
  };
8297
8304
  const showSwitcher = allowUserSwitch && !!demo;
8298
- return /* @__PURE__ */ jsxs68(Fragment18, { children: [
8305
+ return /* @__PURE__ */ jsxs68(Fragment19, { children: [
8299
8306
  /* @__PURE__ */ jsxs68(
8300
8307
  "button",
8301
8308
  {
@@ -9068,7 +9075,7 @@ function ProfilePage({
9068
9075
 
9069
9076
  // src/components/platform/SessionScreen.tsx
9070
9077
  import * as React61 from "react";
9071
- import { Fragment as Fragment21, jsx as jsx85, jsxs as jsxs73 } from "react/jsx-runtime";
9078
+ import { Fragment as Fragment22, jsx as jsx85, jsxs as jsxs73 } from "react/jsx-runtime";
9072
9079
  var COPY = {
9073
9080
  "signing-in": { busy: "Signing you in\u2026" },
9074
9081
  "session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
@@ -9096,7 +9103,7 @@ function SessionScreen({ kind, error, onRetry, productName }) {
9096
9103
  /* @__PURE__ */ jsx85("div", { className: "fd-session-screen-stripe" }),
9097
9104
  /* @__PURE__ */ jsx85(Card, { children: /* @__PURE__ */ jsxs73("div", { className: "fd-session-screen-body", children: [
9098
9105
  /* @__PURE__ */ jsx85("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
9099
- /* @__PURE__ */ jsx85("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ jsxs73(Fragment21, { children: [
9106
+ /* @__PURE__ */ jsx85("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ jsxs73(Fragment22, { children: [
9100
9107
  /* @__PURE__ */ jsx85("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
9101
9108
  /* @__PURE__ */ jsx85("p", { className: "fd-body fd-session-screen-message", children: announced })
9102
9109
  ] }) : null }),
@@ -11123,7 +11130,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
11123
11130
  // src/components/platform/ComingSoon.tsx
11124
11131
  import * as React65 from "react";
11125
11132
  import { createPortal as createPortal6 } from "react-dom";
11126
- import { Fragment as Fragment23, jsx as jsx87, jsxs as jsxs75 } from "react/jsx-runtime";
11133
+ import { Fragment as Fragment24, jsx as jsx87, jsxs as jsxs75 } from "react/jsx-runtime";
11127
11134
  var BYPASS_STORE = "fd.soon.bypass.v1";
11128
11135
  function readBypassed() {
11129
11136
  try {
@@ -11153,7 +11160,7 @@ function useBypass(key) {
11153
11160
  return [on, set];
11154
11161
  }
11155
11162
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
11156
- return /* @__PURE__ */ jsxs75(Fragment23, { children: [
11163
+ return /* @__PURE__ */ jsxs75(Fragment24, { children: [
11157
11164
  /* @__PURE__ */ jsxs75("span", { className: "fd-soon-badge", children: [
11158
11165
  /* @__PURE__ */ jsx87("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
11159
11166
  label
@@ -11543,7 +11550,7 @@ function PermissionHint({ perm, children }) {
11543
11550
  }
11544
11551
 
11545
11552
  // src/components/platform/ModeSwitch.tsx
11546
- import { Fragment as Fragment24, jsx as jsx89, jsxs as jsxs77 } from "react/jsx-runtime";
11553
+ import { Fragment as Fragment25, jsx as jsx89, jsxs as jsxs77 } from "react/jsx-runtime";
11547
11554
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
11548
11555
  const mode2 = useRuntimeMode();
11549
11556
  const panel = useInlinePanel();
@@ -11598,7 +11605,7 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11598
11605
  s.total,
11599
11606
  " features complete"
11600
11607
  ] }),
11601
- onOpenSpec ? /* @__PURE__ */ jsxs77(Fragment24, { children: [
11608
+ onOpenSpec ? /* @__PURE__ */ jsxs77(Fragment25, { children: [
11602
11609
  /* @__PURE__ */ jsx89("span", { style: { flex: 1 } }),
11603
11610
  /* @__PURE__ */ jsxs77("button", { type: "button", className: "fd-soon-link", onClick: () => {
11604
11611
  setOpen(false);
@@ -11790,7 +11797,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11790
11797
 
11791
11798
  // src/components/planner/MixGap.tsx
11792
11799
  import * as React66 from "react";
11793
- import { Fragment as Fragment25, jsx as jsx92, jsxs as jsxs80 } from "react/jsx-runtime";
11800
+ import { Fragment as Fragment26, jsx as jsx92, jsxs as jsxs80 } from "react/jsx-runtime";
11794
11801
  var MIX_GAP_LAYOUT = {
11795
11802
  trackHeight: 30,
11796
11803
  barHeight: 20,
@@ -11834,7 +11841,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11834
11841
  onMouseLeave: () => setHover(null),
11835
11842
  children: [
11836
11843
  /* @__PURE__ */ jsx92("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx92(ChannelTag, { channel: r.channel, size: "sm" }) }),
11837
- /* @__PURE__ */ jsx92("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx92("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ jsxs80(Fragment25, { children: [
11844
+ /* @__PURE__ */ jsx92("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx92("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ jsxs80(Fragment26, { children: [
11838
11845
  /* @__PURE__ */ jsx92("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
11839
11846
  /* @__PURE__ */ jsx92("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
11840
11847
  /* @__PURE__ */ jsxs80("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
@@ -11948,7 +11955,7 @@ function ChannelContribution({
11948
11955
 
11949
11956
  // src/components/planner/BudgetReallocator.tsx
11950
11957
  import * as React67 from "react";
11951
- import { Fragment as Fragment26, jsx as jsx94, jsxs as jsxs82 } from "react/jsx-runtime";
11958
+ import { Fragment as Fragment27, jsx as jsx94, jsxs as jsxs82 } from "react/jsx-runtime";
11952
11959
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
11953
11960
  function BudgetReallocator({
11954
11961
  campus,
@@ -12012,7 +12019,7 @@ function BudgetReallocator({
12012
12019
  /* @__PURE__ */ jsxs82("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
12013
12020
  /* @__PURE__ */ jsx94("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
12014
12021
  /* @__PURE__ */ jsx94(CsiBadge, { band: nowBand, crp, size: "medium" }),
12015
- dirty ? /* @__PURE__ */ jsxs82(Fragment26, { children: [
12022
+ dirty ? /* @__PURE__ */ jsxs82(Fragment27, { children: [
12016
12023
  /* @__PURE__ */ jsx94("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
12017
12024
  /* @__PURE__ */ jsx94(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
12018
12025
  ] }) : null
@@ -13951,7 +13958,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13951
13958
 
13952
13959
  // src/components/files/FileBrowser.tsx
13953
13960
  import * as React76 from "react";
13954
- import { Fragment as Fragment30, jsx as jsx104, jsxs as jsxs92 } from "react/jsx-runtime";
13961
+ import { Fragment as Fragment31, jsx as jsx104, jsxs as jsxs92 } from "react/jsx-runtime";
13955
13962
  function childrenOf(folders, parentId) {
13956
13963
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
13957
13964
  }
@@ -14250,7 +14257,7 @@ function FileBrowser({
14250
14257
  ] }),
14251
14258
  /* @__PURE__ */ jsxs92("span", { className: "fd-fb-actions", children: [
14252
14259
  canCreateFolder ? /* @__PURE__ */ jsx104(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
14253
- canUpload ? /* @__PURE__ */ jsxs92(Fragment30, { children: [
14260
+ canUpload ? /* @__PURE__ */ jsxs92(Fragment31, { children: [
14254
14261
  /* @__PURE__ */ jsx104(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
14255
14262
  /* @__PURE__ */ jsx104(
14256
14263
  "input",
@@ -14317,7 +14324,7 @@ function FileBrowser({
14317
14324
  draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
14318
14325
  isDropTarget: canMove,
14319
14326
  onDropPayload: (p) => moveIntoFolder(p, f.id),
14320
- actions: /* @__PURE__ */ jsxs92(Fragment30, { children: [
14327
+ actions: /* @__PURE__ */ jsxs92(Fragment31, { children: [
14321
14328
  canRenameFolder ? /* @__PURE__ */ jsx104(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
14322
14329
  canMove ? /* @__PURE__ */ jsx104(
14323
14330
  FolderPickerMenu,
@@ -14340,7 +14347,7 @@ function FileBrowser({
14340
14347
  meta: file.size ? formatBytes(file.size) : void 0,
14341
14348
  onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
14342
14349
  draggableId: canMove ? { kind: "file", id: file.id } : void 0,
14343
- actions: /* @__PURE__ */ jsxs92(Fragment30, { children: [
14350
+ actions: /* @__PURE__ */ jsxs92(Fragment31, { children: [
14344
14351
  canMove ? /* @__PURE__ */ jsx104(
14345
14352
  FolderPickerMenu,
14346
14353
  {
@@ -14358,7 +14365,7 @@ function FileBrowser({
14358
14365
  }
14359
14366
  ) })
14360
14367
  ] }),
14361
- /* @__PURE__ */ jsx104(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ jsxs92(Fragment30, { children: [
14368
+ /* @__PURE__ */ jsx104(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ jsxs92(Fragment31, { children: [
14362
14369
  /* @__PURE__ */ jsx104(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
14363
14370
  /* @__PURE__ */ jsx104(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
14364
14371
  ] }), children: /* @__PURE__ */ jsx104(
@@ -14375,7 +14382,7 @@ function FileBrowser({
14375
14382
  autoFocus: true
14376
14383
  }
14377
14384
  ) }),
14378
- /* @__PURE__ */ jsx104(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ jsxs92(Fragment30, { children: [
14385
+ /* @__PURE__ */ jsx104(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ jsxs92(Fragment31, { children: [
14379
14386
  /* @__PURE__ */ jsx104(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
14380
14387
  /* @__PURE__ */ jsx104(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
14381
14388
  ] }), children: /* @__PURE__ */ jsx104(
@@ -14399,7 +14406,7 @@ function FileBrowser({
14399
14406
  title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
14400
14407
  description: "This can't be undone. The folder must be empty.",
14401
14408
  onClose: () => setDeleteTarget(null),
14402
- footer: /* @__PURE__ */ jsxs92(Fragment30, { children: [
14409
+ footer: /* @__PURE__ */ jsxs92(Fragment31, { children: [
14403
14410
  /* @__PURE__ */ jsx104(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
14404
14411
  /* @__PURE__ */ jsx104(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
14405
14412
  ] })