@bian-womp/spark-workbench 0.1.21 → 0.1.23
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/lib/cjs/index.cjs +68 -65
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/misc/DefaultContextMenu.d.ts.map +1 -1
- package/lib/cjs/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/cjs/src/misc/Inspector.d.ts.map +1 -1
- package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/lib/cjs/src/misc/value.d.ts +1 -0
- package/lib/cjs/src/misc/value.d.ts.map +1 -1
- package/lib/cjs/src/runtime/GraphRunner.d.ts +7 -1
- package/lib/cjs/src/runtime/GraphRunner.d.ts.map +1 -1
- package/lib/esm/index.js +69 -67
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/misc/DefaultContextMenu.d.ts.map +1 -1
- package/lib/esm/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/esm/src/misc/Inspector.d.ts.map +1 -1
- package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/lib/esm/src/misc/value.d.ts +1 -0
- package/lib/esm/src/misc/value.d.ts.map +1 -1
- package/lib/esm/src/runtime/GraphRunner.d.ts +7 -1
- package/lib/esm/src/runtime/GraphRunner.d.ts.map +1 -1
- package/package.json +4 -4
package/lib/cjs/index.cjs
CHANGED
|
@@ -327,6 +327,9 @@ class GraphRunner {
|
|
|
327
327
|
this.backend = { kind: "local" };
|
|
328
328
|
if (backend)
|
|
329
329
|
this.backend = backend;
|
|
330
|
+
// Emit initial transport status
|
|
331
|
+
if (this.backend.kind === "local")
|
|
332
|
+
this.emit("transport", { state: "local" });
|
|
330
333
|
}
|
|
331
334
|
build(def) {
|
|
332
335
|
if (this.backend.kind === "local") {
|
|
@@ -615,6 +618,13 @@ class GraphRunner {
|
|
|
615
618
|
this.runningKind = undefined;
|
|
616
619
|
this.emit("status", { running: false, engine: undefined });
|
|
617
620
|
}
|
|
621
|
+
const kind = this.backend.kind === "local"
|
|
622
|
+
? undefined
|
|
623
|
+
: this.backend.kind;
|
|
624
|
+
this.emit("transport", {
|
|
625
|
+
state: this.backend.kind === "local" ? "local" : "disconnected",
|
|
626
|
+
kind,
|
|
627
|
+
});
|
|
618
628
|
}
|
|
619
629
|
isRunning() {
|
|
620
630
|
return !!this.engine;
|
|
@@ -627,6 +637,8 @@ class GraphRunner {
|
|
|
627
637
|
if (this.remote)
|
|
628
638
|
return this.remote;
|
|
629
639
|
let transport;
|
|
640
|
+
const kind = this.backend.kind === "remote-http" ? "remote-http" : "remote-ws";
|
|
641
|
+
this.emit("transport", { state: "connecting", kind });
|
|
630
642
|
if (this.backend.kind === "remote-http") {
|
|
631
643
|
if (!sparkRemote.HttpPollingTransport)
|
|
632
644
|
throw new Error("HttpPollingTransport not available");
|
|
@@ -649,6 +661,7 @@ class GraphRunner {
|
|
|
649
661
|
valueCache: new Map(),
|
|
650
662
|
listenersBound: false,
|
|
651
663
|
};
|
|
664
|
+
this.emit("transport", { state: "connected", kind });
|
|
652
665
|
return this.remote;
|
|
653
666
|
}
|
|
654
667
|
}
|
|
@@ -817,6 +830,19 @@ function useQueryParamString(key, defaultValue) {
|
|
|
817
830
|
return [val, set];
|
|
818
831
|
}
|
|
819
832
|
|
|
833
|
+
function formatDataUrlAsLabel(dataUrl) {
|
|
834
|
+
try {
|
|
835
|
+
const semi = dataUrl.indexOf(";");
|
|
836
|
+
const comma = dataUrl.indexOf(",");
|
|
837
|
+
const mime = dataUrl.slice(5, semi > 0 ? semi : undefined).toUpperCase();
|
|
838
|
+
const b64 = comma >= 0 ? dataUrl.slice(comma + 1) : "";
|
|
839
|
+
const bytes = Math.floor((b64.length * 3) / 4);
|
|
840
|
+
return `${mime} Data (${bytes} bytes)`;
|
|
841
|
+
}
|
|
842
|
+
catch {
|
|
843
|
+
return dataUrl.length > 64 ? dataUrl.slice(0, 64) + "…" : dataUrl;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
820
846
|
function resolveOutputDisplay(raw, declared) {
|
|
821
847
|
if (sparkGraph.isTypedOutput(raw)) {
|
|
822
848
|
return {
|
|
@@ -847,7 +873,7 @@ function preformatValueForDisplay(typeId, value, registry) {
|
|
|
847
873
|
return preformatValueForDisplay(sparkGraph.getTypedOutputTypeId(value), sparkGraph.getTypedOutputValue(value), registry);
|
|
848
874
|
}
|
|
849
875
|
// Enums
|
|
850
|
-
if (typeId && typeId.
|
|
876
|
+
if (typeId && typeId.startsWith("enum:") && registry) {
|
|
851
877
|
const n = Number(value);
|
|
852
878
|
const label = registry.enums.get(typeId)?.valueToLabel.get(n);
|
|
853
879
|
if (label)
|
|
@@ -871,19 +897,8 @@ function preformatValueForDisplay(typeId, value, registry) {
|
|
|
871
897
|
function summarizeDeep(value) {
|
|
872
898
|
// Strings: summarize data URLs and trim extremely long strings
|
|
873
899
|
if (typeof value === "string") {
|
|
874
|
-
if (value.startsWith("data:"))
|
|
875
|
-
|
|
876
|
-
const semi = value.indexOf(";");
|
|
877
|
-
const comma = value.indexOf(",");
|
|
878
|
-
const mime = value.slice(5, semi > 0 ? semi : undefined).toUpperCase();
|
|
879
|
-
const b64 = comma >= 0 ? value.slice(comma + 1) : "";
|
|
880
|
-
const bytes = Math.floor((b64.length * 3) / 4);
|
|
881
|
-
return `${mime} Data (${bytes} bytes)`;
|
|
882
|
-
}
|
|
883
|
-
catch {
|
|
884
|
-
return value.length > 64 ? value.slice(0, 64) + "…" : value;
|
|
885
|
-
}
|
|
886
|
-
}
|
|
900
|
+
if (value.startsWith("data:"))
|
|
901
|
+
return formatDataUrlAsLabel(value);
|
|
887
902
|
return value.length > 512 ? value.slice(0, 512) + "…" : value;
|
|
888
903
|
}
|
|
889
904
|
// Typed output wrapper
|
|
@@ -903,18 +918,8 @@ function summarizeDeep(value) {
|
|
|
903
918
|
if (typeof v === "string" &&
|
|
904
919
|
k.toLowerCase() === "url" &&
|
|
905
920
|
v.startsWith("data:")) {
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
const comma = v.indexOf(",");
|
|
909
|
-
const mime = v.slice(5, semi > 0 ? semi : undefined).toUpperCase();
|
|
910
|
-
const b64 = comma >= 0 ? v.slice(comma + 1) : "";
|
|
911
|
-
const bytes = Math.floor((b64.length * 3) / 4);
|
|
912
|
-
out[k] = `${mime} Data (${bytes} bytes)`;
|
|
913
|
-
continue;
|
|
914
|
-
}
|
|
915
|
-
catch {
|
|
916
|
-
// fallthrough
|
|
917
|
-
}
|
|
921
|
+
out[k] = formatDataUrlAsLabel(v);
|
|
922
|
+
continue;
|
|
918
923
|
}
|
|
919
924
|
out[k] = summarizeDeep(v);
|
|
920
925
|
}
|
|
@@ -1085,11 +1090,14 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
|
1085
1090
|
const out = {};
|
|
1086
1091
|
// Local: runtimeTypeId is not stored; derive from typed wrapper in outputsMap
|
|
1087
1092
|
for (const n of def.nodes) {
|
|
1088
|
-
const
|
|
1093
|
+
const outputsDecl = registry.nodes.get(n.typeId)?.outputs ?? {};
|
|
1094
|
+
const handles = Object.keys(outputsDecl);
|
|
1089
1095
|
const cur = {};
|
|
1090
1096
|
for (const h of handles) {
|
|
1091
1097
|
const v = outputsMap[n.nodeId]?.[h];
|
|
1092
|
-
|
|
1098
|
+
const declared = outputsDecl[h];
|
|
1099
|
+
const { typeId } = resolveOutputDisplay(v, declared);
|
|
1100
|
+
cur[h] = typeId;
|
|
1093
1101
|
}
|
|
1094
1102
|
if (Object.keys(cur).length > 0)
|
|
1095
1103
|
out[n.nodeId] = cur;
|
|
@@ -1524,14 +1532,6 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
1524
1532
|
const safeToString = (typeId, value) => {
|
|
1525
1533
|
try {
|
|
1526
1534
|
if (typeof toString === "function") {
|
|
1527
|
-
// Special-case data URLs for readability
|
|
1528
|
-
if (typeof value === "string" && value.startsWith("data:image/")) {
|
|
1529
|
-
const comma = value.indexOf(",");
|
|
1530
|
-
const b64 = comma >= 0 ? value.slice(comma + 1) : "";
|
|
1531
|
-
const bytes = Math.floor((b64.length * 3) / 4);
|
|
1532
|
-
const fmt = value.slice(5, value.indexOf(";")) || "image";
|
|
1533
|
-
return `${fmt.toUpperCase()} Data (${bytes} bytes)`;
|
|
1534
|
-
}
|
|
1535
1535
|
return toString(typeId, value);
|
|
1536
1536
|
}
|
|
1537
1537
|
return String(value ?? "");
|
|
@@ -1640,7 +1640,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
1640
1640
|
const orig = originals[h] ?? safeToString(typeId, current);
|
|
1641
1641
|
setDrafts((d) => ({ ...d, [h]: orig }));
|
|
1642
1642
|
};
|
|
1643
|
-
const isEnum = typeId?.
|
|
1643
|
+
const isEnum = typeId?.startsWith("enum:");
|
|
1644
1644
|
const inIssues = selectedNodeHandleValidation.inputs.filter((m) => m.handle === h);
|
|
1645
1645
|
const hasValidation = inIssues.length > 0;
|
|
1646
1646
|
const hasErr = inIssues.some((m) => m.level === "error");
|
|
@@ -1747,7 +1747,7 @@ const DefaultNode = React.memo(function DefaultNode({ id, data, selected, isConn
|
|
|
1747
1747
|
whiteSpace: "nowrap",
|
|
1748
1748
|
overflow: "hidden",
|
|
1749
1749
|
textOverflow: "ellipsis",
|
|
1750
|
-
}, title: `${entry.id}: ${entry.typeId}`, children: [entry.id,
|
|
1750
|
+
}, title: `${entry.id}: ${entry.typeId}`, children: [entry.id, hasAny && (jsxRuntime.jsx(IssueBadge, { level: hasErr ? "error" : "warning", size: 12, className: "ml-1", title: title })), showValues && (jsxRuntime.jsx("span", { className: "ml-1 opacity-60", children: toString(resolved.typeId, resolved.value) }))] })] }, `out-${entry.id}`));
|
|
1751
1751
|
})] }));
|
|
1752
1752
|
});
|
|
1753
1753
|
DefaultNode.displayName = "DefaultNode";
|
|
@@ -1756,16 +1756,18 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
1756
1756
|
const { registry } = useWorkbenchContext();
|
|
1757
1757
|
const rf = ReactFlow.useReactFlow();
|
|
1758
1758
|
const ids = Array.from(registry.nodes.keys());
|
|
1759
|
-
|
|
1760
|
-
const grouped = {};
|
|
1759
|
+
const root = { __children: {} };
|
|
1761
1760
|
for (const id of ids) {
|
|
1762
1761
|
const parts = id.split(".");
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1762
|
+
let node = root;
|
|
1763
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1764
|
+
const key = parts[i];
|
|
1765
|
+
node.__children[key] = node.__children[key] || { __children: {} };
|
|
1766
|
+
node = node.__children[key];
|
|
1767
|
+
if (i === parts.length - 1)
|
|
1768
|
+
node.__self = id;
|
|
1769
|
+
}
|
|
1766
1770
|
}
|
|
1767
|
-
const cats = Object.keys(grouped).sort((a, b) => a.localeCompare(b));
|
|
1768
|
-
cats.forEach((c) => grouped[c].sort((a, b) => a.label.localeCompare(b.label)));
|
|
1769
1771
|
const totalCount = ids.length;
|
|
1770
1772
|
// Ref for focus/outside click handling
|
|
1771
1773
|
const ref = React.useRef(null);
|
|
@@ -1809,10 +1811,19 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
1809
1811
|
onAdd(typeId, p);
|
|
1810
1812
|
onClose();
|
|
1811
1813
|
};
|
|
1814
|
+
const renderTree = (tree, path = []) => {
|
|
1815
|
+
const entries = Object.entries(tree.__children).sort((a, b) => a[0].localeCompare(b[0]));
|
|
1816
|
+
return (jsxRuntime.jsx("div", { children: entries.map(([key, child]) => {
|
|
1817
|
+
const label = key;
|
|
1818
|
+
const hasChildren = Object.keys(child.__children).length > 0;
|
|
1819
|
+
!!child.__self && !hasChildren;
|
|
1820
|
+
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wide text-gray-400", children: label }), child.__self && (jsxRuntime.jsx("button", { onClick: () => handleClick(child.__self), className: "block w-full text-left px-3 py-1 hover:bg-gray-100 cursor-pointer", title: child.__self, children: child.__self.split(".").slice(-1)[0] })), hasChildren && (jsxRuntime.jsx("div", { className: "pl-2 border-l border-gray-200 ml-2", children: renderTree(child, [...path, key]) }))] }, [...path, key].join(".")));
|
|
1821
|
+
}) }));
|
|
1822
|
+
};
|
|
1812
1823
|
return (jsxRuntime.jsxs("div", { ref: ref, tabIndex: -1, className: "fixed z-[1000] bg-white border border-gray-300 rounded-none shadow-lg p-1 min-w-[180px] text-sm text-gray-700", style: { left: x, top: y }, onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation(), onContextMenu: (e) => {
|
|
1813
1824
|
e.preventDefault();
|
|
1814
1825
|
e.stopPropagation();
|
|
1815
|
-
}, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Add Node ", jsxRuntime.jsxs("span", { className: "text-gray-500 font-normal", children: ["(", totalCount, ")"] })] }), jsxRuntime.jsx("div", { className: "max-h-60 overflow-auto", children:
|
|
1826
|
+
}, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Add Node ", jsxRuntime.jsxs("span", { className: "text-gray-500 font-normal", children: ["(", totalCount, ")"] })] }), jsxRuntime.jsx("div", { className: "max-h-60 overflow-auto", children: renderTree(root) })] }));
|
|
1816
1827
|
}
|
|
1817
1828
|
|
|
1818
1829
|
function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
|
|
@@ -1981,6 +1992,9 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement }, r
|
|
|
1981
1992
|
|
|
1982
1993
|
function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
|
|
1983
1994
|
const { wb, runner, registry, def, selectedNodeId, runAutoLayout } = useWorkbenchContext();
|
|
1995
|
+
const [transportStatus, setTransportStatus] = React.useState({
|
|
1996
|
+
state: "local",
|
|
1997
|
+
});
|
|
1984
1998
|
const selectedNode = def.nodes.find((n) => n.nodeId === selectedNodeId);
|
|
1985
1999
|
const selectedDesc = selectedNode
|
|
1986
2000
|
? registry.nodes.get(selectedNode.typeId)
|
|
@@ -2194,6 +2208,10 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2194
2208
|
return;
|
|
2195
2209
|
applyExample(example);
|
|
2196
2210
|
}, [example, wb]);
|
|
2211
|
+
React.useEffect(() => {
|
|
2212
|
+
const off = runner.on("transport", (s) => setTransportStatus(s));
|
|
2213
|
+
return () => off();
|
|
2214
|
+
}, [runner]);
|
|
2197
2215
|
React.useEffect(() => {
|
|
2198
2216
|
if (!engine)
|
|
2199
2217
|
return;
|
|
@@ -2337,26 +2355,10 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2337
2355
|
typeof value.url === "string") {
|
|
2338
2356
|
const title = value.title || "";
|
|
2339
2357
|
const url = String(value.url || "");
|
|
2340
|
-
|
|
2341
|
-
try {
|
|
2342
|
-
const semi = url.indexOf(";");
|
|
2343
|
-
const comma = url.indexOf(",");
|
|
2344
|
-
const mime = url
|
|
2345
|
-
.slice(5, semi > 0 ? semi : undefined)
|
|
2346
|
-
.toUpperCase();
|
|
2347
|
-
const b64 = comma >= 0 ? url.slice(comma + 1) : "";
|
|
2348
|
-
const bytes = Math.floor((b64.length * 3) / 4);
|
|
2349
|
-
return title
|
|
2350
|
-
? `${title} (${mime} ${bytes} bytes)`
|
|
2351
|
-
: `${mime} Data (${bytes} bytes)`;
|
|
2352
|
-
}
|
|
2353
|
-
catch {
|
|
2354
|
-
return title || url.slice(0, 32) + (url.length > 32 ? "…" : "");
|
|
2355
|
-
}
|
|
2356
|
-
}
|
|
2358
|
+
// value.ts handles data URL formatting
|
|
2357
2359
|
return title || url.slice(0, 32) + (url.length > 32 ? "…" : "");
|
|
2358
2360
|
}
|
|
2359
|
-
if (typeId && typeId.
|
|
2361
|
+
if (typeId && typeId.startsWith("enum:")) {
|
|
2360
2362
|
const n = Number(value);
|
|
2361
2363
|
const label = registry.enums.get(typeId)?.valueToLabel.get(n);
|
|
2362
2364
|
return label ?? String(n);
|
|
@@ -2400,7 +2402,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2400
2402
|
return overrides.toElement(baseToElement, { registry });
|
|
2401
2403
|
return baseToElement;
|
|
2402
2404
|
}, [overrides, baseToElement, registry]);
|
|
2403
|
-
return (jsxRuntime.jsxs("div", { className: "w-full h-screen flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-2 border-b border-gray-300 flex gap-2 items-center", children: [runner.isRunning() ? (jsxRuntime.jsxs("span", { className: "ml-2 text-sm text-green-700", children: ["Running: ", runner.getRunningEngine()] })) : (jsxRuntime.jsx("span", { className: "ml-2 text-sm text-gray-500", children: "Stopped" })), jsxRuntime.jsx("label", { className: "ml-2 text-sm", children: "Example:" }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: exampleState, onChange: (e) => applyExample(e.target.value), disabled: runner.isRunning(), title: runner.isRunning()
|
|
2405
|
+
return (jsxRuntime.jsxs("div", { className: "w-full h-screen flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-2 border-b border-gray-300 flex gap-2 items-center", children: [runner.isRunning() ? (jsxRuntime.jsxs("span", { className: "ml-2 text-sm text-green-700", children: ["Running: ", runner.getRunningEngine()] })) : (jsxRuntime.jsx("span", { className: "ml-2 text-sm text-gray-500", children: "Stopped" })), jsxRuntime.jsxs("span", { className: "ml-2 flex items-center gap-1 text-xs", title: transportStatus.kind || undefined, children: [transportStatus.state === "local" && (jsxRuntime.jsx(react.PlugsConnectedIcon, { size: 14, className: "text-gray-500" })), transportStatus.state === "connecting" && (jsxRuntime.jsx(react.ClockClockwiseIcon, { size: 14, className: "text-amber-600 animate-pulse" })), transportStatus.state === "connected" && (jsxRuntime.jsx(react.WifiHighIcon, { size: 14, className: "text-green-600" })), transportStatus.state === "disconnected" && (jsxRuntime.jsx(react.WifiSlashIcon, { size: 14, className: "text-red-600" })), transportStatus.state === "retrying" && (jsxRuntime.jsx(react.ClockClockwiseIcon, { size: 14, className: "text-amber-700 animate-pulse" }))] }), jsxRuntime.jsx("label", { className: "ml-2 text-sm", children: "Example:" }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: exampleState, onChange: (e) => applyExample(e.target.value), disabled: runner.isRunning(), title: runner.isRunning()
|
|
2404
2406
|
? "Stop engine before switching example"
|
|
2405
2407
|
: undefined, children: [jsxRuntime.jsx("option", { value: "", children: "Select Example\u2026" }), examples.map((ex) => (jsxRuntime.jsx("option", { value: ex.id, children: ex.label }, ex.id)))] }), jsxRuntime.jsx("label", { className: "ml-2 text-sm", children: "Backend:" }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: backendKind, onChange: (e) => onBackendKindChange(e.target.value), disabled: runner.isRunning(), title: runner.isRunning()
|
|
2406
2408
|
? "Stop engine before switching backend"
|
|
@@ -2453,6 +2455,7 @@ exports.WorkbenchCanvas = WorkbenchCanvas;
|
|
|
2453
2455
|
exports.WorkbenchContext = WorkbenchContext;
|
|
2454
2456
|
exports.WorkbenchProvider = WorkbenchProvider;
|
|
2455
2457
|
exports.WorkbenchStudio = WorkbenchStudio;
|
|
2458
|
+
exports.formatDataUrlAsLabel = formatDataUrlAsLabel;
|
|
2456
2459
|
exports.formatDeclaredTypeSignature = formatDeclaredTypeSignature;
|
|
2457
2460
|
exports.getNodeBorderClassNames = getNodeBorderClassNames;
|
|
2458
2461
|
exports.preformatValueForDisplay = preformatValueForDisplay;
|