@upbound/monarch-blocks 0.8.0 → 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
@@ -2863,21 +2863,74 @@ function ChatInterface(_a) {
2863
2863
  }
2864
2864
 
2865
2865
  // src/code-block.tsx
2866
- import { useEffect as useEffect3, useState as useState5 } from "react";
2866
+ import { useCallback as useCallback3, useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState5 } from "react";
2867
2867
  import { Icon as Icon3 } from "@upbound/monarch-core";
2868
2868
  import {
2869
2869
  Card,
2870
2870
  CardContent,
2871
2871
  CardFooter,
2872
2872
  CardHeader,
2873
+ InputGroup as InputGroup3,
2874
+ InputGroupAddon as InputGroupAddon3,
2875
+ InputGroupButton,
2876
+ InputGroupInput as InputGroupInput2,
2877
+ InputGroupText as InputGroupText2,
2873
2878
  Tooltip as Tooltip3,
2874
2879
  TooltipContent as TooltipContent2,
2875
2880
  TooltipTrigger as TooltipTrigger2
2876
2881
  } from "@upbound/monarch-core";
2877
2882
 
2883
+ // src/lib/find-text.ts
2884
+ function findTextRanges(root, query) {
2885
+ var _a, _b;
2886
+ const needle = query.toLowerCase();
2887
+ if (!needle) return [];
2888
+ const doc = (_a = root.ownerDocument) != null ? _a : document;
2889
+ const walker = doc.createTreeWalker(root, NodeFilter.SHOW_TEXT);
2890
+ const nodes = [];
2891
+ const starts = [];
2892
+ let text = "";
2893
+ for (let node = walker.nextNode(); node; node = walker.nextNode()) {
2894
+ nodes.push(node);
2895
+ starts.push(text.length);
2896
+ text += (_b = node.nodeValue) != null ? _b : "";
2897
+ }
2898
+ let nodeIndex = 0;
2899
+ const locate = (offset, isEnd) => {
2900
+ while (nodeIndex < nodes.length - 1 && (isEnd ? starts[nodeIndex + 1] < offset : starts[nodeIndex + 1] <= offset)) {
2901
+ nodeIndex++;
2902
+ }
2903
+ return [nodes[nodeIndex], offset - starts[nodeIndex]];
2904
+ };
2905
+ const haystack = text.toLowerCase();
2906
+ const ranges = [];
2907
+ for (let at = haystack.indexOf(needle); at !== -1; at = haystack.indexOf(needle, at + needle.length)) {
2908
+ const range = doc.createRange();
2909
+ range.setStart(...locate(at, false));
2910
+ range.setEnd(...locate(at + needle.length, true));
2911
+ ranges.push(range);
2912
+ }
2913
+ return ranges;
2914
+ }
2915
+
2916
+ // src/lib/search-input.ts
2917
+ var SEARCH_INPUT_PROPS = {
2918
+ type: "search",
2919
+ autoComplete: "off",
2920
+ "data-1p-ignore": true,
2921
+ // 1Password
2922
+ "data-lpignore": "true",
2923
+ // LastPass
2924
+ "data-bwignore": true,
2925
+ // Bitwarden
2926
+ "data-form-type": "other"
2927
+ // Dashlane
2928
+ };
2929
+ var SEARCH_INPUT_CLASS = "[&::-webkit-search-cancel-button]:appearance-none";
2930
+
2878
2931
  // src/lib/highlight.ts
2879
2932
  import { createHighlighter } from "shiki";
2880
- var CODE_BLOCK_LANGUAGES = ["tsx", "typescript", "bash", "shell", "json", "css", "yaml"];
2933
+ var CODE_BLOCK_LANGUAGES = ["tsx", "typescript", "bash", "shell", "json", "css", "yaml", "python"];
2881
2934
  var HIGHLIGHTER_KEY = "__monarch_shiki_highlighter__";
2882
2935
  function getHighlighter() {
2883
2936
  const g = globalThis;
@@ -2956,23 +3009,84 @@ var LINE_NUMBER_GUTTER = cn(
2956
3009
  "[&_.line]:before:text-[0.75rem]",
2957
3010
  "[&_.line]:before:select-none"
2958
3011
  );
3012
+ var SHIKI_DARK_THEME = [
3013
+ "dark:[&_.shiki]:text-(--shiki-dark)!",
3014
+ "dark:[&_.shiki_span]:text-(--shiki-dark)!",
3015
+ "dark:[&_.shiki_span]:[font-style:var(--shiki-dark-font-style)]!",
3016
+ "dark:[&_.shiki_span]:[font-weight:var(--shiki-dark-font-weight)]!",
3017
+ "dark:[&_.shiki_span]:[text-decoration:var(--shiki-dark-text-decoration)]!"
3018
+ ];
3019
+ var CODE_BLOCK_ICON_BUTTON = cn(
3020
+ "border-border bg-background inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border motion-safe:transition-colors",
3021
+ "text-muted-foreground hover:bg-accent hover:text-foreground",
3022
+ "focus-visible:ring-ring/30 focus-visible:ring-2 focus-visible:outline-none",
3023
+ "group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted group-data-[variant=terminal]/code-block:hover:bg-terminal-muted-hover-bg group-data-[variant=terminal]/code-block:hover:text-terminal-muted-hover-fg"
3024
+ );
3025
+ function supportsHighlights() {
3026
+ return typeof CSS !== "undefined" && "highlights" in CSS && typeof Highlight !== "undefined";
3027
+ }
3028
+ function useCodeSearch(codeRef, query, renderedCode) {
3029
+ const id = useId2().replace(/[^a-zA-Z0-9_-]/g, "");
3030
+ const names = { all: `code-find-${id}`, current: `code-find-${id}-current` };
3031
+ const [ranges, setRanges] = useState5([]);
3032
+ const [current, setCurrent] = useState5(0);
3033
+ useEffect3(() => {
3034
+ const root = codeRef.current;
3035
+ const next = root ? findTextRanges(root, query) : [];
3036
+ setRanges(next);
3037
+ setCurrent(0);
3038
+ if (!supportsHighlights() || next.length === 0) return;
3039
+ CSS.highlights.set(names.all, new Highlight(...next));
3040
+ return () => {
3041
+ CSS.highlights.delete(names.all);
3042
+ };
3043
+ }, [codeRef, query, renderedCode, names.all]);
3044
+ useEffect3(() => {
3045
+ var _a, _b;
3046
+ const range = ranges[current];
3047
+ if (!range) return;
3048
+ (_b = (_a = range.startContainer.parentElement) == null ? void 0 : _a.scrollIntoView) == null ? void 0 : _b.call(_a, { block: "nearest", inline: "nearest" });
3049
+ if (!supportsHighlights()) return;
3050
+ CSS.highlights.set(names.current, new Highlight(range));
3051
+ return () => {
3052
+ CSS.highlights.delete(names.current);
3053
+ };
3054
+ }, [ranges, current, names.current]);
3055
+ const step = (by) => setCurrent((i) => ranges.length ? (i + by + ranges.length) % ranges.length : 0);
3056
+ return {
3057
+ count: ranges.length,
3058
+ current,
3059
+ next: () => step(1),
3060
+ previous: () => step(-1),
3061
+ highlightCss: `::highlight(${names.all}){background-color:color-mix(in oklch,var(--status-warning) 30%,transparent)}::highlight(${names.current}){background-color:color-mix(in oklch,var(--status-warning) 65%,transparent)}`
3062
+ };
3063
+ }
2959
3064
  function CodeBlockBody(_a) {
2960
3065
  var _b = _a, {
2961
3066
  className,
2962
3067
  code,
2963
3068
  maxHeight,
3069
+ searchable = false,
2964
3070
  copyButton,
2965
3071
  downloadButton
2966
3072
  } = _b, props = __objRest(_b, [
2967
3073
  "className",
2968
3074
  "code",
2969
3075
  "maxHeight",
3076
+ "searchable",
2970
3077
  "copyButton",
2971
3078
  "downloadButton"
2972
3079
  ]);
2973
3080
  const { content, lineNumbers } = code;
2974
3081
  const [html, setHtml] = useState5(null);
2975
3082
  const language = code.type === "parsed" ? code.language : null;
3083
+ const [searchOpen, setSearchOpen] = useState5(false);
3084
+ const [query, setQuery] = useState5("");
3085
+ const codeRef = useRef3(null);
3086
+ const searchInputRef = useRef3(null);
3087
+ const searchInputId = `code-search-${useId2()}`;
3088
+ const searchButtonRef = useRef3(null);
3089
+ const search = useCodeSearch(codeRef, searchOpen ? query : "", html != null ? html : content);
2976
3090
  useEffect3(() => {
2977
3091
  if (!language) {
2978
3092
  setHtml(null);
@@ -2986,32 +3100,127 @@ function CodeBlockBody(_a) {
2986
3100
  cancelled = true;
2987
3101
  };
2988
3102
  }, [content, language]);
2989
- return /* @__PURE__ */ jsxs4(CardContent, __spreadProps(__spreadValues({ "data-line-numbers": lineNumbers || void 0, className: cn("relative p-0!", className) }, props), { children: [
2990
- (copyButton || downloadButton) && /* @__PURE__ */ jsxs4("div", { className: "absolute top-2 right-2 z-10 flex items-center gap-1 opacity-0 transition-opacity group-hover/code-block:opacity-100", children: [
2991
- copyButton,
2992
- downloadButton
2993
- ] }),
2994
- /* @__PURE__ */ jsx6(
2995
- "div",
3103
+ const openSearch = () => {
3104
+ var _a2, _b2;
3105
+ setSearchOpen(true);
3106
+ (_a2 = searchInputRef.current) == null ? void 0 : _a2.focus();
3107
+ (_b2 = searchInputRef.current) == null ? void 0 : _b2.select();
3108
+ };
3109
+ const closeSearch = useCallback3(() => {
3110
+ var _a2;
3111
+ setSearchOpen(false);
3112
+ setQuery("");
3113
+ (_a2 = searchButtonRef.current) == null ? void 0 : _a2.focus();
3114
+ }, []);
3115
+ useEffect3(() => {
3116
+ if (!searchOpen) return;
3117
+ const onKeyDown = (event) => {
3118
+ if (event.key !== "Escape" || event.target !== searchInputRef.current) return;
3119
+ event.preventDefault();
3120
+ event.stopPropagation();
3121
+ closeSearch();
3122
+ };
3123
+ window.addEventListener("keydown", onKeyDown, { capture: true });
3124
+ return () => window.removeEventListener("keydown", onKeyDown, { capture: true });
3125
+ }, [searchOpen, closeSearch]);
3126
+ const searchButton = searchable && /* @__PURE__ */ jsxs4(Tooltip3, { children: [
3127
+ /* @__PURE__ */ jsx6(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx6(
3128
+ "button",
2996
3129
  {
2997
- className: cn("overflow-x-auto", maxHeight && "overflow-y-auto"),
2998
- style: maxHeight ? { maxHeight } : void 0,
2999
- children: /* @__PURE__ */ jsx6(
3000
- "div",
3001
- {
3002
- className: cn(
3003
- "[&_code]:font-mono [&_pre]:m-0 [&_pre]:p-4 group-data-[size=sm]/code-block:[&_pre]:p-3",
3004
- html && "[&_pre]:bg-transparent!",
3005
- lineNumbers && LINE_NUMBER_GUTTER
3006
- ),
3007
- children: html ? /* @__PURE__ */ jsx6("div", { dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx6("pre", { children: /* @__PURE__ */ jsx6("code", { className: lineNumbers ? void 0 : "whitespace-pre", children: lineNumbers ? content.split("\n").map((line, i) => /* @__PURE__ */ jsxs4("span", { className: "line", children: [
3008
- line,
3009
- "\n"
3010
- ] }, i)) : content }) })
3011
- }
3012
- )
3130
+ ref: searchButtonRef,
3131
+ type: "button",
3132
+ "data-slot": "code-block-search-button",
3133
+ "aria-label": "Search",
3134
+ "aria-expanded": searchOpen,
3135
+ onClick: openSearch,
3136
+ className: CODE_BLOCK_ICON_BUTTON,
3137
+ children: /* @__PURE__ */ jsx6(Icon3, { name: "magnifying-glass", size: "sm" })
3013
3138
  }
3014
- )
3139
+ ) }),
3140
+ /* @__PURE__ */ jsx6(TooltipContent2, { children: "Search" })
3141
+ ] });
3142
+ return /* @__PURE__ */ jsxs4(CardContent, __spreadProps(__spreadValues({ "data-line-numbers": lineNumbers || void 0, className: cn("relative p-0!", className) }, props), { children: [
3143
+ searchable && searchOpen && /* @__PURE__ */ jsxs4("div", { "data-slot": "code-block-search", className: "p-2", children: [
3144
+ /* @__PURE__ */ jsx6("style", { children: search.highlightCss }),
3145
+ /* @__PURE__ */ jsxs4(InputGroup3, { children: [
3146
+ /* @__PURE__ */ jsx6(InputGroupAddon3, { children: /* @__PURE__ */ jsx6(Icon3, { name: "magnifying-glass" }) }),
3147
+ /* @__PURE__ */ jsx6(
3148
+ InputGroupInput2,
3149
+ __spreadProps(__spreadValues({
3150
+ ref: searchInputRef,
3151
+ autoFocus: true
3152
+ }, SEARCH_INPUT_PROPS), {
3153
+ id: searchInputId,
3154
+ className: SEARCH_INPUT_CLASS,
3155
+ placeholder: "Find\u2026",
3156
+ "aria-label": "Find in code",
3157
+ value: query,
3158
+ onChange: (e) => setQuery(e.target.value),
3159
+ onKeyDown: (e) => {
3160
+ if (e.key === "Enter") {
3161
+ e.preventDefault();
3162
+ if (e.shiftKey) search.previous();
3163
+ else search.next();
3164
+ }
3165
+ }
3166
+ })
3167
+ ),
3168
+ /* @__PURE__ */ jsxs4(InputGroupAddon3, { align: "inline-end", children: [
3169
+ /* @__PURE__ */ jsx6(InputGroupText2, { "aria-live": "polite", className: "text-caption tabular-nums", children: query ? search.count ? `${search.current + 1} of ${search.count}` : "No results" : null }),
3170
+ /* @__PURE__ */ jsx6(
3171
+ InputGroupButton,
3172
+ {
3173
+ size: "icon-xs",
3174
+ "aria-label": "Previous match",
3175
+ disabled: search.count === 0,
3176
+ onClick: search.previous,
3177
+ children: /* @__PURE__ */ jsx6(Icon3, { name: "chevron-up" })
3178
+ }
3179
+ ),
3180
+ /* @__PURE__ */ jsx6(
3181
+ InputGroupButton,
3182
+ {
3183
+ size: "icon-xs",
3184
+ "aria-label": "Next match",
3185
+ disabled: search.count === 0,
3186
+ onClick: search.next,
3187
+ children: /* @__PURE__ */ jsx6(Icon3, { name: "chevron-down" })
3188
+ }
3189
+ ),
3190
+ /* @__PURE__ */ jsx6(InputGroupButton, { size: "icon-xs", "aria-label": "Close search", onClick: closeSearch, children: /* @__PURE__ */ jsx6(Icon3, { name: "xmark" }) })
3191
+ ] })
3192
+ ] })
3193
+ ] }),
3194
+ /* @__PURE__ */ jsxs4("div", { className: "relative", children: [
3195
+ (searchButton || copyButton || downloadButton) && /* @__PURE__ */ jsxs4("div", { className: "absolute top-2 right-2 z-10 flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code-block:opacity-100 group-hover/code-block:opacity-100", children: [
3196
+ searchButton,
3197
+ copyButton,
3198
+ downloadButton
3199
+ ] }),
3200
+ /* @__PURE__ */ jsx6(
3201
+ "div",
3202
+ {
3203
+ className: cn("overflow-x-auto", maxHeight && "overflow-y-auto"),
3204
+ style: maxHeight ? { maxHeight } : void 0,
3205
+ children: /* @__PURE__ */ jsx6(
3206
+ "div",
3207
+ {
3208
+ ref: codeRef,
3209
+ className: cn(
3210
+ "[&_code]:font-mono [&_pre]:m-0 [&_pre]:p-4 group-data-[size=sm]/code-block:[&_pre]:p-3",
3211
+ html && "[&_pre]:bg-transparent!",
3212
+ html && SHIKI_DARK_THEME,
3213
+ lineNumbers && LINE_NUMBER_GUTTER
3214
+ ),
3215
+ children: html ? /* @__PURE__ */ jsx6("div", { dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx6("pre", { children: /* @__PURE__ */ jsx6("code", { className: lineNumbers ? void 0 : "whitespace-pre", children: lineNumbers ? content.split("\n").map((line, i) => /* @__PURE__ */ jsxs4("span", { className: "line", children: [
3216
+ line,
3217
+ "\n"
3218
+ ] }, i)) : content }) })
3219
+ }
3220
+ )
3221
+ }
3222
+ )
3223
+ ] })
3015
3224
  ] }));
3016
3225
  }
3017
3226
  function CodeBlockFooter(_a) {
@@ -3046,13 +3255,7 @@ function CodeBlockCopyButton(_a) {
3046
3255
  __spreadProps(__spreadValues({
3047
3256
  "data-slot": "code-block-copy-button",
3048
3257
  onClick: handleCopy,
3049
- className: cn(
3050
- "border-border bg-background inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border motion-safe:transition-colors",
3051
- "text-muted-foreground hover:bg-accent hover:text-foreground",
3052
- "focus-visible:ring-ring/30 focus-visible:ring-2 focus-visible:outline-none",
3053
- "group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted group-data-[variant=terminal]/code-block:hover:bg-terminal-muted-hover-bg group-data-[variant=terminal]/code-block:hover:text-terminal-muted-hover-fg",
3054
- className
3055
- ),
3258
+ className: cn(CODE_BLOCK_ICON_BUTTON, className),
3056
3259
  "aria-label": copied ? "Copied" : "Copy code"
3057
3260
  }, props), {
3058
3261
  children: copied ? /* @__PURE__ */ jsx6(Icon3, { name: "check", size: "sm", className: "text-green-500" }) : /* @__PURE__ */ jsx6(Icon3, { name: "copy", size: "sm" })
@@ -3093,13 +3296,7 @@ function CodeBlockDownloadButton(_a) {
3093
3296
  __spreadProps(__spreadValues({
3094
3297
  "data-slot": "code-block-download-button",
3095
3298
  onClick: handleDownload,
3096
- className: cn(
3097
- "border-border bg-background inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border motion-safe:transition-colors",
3098
- "text-muted-foreground hover:bg-accent hover:text-foreground",
3099
- "focus-visible:ring-ring/30 focus-visible:ring-2 focus-visible:outline-none",
3100
- "group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted group-data-[variant=terminal]/code-block:hover:bg-terminal-muted-hover-bg group-data-[variant=terminal]/code-block:hover:text-terminal-muted-hover-fg",
3101
- className
3102
- ),
3299
+ className: cn(CODE_BLOCK_ICON_BUTTON, className),
3103
3300
  "aria-label": downloaded ? "Downloaded" : "Download code"
3104
3301
  }, props), {
3105
3302
  children: downloaded ? /* @__PURE__ */ jsx6(Icon3, { name: "check", size: "sm", className: "text-green-500" }) : /* @__PURE__ */ jsx6(Icon3, { name: "download", size: "sm" })
@@ -3645,7 +3842,7 @@ import {
3645
3842
  useReactTable
3646
3843
  } from "@tanstack/react-table";
3647
3844
  import { Icon as Icon11 } from "@upbound/monarch-core";
3648
- import { InputGroup as InputGroup3, InputGroupAddon as InputGroupAddon3, InputGroupInput as InputGroupInput2 } from "@upbound/monarch-core";
3845
+ import { InputGroup as InputGroup4, InputGroupAddon as InputGroupAddon4, InputGroupInput as InputGroupInput3 } from "@upbound/monarch-core";
3649
3846
 
3650
3847
  // src/lib/data-table/contextual-filters.ts
3651
3848
  function valueToString(value) {
@@ -3741,7 +3938,7 @@ function getColumnFilterCount(filterValue, filter) {
3741
3938
  }
3742
3939
 
3743
3940
  // src/hooks/use-table-column-resizing.ts
3744
- import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef3, useState as useState7 } from "react";
3941
+ import { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
3745
3942
  var RESIZE_MIN = 40;
3746
3943
  var RESIZE_MAX = 500;
3747
3944
  var RESIZE_MAX_UNBOUNDED = Number.MAX_SAFE_INTEGER;
@@ -3829,7 +4026,7 @@ function useTableColumnResizing({
3829
4026
  maxSize
3830
4027
  } = {}) {
3831
4028
  const [columnSizing, setColumnSizing] = useState7(() => clampSizing(initialSizing != null ? initialSizing : {}, maxSize));
3832
- const persistTimerRef = useRef3(null);
4029
+ const persistTimerRef = useRef4(null);
3833
4030
  useEffect4(() => {
3834
4031
  if (!initialSizing) return;
3835
4032
  const next = clampSizing(initialSizing, maxSize);
@@ -3844,14 +4041,14 @@ function useTableColumnResizing({
3844
4041
  if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
3845
4042
  };
3846
4043
  }, []);
3847
- const debouncedPersist = useCallback4(
4044
+ const debouncedPersist = useCallback5(
3848
4045
  (sizing) => {
3849
4046
  if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
3850
4047
  persistTimerRef.current = setTimeout(() => onColumnSizingPersist == null ? void 0 : onColumnSizingPersist(sizing), PERSIST_DEBOUNCE_MS);
3851
4048
  },
3852
4049
  [onColumnSizingPersist]
3853
4050
  );
3854
- const handleColumnSizingChange = useCallback4(
4051
+ const handleColumnSizingChange = useCallback5(
3855
4052
  (updaterOrValue) => {
3856
4053
  setColumnSizing((prev) => {
3857
4054
  const raw = typeof updaterOrValue === "function" ? updaterOrValue(prev) : updaterOrValue;
@@ -3862,18 +4059,18 @@ function useTableColumnResizing({
3862
4059
  },
3863
4060
  [debouncedPersist, maxSize]
3864
4061
  );
3865
- const cancelPendingPersist = useCallback4(() => {
4062
+ const cancelPendingPersist = useCallback5(() => {
3866
4063
  if (persistTimerRef.current) {
3867
4064
  clearTimeout(persistTimerRef.current);
3868
4065
  persistTimerRef.current = null;
3869
4066
  }
3870
4067
  }, []);
3871
- const handleAutosizeAll = useCallback4(() => {
4068
+ const handleAutosizeAll = useCallback5(() => {
3872
4069
  cancelPendingPersist();
3873
4070
  setColumnSizing({});
3874
4071
  onColumnSizingPersist == null ? void 0 : onColumnSizingPersist({});
3875
4072
  }, [cancelPendingPersist, onColumnSizingPersist]);
3876
- const handleAutosizeColumn = useCallback4(
4073
+ const handleAutosizeColumn = useCallback5(
3877
4074
  (columnId) => {
3878
4075
  cancelPendingPersist();
3879
4076
  setColumnSizing((prev) => {
@@ -3887,7 +4084,7 @@ function useTableColumnResizing({
3887
4084
  },
3888
4085
  [cancelPendingPersist, onColumnSizingPersist]
3889
4086
  );
3890
- const handleResetColumnSize = useCallback4(
4087
+ const handleResetColumnSize = useCallback5(
3891
4088
  (columnId) => {
3892
4089
  cancelPendingPersist();
3893
4090
  setColumnSizing((prev) => {
@@ -4501,7 +4698,7 @@ import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-r
4501
4698
  var HEADER_SURFACE_BG = "bg-[color-mix(in_oklch,var(--muted)_50%,var(--card))]";
4502
4699
  var TABLE_HEAD_CLASSES = "text-body-sm text-muted-foreground h-10 px-4 text-left align-middle font-medium whitespace-nowrap has-[[role=checkbox]]:pr-0";
4503
4700
  var TABLE_CELL_CLASSES = "px-4 py-2 align-middle whitespace-nowrap has-[[role=checkbox]]:pr-0";
4504
- var TABLE_ROW_CLASSES = "hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted border-b motion-safe:transition-colors";
4701
+ var TABLE_ROW_CLASSES = "hover:bg-muted/50 has-[[aria-haspopup][aria-expanded=true]]:bg-muted/50 data-[state=selected]:bg-muted border-b motion-safe:transition-colors";
4505
4702
  function DataTableRoot({
4506
4703
  layout = "auto",
4507
4704
  gridTemplateColumns,
@@ -4965,18 +5162,19 @@ function DataTableBody({
4965
5162
  );
4966
5163
  }
4967
5164
  const rows = tableRows.map((row) => {
4968
- var _a, _b, _c, _d;
5165
+ var _a, _b, _c, _d, _e;
4969
5166
  if ((_a = row.getIsGrouped) == null ? void 0 : _a.call(row)) {
4970
5167
  const groupLabel = (_c = row.groupingValue) != null ? _c : row.groupingColumnId ? (_b = row.getGroupingValue) == null ? void 0 : _b.call(row, row.groupingColumnId) : void 0;
4971
5168
  return /* @__PURE__ */ jsx13(DataTableGroupRow, { groupLabel: String(groupLabel != null ? groupLabel : ""), colSpan, layout }, row.id);
4972
5169
  }
4973
- const isExpanded = !!(renderExpandedRow && ((_d = row.getIsExpanded) == null ? void 0 : _d.call(row)));
4974
- const expandedRow = renderExpandedRow ? renderExpandedRow(row.original) : null;
5170
+ const isExpanded = !!(((_d = row.getCanExpand) == null ? void 0 : _d.call(row)) && ((_e = row.getIsExpanded) == null ? void 0 : _e.call(row)));
5171
+ const expandedRow = renderExpandedRow && isExpanded ? renderExpandedRow(row.original) : null;
4975
5172
  return /* @__PURE__ */ jsxs11(React8.Fragment, { children: [
4976
5173
  /* @__PURE__ */ jsx13(
4977
5174
  DataTableRow,
4978
- __spreadProps(__spreadValues({}, onRowRender ? onRowRender(row.original) : {}), {
5175
+ __spreadProps(__spreadValues({}, onRowRender ? onRowRender(row.original, row) : {}), {
4979
5176
  "data-expanded": isExpanded || void 0,
5177
+ "data-depth": row.depth || void 0,
4980
5178
  layout,
4981
5179
  children: row.getVisibleCells().filter((cell) => !isFilterOnlyColumn(cell.column)).map((cell) => /* @__PURE__ */ jsx13(
4982
5180
  DataTableCell,
@@ -4992,7 +5190,7 @@ function DataTableBody({
4992
5190
  ))
4993
5191
  })
4994
5192
  ),
4995
- /* @__PURE__ */ jsx13(DataTableExpandedRow, { colSpan, show: isExpanded, layout, children: expandedRow })
5193
+ /* @__PURE__ */ jsx13(DataTableExpandedRow, { colSpan, show: expandedRow != null, layout, children: expandedRow })
4996
5194
  ] }, row.id);
4997
5195
  });
4998
5196
  if (isGrid) {
@@ -5727,7 +5925,8 @@ function DataTable({
5727
5925
  renderExpandedRow,
5728
5926
  expanded: parentExpanded,
5729
5927
  onExpandedChange: parentOnExpandedChange,
5730
- disableSearch = false,
5928
+ disableSearch: deprecatedDisableSearch = false,
5929
+ search,
5731
5930
  disableFilters = false,
5732
5931
  disableSorting = false,
5733
5932
  paginationConfig = true,
@@ -5762,8 +5961,9 @@ function DataTable({
5762
5961
  celFilterConfig,
5763
5962
  filterVisibility
5764
5963
  }) {
5765
- var _a, _b, _c, _d, _e, _f;
5964
+ var _a, _b, _c, _d, _e, _f, _g, _h;
5766
5965
  const isGrid = layout === "grid";
5966
+ const searchInputId = `table-search-${React11.useId()}`;
5767
5967
  const tableBodyScrollRef = React11.useRef(null);
5768
5968
  const [innerGlobalFilter, setInnerGlobalFilter] = React11.useState("");
5769
5969
  const [innerColumnOrdering, setInnerColumnOrdering] = React11.useState([]);
@@ -5836,23 +6036,24 @@ function DataTable({
5836
6036
  const grouping = parentGrouping != null ? parentGrouping : innerGrouping;
5837
6037
  const setGrouping = parentSetGrouping != null ? parentSetGrouping : setInnerGrouping;
5838
6038
  const hasGrouping = grouping.length > 0;
6039
+ const hasSubRows = !!config.getSubRows;
6040
+ const hasExpansion = !!renderExpandedRow || hasSubRows;
6041
+ const disableSearch = (_f = search == null ? void 0 : search.disabled) != null ? _f : deprecatedDisableSearch;
5839
6042
  const hasExternalSearch = parentGlobalFilter !== void 0;
5840
6043
  const hasExternalFilters = parentColumnFilters !== void 0;
5841
6044
  const shouldDisableFiltersModels = !!disableFilters && !!disableSearch && !hasExternalSearch && !hasExternalFilters;
5842
- const table = useReactTable(__spreadProps(__spreadValues(__spreadProps(__spreadValues(__spreadProps(__spreadValues({}, config), {
6045
+ const table = useReactTable(__spreadProps(__spreadValues(__spreadProps(__spreadValues(__spreadValues(__spreadProps(__spreadValues({}, config), {
5843
6046
  getCoreRowModel: getCoreRowModel(),
5844
6047
  getSortedRowModel: !disableSorting ? getSortedRowModel() : void 0,
5845
6048
  getPaginationRowModel: !shouldDisablePagination ? getPaginationRowModel() : void 0,
5846
6049
  getFilteredRowModel: !shouldDisableFiltersModels ? getFilteredRowModel() : void 0,
5847
6050
  getFacetedRowModel: !shouldDisableFiltersModels ? getFacetedRowModel() : void 0,
5848
6051
  getFacetedUniqueValues: !shouldDisableFiltersModels ? getFacetedUniqueValues() : void 0
5849
- }), !!renderExpandedRow && {
5850
- getExpandedRowModel: getExpandedRowModel(),
5851
- getRowCanExpand: () => true,
5852
- paginateExpandedRows: false
5853
- }), {
6052
+ }), !!renderExpandedRow && { getRowCanExpand: () => true }), hasExpansion && { paginateExpandedRows: false }), {
5854
6053
  getGroupedRowModel: hasGrouping ? getGroupedRowModel() : void 0,
5855
- getExpandedRowModel: hasGrouping ? getExpandedRowModel() : void 0,
6054
+ // Only grouping and `getSubRows` put extra rows in the row model; `renderExpandedRow`
6055
+ // content renders outside it (see `DataTableBody`).
6056
+ getExpandedRowModel: hasGrouping || hasSubRows ? getExpandedRowModel() : void 0,
5856
6057
  groupedColumnMode: hasGrouping ? "reorder" : void 0,
5857
6058
  enableFilters: !shouldDisableFiltersModels,
5858
6059
  enableGlobalFilter: !shouldDisableFiltersModels,
@@ -5875,7 +6076,7 @@ function DataTable({
5875
6076
  columnVisibility: disableColumnVisibility ? {} : columnVisibility,
5876
6077
  columnSizing: disableColumnResizing ? {} : columnSizing,
5877
6078
  columnPinning: disableColumnPinning ? { left: [], right: [] } : columnPinning
5878
- }, !!renderExpandedRow && { expanded }), {
6079
+ }, hasExpansion && { expanded }), {
5879
6080
  grouping
5880
6081
  }), hasGrouping && { expanded: true }),
5881
6082
  manualSorting: serverSidePagination,
@@ -5889,7 +6090,7 @@ function DataTable({
5889
6090
  onColumnVisibilityChange: disableColumnVisibility ? noop : setColumnVisibility,
5890
6091
  onColumnSizingChange: disableColumnResizing ? noop : handleColumnSizingChange,
5891
6092
  onColumnPinningChange: disableColumnPinning ? noop : setColumnPinning
5892
- }), !!renderExpandedRow && {
6093
+ }), hasExpansion && {
5893
6094
  onExpandedChange: (updater) => setExpanded((prev) => typeof updater === "function" ? updater(prev) : updater)
5894
6095
  }), {
5895
6096
  onGroupingChange: setGrouping
@@ -5978,17 +6179,19 @@ function DataTable({
5978
6179
  }, [columnOrdering, disableColumnReordering, flatColumns, setColumnOrdering]);
5979
6180
  const showViewHeader = !!title || !!Actions;
5980
6181
  const showColumnOptions = !disableColumnReordering || !disableColumnVisibility;
5981
- const toolbarSearch = !disableSearch && /* @__PURE__ */ jsxs13(InputGroup3, { className: "w-70", children: [
5982
- /* @__PURE__ */ jsx17(InputGroupAddon3, { align: "inline-start", children: /* @__PURE__ */ jsx17(Icon11, { name: "magnifying-glass" }) }),
6182
+ const toolbarSearch = !disableSearch && /* @__PURE__ */ jsxs13(InputGroup4, { className: cn("w-70", search == null ? void 0 : search.className), children: [
6183
+ /* @__PURE__ */ jsx17(InputGroupAddon4, { align: "inline-start", children: /* @__PURE__ */ jsx17(Icon11, { name: "magnifying-glass" }) }),
5983
6184
  /* @__PURE__ */ jsx17(
5984
- InputGroupInput2,
5985
- {
6185
+ InputGroupInput3,
6186
+ __spreadProps(__spreadValues({}, SEARCH_INPUT_PROPS), {
6187
+ id: searchInputId,
6188
+ className: SEARCH_INPUT_CLASS,
5986
6189
  "aria-label": "Search",
5987
- placeholder: "Search\u2026",
6190
+ placeholder: (_g = search == null ? void 0 : search.placeholder) != null ? _g : "Search\u2026",
5988
6191
  disabled: shouldDisable,
5989
6192
  value: globalFilter,
5990
6193
  onChange: (e) => setGlobalFilter(e.target.value)
5991
- }
6194
+ })
5992
6195
  )
5993
6196
  ] });
5994
6197
  const toolbarColumns = !!showColumnOptions && /* @__PURE__ */ jsx17(
@@ -6097,7 +6300,7 @@ function DataTable({
6097
6300
  DataTablePagination,
6098
6301
  {
6099
6302
  rowCount,
6100
- rowCountRelation: (_f = config.rowCountRelation) != null ? _f : "eq",
6303
+ rowCountRelation: (_h = config.rowCountRelation) != null ? _h : "eq",
6101
6304
  paginationConfig,
6102
6305
  pageSize: pagination.pageSize,
6103
6306
  pageIndex: pagination.pageIndex,
@@ -6310,7 +6513,7 @@ var useGraphActionsContext = () => {
6310
6513
  };
6311
6514
 
6312
6515
  // src/graph/hooks/useGraphActions.ts
6313
- import { useCallback as useCallback9, useState as useState12 } from "react";
6516
+ import { useCallback as useCallback10, useState as useState12 } from "react";
6314
6517
 
6315
6518
  // src/graph/graph-node.tsx
6316
6519
  import * as React13 from "react";
@@ -6605,37 +6808,37 @@ function GraphNodeSkeleton(_props) {
6605
6808
  var useGraphActions = (initialNodes = [], initialEdges = []) => {
6606
6809
  const [nodes, setNodes] = useState12(initialNodes);
6607
6810
  const [edges, setEdges] = useState12(initialEdges);
6608
- const addNodes = useCallback9((newNodes) => {
6811
+ const addNodes = useCallback10((newNodes) => {
6609
6812
  setNodes((prevNodes) => {
6610
6813
  const existingIds = new Set(prevNodes.map((node) => node.id));
6611
6814
  const uniqueNewNodes = newNodes.filter((node) => !existingIds.has(node.id));
6612
6815
  return [...prevNodes, ...uniqueNewNodes];
6613
6816
  });
6614
6817
  }, []);
6615
- const addEdges = useCallback9((newEdges) => {
6818
+ const addEdges = useCallback10((newEdges) => {
6616
6819
  setEdges((prevEdges) => {
6617
6820
  const existingIds = new Set(prevEdges.map((edge) => edge.id));
6618
6821
  const uniqueNewEdges = newEdges.filter((edge) => !existingIds.has(edge.id));
6619
6822
  return [...prevEdges, ...uniqueNewEdges];
6620
6823
  });
6621
6824
  }, []);
6622
- const removeNodes = useCallback9((nodeIds) => {
6825
+ const removeNodes = useCallback10((nodeIds) => {
6623
6826
  const nodeIdSet = new Set(nodeIds);
6624
6827
  setNodes((prevNodes) => prevNodes.filter((node) => !nodeIdSet.has(node.id)));
6625
6828
  setEdges((prevEdges) => prevEdges.filter((edge) => !nodeIdSet.has(edge.source) && !nodeIdSet.has(edge.target)));
6626
6829
  }, []);
6627
- const removeEdges = useCallback9((edgeIds) => {
6830
+ const removeEdges = useCallback10((edgeIds) => {
6628
6831
  const edgeIdSet = new Set(edgeIds);
6629
6832
  setEdges((prevEdges) => prevEdges.filter((edge) => !edgeIdSet.has(edge.id)));
6630
6833
  }, []);
6631
- const resetGraph = useCallback9(() => {
6834
+ const resetGraph = useCallback10(() => {
6632
6835
  setNodes(initialNodes);
6633
6836
  setEdges(initialEdges);
6634
6837
  }, [initialNodes, initialEdges]);
6635
- const updateNode = useCallback9((nodeId, node) => {
6838
+ const updateNode = useCallback10((nodeId, node) => {
6636
6839
  setNodes((prevNodes) => prevNodes.map((n) => n.id === nodeId ? node : n));
6637
6840
  }, []);
6638
- const toggleNodeExpansion = useCallback9((nodeId) => {
6841
+ const toggleNodeExpansion = useCallback10((nodeId) => {
6639
6842
  setNodes(
6640
6843
  (prevNodes) => prevNodes.map((node) => {
6641
6844
  if (node.id === nodeId && isDefaultNode(node)) {
@@ -6696,7 +6899,7 @@ import {
6696
6899
  getFilteredRowModel as getFilteredRowModel2,
6697
6900
  useReactTable as useReactTable2
6698
6901
  } from "@tanstack/react-table";
6699
- import { Icon as Icon14, InputGroup as InputGroup4, InputGroupAddon as InputGroupAddon4, InputGroupInput as InputGroupInput3 } from "@upbound/monarch-core";
6902
+ import { Icon as Icon14, InputGroup as InputGroup5, InputGroupAddon as InputGroupAddon5, InputGroupInput as InputGroupInput4 } from "@upbound/monarch-core";
6700
6903
 
6701
6904
  // src/graph/graph-view.tsx
6702
6905
  import * as React16 from "react";
@@ -6839,9 +7042,9 @@ var useAutoLayout = (nodes, edges, { viewportFocusNodeId }) => {
6839
7042
  };
6840
7043
 
6841
7044
  // src/graph/hooks/useNodeVisibility.ts
6842
- import { useCallback as useCallback10, useMemo as useMemo11 } from "react";
7045
+ import { useCallback as useCallback11, useMemo as useMemo11 } from "react";
6843
7046
  var useNodeVisibility = (nodes, edges) => {
6844
- const hasRealChildren = useCallback10(
7047
+ const hasRealChildren = useCallback11(
6845
7048
  (nodeId) => {
6846
7049
  const childEdges = edges.filter((edge) => edge.source === nodeId);
6847
7050
  const childNodes = childEdges.map((edge) => nodes.find((node) => node.id === edge.target)).filter(Boolean);
@@ -6849,7 +7052,7 @@ var useNodeVisibility = (nodes, edges) => {
6849
7052
  },
6850
7053
  [nodes, edges]
6851
7054
  );
6852
- const areAllAncestorsExpanded = useCallback10(
7055
+ const areAllAncestorsExpanded = useCallback11(
6853
7056
  (nodeId) => {
6854
7057
  const parentEdges = edges.filter((edge) => edge.target === nodeId);
6855
7058
  if (parentEdges.length === 0) {
@@ -7039,6 +7242,7 @@ function Graph({
7039
7242
  }) {
7040
7243
  var _a, _b, _c;
7041
7244
  const graphRef = React17.useRef(null);
7245
+ const searchInputId = `graph-search-${React17.useId()}`;
7042
7246
  const [innerGlobalFilter, setInnerGlobalFilter] = React17.useState("");
7043
7247
  const [innerColumnFilters, setInnerColumnFilters] = React17.useState([]);
7044
7248
  const globalFilter = parentGlobalFilter != null ? parentGlobalFilter : innerGlobalFilter;
@@ -7104,17 +7308,19 @@ function Graph({
7104
7308
  return /* @__PURE__ */ jsxs18("div", { id: `graph-${id}`, className: cn("flex size-full flex-1 flex-col", className), children: [
7105
7309
  !!title && /* @__PURE__ */ jsx23(SectionHeader, { className: "mb-4", children: /* @__PURE__ */ jsx23(SectionHeaderContent, { children: /* @__PURE__ */ jsx23(SectionHeaderTitle, { children: title }) }) }),
7106
7310
  showToolbar && /* @__PURE__ */ jsxs18("div", { className: "mb-4 flex flex-row gap-2", children: [
7107
- !disableSearch && /* @__PURE__ */ jsxs18(InputGroup4, { className: "w-70", children: [
7108
- /* @__PURE__ */ jsx23(InputGroupAddon4, { align: "inline-start", children: /* @__PURE__ */ jsx23(Icon14, { name: "magnifying-glass" }) }),
7311
+ !disableSearch && /* @__PURE__ */ jsxs18(InputGroup5, { className: "w-70", children: [
7312
+ /* @__PURE__ */ jsx23(InputGroupAddon5, { align: "inline-start", children: /* @__PURE__ */ jsx23(Icon14, { name: "magnifying-glass" }) }),
7109
7313
  /* @__PURE__ */ jsx23(
7110
- InputGroupInput3,
7111
- {
7314
+ InputGroupInput4,
7315
+ __spreadProps(__spreadValues({}, SEARCH_INPUT_PROPS), {
7316
+ id: searchInputId,
7317
+ className: SEARCH_INPUT_CLASS,
7112
7318
  "aria-label": "Search",
7113
7319
  placeholder: "Search\u2026",
7114
7320
  disabled: shouldDisable,
7115
7321
  value: globalFilter,
7116
7322
  onChange: (e) => setGlobalFilter(e.target.value)
7117
- }
7323
+ })
7118
7324
  )
7119
7325
  ] }),
7120
7326
  !!Actions && /* @__PURE__ */ jsx23("div", { className: "ml-auto flex items-center gap-2", children: /* @__PURE__ */ jsx23(Actions, { state: graphState }) })
@@ -7153,10 +7359,10 @@ function Graph({
7153
7359
  }
7154
7360
 
7155
7361
  // src/graph/hooks/useGetViewportNodeIds.ts
7156
- import { useEffect as useEffect10, useMemo as useMemo14, useRef as useRef9, useState as useState14 } from "react";
7362
+ import { useEffect as useEffect10, useMemo as useMemo14, useRef as useRef10, useState as useState14 } from "react";
7157
7363
  import { useStore as useStore2, useViewport } from "reactflow";
7158
7364
  var useGetDebouncedViewport = (debounceDelay = 1e3) => {
7159
- const timerRef = useRef9(null);
7365
+ const timerRef = useRef10(null);
7160
7366
  const [debouncedValues, setDebouncedValues] = useState14({ x: 0, y: 0, zoom: 1, width: 0, height: 0, nodes: [] });
7161
7367
  const { x, y, zoom } = useViewport();
7162
7368
  const { width, height, nodes } = useStore2((state) => ({