modern-json-react 1.0.0 → 1.1.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
@@ -84,6 +84,179 @@ var Toolbar = ({
84
84
  )
85
85
  ] });
86
86
  };
87
+ var SearchBar = ({
88
+ query,
89
+ onQueryChange,
90
+ currentMatchIndex,
91
+ totalMatches,
92
+ onNext,
93
+ onPrevious,
94
+ onClose,
95
+ options,
96
+ onOptionsChange
97
+ }) => {
98
+ const inputRef = react.useRef(null);
99
+ react.useEffect(() => {
100
+ inputRef.current?.focus();
101
+ }, []);
102
+ const handleKeyDown = react.useCallback(
103
+ (e) => {
104
+ if (e.key === "Enter") {
105
+ e.preventDefault();
106
+ if (e.shiftKey) {
107
+ onPrevious();
108
+ } else {
109
+ onNext();
110
+ }
111
+ }
112
+ if (e.key === "Escape") {
113
+ e.preventDefault();
114
+ onClose();
115
+ }
116
+ },
117
+ [onNext, onPrevious, onClose]
118
+ );
119
+ const matchLabel = totalMatches === 0 ? query ? "No results" : "" : `${currentMatchIndex + 1} of ${totalMatches}`;
120
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-search", role: "search", "aria-label": "Search in editor", children: [
121
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-search__input-group", children: [
122
+ /* @__PURE__ */ jsxRuntime.jsxs(
123
+ "svg",
124
+ {
125
+ className: "mjr-search__icon",
126
+ width: "14",
127
+ height: "14",
128
+ viewBox: "0 0 24 24",
129
+ fill: "none",
130
+ stroke: "currentColor",
131
+ strokeWidth: "2",
132
+ strokeLinecap: "round",
133
+ strokeLinejoin: "round",
134
+ "aria-hidden": "true",
135
+ children: [
136
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "8" }),
137
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })
138
+ ]
139
+ }
140
+ ),
141
+ /* @__PURE__ */ jsxRuntime.jsx(
142
+ "input",
143
+ {
144
+ ref: inputRef,
145
+ className: "mjr-search__input",
146
+ type: "text",
147
+ value: query,
148
+ onChange: (e) => onQueryChange(e.target.value),
149
+ onKeyDown: handleKeyDown,
150
+ placeholder: "Search...",
151
+ "aria-label": "Search query",
152
+ spellCheck: false,
153
+ autoComplete: "off"
154
+ }
155
+ ),
156
+ query && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-search__count", "aria-live": "polite", children: matchLabel })
157
+ ] }),
158
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-search__options", children: [
159
+ /* @__PURE__ */ jsxRuntime.jsx(
160
+ "button",
161
+ {
162
+ className: `mjr-search__option-btn ${options.caseSensitive ? "mjr-search__option-btn--active" : ""}`,
163
+ onClick: () => onOptionsChange({ caseSensitive: !options.caseSensitive }),
164
+ "aria-pressed": options.caseSensitive,
165
+ title: "Match case",
166
+ "aria-label": "Match case",
167
+ children: "Aa"
168
+ }
169
+ ),
170
+ /* @__PURE__ */ jsxRuntime.jsx(
171
+ "button",
172
+ {
173
+ className: `mjr-search__option-btn ${options.useRegex ? "mjr-search__option-btn--active" : ""}`,
174
+ onClick: () => onOptionsChange({ useRegex: !options.useRegex }),
175
+ "aria-pressed": options.useRegex,
176
+ title: "Use regular expression",
177
+ "aria-label": "Use regular expression",
178
+ children: ".*"
179
+ }
180
+ )
181
+ ] }),
182
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-search__nav", children: [
183
+ /* @__PURE__ */ jsxRuntime.jsx(
184
+ "button",
185
+ {
186
+ className: "mjr-search__nav-btn",
187
+ onClick: onPrevious,
188
+ disabled: totalMatches === 0,
189
+ "aria-label": "Previous match",
190
+ title: "Previous match (Shift+Enter)",
191
+ children: /* @__PURE__ */ jsxRuntime.jsx(
192
+ "svg",
193
+ {
194
+ width: "12",
195
+ height: "12",
196
+ viewBox: "0 0 24 24",
197
+ fill: "none",
198
+ stroke: "currentColor",
199
+ strokeWidth: "2.5",
200
+ strokeLinecap: "round",
201
+ strokeLinejoin: "round",
202
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" })
203
+ }
204
+ )
205
+ }
206
+ ),
207
+ /* @__PURE__ */ jsxRuntime.jsx(
208
+ "button",
209
+ {
210
+ className: "mjr-search__nav-btn",
211
+ onClick: onNext,
212
+ disabled: totalMatches === 0,
213
+ "aria-label": "Next match",
214
+ title: "Next match (Enter)",
215
+ children: /* @__PURE__ */ jsxRuntime.jsx(
216
+ "svg",
217
+ {
218
+ width: "12",
219
+ height: "12",
220
+ viewBox: "0 0 24 24",
221
+ fill: "none",
222
+ stroke: "currentColor",
223
+ strokeWidth: "2.5",
224
+ strokeLinecap: "round",
225
+ strokeLinejoin: "round",
226
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
227
+ }
228
+ )
229
+ }
230
+ )
231
+ ] }),
232
+ /* @__PURE__ */ jsxRuntime.jsx(
233
+ "button",
234
+ {
235
+ className: "mjr-search__close",
236
+ onClick: onClose,
237
+ "aria-label": "Close search",
238
+ title: "Close (Escape)",
239
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
240
+ "svg",
241
+ {
242
+ width: "14",
243
+ height: "14",
244
+ viewBox: "0 0 24 24",
245
+ fill: "none",
246
+ stroke: "currentColor",
247
+ strokeWidth: "2",
248
+ strokeLinecap: "round",
249
+ strokeLinejoin: "round",
250
+ children: [
251
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
252
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
253
+ ]
254
+ }
255
+ )
256
+ }
257
+ )
258
+ ] });
259
+ };
87
260
  var CodeEditor = ({
88
261
  value,
89
262
  onChange,
@@ -96,6 +269,7 @@ var CodeEditor = ({
96
269
  className = ""
97
270
  }) => {
98
271
  const textareaRef = react.useRef(null);
272
+ const wrapperRef = react.useRef(null);
99
273
  const lines = react.useMemo(() => value.split("\n"), [value]);
100
274
  const handleChange = react.useCallback(
101
275
  (e) => {
@@ -138,6 +312,19 @@ var CodeEditor = ({
138
312
  },
139
313
  [value, onChange, readOnly]
140
314
  );
315
+ react.useEffect(() => {
316
+ const wrapper = wrapperRef.current;
317
+ if (!wrapper) return;
318
+ const syncScroll = () => {
319
+ const textarea = textareaRef.current;
320
+ if (textarea) {
321
+ textarea.scrollTop = wrapper.scrollTop;
322
+ textarea.scrollLeft = wrapper.scrollLeft;
323
+ }
324
+ };
325
+ wrapper.addEventListener("scroll", syncScroll, { passive: true });
326
+ return () => wrapper.removeEventListener("scroll", syncScroll);
327
+ }, []);
141
328
  const handleCursorMove = react.useCallback(() => {
142
329
  const textarea = textareaRef.current;
143
330
  if (!textarea) return;
@@ -148,24 +335,37 @@ var CodeEditor = ({
148
335
  const column = linesBefore[linesBefore.length - 1].length + 1;
149
336
  onCursorChange({ line, column, offset: pos });
150
337
  }, [value, onCursorChange]);
338
+ const matchesByLine = react.useMemo(() => {
339
+ const map = /* @__PURE__ */ new Map();
340
+ searchMatches.forEach((m, i) => {
341
+ if (!map.has(m.line)) map.set(m.line, []);
342
+ map.get(m.line).push({ match: m, isActive: i === currentMatchIndex });
343
+ });
344
+ return map;
345
+ }, [searchMatches, currentMatchIndex]);
346
+ react.useEffect(() => {
347
+ if (searchMatches.length === 0) return;
348
+ const currentMatch = searchMatches[currentMatchIndex];
349
+ if (!currentMatch) return;
350
+ const wrapper = wrapperRef.current;
351
+ if (!wrapper) return;
352
+ const activeEl = wrapper.querySelector(".mjr-code__match--active");
353
+ if (activeEl) {
354
+ activeEl.scrollIntoView?.({ block: "nearest", inline: "nearest" });
355
+ }
356
+ }, [currentMatchIndex, searchMatches]);
151
357
  const highlightedLines = react.useMemo(() => {
152
358
  return lines.map((line, idx) => {
153
359
  const lineNum = idx + 1;
154
360
  const isErrorLine = parseError?.line === lineNum;
155
- return /* @__PURE__ */ jsxRuntime.jsxs(
156
- "div",
157
- {
158
- className: `mjr-code__line ${isErrorLine ? "mjr-code__line--error" : ""}`,
159
- children: [
160
- lineNumbers && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-code__line-number", "aria-hidden": "true", children: lineNum }),
161
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-code__line-content", children: highlightJsonLine(line) })
162
- ]
163
- },
164
- idx
165
- );
361
+ const lineMatches = matchesByLine.get(lineNum);
362
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mjr-code__line ${isErrorLine ? "mjr-code__line--error" : ""}`, children: [
363
+ lineNumbers && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-code__line-number", "aria-hidden": "true", children: lineNum }),
364
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-code__line-content", children: lineMatches && lineMatches.length > 0 ? highlightLineWithMatches(line, lineMatches) : highlightJsonLine(line) })
365
+ ] }, idx);
166
366
  });
167
- }, [lines, lineNumbers, parseError]);
168
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mjr-code-editor ${className}`, children: [
367
+ }, [lines, lineNumbers, parseError, matchesByLine]);
368
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapperRef, className: `mjr-code-editor ${className}`, children: [
169
369
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mjr-code__display", "aria-hidden": "true", children: highlightedLines }),
170
370
  /* @__PURE__ */ jsxRuntime.jsx(
171
371
  "textarea",
@@ -206,6 +406,36 @@ var CodeEditor = ({
206
406
  )
207
407
  ] });
208
408
  };
409
+ function highlightLineWithMatches(line, lineMatches) {
410
+ const sorted = [...lineMatches].sort((a, b) => a.match.columnStart - b.match.columnStart);
411
+ const result = [];
412
+ let pos = 0;
413
+ let key = 0;
414
+ for (const { match, isActive } of sorted) {
415
+ if (match.columnStart > pos) {
416
+ const before = line.substring(pos, match.columnStart);
417
+ result.push(/* @__PURE__ */ jsxRuntime.jsx("span", { children: highlightJsonLine(before) }, key++));
418
+ }
419
+ const matchText = line.substring(match.columnStart, match.columnEnd);
420
+ const cls = isActive ? "mjr-code__match mjr-code__match--active" : "mjr-code__match";
421
+ result.push(
422
+ /* @__PURE__ */ jsxRuntime.jsx(
423
+ "mark",
424
+ {
425
+ className: cls,
426
+ "data-testid": isActive ? "search-match-active" : "search-match",
427
+ children: highlightJsonLine(matchText)
428
+ },
429
+ key++
430
+ )
431
+ );
432
+ pos = match.columnEnd;
433
+ }
434
+ if (pos < line.length) {
435
+ result.push(/* @__PURE__ */ jsxRuntime.jsx("span", { children: highlightJsonLine(line.substring(pos)) }, key++));
436
+ }
437
+ return result;
438
+ }
209
439
  function highlightJsonLine(line) {
210
440
  const tokens = [];
211
441
  let i = 0;
@@ -246,7 +476,7 @@ function highlightJsonLine(line) {
246
476
  }
247
477
  if (ch === "-" || ch >= "0" && ch <= "9") {
248
478
  let num = "";
249
- while (i < line.length && /[\d.eE+\-]/.test(line[i])) {
479
+ while (i < line.length && /[\d.eE+-]/.test(line[i])) {
250
480
  num += line[i];
251
481
  i++;
252
482
  }
@@ -256,26 +486,36 @@ function highlightJsonLine(line) {
256
486
  continue;
257
487
  }
258
488
  if (line.substring(i, i + 4) === "true") {
259
- tokens.push(/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-boolean", children: "true" }, key++));
489
+ tokens.push(
490
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-boolean", children: "true" }, key++)
491
+ );
260
492
  i += 4;
261
493
  continue;
262
494
  }
263
495
  if (line.substring(i, i + 5) === "false") {
264
- tokens.push(/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-boolean", children: "false" }, key++));
496
+ tokens.push(
497
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-boolean", children: "false" }, key++)
498
+ );
265
499
  i += 5;
266
500
  continue;
267
501
  }
268
502
  if (line.substring(i, i + 4) === "null") {
269
- tokens.push(/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-null", children: "null" }, key++));
503
+ tokens.push(
504
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-null", children: "null" }, key++)
505
+ );
270
506
  i += 4;
271
507
  continue;
272
508
  }
273
509
  if (ch === "{" || ch === "}" || ch === "[" || ch === "]") {
274
- tokens.push(/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-bracket", children: ch }, key++));
510
+ tokens.push(
511
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-bracket", children: ch }, key++)
512
+ );
275
513
  i++;
276
514
  continue;
277
515
  }
278
- tokens.push(/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-punctuation", children: ch }, key++));
516
+ tokens.push(
517
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-syn-punctuation", children: ch }, key++)
518
+ );
279
519
  i++;
280
520
  }
281
521
  return tokens;
@@ -288,6 +528,14 @@ var TYPE_LABELS = {
288
528
  object: "obj",
289
529
  array: "arr"
290
530
  };
531
+ var TYPE_COLORS = {
532
+ string: "mjr-badge--string",
533
+ number: "mjr-badge--number",
534
+ boolean: "mjr-badge--boolean",
535
+ null: "mjr-badge--null",
536
+ object: "mjr-badge--object",
537
+ array: "mjr-badge--array"
538
+ };
291
539
  var TreeNodeComponent = ({
292
540
  node,
293
541
  onToggle,
@@ -295,7 +543,9 @@ var TreeNodeComponent = ({
295
543
  onKeyChange,
296
544
  onDelete,
297
545
  onTypeChange,
298
- readOnly
546
+ readOnly,
547
+ searchQuery = "",
548
+ searchCaseSensitive = false
299
549
  }) => {
300
550
  const [isEditing, setIsEditing] = react.useState(false);
301
551
  const [editValue, setEditValue] = react.useState("");
@@ -303,9 +553,7 @@ var TreeNodeComponent = ({
303
553
  const [editKey, setEditKey] = react.useState("");
304
554
  const isExpandable = node.type === "object" || node.type === "array";
305
555
  const handleToggle = react.useCallback(() => {
306
- if (isExpandable) {
307
- onToggle(node.id);
308
- }
556
+ if (isExpandable) onToggle(node.id);
309
557
  }, [isExpandable, node.id, onToggle]);
310
558
  const handleStartEdit = react.useCallback(() => {
311
559
  if (readOnly || isExpandable) return;
@@ -346,17 +594,80 @@ var TreeNodeComponent = ({
346
594
  }, [editKey, node.key, node.path, onKeyChange]);
347
595
  const handleTypeChange = react.useCallback(
348
596
  (e) => {
349
- const newType = e.target.value;
350
- onTypeChange(node.path, newType);
597
+ onTypeChange(node.path, e.target.value);
351
598
  },
352
599
  [node.path, onTypeChange]
353
600
  );
601
+ const renderArrow = () => /* @__PURE__ */ jsxRuntime.jsx(
602
+ "button",
603
+ {
604
+ className: `mjr-tree__arrow ${isExpandable ? "mjr-tree__arrow--expandable" : ""}`,
605
+ onClick: handleToggle,
606
+ tabIndex: isExpandable ? 0 : -1,
607
+ "aria-hidden": !isExpandable,
608
+ "aria-label": isExpandable ? node.expanded ? "Collapse" : "Expand" : void 0,
609
+ children: isExpandable ? /* @__PURE__ */ jsxRuntime.jsx(
610
+ "svg",
611
+ {
612
+ className: `mjr-tree__chevron ${node.expanded ? "mjr-tree__chevron--open" : ""}`,
613
+ width: "12",
614
+ height: "12",
615
+ viewBox: "0 0 12 12",
616
+ fill: "none",
617
+ children: /* @__PURE__ */ jsxRuntime.jsx(
618
+ "path",
619
+ {
620
+ d: "M4.5 2.5L8 6L4.5 9.5",
621
+ stroke: "currentColor",
622
+ strokeWidth: "1.5",
623
+ strokeLinecap: "round",
624
+ strokeLinejoin: "round"
625
+ }
626
+ )
627
+ }
628
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree__arrow-spacer" })
629
+ }
630
+ );
631
+ const renderKey = () => {
632
+ if (isEditingKey) {
633
+ return /* @__PURE__ */ jsxRuntime.jsx(
634
+ "input",
635
+ {
636
+ className: "mjr-tree__input mjr-tree__input--key",
637
+ value: editKey,
638
+ onChange: (e) => setEditKey(e.target.value),
639
+ onBlur: handleFinishKeyEdit,
640
+ onKeyDown: (e) => {
641
+ if (e.key === "Enter") handleFinishKeyEdit();
642
+ if (e.key === "Escape") setIsEditingKey(false);
643
+ },
644
+ autoFocus: true,
645
+ "aria-label": "Edit key name"
646
+ }
647
+ );
648
+ }
649
+ const keyStr = String(node.key);
650
+ const keyContent = searchQuery ? highlightText(keyStr, searchQuery, searchCaseSensitive) : keyStr;
651
+ return /* @__PURE__ */ jsxRuntime.jsx(
652
+ "span",
653
+ {
654
+ className: `mjr-tree__key ${typeof node.key !== "number" && !readOnly ? "mjr-tree__key--editable" : ""}`,
655
+ onDoubleClick: handleKeyEdit,
656
+ "data-testid": `key-${node.path}`,
657
+ children: typeof node.key === "number" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree__index", children: node.key }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
658
+ '"',
659
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree__key-text", children: keyContent }),
660
+ '"'
661
+ ] })
662
+ }
663
+ );
664
+ };
354
665
  const renderValue = () => {
355
666
  if (isEditing) {
356
667
  return /* @__PURE__ */ jsxRuntime.jsx(
357
668
  "input",
358
669
  {
359
- className: "mjr-tree-node__edit-input",
670
+ className: "mjr-tree__input mjr-tree__input--value",
360
671
  value: editValue,
361
672
  onChange: (e) => setEditValue(e.target.value),
362
673
  onBlur: handleFinishEdit,
@@ -371,31 +682,79 @@ var TreeNodeComponent = ({
371
682
  );
372
683
  }
373
684
  if (isExpandable) {
374
- const symbol = node.type === "object" ? "{}" : "[]";
375
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mjr-tree-node__preview", children: [
376
- node.expanded ? "" : `${symbol}`,
377
- !node.expanded && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mjr-tree-node__count", children: [
378
- "(",
379
- node.childCount,
380
- " ",
381
- node.childCount === 1 ? "item" : "items",
382
- ")"
685
+ const open = node.type === "object" ? "{" : "[";
686
+ const close = node.type === "object" ? "}" : "]";
687
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mjr-tree__preview", children: [
688
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree__bracket", children: open }),
689
+ !node.expanded && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
690
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mjr-tree__ellipsis", children: [
691
+ node.childCount,
692
+ " ",
693
+ node.childCount === 1 ? "item" : "items"
694
+ ] }),
695
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree__bracket", children: close })
383
696
  ] })
384
697
  ] });
385
698
  }
699
+ const display = formatDisplayValue(node.value, node.type);
700
+ const displayContent = searchQuery ? highlightText(display, searchQuery, searchCaseSensitive) : display;
386
701
  return /* @__PURE__ */ jsxRuntime.jsx(
387
702
  "span",
388
703
  {
389
- className: `mjr-tree-node__value mjr-tree-node__value--${node.type}`,
704
+ className: `mjr-tree__value mjr-tree__value--${node.type} ${!readOnly ? "mjr-tree__value--editable" : ""}`,
390
705
  onDoubleClick: handleStartEdit,
391
706
  role: "button",
392
707
  tabIndex: 0,
393
- "aria-label": `Value: ${formatDisplayValue(node.value, node.type)}. Double-click to edit.`,
708
+ "aria-label": `Value: ${display}. Double-click to edit.`,
394
709
  "data-testid": `value-${node.path}`,
395
- children: formatDisplayValue(node.value, node.type)
710
+ children: displayContent
396
711
  }
397
712
  );
398
713
  };
714
+ const renderBadge = () => {
715
+ const colorClass = TYPE_COLORS[node.type];
716
+ if (!readOnly) {
717
+ return /* @__PURE__ */ jsxRuntime.jsx(
718
+ "select",
719
+ {
720
+ className: `mjr-tree__badge ${colorClass}`,
721
+ value: node.type,
722
+ onChange: handleTypeChange,
723
+ "aria-label": `Type for ${node.key}`,
724
+ "data-testid": `type-${node.path}`,
725
+ children: Object.entries(TYPE_LABELS).map(([type, label]) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: type, children: label }, type))
726
+ }
727
+ );
728
+ }
729
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `mjr-tree__badge mjr-tree__badge--ro ${colorClass}`, children: TYPE_LABELS[node.type] });
730
+ };
731
+ const renderActions = () => {
732
+ if (readOnly) return null;
733
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mjr-tree__actions", children: /* @__PURE__ */ jsxRuntime.jsx(
734
+ "button",
735
+ {
736
+ className: "mjr-tree__delete",
737
+ onClick: () => onDelete(node.path),
738
+ "aria-label": `Delete ${node.key}`,
739
+ title: "Delete",
740
+ "data-testid": `delete-${node.path}`,
741
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
742
+ "path",
743
+ {
744
+ d: "M9 3L3 9M3 3l6 6",
745
+ stroke: "currentColor",
746
+ strokeWidth: "1.5",
747
+ strokeLinecap: "round"
748
+ }
749
+ ) })
750
+ }
751
+ ) });
752
+ };
753
+ const renderClosingBracket = () => {
754
+ if (!isExpandable || !node.expanded) return null;
755
+ const close = node.type === "object" ? "}" : "]";
756
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mjr-tree__close-bracket", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree__bracket", children: close }) });
757
+ };
399
758
  return /* @__PURE__ */ jsxRuntime.jsxs(
400
759
  "div",
401
760
  {
@@ -404,85 +763,67 @@ var TreeNodeComponent = ({
404
763
  "aria-expanded": isExpandable ? node.expanded : void 0,
405
764
  "aria-level": node.depth + 1,
406
765
  "aria-label": `${node.key}: ${node.type}`,
407
- style: { paddingLeft: `${node.depth * 20}px` },
408
766
  "data-testid": `tree-node-${node.path}`,
409
767
  children: [
410
- /* @__PURE__ */ jsxRuntime.jsx(
411
- "span",
412
- {
413
- className: `mjr-tree-node__arrow ${isExpandable ? "mjr-tree-node__arrow--expandable" : ""} ${node.expanded ? "mjr-tree-node__arrow--expanded" : ""}`,
414
- onClick: handleToggle,
415
- "aria-hidden": "true",
416
- children: isExpandable ? node.expanded ? "\u25BC" : "\u25B6" : "\xA0"
417
- }
418
- ),
419
- isEditingKey ? /* @__PURE__ */ jsxRuntime.jsx(
420
- "input",
421
- {
422
- className: "mjr-tree-node__key-input",
423
- value: editKey,
424
- onChange: (e) => setEditKey(e.target.value),
425
- onBlur: handleFinishKeyEdit,
426
- onKeyDown: (e) => {
427
- if (e.key === "Enter") handleFinishKeyEdit();
428
- if (e.key === "Escape") setIsEditingKey(false);
768
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-tree__row", children: [
769
+ renderArrow(),
770
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-tree__content", children: [
771
+ renderKey(),
772
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree__colon", "aria-hidden": "true", children: ":" }),
773
+ renderValue(),
774
+ renderBadge()
775
+ ] }),
776
+ renderActions()
777
+ ] }),
778
+ isExpandable && node.expanded && node.children.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", className: "mjr-tree__children", children: [
779
+ node.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
780
+ TreeNodeComponent,
781
+ {
782
+ node: child,
783
+ onToggle,
784
+ onValueChange,
785
+ onKeyChange,
786
+ onDelete,
787
+ onTypeChange,
788
+ readOnly,
789
+ searchQuery,
790
+ searchCaseSensitive
429
791
  },
430
- autoFocus: true,
431
- "aria-label": `Edit key name`
432
- }
433
- ) : /* @__PURE__ */ jsxRuntime.jsx(
434
- "span",
435
- {
436
- className: "mjr-tree-node__key",
437
- onDoubleClick: handleKeyEdit,
438
- "data-testid": `key-${node.path}`,
439
- children: typeof node.key === "number" ? node.key : `"${node.key}"`
440
- }
441
- ),
442
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree-node__colon", "aria-hidden": "true", children: ":" }),
443
- renderValue(),
444
- !readOnly ? /* @__PURE__ */ jsxRuntime.jsx(
445
- "select",
446
- {
447
- className: "mjr-tree-node__type-badge",
448
- value: node.type,
449
- onChange: handleTypeChange,
450
- "aria-label": `Type for ${node.key}`,
451
- "data-testid": `type-${node.path}`,
452
- children: Object.entries(TYPE_LABELS).map(([type, label]) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: type, children: label }, type))
453
- }
454
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mjr-tree-node__type-badge-ro", children: TYPE_LABELS[node.type] }),
455
- !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
456
- "button",
457
- {
458
- className: "mjr-tree-node__delete",
459
- onClick: () => onDelete(node.path),
460
- "aria-label": `Delete ${node.key}`,
461
- title: "Delete",
462
- "data-testid": `delete-${node.path}`,
463
- children: "\\u2715"
464
- }
465
- ),
466
- isExpandable && node.expanded && node.children.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", className: "mjr-tree-node__children", children: node.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
467
- TreeNodeComponent,
468
- {
469
- node: child,
470
- onToggle,
471
- onValueChange,
472
- onKeyChange,
473
- onDelete,
474
- onTypeChange,
475
- readOnly
476
- },
477
- child.id
478
- )) })
792
+ child.id
793
+ )),
794
+ renderClosingBracket()
795
+ ] }),
796
+ isExpandable && node.expanded && node.children.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mjr-tree__children", children: renderClosingBracket() })
479
797
  ]
480
798
  }
481
799
  );
482
800
  };
801
+ function highlightText(text, query, caseSensitive) {
802
+ if (!query || !text) return text;
803
+ try {
804
+ const flags = caseSensitive ? "g" : "gi";
805
+ const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
806
+ const regex = new RegExp(`(${escaped})`, flags);
807
+ const parts = text.split(regex);
808
+ if (parts.length === 1) return text;
809
+ return parts.map((part, i) => {
810
+ if (regex.test(part)) {
811
+ regex.lastIndex = 0;
812
+ return /* @__PURE__ */ jsxRuntime.jsx("mark", { className: "mjr-tree__match", "data-testid": "tree-search-match", children: part }, i);
813
+ }
814
+ return part;
815
+ });
816
+ } catch {
817
+ return text;
818
+ }
819
+ }
483
820
  function formatDisplayValue(value, type) {
484
821
  if (type === "null") return "null";
485
- if (type === "string") return `"${String(value)}"`;
822
+ if (type === "string") {
823
+ const str = String(value);
824
+ if (str.length > 80) return `"${str.slice(0, 77)}..."`;
825
+ return `"${str}"`;
826
+ }
486
827
  if (type === "boolean") return String(value);
487
828
  if (type === "number") return String(value);
488
829
  return "";
@@ -552,7 +893,7 @@ function deleteBySegments(current, segments, index) {
552
893
  return current.filter((_, i) => i !== arrIndex);
553
894
  }
554
895
  if (typeof current === "object" && current !== null) {
555
- const { [segment2]: _, ...rest } = current;
896
+ const { [segment2]: _omit, ...rest } = current;
556
897
  return rest;
557
898
  }
558
899
  return current;
@@ -591,6 +932,8 @@ var TreeEditor = ({
591
932
  value,
592
933
  onChange,
593
934
  readOnly,
935
+ searchQuery = "",
936
+ searchCaseSensitive = false,
594
937
  className = ""
595
938
  }) => {
596
939
  const [expandedPaths, setExpandedPaths] = react.useState(/* @__PURE__ */ new Set(["$"]));
@@ -601,18 +944,14 @@ var TreeEditor = ({
601
944
  setExpandedPaths((prev) => {
602
945
  const next = new Set(prev);
603
946
  const path = id;
604
- if (next.has(path)) {
605
- next.delete(path);
606
- } else {
607
- next.add(path);
608
- }
947
+ if (next.has(path)) next.delete(path);
948
+ else next.add(path);
609
949
  return next;
610
950
  });
611
951
  }, []);
612
952
  const handleValueChange = react.useCallback(
613
953
  (path, newValue) => {
614
- const updated = setByPath(value, path, newValue);
615
- onChange(updated);
954
+ onChange(setByPath(value, path, newValue));
616
955
  },
617
956
  [value, onChange]
618
957
  );
@@ -630,8 +969,7 @@ var TreeEditor = ({
630
969
  );
631
970
  const handleDelete = react.useCallback(
632
971
  (path) => {
633
- const updated = deleteByPath(value, path);
634
- onChange(updated);
972
+ onChange(deleteByPath(value, path));
635
973
  },
636
974
  [value, onChange]
637
975
  );
@@ -645,8 +983,7 @@ var TreeEditor = ({
645
983
  object: {},
646
984
  array: []
647
985
  };
648
- const updated = setByPath(value, path, defaults[newType]);
649
- onChange(updated);
986
+ onChange(setByPath(value, path, defaults[newType]));
650
987
  },
651
988
  [value, onChange]
652
989
  );
@@ -659,19 +996,39 @@ var TreeEditor = ({
659
996
  const obj = value;
660
997
  let newKey = "newKey";
661
998
  let counter = 1;
662
- while (newKey in obj) {
663
- newKey = `newKey${counter++}`;
664
- }
999
+ while (newKey in obj) newKey = `newKey${counter++}`;
665
1000
  onChange({ ...obj, [newKey]: "" });
666
1001
  } else if (Array.isArray(value)) {
667
1002
  onChange([...value, ""]);
668
1003
  }
669
1004
  }, [value, onChange]);
670
1005
  if (tree === null) {
671
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mjr-tree-editor mjr-tree-editor--empty ${className}`, children: [
672
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mjr-tree-editor__empty-msg", children: "No valid JSON to display" }),
673
- !readOnly && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "mjr-tree-editor__add-btn", onClick: () => onChange({}), children: "+ Create empty object" })
674
- ] });
1006
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mjr-tree-editor mjr-tree-editor--empty ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-tree__empty", children: [
1007
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", opacity: "0.3", children: [
1008
+ /* @__PURE__ */ jsxRuntime.jsx(
1009
+ "path",
1010
+ {
1011
+ d: "M3 7V17C3 18.1 3.9 19 5 19H19C20.1 19 21 18.1 21 17V7C21 5.9 20.1 5 19 5H5C3.9 5 3 5.9 3 7Z",
1012
+ stroke: "currentColor",
1013
+ strokeWidth: "1.5"
1014
+ }
1015
+ ),
1016
+ /* @__PURE__ */ jsxRuntime.jsx(
1017
+ "path",
1018
+ {
1019
+ d: "M7 9H17M7 13H13",
1020
+ stroke: "currentColor",
1021
+ strokeWidth: "1.5",
1022
+ strokeLinecap: "round"
1023
+ }
1024
+ )
1025
+ ] }),
1026
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No valid JSON to display" }),
1027
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "mjr-tree__add-btn", onClick: () => onChange({}), children: [
1028
+ "+",
1029
+ " Create empty object"
1030
+ ] })
1031
+ ] }) });
675
1032
  }
676
1033
  return /* @__PURE__ */ jsxRuntime.jsxs(
677
1034
  "div",
@@ -690,16 +1047,21 @@ var TreeEditor = ({
690
1047
  onKeyChange: handleKeyChange,
691
1048
  onDelete: handleDelete,
692
1049
  onTypeChange: handleTypeChange,
693
- readOnly
1050
+ readOnly,
1051
+ searchQuery,
1052
+ searchCaseSensitive
694
1053
  }
695
1054
  ),
696
- !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
1055
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs(
697
1056
  "button",
698
1057
  {
699
- className: "mjr-tree-editor__add-root",
1058
+ className: "mjr-tree__add-btn mjr-tree__add-btn--root",
700
1059
  onClick: handleAddProperty,
701
1060
  "data-testid": "add-property",
702
- children: "+ Add property"
1061
+ children: [
1062
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 2v8M2 6h8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }),
1063
+ "Add property"
1064
+ ]
703
1065
  }
704
1066
  )
705
1067
  ]
@@ -727,17 +1089,13 @@ function buildTree(value, path, key, depth, expandedPaths) {
727
1089
  const keys = Object.keys(obj);
728
1090
  node.childCount = keys.length;
729
1091
  if (expanded) {
730
- node.children = keys.map(
731
- (k) => buildTree(obj[k], `${path}.${k}`, k, depth + 1, expandedPaths)
732
- ).filter(Boolean);
1092
+ node.children = keys.map((k) => buildTree(obj[k], `${path}.${k}`, k, depth + 1, expandedPaths)).filter(Boolean);
733
1093
  }
734
1094
  } else if (type === "array") {
735
1095
  const arr = value;
736
1096
  node.childCount = arr.length;
737
1097
  if (expanded) {
738
- node.children = arr.map(
739
- (item, i) => buildTree(item, `${path}[${i}]`, i, depth + 1, expandedPaths)
740
- ).filter(Boolean);
1098
+ node.children = arr.map((item, i) => buildTree(item, `${path}[${i}]`, i, depth + 1, expandedPaths)).filter(Boolean);
741
1099
  }
742
1100
  }
743
1101
  return node;
@@ -757,11 +1115,8 @@ function getNestedValue(obj, path) {
757
1115
  let current = obj;
758
1116
  for (const seg of segments) {
759
1117
  if (current === null || current === void 0) return void 0;
760
- if (Array.isArray(current)) {
761
- current = current[parseInt(seg, 10)];
762
- } else if (typeof current === "object") {
763
- current = current[seg];
764
- }
1118
+ if (Array.isArray(current)) current = current[parseInt(seg, 10)];
1119
+ else if (typeof current === "object") current = current[seg];
765
1120
  }
766
1121
  return current;
767
1122
  }
@@ -975,7 +1330,13 @@ function validateSchema(value, schema, path = "$") {
975
1330
  const re = new RegExp(schema.pattern);
976
1331
  if (!re.test(value)) {
977
1332
  errors.push(
978
- makeError(`String must match pattern "${schema.pattern}"`, path, "pattern", schema.pattern, value)
1333
+ makeError(
1334
+ `String must match pattern "${schema.pattern}"`,
1335
+ path,
1336
+ "pattern",
1337
+ schema.pattern,
1338
+ value
1339
+ )
979
1340
  );
980
1341
  }
981
1342
  }
@@ -1015,19 +1376,37 @@ function validateSchema(value, schema, path = "$") {
1015
1376
  }
1016
1377
  if (schema.multipleOf !== void 0 && value % schema.multipleOf !== 0) {
1017
1378
  errors.push(
1018
- makeError(`Value must be a multiple of ${schema.multipleOf}`, path, "multipleOf", schema.multipleOf, value)
1379
+ makeError(
1380
+ `Value must be a multiple of ${schema.multipleOf}`,
1381
+ path,
1382
+ "multipleOf",
1383
+ schema.multipleOf,
1384
+ value
1385
+ )
1019
1386
  );
1020
1387
  }
1021
1388
  }
1022
1389
  if (Array.isArray(value)) {
1023
1390
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
1024
1391
  errors.push(
1025
- makeError(`Array must have at least ${schema.minItems} items`, path, "minItems", schema.minItems, value)
1392
+ makeError(
1393
+ `Array must have at least ${schema.minItems} items`,
1394
+ path,
1395
+ "minItems",
1396
+ schema.minItems,
1397
+ value
1398
+ )
1026
1399
  );
1027
1400
  }
1028
1401
  if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
1029
1402
  errors.push(
1030
- makeError(`Array must have at most ${schema.maxItems} items`, path, "maxItems", schema.maxItems, value)
1403
+ makeError(
1404
+ `Array must have at most ${schema.maxItems} items`,
1405
+ path,
1406
+ "maxItems",
1407
+ schema.maxItems,
1408
+ value
1409
+ )
1031
1410
  );
1032
1411
  }
1033
1412
  if (schema.uniqueItems && new Set(value.map((v) => JSON.stringify(v))).size !== value.length) {
@@ -1326,6 +1705,27 @@ function useSearch(text) {
1326
1705
  function escapeRegex(str) {
1327
1706
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1328
1707
  }
1708
+ function useContainerWidth(ref) {
1709
+ const [width, setWidth] = react.useState(0);
1710
+ const updateWidth = react.useCallback(() => {
1711
+ if (ref.current) {
1712
+ setWidth(ref.current.clientWidth);
1713
+ }
1714
+ }, [ref]);
1715
+ react.useEffect(() => {
1716
+ const el = ref.current;
1717
+ if (!el) return;
1718
+ updateWidth();
1719
+ if (typeof ResizeObserver !== "undefined") {
1720
+ const observer = new ResizeObserver(() => updateWidth());
1721
+ observer.observe(el);
1722
+ return () => observer.disconnect();
1723
+ }
1724
+ window.addEventListener("resize", updateWidth);
1725
+ return () => window.removeEventListener("resize", updateWidth);
1726
+ }, [ref, updateWidth]);
1727
+ return width;
1728
+ }
1329
1729
 
1330
1730
  // src/core/formatter.ts
1331
1731
  function formatJson(text, indent = 2) {
@@ -1447,6 +1847,8 @@ var darkTheme = {
1447
1847
  treeSelected: "#094771",
1448
1848
  typeBadgeBg: "#2d2d30"
1449
1849
  };
1850
+ var BREAKPOINT_SM = 480;
1851
+ var BREAKPOINT_MD = 768;
1450
1852
  var JsonEditor = ({
1451
1853
  value: externalValue,
1452
1854
  onChange,
@@ -1460,13 +1862,13 @@ var JsonEditor = ({
1460
1862
  height = 400,
1461
1863
  readOnly = false,
1462
1864
  searchable = true,
1463
- sortable = true,
1865
+ sortable: _sortable = true,
1464
1866
  indentation = 2,
1465
1867
  lineNumbers = true,
1466
1868
  bracketMatching = true,
1467
- maxSize,
1468
- virtualize = "auto",
1469
- onError,
1869
+ maxSize: _maxSize,
1870
+ virtualize: _virtualize = "auto",
1871
+ onError: _onError,
1470
1872
  onFocus,
1471
1873
  onBlur,
1472
1874
  className = "",
@@ -1597,11 +1999,18 @@ var JsonEditor = ({
1597
1999
  document.addEventListener("keydown", handleKeyDown);
1598
2000
  return () => document.removeEventListener("keydown", handleKeyDown);
1599
2001
  }, [history, parser, search, searchable]);
2002
+ const containerRef = react.useRef(null);
2003
+ const containerWidth = useContainerWidth(containerRef);
2004
+ const isSmall = containerWidth > 0 && containerWidth <= BREAKPOINT_SM;
2005
+ const isMedium = containerWidth > 0 && containerWidth <= BREAKPOINT_MD;
2006
+ const sizeClass = isSmall ? "mjr-editor--sm" : isMedium ? "mjr-editor--md" : "";
2007
+ const shouldStackSplit = mode === "split" && isMedium;
1600
2008
  const heightStyle = typeof height === "number" ? `${height}px` : height;
1601
2009
  return /* @__PURE__ */ jsxRuntime.jsxs(
1602
2010
  "div",
1603
2011
  {
1604
- className: `mjr-editor ${className}`,
2012
+ ref: containerRef,
2013
+ className: `mjr-editor ${sizeClass} ${className}`.trim(),
1605
2014
  style: { ...themeVars, height: heightStyle, ...style },
1606
2015
  role: "application",
1607
2016
  "aria-label": ariaLabel,
@@ -1629,30 +2038,53 @@ var JsonEditor = ({
1629
2038
  readOnly
1630
2039
  }
1631
2040
  ),
1632
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mjr-editor__content", children: [
1633
- (mode === "code" || mode === "split") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mjr-editor__panel ${mode === "split" ? "mjr-editor__panel--half" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(
1634
- CodeEditor,
1635
- {
1636
- value: parser.text,
1637
- onChange: handleTextChange,
1638
- parseError: parser.parseError,
1639
- readOnly,
1640
- lineNumbers,
1641
- bracketMatching,
1642
- searchMatches: search.matches,
1643
- currentMatchIndex: search.currentMatchIndex,
1644
- onCursorChange: setCursor
1645
- }
1646
- ) }),
1647
- (mode === "tree" || mode === "split") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mjr-editor__panel ${mode === "split" ? "mjr-editor__panel--half" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(
1648
- TreeEditor,
1649
- {
1650
- value: parser.parsedValue,
1651
- onChange: handleTreeChange,
1652
- readOnly
1653
- }
1654
- ) })
1655
- ] }),
2041
+ search.isActive && /* @__PURE__ */ jsxRuntime.jsx(
2042
+ SearchBar,
2043
+ {
2044
+ query: search.query,
2045
+ onQueryChange: search.setQuery,
2046
+ matches: search.matches,
2047
+ currentMatchIndex: search.currentMatchIndex,
2048
+ totalMatches: search.totalMatches,
2049
+ onNext: search.goToNext,
2050
+ onPrevious: search.goToPrevious,
2051
+ onClose: search.close,
2052
+ options: search.options,
2053
+ onOptionsChange: search.setOptions
2054
+ }
2055
+ ),
2056
+ /* @__PURE__ */ jsxRuntime.jsxs(
2057
+ "div",
2058
+ {
2059
+ className: `mjr-editor__content ${shouldStackSplit ? "mjr-editor__content--responsive-stack" : ""}`,
2060
+ children: [
2061
+ (mode === "code" || mode === "split") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mjr-editor__panel ${mode === "split" ? "mjr-editor__panel--half" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(
2062
+ CodeEditor,
2063
+ {
2064
+ value: parser.text,
2065
+ onChange: handleTextChange,
2066
+ parseError: parser.parseError,
2067
+ readOnly,
2068
+ lineNumbers: isSmall ? false : lineNumbers,
2069
+ bracketMatching,
2070
+ searchMatches: search.matches,
2071
+ currentMatchIndex: search.currentMatchIndex,
2072
+ onCursorChange: setCursor
2073
+ }
2074
+ ) }),
2075
+ (mode === "tree" || mode === "split") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mjr-editor__panel ${mode === "split" ? "mjr-editor__panel--half" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(
2076
+ TreeEditor,
2077
+ {
2078
+ value: parser.parsedValue,
2079
+ onChange: handleTreeChange,
2080
+ readOnly,
2081
+ searchQuery: search.isActive ? search.query : "",
2082
+ searchCaseSensitive: search.options.caseSensitive
2083
+ }
2084
+ ) })
2085
+ ]
2086
+ }
2087
+ ),
1656
2088
  /* @__PURE__ */ jsxRuntime.jsx(
1657
2089
  StatusBar,
1658
2090
  {
@@ -1683,6 +2115,7 @@ exports.runCustomValidators = runCustomValidators;
1683
2115
  exports.setByPath = setByPath;
1684
2116
  exports.sortJsonKeys = sortJsonKeys;
1685
2117
  exports.stringifyJson = stringifyJson;
2118
+ exports.useContainerWidth = useContainerWidth;
1686
2119
  exports.useJsonParser = useJsonParser;
1687
2120
  exports.useSearch = useSearch;
1688
2121
  exports.useUndoRedo = useUndoRedo;