najm-kit 0.0.7
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/README.md +70 -0
- package/dist/NTableJson-tXqgfZI1.d.ts +5 -0
- package/dist/adapters/next.d.ts +20 -0
- package/dist/adapters/next.mjs +23 -0
- package/dist/index.d.ts +2812 -0
- package/dist/index.mjs +8455 -0
- package/dist/json.d.ts +54 -0
- package/dist/json.mjs +839 -0
- package/dist/styles.css +3754 -0
- package/dist/styles.css.d.ts +2 -0
- package/package.json +133 -0
package/dist/json.mjs
ADDED
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
import * as React3 from 'react';
|
|
2
|
+
import React3__default, { createContext, useContext, useMemo, useRef, useCallback } from 'react';
|
|
3
|
+
import CodeMirror from '@uiw/react-codemirror';
|
|
4
|
+
import { json } from '@codemirror/lang-json';
|
|
5
|
+
import { keymap, EditorView, Decoration, ViewPlugin } from '@codemirror/view';
|
|
6
|
+
import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
|
|
7
|
+
import { tags } from '@lezer/highlight';
|
|
8
|
+
import { EditorSelection, EditorState, RangeSetBuilder } from '@codemirror/state';
|
|
9
|
+
import { clsx } from 'clsx';
|
|
10
|
+
import { twMerge } from 'tailwind-merge';
|
|
11
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
13
|
+
import * as LucideIcons from 'lucide-react';
|
|
14
|
+
import { LoaderCircleIcon, Loader2, AlertCircle, ClipboardPaste, Copy, RotateCcw } from 'lucide-react';
|
|
15
|
+
import { cva } from 'class-variance-authority';
|
|
16
|
+
|
|
17
|
+
// src/json/JsonViewer.tsx
|
|
18
|
+
function cn(...inputs) {
|
|
19
|
+
return twMerge(clsx(inputs));
|
|
20
|
+
}
|
|
21
|
+
var defaultJsonViewColors = {
|
|
22
|
+
toolName: "#10b981",
|
|
23
|
+
langCode: "#f59e0b",
|
|
24
|
+
phrase: "#06b6d4",
|
|
25
|
+
bracket: "#9ca3af",
|
|
26
|
+
key: "#a78bfa",
|
|
27
|
+
string: "#34d399",
|
|
28
|
+
number: "#f472b6",
|
|
29
|
+
background: "#1f2937"
|
|
30
|
+
};
|
|
31
|
+
function buildStudioTheme(colors, fullPage = false) {
|
|
32
|
+
return EditorView.theme(
|
|
33
|
+
{
|
|
34
|
+
"&": {
|
|
35
|
+
backgroundColor: colors.background,
|
|
36
|
+
fontSize: "0.8125rem",
|
|
37
|
+
fontFamily: "'JetBrains Mono', monospace",
|
|
38
|
+
height: fullPage ? "100%" : "auto",
|
|
39
|
+
minHeight: fullPage ? 0 : void 0
|
|
40
|
+
},
|
|
41
|
+
".cm-scroller": {
|
|
42
|
+
backgroundColor: colors.background,
|
|
43
|
+
overflow: "auto"
|
|
44
|
+
},
|
|
45
|
+
".cm-content": {
|
|
46
|
+
backgroundColor: colors.background,
|
|
47
|
+
paddingTop: "0.5rem",
|
|
48
|
+
paddingBottom: "0.5rem",
|
|
49
|
+
color: "#e2e8f0"
|
|
50
|
+
},
|
|
51
|
+
".cm-gutters": {
|
|
52
|
+
backgroundColor: colors.background,
|
|
53
|
+
color: colors.bracket + "88",
|
|
54
|
+
borderRight: "none",
|
|
55
|
+
fontFamily: "'JetBrains Mono', monospace",
|
|
56
|
+
fontSize: "0.8125rem"
|
|
57
|
+
},
|
|
58
|
+
".cm-activeLineGutter": {
|
|
59
|
+
backgroundColor: colors.bracket + "11"
|
|
60
|
+
},
|
|
61
|
+
".cm-activeLine": {
|
|
62
|
+
backgroundColor: colors.bracket + "0D"
|
|
63
|
+
},
|
|
64
|
+
".cm-selectionBackground": {
|
|
65
|
+
backgroundColor: colors.bracket + "33"
|
|
66
|
+
},
|
|
67
|
+
".cm-line": {
|
|
68
|
+
padding: "0 0.75rem"
|
|
69
|
+
},
|
|
70
|
+
"@media (max-width: 640px)": {
|
|
71
|
+
"&": {
|
|
72
|
+
fontSize: "0.75rem"
|
|
73
|
+
},
|
|
74
|
+
".cm-gutters": {
|
|
75
|
+
display: "none"
|
|
76
|
+
},
|
|
77
|
+
".cm-line": {
|
|
78
|
+
padding: "0 0.5rem"
|
|
79
|
+
},
|
|
80
|
+
".cm-content": {
|
|
81
|
+
paddingTop: "0.375rem",
|
|
82
|
+
paddingBottom: "0.375rem"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{ dark: true }
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
function buildJsonHighlightStyle(colors) {
|
|
90
|
+
const highlightStyle = HighlightStyle.define([
|
|
91
|
+
{ tag: tags.string, color: colors.string },
|
|
92
|
+
{ tag: tags.number, color: colors.number },
|
|
93
|
+
{ tag: tags.propertyName, color: colors.key },
|
|
94
|
+
{ tag: tags.bool, color: colors.number },
|
|
95
|
+
{ tag: tags.null, color: colors.number },
|
|
96
|
+
{ tag: tags.bracket, color: colors.bracket },
|
|
97
|
+
{ tag: tags.squareBracket, color: colors.bracket },
|
|
98
|
+
{ tag: tags.brace, color: colors.bracket },
|
|
99
|
+
{ tag: tags.punctuation, color: colors.bracket }
|
|
100
|
+
]);
|
|
101
|
+
return syntaxHighlighting(highlightStyle);
|
|
102
|
+
}
|
|
103
|
+
function JsonViewer({ value, colors = defaultJsonViewColors, className, maxHeight = "240px" }) {
|
|
104
|
+
const fullPage = maxHeight === "none";
|
|
105
|
+
const text = useMemo(() => {
|
|
106
|
+
if (typeof value === "string") return value;
|
|
107
|
+
try {
|
|
108
|
+
return JSON.stringify(value, null, 2);
|
|
109
|
+
} catch {
|
|
110
|
+
return String(value);
|
|
111
|
+
}
|
|
112
|
+
}, [value]);
|
|
113
|
+
const theme = useMemo(() => buildStudioTheme(colors, fullPage), [colors, fullPage]);
|
|
114
|
+
const highlightStyle = useMemo(() => buildJsonHighlightStyle(colors), [colors]);
|
|
115
|
+
const selectAllKeymap = useMemo(
|
|
116
|
+
() => keymap.of([
|
|
117
|
+
{
|
|
118
|
+
key: "Mod-a",
|
|
119
|
+
run: (view) => {
|
|
120
|
+
view.dispatch({
|
|
121
|
+
selection: EditorSelection.range(0, view.state.doc.length)
|
|
122
|
+
});
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
]),
|
|
127
|
+
[]
|
|
128
|
+
);
|
|
129
|
+
const extensions = useMemo(
|
|
130
|
+
() => [
|
|
131
|
+
json(),
|
|
132
|
+
theme,
|
|
133
|
+
highlightStyle,
|
|
134
|
+
EditorView.lineWrapping,
|
|
135
|
+
EditorState.readOnly.of(true),
|
|
136
|
+
selectAllKeymap
|
|
137
|
+
],
|
|
138
|
+
[theme, highlightStyle, selectAllKeymap]
|
|
139
|
+
);
|
|
140
|
+
return /* @__PURE__ */ jsx(
|
|
141
|
+
"div",
|
|
142
|
+
{
|
|
143
|
+
className: cn(
|
|
144
|
+
"rounded-md border border-border",
|
|
145
|
+
fullPage ? "relative flex-1 min-h-0 overflow-hidden" : "overflow-hidden",
|
|
146
|
+
className
|
|
147
|
+
),
|
|
148
|
+
style: { backgroundColor: colors.background, maxHeight },
|
|
149
|
+
children: /* @__PURE__ */ jsx(
|
|
150
|
+
CodeMirror,
|
|
151
|
+
{
|
|
152
|
+
value: text,
|
|
153
|
+
className: fullPage ? "absolute inset-0" : "text-xs",
|
|
154
|
+
height: fullPage ? "100%" : "auto",
|
|
155
|
+
extensions,
|
|
156
|
+
editable: true,
|
|
157
|
+
basicSetup: {
|
|
158
|
+
lineNumbers: fullPage,
|
|
159
|
+
highlightActiveLineGutter: false,
|
|
160
|
+
highlightActiveLine: false,
|
|
161
|
+
foldGutter: false,
|
|
162
|
+
dropCursor: false,
|
|
163
|
+
allowMultipleSelections: false,
|
|
164
|
+
indentOnInput: false,
|
|
165
|
+
bracketMatching: true,
|
|
166
|
+
closeBrackets: false,
|
|
167
|
+
autocompletion: false,
|
|
168
|
+
searchKeymap: false
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
function toPascalCase(value) {
|
|
176
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[\s_-]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
177
|
+
}
|
|
178
|
+
function isImageSource(value) {
|
|
179
|
+
return value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:image/") || /\.(avif|gif|jpe?g|png|svg|webp)(\?.*)?$/i.test(value);
|
|
180
|
+
}
|
|
181
|
+
function isComponentSource(value) {
|
|
182
|
+
return typeof value === "function" || Boolean(value && typeof value === "object" && "$$typeof" in value);
|
|
183
|
+
}
|
|
184
|
+
var NIcon = ({
|
|
185
|
+
icon = "circle",
|
|
186
|
+
size = 24,
|
|
187
|
+
alt = "",
|
|
188
|
+
className,
|
|
189
|
+
style,
|
|
190
|
+
onClick,
|
|
191
|
+
...rest
|
|
192
|
+
}) => {
|
|
193
|
+
const dimensionStyle = {
|
|
194
|
+
width: size,
|
|
195
|
+
height: size,
|
|
196
|
+
...style
|
|
197
|
+
};
|
|
198
|
+
if (React3__default.isValidElement(icon)) {
|
|
199
|
+
return React3__default.cloneElement(icon, {
|
|
200
|
+
className: cn(icon.props.className, className),
|
|
201
|
+
onClick,
|
|
202
|
+
...rest
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (icon && typeof icon === "object" && "src" in icon) {
|
|
206
|
+
return /* @__PURE__ */ jsx(
|
|
207
|
+
"img",
|
|
208
|
+
{
|
|
209
|
+
alt: icon.alt ?? alt,
|
|
210
|
+
className: cn("inline-block shrink-0 object-contain", className),
|
|
211
|
+
src: icon.src,
|
|
212
|
+
style: dimensionStyle,
|
|
213
|
+
onClick,
|
|
214
|
+
...rest
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
if (isComponentSource(icon)) {
|
|
219
|
+
const IconComponent = icon;
|
|
220
|
+
return /* @__PURE__ */ jsx(IconComponent, { size, className, onClick, style, ...rest });
|
|
221
|
+
}
|
|
222
|
+
if (typeof icon === "string") {
|
|
223
|
+
if (isImageSource(icon)) {
|
|
224
|
+
return /* @__PURE__ */ jsx(
|
|
225
|
+
"img",
|
|
226
|
+
{
|
|
227
|
+
alt,
|
|
228
|
+
className: cn("inline-block shrink-0 object-contain", className),
|
|
229
|
+
src: icon,
|
|
230
|
+
style: dimensionStyle,
|
|
231
|
+
onClick,
|
|
232
|
+
...rest
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
const pascalCaseIcon = toPascalCase(icon);
|
|
237
|
+
if (LucideIcons[pascalCaseIcon]) {
|
|
238
|
+
const LucideIcon = LucideIcons[pascalCaseIcon];
|
|
239
|
+
return /* @__PURE__ */ jsx(LucideIcon, { size, className, onClick, style, ...rest });
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
};
|
|
245
|
+
NIcon.displayName = "NIcon";
|
|
246
|
+
var buttonVariants = cva(
|
|
247
|
+
[
|
|
248
|
+
"relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium outline-none transition-all",
|
|
249
|
+
"disabled:pointer-events-none disabled:opacity-50 data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
|
|
250
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
251
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
252
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
253
|
+
].join(" "),
|
|
254
|
+
{
|
|
255
|
+
variants: {
|
|
256
|
+
variant: {
|
|
257
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
258
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
259
|
+
outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:hover:bg-input/50",
|
|
260
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
261
|
+
tertiary: "bg-tertiary text-tertiary-foreground shadow-xs hover:bg-tertiary/80",
|
|
262
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
263
|
+
link: "h-auto p-0 text-primary underline-offset-4 hover:underline",
|
|
264
|
+
success: "bg-emerald-600 text-white shadow-xs hover:bg-emerald-700",
|
|
265
|
+
warning: "bg-amber-400 text-slate-950 shadow-xs hover:bg-amber-500",
|
|
266
|
+
info: "bg-sky-600 text-white shadow-xs hover:bg-sky-700",
|
|
267
|
+
soft: "bg-primary/10 text-primary shadow-none hover:bg-primary/15",
|
|
268
|
+
subtle: "bg-muted text-foreground shadow-none hover:bg-muted/80",
|
|
269
|
+
plain: "bg-transparent shadow-none hover:bg-transparent"
|
|
270
|
+
},
|
|
271
|
+
size: {
|
|
272
|
+
"2xs": "h-5 gap-1 px-1.5 text-[11px] [&_svg:not([class*='size-'])]:size-3",
|
|
273
|
+
xs: "h-6 gap-1 px-2 text-xs [&_svg:not([class*='size-'])]:size-3",
|
|
274
|
+
sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
275
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
276
|
+
md: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
277
|
+
lg: "h-10 px-6 has-[>svg]:px-4",
|
|
278
|
+
xl: "h-12 px-8 text-base [&_svg:not([class*='size-'])]:size-5",
|
|
279
|
+
"2xl": "h-14 px-10 text-base [&_svg:not([class*='size-'])]:size-5",
|
|
280
|
+
icon: "size-9",
|
|
281
|
+
"icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
|
|
282
|
+
"icon-sm": "size-8",
|
|
283
|
+
"icon-lg": "size-10 [&_svg:not([class*='size-'])]:size-5",
|
|
284
|
+
"icon-xl": "size-12 [&_svg:not([class*='size-'])]:size-5"
|
|
285
|
+
},
|
|
286
|
+
rounded: {
|
|
287
|
+
none: "rounded-none",
|
|
288
|
+
sm: "rounded-sm",
|
|
289
|
+
default: "rounded-md",
|
|
290
|
+
md: "rounded-md",
|
|
291
|
+
lg: "rounded-lg",
|
|
292
|
+
xl: "rounded-xl",
|
|
293
|
+
"2xl": "rounded-2xl",
|
|
294
|
+
full: "rounded-full"
|
|
295
|
+
},
|
|
296
|
+
fullWidth: {
|
|
297
|
+
true: "w-full",
|
|
298
|
+
false: ""
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
defaultVariants: {
|
|
302
|
+
variant: "default",
|
|
303
|
+
size: "default",
|
|
304
|
+
rounded: "default",
|
|
305
|
+
fullWidth: false
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
function isPromiseLike(value) {
|
|
310
|
+
return Boolean(value && typeof value.then === "function");
|
|
311
|
+
}
|
|
312
|
+
var defaultLoader = /* @__PURE__ */ jsx(LoaderCircleIcon, { "aria-hidden": "true", className: "animate-spin" });
|
|
313
|
+
function renderIcon(icon) {
|
|
314
|
+
if (!icon) return null;
|
|
315
|
+
return /* @__PURE__ */ jsx(NIcon, { "aria-hidden": "true", icon, className: "shrink-0" });
|
|
316
|
+
}
|
|
317
|
+
var Button = React3.forwardRef(
|
|
318
|
+
({
|
|
319
|
+
className,
|
|
320
|
+
variant,
|
|
321
|
+
size,
|
|
322
|
+
rounded,
|
|
323
|
+
fullWidth,
|
|
324
|
+
asChild = false,
|
|
325
|
+
loading = false,
|
|
326
|
+
autoLoading = true,
|
|
327
|
+
disabledWhileLoading = true,
|
|
328
|
+
loadingText,
|
|
329
|
+
loader = defaultLoader,
|
|
330
|
+
loaderPosition = "left",
|
|
331
|
+
leftIcon,
|
|
332
|
+
rightIcon,
|
|
333
|
+
disabled,
|
|
334
|
+
children,
|
|
335
|
+
onClick,
|
|
336
|
+
...props
|
|
337
|
+
}, ref) => {
|
|
338
|
+
const [pending, setPending] = React3.useState(false);
|
|
339
|
+
const isLoading = loading || pending;
|
|
340
|
+
const isDisabled = disabled || disabledWhileLoading && isLoading;
|
|
341
|
+
const Comp = asChild ? Slot : "button";
|
|
342
|
+
const handleClick = React3.useCallback(
|
|
343
|
+
(event) => {
|
|
344
|
+
if (isDisabled) {
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const result = onClick?.(event);
|
|
349
|
+
if (autoLoading && isPromiseLike(result)) {
|
|
350
|
+
setPending(true);
|
|
351
|
+
void result.then(
|
|
352
|
+
() => setPending(false),
|
|
353
|
+
() => setPending(false)
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
[autoLoading, isDisabled, onClick]
|
|
358
|
+
);
|
|
359
|
+
const content = loadingText && isLoading ? loadingText : children;
|
|
360
|
+
const loaderNode = isLoading ? loader : null;
|
|
361
|
+
const leftIconNode = renderIcon(leftIcon);
|
|
362
|
+
const rightIconNode = renderIcon(rightIcon);
|
|
363
|
+
const showCenteredLoader = Boolean(loaderNode && loaderPosition === "center");
|
|
364
|
+
return /* @__PURE__ */ jsx(
|
|
365
|
+
Comp,
|
|
366
|
+
{
|
|
367
|
+
ref,
|
|
368
|
+
"data-slot": "button",
|
|
369
|
+
"data-loading": isLoading || void 0,
|
|
370
|
+
"data-disabled": isDisabled || void 0,
|
|
371
|
+
"aria-busy": isLoading || void 0,
|
|
372
|
+
"aria-disabled": asChild && isDisabled ? true : void 0,
|
|
373
|
+
disabled: !asChild ? isDisabled : void 0,
|
|
374
|
+
className: cn(buttonVariants({ variant, size, rounded, fullWidth, className })),
|
|
375
|
+
onClick: handleClick,
|
|
376
|
+
...props,
|
|
377
|
+
children: showCenteredLoader ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
378
|
+
/* @__PURE__ */ jsxs("span", { className: "invisible inline-flex items-center gap-2", children: [
|
|
379
|
+
leftIconNode,
|
|
380
|
+
content,
|
|
381
|
+
rightIconNode
|
|
382
|
+
] }),
|
|
383
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-0 inline-flex items-center justify-center", children: loaderNode })
|
|
384
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
385
|
+
loaderNode && loaderPosition === "left" ? loaderNode : leftIconNode,
|
|
386
|
+
content,
|
|
387
|
+
loaderNode && loaderPosition === "right" ? loaderNode : rightIconNode
|
|
388
|
+
] })
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
Button.displayName = "Button";
|
|
394
|
+
function buildStudioTheme2(colors) {
|
|
395
|
+
return EditorView.theme(
|
|
396
|
+
{
|
|
397
|
+
"&": {
|
|
398
|
+
backgroundColor: colors.background,
|
|
399
|
+
fontSize: "0.875rem",
|
|
400
|
+
fontFamily: "'JetBrains Mono', monospace",
|
|
401
|
+
height: "100%",
|
|
402
|
+
minHeight: 0
|
|
403
|
+
},
|
|
404
|
+
".cm-scroller": {
|
|
405
|
+
backgroundColor: colors.background,
|
|
406
|
+
overflow: "auto"
|
|
407
|
+
},
|
|
408
|
+
".cm-content": {
|
|
409
|
+
caretColor: colors.phrase,
|
|
410
|
+
backgroundColor: colors.background,
|
|
411
|
+
paddingTop: "1rem",
|
|
412
|
+
paddingBottom: "1rem",
|
|
413
|
+
color: "#e2e8f0"
|
|
414
|
+
},
|
|
415
|
+
".cm-gutters": {
|
|
416
|
+
backgroundColor: colors.background,
|
|
417
|
+
color: colors.bracket + "88",
|
|
418
|
+
borderRight: "none",
|
|
419
|
+
fontFamily: "'JetBrains Mono', monospace",
|
|
420
|
+
fontSize: "0.875rem"
|
|
421
|
+
},
|
|
422
|
+
".cm-activeLineGutter": {
|
|
423
|
+
backgroundColor: colors.bracket + "11"
|
|
424
|
+
},
|
|
425
|
+
".cm-activeLine": {
|
|
426
|
+
backgroundColor: colors.bracket + "0D"
|
|
427
|
+
},
|
|
428
|
+
".cm-selectionBackground": {
|
|
429
|
+
backgroundColor: colors.bracket + "33"
|
|
430
|
+
},
|
|
431
|
+
".cm-cursor": {
|
|
432
|
+
borderLeftColor: colors.phrase
|
|
433
|
+
},
|
|
434
|
+
".cm-line": {
|
|
435
|
+
padding: "0 1rem"
|
|
436
|
+
},
|
|
437
|
+
"@media (max-width: 640px)": {
|
|
438
|
+
"&": {
|
|
439
|
+
fontSize: "0.75rem"
|
|
440
|
+
},
|
|
441
|
+
".cm-gutters": {
|
|
442
|
+
display: "none"
|
|
443
|
+
},
|
|
444
|
+
".cm-content": {
|
|
445
|
+
paddingTop: "0.5rem",
|
|
446
|
+
paddingBottom: "0.5rem"
|
|
447
|
+
},
|
|
448
|
+
".cm-line": {
|
|
449
|
+
padding: "0 0.5rem"
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
{ dark: true }
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
function buildJsonHighlightStyle2(colors) {
|
|
457
|
+
const highlightStyle = HighlightStyle.define([
|
|
458
|
+
{ tag: tags.string, color: colors.string },
|
|
459
|
+
{ tag: tags.number, color: colors.number },
|
|
460
|
+
{ tag: tags.propertyName, color: colors.key },
|
|
461
|
+
{ tag: tags.bool, color: colors.number },
|
|
462
|
+
{ tag: tags.null, color: colors.number },
|
|
463
|
+
{ tag: tags.bracket, color: colors.bracket },
|
|
464
|
+
{ tag: tags.squareBracket, color: colors.bracket },
|
|
465
|
+
{ tag: tags.brace, color: colors.bracket },
|
|
466
|
+
{ tag: tags.punctuation, color: colors.bracket }
|
|
467
|
+
]);
|
|
468
|
+
return syntaxHighlighting(highlightStyle);
|
|
469
|
+
}
|
|
470
|
+
function buildDuplicateStringHighlight(colors) {
|
|
471
|
+
const duplicateMark = Decoration.mark({
|
|
472
|
+
attributes: {
|
|
473
|
+
style: `background-color: ${colors.phrase}22; box-shadow: inset 0 0 0 1px ${colors.phrase}55; border-radius: 3px;`
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
const collectDuplicateRanges = (doc) => {
|
|
477
|
+
const stringPattern = /"(?:\\.|[^"\\])*"/g;
|
|
478
|
+
const occurrences = /* @__PURE__ */ new Map();
|
|
479
|
+
let match;
|
|
480
|
+
while ((match = stringPattern.exec(doc)) !== null) {
|
|
481
|
+
const token = match[0];
|
|
482
|
+
const after = doc.slice(match.index + token.length).match(/^\s*:/);
|
|
483
|
+
if (after) continue;
|
|
484
|
+
let value = "";
|
|
485
|
+
try {
|
|
486
|
+
value = JSON.parse(token);
|
|
487
|
+
} catch {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (typeof value !== "string" || value.trim().length === 0) continue;
|
|
491
|
+
const ranges = occurrences.get(value) ?? [];
|
|
492
|
+
ranges.push({ from: match.index, to: match.index + token.length });
|
|
493
|
+
occurrences.set(value, ranges);
|
|
494
|
+
}
|
|
495
|
+
return Array.from(occurrences.values()).filter((ranges) => ranges.length > 1).flat();
|
|
496
|
+
};
|
|
497
|
+
return ViewPlugin.fromClass(
|
|
498
|
+
class {
|
|
499
|
+
decorations;
|
|
500
|
+
constructor(view) {
|
|
501
|
+
this.decorations = this.build(view);
|
|
502
|
+
}
|
|
503
|
+
update(update) {
|
|
504
|
+
if (update.docChanged || update.viewportChanged) {
|
|
505
|
+
this.decorations = this.build(update.view);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
build(view) {
|
|
509
|
+
const builder = new RangeSetBuilder();
|
|
510
|
+
const ranges = collectDuplicateRanges(view.state.doc.toString());
|
|
511
|
+
ranges.sort((a, b) => a.from - b.from || a.to - b.to);
|
|
512
|
+
for (const range of ranges) {
|
|
513
|
+
builder.add(range.from, range.to, duplicateMark);
|
|
514
|
+
}
|
|
515
|
+
return builder.finish();
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
decorations: (plugin) => plugin.decorations
|
|
520
|
+
}
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
function buildStatusStringHighlight() {
|
|
524
|
+
const marks = {
|
|
525
|
+
fail: Decoration.mark({
|
|
526
|
+
attributes: {
|
|
527
|
+
style: "background-color: rgba(239, 68, 68, 0.18); color: #fca5a5; box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.45); border-radius: 3px;"
|
|
528
|
+
}
|
|
529
|
+
}),
|
|
530
|
+
low_confidence: Decoration.mark({
|
|
531
|
+
attributes: {
|
|
532
|
+
style: "background-color: rgba(245, 158, 11, 0.18); color: #fcd34d; box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.45); border-radius: 3px;"
|
|
533
|
+
}
|
|
534
|
+
}),
|
|
535
|
+
pass: Decoration.mark({
|
|
536
|
+
attributes: {
|
|
537
|
+
style: "background-color: rgba(16, 185, 129, 0.18); color: #6ee7b7; box-shadow: inset 0 0 0 1px rgba(16, 185, 129, 0.45); border-radius: 3px;"
|
|
538
|
+
}
|
|
539
|
+
}),
|
|
540
|
+
pending: Decoration.mark({
|
|
541
|
+
attributes: {
|
|
542
|
+
style: "background-color: rgba(148, 163, 184, 0.14); color: #cbd5e1; box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.35); border-radius: 3px;"
|
|
543
|
+
}
|
|
544
|
+
}),
|
|
545
|
+
missing: Decoration.mark({
|
|
546
|
+
attributes: {
|
|
547
|
+
style: "background-color: rgba(239, 68, 68, 0.18); color: #fca5a5; box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.45); border-radius: 3px;"
|
|
548
|
+
}
|
|
549
|
+
}),
|
|
550
|
+
extra: Decoration.mark({
|
|
551
|
+
attributes: {
|
|
552
|
+
style: "background-color: rgba(245, 158, 11, 0.18); color: #fcd34d; box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.45); border-radius: 3px;"
|
|
553
|
+
}
|
|
554
|
+
})
|
|
555
|
+
};
|
|
556
|
+
return ViewPlugin.fromClass(
|
|
557
|
+
class {
|
|
558
|
+
decorations;
|
|
559
|
+
constructor(view) {
|
|
560
|
+
this.decorations = this.build(view);
|
|
561
|
+
}
|
|
562
|
+
update(update) {
|
|
563
|
+
if (update.docChanged || update.viewportChanged) {
|
|
564
|
+
this.decorations = this.build(update.view);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
build(view) {
|
|
568
|
+
const builder = new RangeSetBuilder();
|
|
569
|
+
const doc = view.state.doc.toString();
|
|
570
|
+
const ranges = [];
|
|
571
|
+
const pattern = /"status"\s*:\s*"(fail|low_confidence|pass|pending)"/g;
|
|
572
|
+
let match;
|
|
573
|
+
while ((match = pattern.exec(doc)) !== null) {
|
|
574
|
+
const status = match[1];
|
|
575
|
+
const valueStart = match.index + match[0].lastIndexOf(`"${status}"`);
|
|
576
|
+
ranges.push({ from: valueStart, to: valueStart + status.length + 2, mark: marks[status] });
|
|
577
|
+
}
|
|
578
|
+
const toolArrayPattern = /"(missingTools|extraTools)"\s*:\s*\[([\s\S]*?)\]/g;
|
|
579
|
+
let arrayMatch;
|
|
580
|
+
while ((arrayMatch = toolArrayPattern.exec(doc)) !== null) {
|
|
581
|
+
const key = arrayMatch[1];
|
|
582
|
+
const content = arrayMatch[2] ?? "";
|
|
583
|
+
const contentStart = arrayMatch.index + arrayMatch[0].indexOf(content);
|
|
584
|
+
const stringPattern = /"(?:\\.|[^"\\])*"/g;
|
|
585
|
+
let stringMatch;
|
|
586
|
+
while ((stringMatch = stringPattern.exec(content)) !== null) {
|
|
587
|
+
const from = contentStart + stringMatch.index;
|
|
588
|
+
const to = from + stringMatch[0].length;
|
|
589
|
+
ranges.push({ from, to, mark: key === "missingTools" ? marks.missing : marks.extra });
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
ranges.sort((a, b) => a.from - b.from || a.to - b.to);
|
|
593
|
+
for (const range of ranges) builder.add(range.from, range.to, range.mark);
|
|
594
|
+
return builder.finish();
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
decorations: (plugin) => plugin.decorations
|
|
599
|
+
}
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
function JsonEditor({
|
|
603
|
+
value,
|
|
604
|
+
onChange,
|
|
605
|
+
onSave,
|
|
606
|
+
onReset,
|
|
607
|
+
onCancel,
|
|
608
|
+
dirty,
|
|
609
|
+
parseError,
|
|
610
|
+
saveError,
|
|
611
|
+
saveSuccess,
|
|
612
|
+
loading,
|
|
613
|
+
saving,
|
|
614
|
+
colors,
|
|
615
|
+
lineCount,
|
|
616
|
+
itemCount,
|
|
617
|
+
itemLabel,
|
|
618
|
+
loadingLabel,
|
|
619
|
+
readOnly = false,
|
|
620
|
+
smartPasteLabel,
|
|
621
|
+
onSmartPaste,
|
|
622
|
+
onCopy,
|
|
623
|
+
copyLabel,
|
|
624
|
+
headerMiddle,
|
|
625
|
+
statusAddon,
|
|
626
|
+
showActions = true,
|
|
627
|
+
highlightDuplicateStrings = false,
|
|
628
|
+
highlightStatusStrings = false
|
|
629
|
+
}) {
|
|
630
|
+
const onSaveRef = useRef(onSave);
|
|
631
|
+
onSaveRef.current = onSave;
|
|
632
|
+
const dirtyRef = useRef(dirty);
|
|
633
|
+
dirtyRef.current = dirty;
|
|
634
|
+
const parseErrorRef = useRef(parseError);
|
|
635
|
+
parseErrorRef.current = parseError;
|
|
636
|
+
const savingRef = useRef(saving);
|
|
637
|
+
savingRef.current = saving;
|
|
638
|
+
const customKeymap = useMemo(
|
|
639
|
+
() => keymap.of([
|
|
640
|
+
{
|
|
641
|
+
key: "Mod-s",
|
|
642
|
+
run: () => {
|
|
643
|
+
if (dirtyRef.current && !parseErrorRef.current && !savingRef.current) {
|
|
644
|
+
onSaveRef.current();
|
|
645
|
+
}
|
|
646
|
+
return true;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
]),
|
|
650
|
+
[]
|
|
651
|
+
);
|
|
652
|
+
const selectAllKeymap = useMemo(
|
|
653
|
+
() => keymap.of([
|
|
654
|
+
{
|
|
655
|
+
key: "Mod-a",
|
|
656
|
+
run: (view) => {
|
|
657
|
+
view.dispatch({
|
|
658
|
+
selection: EditorSelection.range(0, view.state.doc.length)
|
|
659
|
+
});
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
]),
|
|
664
|
+
[]
|
|
665
|
+
);
|
|
666
|
+
const theme = useMemo(() => buildStudioTheme2(colors), [colors]);
|
|
667
|
+
const highlightStyle = useMemo(() => buildJsonHighlightStyle2(colors), [colors]);
|
|
668
|
+
const duplicateStringHighlight = useMemo(
|
|
669
|
+
() => buildDuplicateStringHighlight(colors),
|
|
670
|
+
[colors]
|
|
671
|
+
);
|
|
672
|
+
const statusStringHighlight = useMemo(() => buildStatusStringHighlight(), []);
|
|
673
|
+
const extensions = useMemo(
|
|
674
|
+
() => [
|
|
675
|
+
json(),
|
|
676
|
+
theme,
|
|
677
|
+
highlightStyle,
|
|
678
|
+
customKeymap,
|
|
679
|
+
selectAllKeymap,
|
|
680
|
+
EditorView.lineWrapping,
|
|
681
|
+
...highlightDuplicateStrings ? [duplicateStringHighlight] : [],
|
|
682
|
+
...highlightStatusStrings ? [statusStringHighlight] : []
|
|
683
|
+
],
|
|
684
|
+
[
|
|
685
|
+
json,
|
|
686
|
+
theme,
|
|
687
|
+
highlightStyle,
|
|
688
|
+
customKeymap,
|
|
689
|
+
selectAllKeymap,
|
|
690
|
+
highlightDuplicateStrings,
|
|
691
|
+
duplicateStringHighlight,
|
|
692
|
+
highlightStatusStrings,
|
|
693
|
+
statusStringHighlight
|
|
694
|
+
]
|
|
695
|
+
);
|
|
696
|
+
const handleChange = useCallback(
|
|
697
|
+
(newValue) => {
|
|
698
|
+
onChange(newValue);
|
|
699
|
+
},
|
|
700
|
+
[onChange]
|
|
701
|
+
);
|
|
702
|
+
const statusMessage = useMemo(() => {
|
|
703
|
+
if (loading) return { text: loadingLabel, type: "loading" };
|
|
704
|
+
if (saving) return { text: "Saving...", type: "saving" };
|
|
705
|
+
if (saveError) return { text: saveError.slice(0, 120), type: "error" };
|
|
706
|
+
if (dirty) {
|
|
707
|
+
if (parseError) return { text: `JSON error: ${parseError.slice(0, 120)}`, type: "error" };
|
|
708
|
+
return { text: "Valid JSON - unsaved changes", type: "success" };
|
|
709
|
+
}
|
|
710
|
+
return { text: readOnly ? "Read-only" : "Saved", type: "idle" };
|
|
711
|
+
}, [loading, saving, saveError, dirty, parseError, loadingLabel, readOnly]);
|
|
712
|
+
const dotClass = saving ? "bg-amber-400 animate-ping" : !saving && dirty && parseError ? "bg-rose-500" : !saving && dirty && !parseError ? "bg-amber-400" : "bg-emerald-600";
|
|
713
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-h-0", style: { backgroundColor: colors.background }, children: [
|
|
714
|
+
/* @__PURE__ */ jsxs(
|
|
715
|
+
"div",
|
|
716
|
+
{
|
|
717
|
+
className: "relative flex items-center justify-between gap-3 border-b px-3 py-2 shrink-0 sm:px-4",
|
|
718
|
+
style: { borderColor: colors.bracket + "44", minHeight: "44px" },
|
|
719
|
+
children: [
|
|
720
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
721
|
+
statusMessage.type === "loading" && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: statusMessage.text }),
|
|
722
|
+
statusMessage.type === "saving" && /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1.5 text-xs text-amber-400 animate-pulse", children: [
|
|
723
|
+
/* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin" }),
|
|
724
|
+
" ",
|
|
725
|
+
statusMessage.text
|
|
726
|
+
] }),
|
|
727
|
+
statusMessage.type === "error" && /* @__PURE__ */ jsxs("span", { className: "truncate text-xs text-rose-400", children: [
|
|
728
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "h-3 w-3 inline mr-1" }),
|
|
729
|
+
" ",
|
|
730
|
+
statusMessage.text
|
|
731
|
+
] }),
|
|
732
|
+
statusMessage.type === "success" && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-emerald-400", children: statusMessage.text }),
|
|
733
|
+
statusMessage.type === "idle" && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs", style: { color: colors.bracket }, children: statusMessage.text }),
|
|
734
|
+
statusAddon && /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: statusAddon })
|
|
735
|
+
] }),
|
|
736
|
+
headerMiddle && /* @__PURE__ */ jsx("div", { className: "hidden shrink-0 items-center gap-1.5 md:flex", children: headerMiddle }),
|
|
737
|
+
showActions && /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1.5 overflow-x-auto", children: [
|
|
738
|
+
onSmartPaste && /* @__PURE__ */ jsxs(Button, { variant: "secondary", disabled: saving || loading, onClick: onSmartPaste, title: "Paste & merge JSON from clipboard", className: "gap-1.5 whitespace-nowrap px-2 sm:px-3", children: [
|
|
739
|
+
/* @__PURE__ */ jsx(ClipboardPaste, { className: "h-3.5 w-3.5 mr-1" }),
|
|
740
|
+
/* @__PURE__ */ jsx("span", { children: smartPasteLabel ?? "Paste" })
|
|
741
|
+
] }),
|
|
742
|
+
onCopy && /* @__PURE__ */ jsxs(Button, { variant: "outline", disabled: loading, onClick: onCopy, title: "Copy JSON to clipboard", className: "gap-1.5 whitespace-nowrap px-2 sm:px-3", children: [
|
|
743
|
+
/* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5 mr-1" }),
|
|
744
|
+
copyLabel ?? "Copy"
|
|
745
|
+
] }),
|
|
746
|
+
/* @__PURE__ */ jsxs(Button, { variant: "ghost", disabled: !dirty || saving, onClick: onReset, title: "Reset all JSON changes", className: "gap-1.5 whitespace-nowrap px-2 sm:px-3", children: [
|
|
747
|
+
/* @__PURE__ */ jsx(RotateCcw, { className: "h-3.5 w-3.5 mr-1" }),
|
|
748
|
+
"Reset All"
|
|
749
|
+
] })
|
|
750
|
+
] })
|
|
751
|
+
]
|
|
752
|
+
}
|
|
753
|
+
),
|
|
754
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 relative overflow-hidden", children: loading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center h-full text-muted-foreground text-sm", children: [
|
|
755
|
+
/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin mr-2" }),
|
|
756
|
+
" ",
|
|
757
|
+
loadingLabel
|
|
758
|
+
] }) : /* @__PURE__ */ jsx(
|
|
759
|
+
CodeMirror,
|
|
760
|
+
{
|
|
761
|
+
value,
|
|
762
|
+
className: "absolute inset-0",
|
|
763
|
+
height: "100%",
|
|
764
|
+
extensions,
|
|
765
|
+
onChange: handleChange,
|
|
766
|
+
editable: !readOnly && !saving,
|
|
767
|
+
basicSetup: {
|
|
768
|
+
lineNumbers: true,
|
|
769
|
+
highlightActiveLineGutter: true,
|
|
770
|
+
highlightActiveLine: true,
|
|
771
|
+
foldGutter: false,
|
|
772
|
+
dropCursor: false,
|
|
773
|
+
allowMultipleSelections: false,
|
|
774
|
+
indentOnInput: true,
|
|
775
|
+
bracketMatching: true,
|
|
776
|
+
closeBrackets: true,
|
|
777
|
+
autocompletion: false,
|
|
778
|
+
searchKeymap: false
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
) }),
|
|
782
|
+
/* @__PURE__ */ jsxs(
|
|
783
|
+
"div",
|
|
784
|
+
{
|
|
785
|
+
className: "grid gap-1.5 border-t px-3 py-2 text-[11px] shrink-0 sm:flex sm:items-center sm:justify-between sm:px-4 sm:py-1.5",
|
|
786
|
+
style: { color: colors.bracket, borderColor: colors.bracket + "33" },
|
|
787
|
+
children: [
|
|
788
|
+
/* @__PURE__ */ jsxs("div", { className: "hidden items-center gap-4 sm:flex", children: [
|
|
789
|
+
/* @__PURE__ */ jsx("span", { children: "Edit freely - copy, paste, find & replace" }),
|
|
790
|
+
/* @__PURE__ */ jsx("span", { children: "Ctrl+S to save" })
|
|
791
|
+
] }),
|
|
792
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 justify-start sm:flex-1 sm:justify-center sm:px-4", children: saveSuccess && /* @__PURE__ */ jsx("span", { className: "text-emerald-400 truncate", children: saveSuccess }) }),
|
|
793
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: [
|
|
794
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
795
|
+
lineCount,
|
|
796
|
+
" lines"
|
|
797
|
+
] }),
|
|
798
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
799
|
+
itemCount,
|
|
800
|
+
" ",
|
|
801
|
+
itemLabel
|
|
802
|
+
] }),
|
|
803
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
804
|
+
/* @__PURE__ */ jsx("span", { className: `inline-block h-2 w-2 rounded-full ${dotClass}` }),
|
|
805
|
+
/* @__PURE__ */ jsx("span", { className: dirty ? "text-amber-400" : "text-emerald-400", children: saving ? "Saving\u2026" : dirty ? "Modified" : "Saved" })
|
|
806
|
+
] })
|
|
807
|
+
] })
|
|
808
|
+
]
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
] });
|
|
812
|
+
}
|
|
813
|
+
var TableStoreContext = createContext(null);
|
|
814
|
+
var useTableStore = { use: {} };
|
|
815
|
+
var handler = {
|
|
816
|
+
get: (_, prop) => () => {
|
|
817
|
+
const store = useContext(TableStoreContext);
|
|
818
|
+
if (!store) throw new Error("useTableStore must be used within NTable");
|
|
819
|
+
return store.use[prop]();
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
useTableStore.use = new Proxy({}, handler);
|
|
823
|
+
function formatJsonValue(value) {
|
|
824
|
+
if (typeof value === "string") return value;
|
|
825
|
+
try {
|
|
826
|
+
return JSON.stringify(value ?? null, null, 2) ?? String(value);
|
|
827
|
+
} catch {
|
|
828
|
+
return String(value);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
function NTableJson() {
|
|
832
|
+
const viewMode = useTableStore.use.viewMode();
|
|
833
|
+
const renderJson = useTableStore.use.renderJson();
|
|
834
|
+
const jsonValue = useTableStore.use.jsonValue();
|
|
835
|
+
if (viewMode !== "json") return null;
|
|
836
|
+
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col min-h-0 overflow-hidden", children: renderJson?.() ?? /* @__PURE__ */ jsx("pre", { className: "h-full min-h-0 overflow-auto rounded-md border border-border bg-muted/40 p-4 font-mono text-xs leading-relaxed text-foreground", children: formatJsonValue(jsonValue) }) });
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
export { JsonEditor, JsonViewer, NTableJson };
|