@flytedan/flytebot-design-system 0.7.2 → 0.8.1

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
@@ -2294,7 +2294,7 @@ function QuotaRow({ label, percent = 0, note, tone, className = "" }) {
2294
2294
  // src/components/data/SortMenu.tsx
2295
2295
  import * as React13 from "react";
2296
2296
  import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
2297
- function SortMenu({ fields = [], sort, onSort, align = "right", className = "", ...rest }) {
2297
+ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
2298
2298
  const [open, setOpen] = React13.useState(false);
2299
2299
  const ref = React13.useRef(null);
2300
2300
  React13.useEffect(() => {
@@ -2340,7 +2340,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", className = "",
2340
2340
  );
2341
2341
  };
2342
2342
  return /* @__PURE__ */ jsxs31("span", { className, style: { position: "relative", display: "inline-flex" }, ref, ...rest, children: [
2343
- /* @__PURE__ */ jsxs31(Button, { size: "sm", variant: "secondary", icon: dir === "asc" ? "sort-ascending" : "sort-descending", onClick: () => setOpen(!open), children: [
2343
+ /* @__PURE__ */ jsxs31(Button, { size, variant: "secondary", icon: dir === "asc" ? "sort-ascending" : "sort-descending", onClick: () => setOpen(!open), children: [
2344
2344
  cur ? cur.label : "Unsorted",
2345
2345
  /* @__PURE__ */ jsx35("i", { className: "ph ph-" + (dir === "asc" ? "arrow-up" : "arrow-down"), style: { fontSize: 12, marginLeft: 6, opacity: 0.75 } })
2346
2346
  ] }),
@@ -2469,6 +2469,8 @@ function VirtualList({
2469
2469
  onNeedMore,
2470
2470
  hasMore,
2471
2471
  loading = false,
2472
+ refreshing = false,
2473
+ refreshingLabel = "Searching\u2026",
2472
2474
  keyOf,
2473
2475
  height = 400,
2474
2476
  emptyState,
@@ -2494,54 +2496,83 @@ function VirtualList({
2494
2496
  requested.current.end = items.length;
2495
2497
  onNeedMore("end");
2496
2498
  }, [wantEnd, loading, items.length, onNeedMore]);
2497
- if (!items.length && !loading && emptyState) {
2498
- return /* @__PURE__ */ jsx37("div", { className: ["fd-vlist", className].filter(Boolean).join(" "), style: { height, overflow: "auto", ...style }, children: emptyState });
2499
+ const lastKeysRef = React15.useRef(null);
2500
+ const newKeys = React15.useMemo(() => {
2501
+ const prev = lastKeysRef.current;
2502
+ if (!prev) return /* @__PURE__ */ new Set();
2503
+ const fresh = /* @__PURE__ */ new Set();
2504
+ for (const item of items) {
2505
+ const k = keyOf(item);
2506
+ if (!prev.has(k)) fresh.add(k);
2507
+ }
2508
+ return fresh;
2509
+ }, [items]);
2510
+ React15.useEffect(() => {
2511
+ lastKeysRef.current = new Set(items.map(keyOf));
2512
+ }, [items]);
2513
+ if (!items.length && !loading && !refreshing && emptyState) {
2514
+ return /* @__PURE__ */ jsx37("div", { className: ["fd-vlist-wrap", className].filter(Boolean).join(" "), style: { height, position: "relative", ...style }, children: /* @__PURE__ */ jsx37("div", { className: "fd-vlist fd-scrollbar", style: { height: "100%", overflow: "auto" }, children: emptyState }) });
2499
2515
  }
2500
2516
  const rows = [];
2501
2517
  for (let i = win.startIndex; i <= win.endIndex; i++) {
2502
2518
  const item = items[i];
2503
2519
  if (item === void 0) continue;
2520
+ const key = keyOf(item);
2504
2521
  rows.push(
2505
- /* @__PURE__ */ jsx37("div", { style: { height: itemHeight, boxSizing: "border-box" }, children: renderItem(item, i) }, keyOf(item))
2522
+ /* @__PURE__ */ jsx37(
2523
+ "div",
2524
+ {
2525
+ className: "fd-vlist-row",
2526
+ style: { height: itemHeight, boxSizing: "border-box", transform: "translateY(" + i * itemHeight + "px)" },
2527
+ children: /* @__PURE__ */ jsx37("div", { className: newKeys.has(key) ? "fd-vlist-row-content fd-vlist-row-enter" : "fd-vlist-row-content", children: renderItem(item, i) })
2528
+ },
2529
+ key
2530
+ )
2506
2531
  );
2507
2532
  }
2508
- return /* @__PURE__ */ jsxs33(
2509
- "div",
2510
- {
2511
- className: ["fd-vlist", className].filter(Boolean).join(" "),
2512
- style: { height, overflowY: "auto", overflowX: "hidden", position: "relative", ...style },
2513
- onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
2514
- children: [
2515
- /* @__PURE__ */ jsx37("div", { style: { height: win.totalHeight, position: "relative" }, children: /* @__PURE__ */ jsx37("div", { style: { position: "absolute", top: win.offsetY, left: 0, right: 0 }, children: rows }) }),
2516
- loading ? /* @__PURE__ */ jsx37("div", { style: { position: "sticky", bottom: 0, left: 0, right: 0, display: "grid", placeItems: "center", padding: "8px 0", background: "var(--surface)" }, children: /* @__PURE__ */ jsx37("span", { className: "fd-spinner", "aria-hidden": "true" }) }) : null
2517
- ]
2518
- }
2519
- );
2533
+ return /* @__PURE__ */ jsxs33("div", { className: ["fd-vlist-wrap", className].filter(Boolean).join(" "), style: { height, position: "relative", ...style }, children: [
2534
+ /* @__PURE__ */ jsxs33(
2535
+ "div",
2536
+ {
2537
+ className: "fd-vlist fd-scrollbar",
2538
+ style: { height: "100%", overflowY: "auto", overflowX: "hidden", position: "relative" },
2539
+ onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
2540
+ children: [
2541
+ /* @__PURE__ */ jsx37("div", { style: { height: win.totalHeight, position: "relative" }, children: rows }),
2542
+ loading ? /* @__PURE__ */ jsx37("div", { style: { position: "sticky", bottom: 0, left: 0, right: 0, display: "grid", placeItems: "center", padding: "8px 0", background: "var(--surface)" }, children: /* @__PURE__ */ jsx37("span", { className: "fd-spinner", "aria-hidden": "true" }) }) : null
2543
+ ]
2544
+ }
2545
+ ),
2546
+ refreshing ? /* @__PURE__ */ jsx37("div", { className: "fd-vlist-refresh-scrim", children: /* @__PURE__ */ jsxs33("div", { className: "fd-vlist-refresh-card", children: [
2547
+ /* @__PURE__ */ jsx37("span", { className: "fd-spinner", "aria-hidden": "true" }),
2548
+ /* @__PURE__ */ jsx37("span", { className: "fd-body-sm", children: refreshingLabel })
2549
+ ] }) }) : null
2550
+ ] });
2520
2551
  }
2521
2552
 
2522
2553
  // src/components/data/EntityRow.tsx
2523
2554
  import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
2524
- function EntityRow({ title, meta, action, draggable = false, onDragStart, onDragEnd, style, className = "" }) {
2555
+ function EntityRow({ title, meta, action, draggable = false, onPointerDown, style, className = "" }) {
2525
2556
  return /* @__PURE__ */ jsxs34(
2526
2557
  "div",
2527
2558
  {
2528
- draggable,
2529
- onDragStart,
2530
- onDragEnd,
2559
+ onPointerDown,
2531
2560
  className: ["fd-erow", className].filter(Boolean).join(" "),
2532
2561
  style: {
2533
2562
  display: "flex",
2534
2563
  alignItems: "center",
2535
- gap: 8,
2564
+ gap: 10,
2536
2565
  height: "100%",
2537
- padding: "0 8px",
2538
- borderRadius: 6,
2566
+ padding: "0 14px",
2539
2567
  cursor: draggable ? "grab" : void 0,
2568
+ // Own the gesture on touch too — without this, a touch-drag on a draggable row
2569
+ // starts the page scrolling instead of (or as well as) the pointer drag.
2570
+ touchAction: draggable ? "none" : void 0,
2540
2571
  ...style
2541
2572
  },
2542
2573
  children: [
2543
- draggable ? /* @__PURE__ */ jsx38("i", { className: "ph ph-dots-six-vertical", "aria-hidden": "true", style: { fontSize: 13, flex: "none", color: "var(--text-muted)" } }) : null,
2544
- /* @__PURE__ */ jsxs34("span", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 1 }, children: [
2574
+ draggable ? /* @__PURE__ */ jsx38("i", { className: "ph ph-dots-six-vertical", "aria-hidden": "true", style: { fontSize: 14, flex: "none", color: "var(--text-muted)" } }) : null,
2575
+ /* @__PURE__ */ jsxs34("span", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 2 }, children: [
2545
2576
  /* @__PURE__ */ jsx38("span", { className: "fd-body-sm", style: { fontWeight: 600, color: "var(--text)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: title }),
2546
2577
  meta ? /* @__PURE__ */ jsx38("span", { style: { fontSize: "var(--overline-size)", color: "var(--text-muted)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: meta }) : null
2547
2578
  ] }),
@@ -2562,6 +2593,7 @@ function EntityRow({ title, meta, action, draggable = false, onDragStart, onDrag
2562
2593
 
2563
2594
  // src/components/data/TransferList.tsx
2564
2595
  import * as React16 from "react";
2596
+ import { createPortal as createPortal4 } from "react-dom";
2565
2597
 
2566
2598
  // src/components/forms/Input.tsx
2567
2599
  import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
@@ -2658,6 +2690,7 @@ function SearchField({
2658
2690
  // src/components/data/TransferList.tsx
2659
2691
  import { jsx as jsx41, jsxs as jsxs36 } from "react/jsx-runtime";
2660
2692
  var emptyHasMore = {};
2693
+ var DRAG_THRESHOLD_PX = 5;
2661
2694
  function TransferList({
2662
2695
  left,
2663
2696
  right,
@@ -2669,97 +2702,199 @@ function TransferList({
2669
2702
  listHeight = 440,
2670
2703
  className = ""
2671
2704
  }) {
2672
- const [dragging, setDragging] = React16.useState(null);
2705
+ const [drag, setDrag] = React16.useState(null);
2673
2706
  const [dragOverSide, setDragOverSide] = React16.useState(null);
2674
- const startDrag = (e, item, from) => {
2675
- const key = keyOf(item);
2676
- setDragging({ key, from });
2677
- e.dataTransfer.effectAllowed = "move";
2678
- e.dataTransfer.setData("text/plain", String(key));
2679
- };
2680
- const endDrag = () => {
2681
- setDragging(null);
2682
- setDragOverSide(null);
2683
- };
2684
- const findItem = (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key);
2685
- const dropOnSide = (e, side) => {
2707
+ const dragRef = React16.useRef(null);
2708
+ const armedRef = React16.useRef(null);
2709
+ const sideRefs = React16.useRef({ left: null, right: null });
2710
+ const hitTestSide = React16.useCallback((x, y) => {
2711
+ for (const side of ["left", "right"]) {
2712
+ const el = sideRefs.current[side];
2713
+ if (!el) continue;
2714
+ const r = el.getBoundingClientRect();
2715
+ if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) return side;
2716
+ }
2717
+ return null;
2718
+ }, []);
2719
+ const findItem = React16.useCallback(
2720
+ (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
2721
+ [left.items, right.items, keyOf]
2722
+ );
2723
+ const beginDrag = (e, item, from) => {
2724
+ if (e.button !== 0) return;
2725
+ if (e.target.closest && e.target.closest("button")) return;
2686
2726
  e.preventDefault();
2687
- setDragOverSide(null);
2688
- if (!dragging || dragging.from === side) return;
2689
- const item = findItem(dragging.from, dragging.key);
2690
- if (item !== void 0) onMove(item, dragging.from, side);
2691
- setDragging(null);
2727
+ const rect = e.currentTarget.getBoundingClientRect();
2728
+ armedRef.current = {
2729
+ item,
2730
+ from,
2731
+ key: keyOf(item),
2732
+ pointerId: e.pointerId,
2733
+ startX: e.clientX,
2734
+ startY: e.clientY,
2735
+ offsetX: e.clientX - rect.left,
2736
+ offsetY: e.clientY - rect.top,
2737
+ width: rect.width,
2738
+ height: rect.height
2739
+ };
2692
2740
  };
2693
- const renderSide = (side, cfg, opposite) => /* @__PURE__ */ jsxs36(
2694
- "div",
2695
- {
2696
- style: {
2697
- flex: 1,
2698
- minWidth: 0,
2699
- display: "flex",
2700
- flexDirection: "column",
2701
- gap: 8,
2702
- padding: 10,
2703
- borderRadius: 10,
2704
- border: "1px solid " + (dragOverSide === side ? "var(--brand)" : "var(--border)"),
2705
- background: "var(--surface)"
2706
- },
2707
- onDragOver: (e) => {
2708
- if (!dragging || dragging.from === side) return;
2709
- e.preventDefault();
2710
- e.dataTransfer.dropEffect = "move";
2711
- if (dragOverSide !== side) setDragOverSide(side);
2712
- },
2713
- onDragLeave: (e) => {
2714
- if (e.currentTarget.contains(e.relatedTarget)) return;
2715
- setDragOverSide((s) => s === side ? null : s);
2716
- },
2717
- onDrop: (e) => dropOnSide(e, side),
2718
- children: [
2719
- cfg.label ? /* @__PURE__ */ jsxs36("span", { className: "fd-overline fd-muted", children: [
2720
- cfg.label,
2721
- cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
2722
- ] }) : null,
2723
- /* @__PURE__ */ jsxs36("span", { className: "fd-row", style: { gap: 8 }, children: [
2724
- /* @__PURE__ */ jsx41(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
2725
- /* @__PURE__ */ jsx41(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
2726
- ] }),
2727
- /* @__PURE__ */ jsx41(
2728
- VirtualList,
2729
- {
2730
- items: cfg.items,
2731
- itemHeight,
2732
- height: listHeight,
2733
- keyOf,
2734
- loading: cfg.loading,
2735
- hasMore: cfg.hasMore || emptyHasMore,
2736
- onNeedMore: cfg.onNeedMore,
2737
- emptyState: /* @__PURE__ */ jsx41(EmptyState, { icon: "tray", title: "Nothing here" }),
2738
- renderItem: (item) => /* @__PURE__ */ jsx41(
2739
- EntityRow,
2740
- {
2741
- title: renderLabel(item),
2742
- meta: renderMeta ? renderMeta(item) : void 0,
2743
- draggable: true,
2744
- onDragStart: (e) => startDrag(e, item, side),
2745
- onDragEnd: endDrag,
2746
- style: { opacity: dragging && dragging.from === side && dragging.key === keyOf(item) ? 0.4 : 1 },
2747
- action: {
2748
- icon: side === "left" ? "plus" : "minus",
2749
- label: (side === "left" ? "Move to " : "Move from ") + (side === "left" ? right.label || "the other list" : left.label || "the other list"),
2750
- tone: side === "left" ? "add" : "remove",
2751
- onClick: () => onMove(item, side, opposite)
2741
+ React16.useEffect(() => {
2742
+ const onMovePointer = (e) => {
2743
+ const armed = armedRef.current;
2744
+ if (!armed || e.pointerId !== armed.pointerId) return;
2745
+ if (!dragRef.current) {
2746
+ const dx = e.clientX - armed.startX;
2747
+ const dy = e.clientY - armed.startY;
2748
+ if (Math.hypot(dx, dy) < DRAG_THRESHOLD_PX) return;
2749
+ const started = {
2750
+ item: armed.item,
2751
+ from: armed.from,
2752
+ key: armed.key,
2753
+ pointerId: armed.pointerId,
2754
+ offsetX: armed.offsetX,
2755
+ offsetY: armed.offsetY,
2756
+ width: armed.width,
2757
+ height: armed.height,
2758
+ x: e.clientX,
2759
+ y: e.clientY
2760
+ };
2761
+ dragRef.current = started;
2762
+ setDrag(started);
2763
+ } else {
2764
+ dragRef.current = { ...dragRef.current, x: e.clientX, y: e.clientY };
2765
+ setDrag(dragRef.current);
2766
+ }
2767
+ const hit = hitTestSide(e.clientX, e.clientY);
2768
+ setDragOverSide(hit && hit !== armed.from ? hit : null);
2769
+ };
2770
+ const endDrag = (e) => {
2771
+ const armed = armedRef.current;
2772
+ if (!armed || e.pointerId !== armed.pointerId) return;
2773
+ const wasDragging = dragRef.current;
2774
+ armedRef.current = null;
2775
+ dragRef.current = null;
2776
+ setDrag(null);
2777
+ setDragOverSide(null);
2778
+ if (!wasDragging) return;
2779
+ const hit = hitTestSide(e.clientX, e.clientY);
2780
+ if (hit && hit !== armed.from) {
2781
+ const item = findItem(armed.from, armed.key);
2782
+ if (item !== void 0) onMove(item, armed.from, hit);
2783
+ }
2784
+ };
2785
+ window.addEventListener("pointermove", onMovePointer);
2786
+ window.addEventListener("pointerup", endDrag);
2787
+ window.addEventListener("pointercancel", endDrag);
2788
+ return () => {
2789
+ window.removeEventListener("pointermove", onMovePointer);
2790
+ window.removeEventListener("pointerup", endDrag);
2791
+ window.removeEventListener("pointercancel", endDrag);
2792
+ };
2793
+ }, [hitTestSide, findItem, onMove]);
2794
+ React16.useEffect(() => {
2795
+ if (!drag || typeof document === "undefined") return;
2796
+ const prev = document.body.style.userSelect;
2797
+ document.body.style.userSelect = "none";
2798
+ return () => {
2799
+ document.body.style.userSelect = prev;
2800
+ };
2801
+ }, [drag]);
2802
+ const renderSide = (side, cfg, opposite) => {
2803
+ const showOverlay = drag != null && dragOverSide === side;
2804
+ return /* @__PURE__ */ jsxs36(
2805
+ "div",
2806
+ {
2807
+ ref: (el) => {
2808
+ sideRefs.current[side] = el;
2809
+ },
2810
+ style: {
2811
+ flex: 1,
2812
+ minWidth: 0,
2813
+ display: "flex",
2814
+ flexDirection: "column",
2815
+ gap: 8,
2816
+ padding: 10,
2817
+ borderRadius: 10,
2818
+ border: "1px solid " + (dragOverSide === side ? "var(--brand)" : "var(--border)"),
2819
+ background: "var(--surface)",
2820
+ position: "relative"
2821
+ },
2822
+ children: [
2823
+ cfg.label ? /* @__PURE__ */ jsxs36("span", { className: "fd-overline fd-muted", children: [
2824
+ cfg.label,
2825
+ cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
2826
+ ] }) : null,
2827
+ /* @__PURE__ */ jsxs36("span", { className: "fd-row", style: { gap: 8 }, children: [
2828
+ /* @__PURE__ */ jsx41(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
2829
+ /* @__PURE__ */ jsx41(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
2830
+ ] }),
2831
+ /* @__PURE__ */ jsx41(
2832
+ VirtualList,
2833
+ {
2834
+ items: cfg.items,
2835
+ itemHeight,
2836
+ height: listHeight,
2837
+ keyOf,
2838
+ loading: cfg.loading,
2839
+ refreshing: cfg.refreshing,
2840
+ hasMore: cfg.hasMore || emptyHasMore,
2841
+ onNeedMore: cfg.onNeedMore,
2842
+ emptyState: /* @__PURE__ */ jsx41(EmptyState, { icon: "tray", title: "Nothing here" }),
2843
+ renderItem: (item) => {
2844
+ const isBeingDragged = drag != null && drag.from === side && drag.key === keyOf(item);
2845
+ if (isBeingDragged) {
2846
+ return /* @__PURE__ */ jsx41("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
2752
2847
  }
2848
+ return /* @__PURE__ */ jsx41(
2849
+ EntityRow,
2850
+ {
2851
+ title: renderLabel(item),
2852
+ meta: renderMeta ? renderMeta(item) : void 0,
2853
+ draggable: true,
2854
+ onPointerDown: (e) => beginDrag(e, item, side),
2855
+ action: {
2856
+ icon: side === "left" ? "plus" : "minus",
2857
+ label: (side === "left" ? "Move to " : "Move from ") + (side === "left" ? right.label || "the other list" : left.label || "the other list"),
2858
+ tone: side === "left" ? "add" : "remove",
2859
+ onClick: () => onMove(item, side, opposite)
2860
+ }
2861
+ }
2862
+ );
2753
2863
  }
2754
- )
2755
- }
2756
- )
2757
- ]
2758
- }
2759
- );
2864
+ }
2865
+ ),
2866
+ showOverlay ? /* @__PURE__ */ jsx41("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ jsxs36("span", { className: "fd-tlist-drop-card", children: [
2867
+ /* @__PURE__ */ jsx41("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
2868
+ /* @__PURE__ */ jsx41("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
2869
+ ] }) }) : null
2870
+ ]
2871
+ }
2872
+ );
2873
+ };
2760
2874
  return /* @__PURE__ */ jsxs36("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
2761
2875
  renderSide("left", left, "right"),
2762
- renderSide("right", right, "left")
2876
+ renderSide("right", right, "left"),
2877
+ drag ? createPortal4(
2878
+ /* @__PURE__ */ jsx41(
2879
+ "div",
2880
+ {
2881
+ "aria-hidden": "true",
2882
+ className: "fd-erow-ghost",
2883
+ style: {
2884
+ position: "fixed",
2885
+ left: 0,
2886
+ top: 0,
2887
+ width: drag.width,
2888
+ height: drag.height,
2889
+ transform: `translate(${drag.x - drag.offsetX}px, ${drag.y - drag.offsetY}px) rotate(-3deg)`,
2890
+ pointerEvents: "none",
2891
+ zIndex: 1e3
2892
+ },
2893
+ children: /* @__PURE__ */ jsx41(EntityRow, { title: renderLabel(drag.item), meta: renderMeta ? renderMeta(drag.item) : void 0, draggable: true, className: "fd-erow-dragging" })
2894
+ }
2895
+ ),
2896
+ document.body
2897
+ ) : null
2763
2898
  ] });
2764
2899
  }
2765
2900
 
@@ -2969,7 +3104,7 @@ function NumberInput({
2969
3104
 
2970
3105
  // src/components/forms/Select.tsx
2971
3106
  import * as React19 from "react";
2972
- import { createPortal as createPortal4 } from "react-dom";
3107
+ import { createPortal as createPortal5 } from "react-dom";
2973
3108
  import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
2974
3109
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
2975
3110
  function usePopPos(open, ref, estH, estW) {
@@ -3175,7 +3310,7 @@ function Select({
3175
3310
  ) : null,
3176
3311
  loading ? /* @__PURE__ */ jsx47("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx47("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx47("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3177
3312
  ] }),
3178
- open && pos ? createPortal4(
3313
+ open && pos ? createPortal5(
3179
3314
  /* @__PURE__ */ jsxs42(
3180
3315
  "div",
3181
3316
  {
@@ -3272,7 +3407,7 @@ function Select({
3272
3407
 
3273
3408
  // src/components/forms/DatePicker.tsx
3274
3409
  import * as React20 from "react";
3275
- import { createPortal as createPortal5 } from "react-dom";
3410
+ import { createPortal as createPortal6 } from "react-dom";
3276
3411
  import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
3277
3412
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3278
3413
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
@@ -3501,7 +3636,7 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3501
3636
  ),
3502
3637
  /* @__PURE__ */ jsx48("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3503
3638
  ] }),
3504
- open && pos ? createPortal5(
3639
+ open && pos ? createPortal6(
3505
3640
  /* @__PURE__ */ jsx48("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ jsx48(
3506
3641
  Calendar,
3507
3642
  {
@@ -3525,7 +3660,7 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3525
3660
 
3526
3661
  // src/components/forms/TimePicker.tsx
3527
3662
  import * as React21 from "react";
3528
- import { createPortal as createPortal6 } from "react-dom";
3663
+ import { createPortal as createPortal7 } from "react-dom";
3529
3664
  import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
3530
3665
  var pad = (n) => String(n).padStart(2, "0");
3531
3666
  function usePopPos3(open, ref, estH, estW) {
@@ -3704,7 +3839,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
3704
3839
  ),
3705
3840
  /* @__PURE__ */ jsx49("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3706
3841
  ] }),
3707
- open && pos ? createPortal6(
3842
+ open && pos ? createPortal7(
3708
3843
  /* @__PURE__ */ jsxs44("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
3709
3844
  /* @__PURE__ */ jsx49(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
3710
3845
  /* @__PURE__ */ jsxs44("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
@@ -4166,7 +4301,7 @@ function FileTile({ file, onOpen, onRemove, maxHeight = 200, className = "" }) {
4166
4301
  function FileStrip({ files = [], size = 68, onOpen, onRemove, onRetry, className = "" }) {
4167
4302
  const list = files.filter(Boolean);
4168
4303
  if (!list.length) return null;
4169
- return /* @__PURE__ */ jsx53("div", { className: ["fd-filestrip", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx53(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
4304
+ return /* @__PURE__ */ jsx53("div", { className: ["fd-filestrip", "fd-scrollbar", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx53(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
4170
4305
  }
4171
4306
  var shortName = (name, keep = 5) => {
4172
4307
  const s = String(name || "file");
@@ -7164,7 +7299,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7164
7299
 
7165
7300
  // src/components/platform/ComingSoon.tsx
7166
7301
  import * as React32 from "react";
7167
- import { createPortal as createPortal7 } from "react-dom";
7302
+ import { createPortal as createPortal8 } from "react-dom";
7168
7303
  import { Fragment as Fragment13, jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
7169
7304
  var BYPASS_STORE = "fd.soon.bypass.v1";
7170
7305
  function readBypassed() {
@@ -7405,7 +7540,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7405
7540
  children: /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7406
7541
  }
7407
7542
  ),
7408
- open && pos ? createPortal7(
7543
+ open && pos ? createPortal8(
7409
7544
  /* @__PURE__ */ jsx59(
7410
7545
  "div",
7411
7546
  {