@flanksource/clicky-ui 0.3.7 → 0.3.9
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/data/ObjectGraph.cjs +39 -4
- package/dist/data/ObjectGraph.cjs.map +1 -1
- package/dist/data/ObjectGraph.d.ts +9 -1
- package/dist/data/ObjectGraph.d.ts.map +1 -1
- package/dist/data/ObjectGraph.js +39 -4
- package/dist/data/ObjectGraph.js.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/package.json +4 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const utils = require("../lib/utils.cjs");
|
|
4
5
|
const Tree = require("./Tree.cjs");
|
|
5
6
|
function ObjectGraph({
|
|
6
7
|
roots,
|
|
@@ -9,7 +10,9 @@ function ObjectGraph({
|
|
|
9
10
|
showControls,
|
|
10
11
|
defaultOpenDepth = 2,
|
|
11
12
|
renderLabel,
|
|
12
|
-
loadChildren
|
|
13
|
+
loadChildren,
|
|
14
|
+
onNodeSelect,
|
|
15
|
+
selectedId
|
|
13
16
|
}) {
|
|
14
17
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15
18
|
Tree.Tree,
|
|
@@ -23,16 +26,48 @@ function ObjectGraph({
|
|
|
23
26
|
...showControls !== void 0 ? { showControls } : {},
|
|
24
27
|
...loadChildren ? { loadChildren, hasMoreChildren: (n) => n.expandable === true } : {},
|
|
25
28
|
renderRow: ({ node, loading, error }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-2 font-mono text-xs", children: [
|
|
26
|
-
renderLabel ? renderLabel(node) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
29
|
+
renderLabel ? renderLabel(node) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
30
|
+
DefaultObjectLabel,
|
|
31
|
+
{
|
|
32
|
+
node,
|
|
33
|
+
selected: selectedId != null && node.id === selectedId,
|
|
34
|
+
...onNodeSelect ? { onSelect: onNodeSelect } : {}
|
|
35
|
+
}
|
|
36
|
+
),
|
|
27
37
|
loading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: "…" }),
|
|
28
38
|
error != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-all text-red-600", children: error instanceof Error ? error.message : String(error) })
|
|
29
39
|
] })
|
|
30
40
|
}
|
|
31
41
|
);
|
|
32
42
|
}
|
|
33
|
-
function DefaultObjectLabel({
|
|
43
|
+
function DefaultObjectLabel({
|
|
44
|
+
node,
|
|
45
|
+
onSelect,
|
|
46
|
+
selected = false
|
|
47
|
+
}) {
|
|
48
|
+
const label = onSelect ? (
|
|
49
|
+
// A button so the label is a first-class click target; stopPropagation keeps
|
|
50
|
+
// the row's onClick (which toggles the node) from firing, so selecting a node
|
|
51
|
+
// never expands or collapses it.
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
53
|
+
"button",
|
|
54
|
+
{
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: (e) => {
|
|
57
|
+
e.stopPropagation();
|
|
58
|
+
onSelect(node);
|
|
59
|
+
},
|
|
60
|
+
title: "Select this path",
|
|
61
|
+
className: utils.cn(
|
|
62
|
+
"rounded px-0.5 text-left text-muted-foreground hover:text-foreground hover:underline",
|
|
63
|
+
selected && "bg-primary/15 text-foreground"
|
|
64
|
+
),
|
|
65
|
+
children: node.label
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: node.label });
|
|
34
69
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
35
|
-
|
|
70
|
+
label,
|
|
36
71
|
node.type && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground/60", children: [
|
|
37
72
|
"@",
|
|
38
73
|
node.type
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectGraph.cjs","sources":["../../src/data/ObjectGraph.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Tree } from \"./Tree\";\n\n// ObjectGraph renders a generic, type-agnostic expandable object/value\n// inspector — a bean's fields, a map's entries, a list's elements, a scalar\n// leaf. It is the shared home for what used to be per-feature object viewers\n// (e.g. an OGNL inspector): any producer maps its data into ObjectGraphNode and\n// gets the same tree, search, and lazy-expansion behaviour.\n\nexport type ObjectGraphNode = {\n /** Stable unique key within the tree. */\n id: string;\n /** Display label (field name, map key, index, …). */\n label: string;\n /** Optional type annotation rendered as `@type`. */\n type?: string;\n /** Scalar value for a leaf; absent for containers. */\n value?: string | number | boolean | null;\n /** Free-form node kind hint (object|map|list|scalar|…). */\n kind?: string;\n /** Accessor path from the root (used by lazy expansion). */\n path?: string;\n /** Verbatim preview for an opaque node with no structured children. */\n raw?: string;\n /** Node can be expanded via loadChildren even with no inline children. */\n expandable?: boolean;\n /** Caller-opaque context (carried through, not rendered by default). */\n metadata?: Record<string, unknown>;\n children?: ObjectGraphNode[];\n};\n\nexport type ObjectGraphProps<T extends ObjectGraphNode = ObjectGraphNode> = {\n roots: T[];\n className?: string;\n empty?: ReactNode;\n showControls?: boolean;\n /** Open nodes shallower than this depth on first render (default 2). */\n defaultOpenDepth?: number;\n /** Override the row label rendering. */\n renderLabel?: (node: T) => ReactNode;\n /**\n * Lazily fetch a node's children the first time an `expandable` node opens.\n * When omitted, only inline `children` are shown.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n};\n\nexport function ObjectGraph<T extends ObjectGraphNode = ObjectGraphNode>({\n roots,\n className,\n empty,\n showControls,\n defaultOpenDepth = 2,\n renderLabel,\n loadChildren,\n}: ObjectGraphProps<T>) {\n return (\n <Tree<T>\n roots={roots}\n getKey={(n) => n.id}\n getChildren={(n) => n.children as T[] | undefined}\n defaultOpen={(_n, depth) => depth < defaultOpenDepth}\n {...(className !== undefined ? { className } : {})}\n {...(empty !== undefined ? { empty } : {})}\n {...(showControls !== undefined ? { showControls } : {})}\n {...(loadChildren ? { loadChildren, hasMoreChildren: (n: T) => n.expandable === true } : {})}\n renderRow={({ node, loading, error }) => (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2 font-mono text-xs\">\n {renderLabel ? renderLabel(node) : <DefaultObjectLabel
|
|
1
|
+
{"version":3,"file":"ObjectGraph.cjs","sources":["../../src/data/ObjectGraph.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Tree } from \"./Tree\";\n\n// ObjectGraph renders a generic, type-agnostic expandable object/value\n// inspector — a bean's fields, a map's entries, a list's elements, a scalar\n// leaf. It is the shared home for what used to be per-feature object viewers\n// (e.g. an OGNL inspector): any producer maps its data into ObjectGraphNode and\n// gets the same tree, search, and lazy-expansion behaviour.\n\nexport type ObjectGraphNode = {\n /** Stable unique key within the tree. */\n id: string;\n /** Display label (field name, map key, index, …). */\n label: string;\n /** Optional type annotation rendered as `@type`. */\n type?: string;\n /** Scalar value for a leaf; absent for containers. */\n value?: string | number | boolean | null;\n /** Free-form node kind hint (object|map|list|scalar|…). */\n kind?: string;\n /** Accessor path from the root (used by lazy expansion). */\n path?: string;\n /** Verbatim preview for an opaque node with no structured children. */\n raw?: string;\n /** Node can be expanded via loadChildren even with no inline children. */\n expandable?: boolean;\n /** Caller-opaque context (carried through, not rendered by default). */\n metadata?: Record<string, unknown>;\n children?: ObjectGraphNode[];\n};\n\nexport type ObjectGraphProps<T extends ObjectGraphNode = ObjectGraphNode> = {\n roots: T[];\n className?: string;\n empty?: ReactNode;\n showControls?: boolean;\n /** Open nodes shallower than this depth on first render (default 2). */\n defaultOpenDepth?: number;\n /** Override the row label rendering. */\n renderLabel?: (node: T) => ReactNode;\n /**\n * Lazily fetch a node's children the first time an `expandable` node opens.\n * When omitted, only inline `children` are shown.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Called when a node's label is clicked. This makes the label an actionable\n * target (e.g. copy/drill its `path`) **without toggling expansion** — the\n * chevron stays the only expand/collapse control. Omit for a static tree.\n */\n onNodeSelect?: (node: T) => void;\n /** `id` of the currently-selected node; its label is highlighted. */\n selectedId?: string;\n};\n\nexport function ObjectGraph<T extends ObjectGraphNode = ObjectGraphNode>({\n roots,\n className,\n empty,\n showControls,\n defaultOpenDepth = 2,\n renderLabel,\n loadChildren,\n onNodeSelect,\n selectedId,\n}: ObjectGraphProps<T>) {\n return (\n <Tree<T>\n roots={roots}\n getKey={(n) => n.id}\n getChildren={(n) => n.children as T[] | undefined}\n defaultOpen={(_n, depth) => depth < defaultOpenDepth}\n {...(className !== undefined ? { className } : {})}\n {...(empty !== undefined ? { empty } : {})}\n {...(showControls !== undefined ? { showControls } : {})}\n {...(loadChildren ? { loadChildren, hasMoreChildren: (n: T) => n.expandable === true } : {})}\n renderRow={({ node, loading, error }) => (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2 font-mono text-xs\">\n {renderLabel ? (\n renderLabel(node)\n ) : (\n <DefaultObjectLabel\n node={node}\n selected={selectedId != null && node.id === selectedId}\n {...(onNodeSelect ? { onSelect: onNodeSelect } : {})}\n />\n )}\n {loading && <span className=\"shrink-0 text-muted-foreground\">…</span>}\n {error != null && (\n <span className=\"break-all text-red-600\">\n {error instanceof Error ? error.message : String(error)}\n </span>\n )}\n </div>\n )}\n />\n );\n}\n\nfunction DefaultObjectLabel<T extends ObjectGraphNode>({\n node,\n onSelect,\n selected = false,\n}: {\n node: T;\n onSelect?: (node: T) => void;\n selected?: boolean;\n}) {\n const label = onSelect ? (\n // A button so the label is a first-class click target; stopPropagation keeps\n // the row's onClick (which toggles the node) from firing, so selecting a node\n // never expands or collapses it.\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onSelect(node);\n }}\n title=\"Select this path\"\n className={cn(\n \"rounded px-0.5 text-left text-muted-foreground hover:text-foreground hover:underline\",\n selected && \"bg-primary/15 text-foreground\",\n )}\n >\n {node.label}\n </button>\n ) : (\n <span className=\"text-muted-foreground\">{node.label}</span>\n );\n return (\n <>\n {label}\n {node.type && <span className=\"text-muted-foreground/60\">@{node.type}</span>}\n {node.value != null ? (\n <span className=\"break-all text-foreground\">{String(node.value)}</span>\n ) : node.raw && !node.children ? (\n <span className=\"break-all italic text-muted-foreground/70\">{node.raw}</span>\n ) : null}\n </>\n );\n}\n"],"names":["jsx","Tree","jsxs","cn","Fragment"],"mappings":";;;;;AAwDO,SAAS,YAAyD;AAAA,EACvE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,SACEA,2BAAAA;AAAAA,IAACC,KAAAA;AAAAA,IAAA;AAAA,MACC;AAAA,MACA,QAAQ,CAAC,MAAM,EAAE;AAAA,MACjB,aAAa,CAAC,MAAM,EAAE;AAAA,MACtB,aAAa,CAAC,IAAI,UAAU,QAAQ;AAAA,MACnC,GAAI,cAAc,SAAY,EAAE,UAAA,IAAc,CAAA;AAAA,MAC9C,GAAI,UAAU,SAAY,EAAE,MAAA,IAAU,CAAA;AAAA,MACtC,GAAI,iBAAiB,SAAY,EAAE,aAAA,IAAiB,CAAA;AAAA,MACpD,GAAI,eAAe,EAAE,cAAc,iBAAiB,CAAC,MAAS,EAAE,eAAe,KAAA,IAAS,CAAA;AAAA,MACzF,WAAW,CAAC,EAAE,MAAM,SAAS,YAC3BC,2BAAAA,KAAC,OAAA,EAAI,WAAU,sEACZ,UAAA;AAAA,QAAA,cACC,YAAY,IAAI,IAEhBF,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA,UAAU,cAAc,QAAQ,KAAK,OAAO;AAAA,YAC3C,GAAI,eAAe,EAAE,UAAU,iBAAiB,CAAA;AAAA,UAAC;AAAA,QAAA;AAAA,QAGrD,WAAWA,2BAAAA,IAAC,QAAA,EAAK,WAAU,kCAAiC,UAAA,KAAC;AAAA,QAC7D,SAAS,QACRA,2BAAAA,IAAC,QAAA,EAAK,WAAU,0BACb,UAAA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAA,CACxD;AAAA,MAAA,EAAA,CAEJ;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,mBAA8C;AAAA,EACrD;AAAA,EACA;AAAA,EACA,WAAW;AACb,GAIG;AACD,QAAM,QAAQ;AAAA;AAAA;AAAA;AAAA,IAIZA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,CAAC,MAAM;AACd,YAAE,gBAAA;AACF,mBAAS,IAAI;AAAA,QACf;AAAA,QACA,OAAM;AAAA,QACN,WAAWG,MAAAA;AAAAA,UACT;AAAA,UACA,YAAY;AAAA,QAAA;AAAA,QAGb,UAAA,KAAK;AAAA,MAAA;AAAA,IAAA;AAAA,MAGRH,2BAAAA,IAAC,QAAA,EAAK,WAAU,yBAAyB,eAAK,OAAM;AAEtD,SACEE,2BAAAA,KAAAE,qBAAA,EACG,UAAA;AAAA,IAAA;AAAA,IACA,KAAK,QAAQF,gCAAC,QAAA,EAAK,WAAU,4BAA2B,UAAA;AAAA,MAAA;AAAA,MAAE,KAAK;AAAA,IAAA,GAAK;AAAA,IACpE,KAAK,SAAS,OACbF,2BAAAA,IAAC,UAAK,WAAU,6BAA6B,UAAA,OAAO,KAAK,KAAK,EAAA,CAAE,IAC9D,KAAK,OAAO,CAAC,KAAK,WACpBA,2BAAAA,IAAC,UAAK,WAAU,6CAA6C,UAAA,KAAK,IAAA,CAAI,IACpE;AAAA,EAAA,GACN;AAEJ;;"}
|
|
@@ -34,6 +34,14 @@ export type ObjectGraphProps<T extends ObjectGraphNode = ObjectGraphNode> = {
|
|
|
34
34
|
* When omitted, only inline `children` are shown.
|
|
35
35
|
*/
|
|
36
36
|
loadChildren?: (node: T) => Promise<T[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Called when a node's label is clicked. This makes the label an actionable
|
|
39
|
+
* target (e.g. copy/drill its `path`) **without toggling expansion** — the
|
|
40
|
+
* chevron stays the only expand/collapse control. Omit for a static tree.
|
|
41
|
+
*/
|
|
42
|
+
onNodeSelect?: (node: T) => void;
|
|
43
|
+
/** `id` of the currently-selected node; its label is highlighted. */
|
|
44
|
+
selectedId?: string;
|
|
37
45
|
};
|
|
38
|
-
export declare function ObjectGraph<T extends ObjectGraphNode = ObjectGraphNode>({ roots, className, empty, showControls, defaultOpenDepth, renderLabel, loadChildren, }: ObjectGraphProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
export declare function ObjectGraph<T extends ObjectGraphNode = ObjectGraphNode>({ roots, className, empty, showControls, defaultOpenDepth, renderLabel, loadChildren, onNodeSelect, selectedId, }: ObjectGraphProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
39
47
|
//# sourceMappingURL=ObjectGraph.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectGraph.d.ts","sourceRoot":"","sources":["../../src/data/ObjectGraph.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ObjectGraph.d.ts","sourceRoot":"","sources":["../../src/data/ObjectGraph.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,MAAM,MAAM,eAAe,GAAG;IAC5B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACzC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,IAAI;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wCAAwC;IACxC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IACrC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IACjC,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,wBAAgB,WAAW,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,EACvE,KAAK,EACL,SAAS,EACT,KAAK,EACL,YAAY,EACZ,gBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,GACX,EAAE,gBAAgB,CAAC,CAAC,CAAC,2CAgCrB"}
|
package/dist/data/ObjectGraph.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
2
3
|
import { Tree } from "./Tree.js";
|
|
3
4
|
function ObjectGraph({
|
|
4
5
|
roots,
|
|
@@ -7,7 +8,9 @@ function ObjectGraph({
|
|
|
7
8
|
showControls,
|
|
8
9
|
defaultOpenDepth = 2,
|
|
9
10
|
renderLabel,
|
|
10
|
-
loadChildren
|
|
11
|
+
loadChildren,
|
|
12
|
+
onNodeSelect,
|
|
13
|
+
selectedId
|
|
11
14
|
}) {
|
|
12
15
|
return /* @__PURE__ */ jsx(
|
|
13
16
|
Tree,
|
|
@@ -21,16 +24,48 @@ function ObjectGraph({
|
|
|
21
24
|
...showControls !== void 0 ? { showControls } : {},
|
|
22
25
|
...loadChildren ? { loadChildren, hasMoreChildren: (n) => n.expandable === true } : {},
|
|
23
26
|
renderRow: ({ node, loading, error }) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-2 font-mono text-xs", children: [
|
|
24
|
-
renderLabel ? renderLabel(node) : /* @__PURE__ */ jsx(
|
|
27
|
+
renderLabel ? renderLabel(node) : /* @__PURE__ */ jsx(
|
|
28
|
+
DefaultObjectLabel,
|
|
29
|
+
{
|
|
30
|
+
node,
|
|
31
|
+
selected: selectedId != null && node.id === selectedId,
|
|
32
|
+
...onNodeSelect ? { onSelect: onNodeSelect } : {}
|
|
33
|
+
}
|
|
34
|
+
),
|
|
25
35
|
loading && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: "…" }),
|
|
26
36
|
error != null && /* @__PURE__ */ jsx("span", { className: "break-all text-red-600", children: error instanceof Error ? error.message : String(error) })
|
|
27
37
|
] })
|
|
28
38
|
}
|
|
29
39
|
);
|
|
30
40
|
}
|
|
31
|
-
function DefaultObjectLabel({
|
|
41
|
+
function DefaultObjectLabel({
|
|
42
|
+
node,
|
|
43
|
+
onSelect,
|
|
44
|
+
selected = false
|
|
45
|
+
}) {
|
|
46
|
+
const label = onSelect ? (
|
|
47
|
+
// A button so the label is a first-class click target; stopPropagation keeps
|
|
48
|
+
// the row's onClick (which toggles the node) from firing, so selecting a node
|
|
49
|
+
// never expands or collapses it.
|
|
50
|
+
/* @__PURE__ */ jsx(
|
|
51
|
+
"button",
|
|
52
|
+
{
|
|
53
|
+
type: "button",
|
|
54
|
+
onClick: (e) => {
|
|
55
|
+
e.stopPropagation();
|
|
56
|
+
onSelect(node);
|
|
57
|
+
},
|
|
58
|
+
title: "Select this path",
|
|
59
|
+
className: cn(
|
|
60
|
+
"rounded px-0.5 text-left text-muted-foreground hover:text-foreground hover:underline",
|
|
61
|
+
selected && "bg-primary/15 text-foreground"
|
|
62
|
+
),
|
|
63
|
+
children: node.label
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: node.label });
|
|
32
67
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
33
|
-
|
|
68
|
+
label,
|
|
34
69
|
node.type && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/60", children: [
|
|
35
70
|
"@",
|
|
36
71
|
node.type
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectGraph.js","sources":["../../src/data/ObjectGraph.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Tree } from \"./Tree\";\n\n// ObjectGraph renders a generic, type-agnostic expandable object/value\n// inspector — a bean's fields, a map's entries, a list's elements, a scalar\n// leaf. It is the shared home for what used to be per-feature object viewers\n// (e.g. an OGNL inspector): any producer maps its data into ObjectGraphNode and\n// gets the same tree, search, and lazy-expansion behaviour.\n\nexport type ObjectGraphNode = {\n /** Stable unique key within the tree. */\n id: string;\n /** Display label (field name, map key, index, …). */\n label: string;\n /** Optional type annotation rendered as `@type`. */\n type?: string;\n /** Scalar value for a leaf; absent for containers. */\n value?: string | number | boolean | null;\n /** Free-form node kind hint (object|map|list|scalar|…). */\n kind?: string;\n /** Accessor path from the root (used by lazy expansion). */\n path?: string;\n /** Verbatim preview for an opaque node with no structured children. */\n raw?: string;\n /** Node can be expanded via loadChildren even with no inline children. */\n expandable?: boolean;\n /** Caller-opaque context (carried through, not rendered by default). */\n metadata?: Record<string, unknown>;\n children?: ObjectGraphNode[];\n};\n\nexport type ObjectGraphProps<T extends ObjectGraphNode = ObjectGraphNode> = {\n roots: T[];\n className?: string;\n empty?: ReactNode;\n showControls?: boolean;\n /** Open nodes shallower than this depth on first render (default 2). */\n defaultOpenDepth?: number;\n /** Override the row label rendering. */\n renderLabel?: (node: T) => ReactNode;\n /**\n * Lazily fetch a node's children the first time an `expandable` node opens.\n * When omitted, only inline `children` are shown.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n};\n\nexport function ObjectGraph<T extends ObjectGraphNode = ObjectGraphNode>({\n roots,\n className,\n empty,\n showControls,\n defaultOpenDepth = 2,\n renderLabel,\n loadChildren,\n}: ObjectGraphProps<T>) {\n return (\n <Tree<T>\n roots={roots}\n getKey={(n) => n.id}\n getChildren={(n) => n.children as T[] | undefined}\n defaultOpen={(_n, depth) => depth < defaultOpenDepth}\n {...(className !== undefined ? { className } : {})}\n {...(empty !== undefined ? { empty } : {})}\n {...(showControls !== undefined ? { showControls } : {})}\n {...(loadChildren ? { loadChildren, hasMoreChildren: (n: T) => n.expandable === true } : {})}\n renderRow={({ node, loading, error }) => (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2 font-mono text-xs\">\n {renderLabel ? renderLabel(node) : <DefaultObjectLabel
|
|
1
|
+
{"version":3,"file":"ObjectGraph.js","sources":["../../src/data/ObjectGraph.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Tree } from \"./Tree\";\n\n// ObjectGraph renders a generic, type-agnostic expandable object/value\n// inspector — a bean's fields, a map's entries, a list's elements, a scalar\n// leaf. It is the shared home for what used to be per-feature object viewers\n// (e.g. an OGNL inspector): any producer maps its data into ObjectGraphNode and\n// gets the same tree, search, and lazy-expansion behaviour.\n\nexport type ObjectGraphNode = {\n /** Stable unique key within the tree. */\n id: string;\n /** Display label (field name, map key, index, …). */\n label: string;\n /** Optional type annotation rendered as `@type`. */\n type?: string;\n /** Scalar value for a leaf; absent for containers. */\n value?: string | number | boolean | null;\n /** Free-form node kind hint (object|map|list|scalar|…). */\n kind?: string;\n /** Accessor path from the root (used by lazy expansion). */\n path?: string;\n /** Verbatim preview for an opaque node with no structured children. */\n raw?: string;\n /** Node can be expanded via loadChildren even with no inline children. */\n expandable?: boolean;\n /** Caller-opaque context (carried through, not rendered by default). */\n metadata?: Record<string, unknown>;\n children?: ObjectGraphNode[];\n};\n\nexport type ObjectGraphProps<T extends ObjectGraphNode = ObjectGraphNode> = {\n roots: T[];\n className?: string;\n empty?: ReactNode;\n showControls?: boolean;\n /** Open nodes shallower than this depth on first render (default 2). */\n defaultOpenDepth?: number;\n /** Override the row label rendering. */\n renderLabel?: (node: T) => ReactNode;\n /**\n * Lazily fetch a node's children the first time an `expandable` node opens.\n * When omitted, only inline `children` are shown.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Called when a node's label is clicked. This makes the label an actionable\n * target (e.g. copy/drill its `path`) **without toggling expansion** — the\n * chevron stays the only expand/collapse control. Omit for a static tree.\n */\n onNodeSelect?: (node: T) => void;\n /** `id` of the currently-selected node; its label is highlighted. */\n selectedId?: string;\n};\n\nexport function ObjectGraph<T extends ObjectGraphNode = ObjectGraphNode>({\n roots,\n className,\n empty,\n showControls,\n defaultOpenDepth = 2,\n renderLabel,\n loadChildren,\n onNodeSelect,\n selectedId,\n}: ObjectGraphProps<T>) {\n return (\n <Tree<T>\n roots={roots}\n getKey={(n) => n.id}\n getChildren={(n) => n.children as T[] | undefined}\n defaultOpen={(_n, depth) => depth < defaultOpenDepth}\n {...(className !== undefined ? { className } : {})}\n {...(empty !== undefined ? { empty } : {})}\n {...(showControls !== undefined ? { showControls } : {})}\n {...(loadChildren ? { loadChildren, hasMoreChildren: (n: T) => n.expandable === true } : {})}\n renderRow={({ node, loading, error }) => (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2 font-mono text-xs\">\n {renderLabel ? (\n renderLabel(node)\n ) : (\n <DefaultObjectLabel\n node={node}\n selected={selectedId != null && node.id === selectedId}\n {...(onNodeSelect ? { onSelect: onNodeSelect } : {})}\n />\n )}\n {loading && <span className=\"shrink-0 text-muted-foreground\">…</span>}\n {error != null && (\n <span className=\"break-all text-red-600\">\n {error instanceof Error ? error.message : String(error)}\n </span>\n )}\n </div>\n )}\n />\n );\n}\n\nfunction DefaultObjectLabel<T extends ObjectGraphNode>({\n node,\n onSelect,\n selected = false,\n}: {\n node: T;\n onSelect?: (node: T) => void;\n selected?: boolean;\n}) {\n const label = onSelect ? (\n // A button so the label is a first-class click target; stopPropagation keeps\n // the row's onClick (which toggles the node) from firing, so selecting a node\n // never expands or collapses it.\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onSelect(node);\n }}\n title=\"Select this path\"\n className={cn(\n \"rounded px-0.5 text-left text-muted-foreground hover:text-foreground hover:underline\",\n selected && \"bg-primary/15 text-foreground\",\n )}\n >\n {node.label}\n </button>\n ) : (\n <span className=\"text-muted-foreground\">{node.label}</span>\n );\n return (\n <>\n {label}\n {node.type && <span className=\"text-muted-foreground/60\">@{node.type}</span>}\n {node.value != null ? (\n <span className=\"break-all text-foreground\">{String(node.value)}</span>\n ) : node.raw && !node.children ? (\n <span className=\"break-all italic text-muted-foreground/70\">{node.raw}</span>\n ) : null}\n </>\n );\n}\n"],"names":[],"mappings":";;;AAwDO,SAAS,YAAyD;AAAA,EACvE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,QAAQ,CAAC,MAAM,EAAE;AAAA,MACjB,aAAa,CAAC,MAAM,EAAE;AAAA,MACtB,aAAa,CAAC,IAAI,UAAU,QAAQ;AAAA,MACnC,GAAI,cAAc,SAAY,EAAE,UAAA,IAAc,CAAA;AAAA,MAC9C,GAAI,UAAU,SAAY,EAAE,MAAA,IAAU,CAAA;AAAA,MACtC,GAAI,iBAAiB,SAAY,EAAE,aAAA,IAAiB,CAAA;AAAA,MACpD,GAAI,eAAe,EAAE,cAAc,iBAAiB,CAAC,MAAS,EAAE,eAAe,KAAA,IAAS,CAAA;AAAA,MACzF,WAAW,CAAC,EAAE,MAAM,SAAS,YAC3B,qBAAC,OAAA,EAAI,WAAU,sEACZ,UAAA;AAAA,QAAA,cACC,YAAY,IAAI,IAEhB;AAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA,UAAU,cAAc,QAAQ,KAAK,OAAO;AAAA,YAC3C,GAAI,eAAe,EAAE,UAAU,iBAAiB,CAAA;AAAA,UAAC;AAAA,QAAA;AAAA,QAGrD,WAAW,oBAAC,QAAA,EAAK,WAAU,kCAAiC,UAAA,KAAC;AAAA,QAC7D,SAAS,QACR,oBAAC,QAAA,EAAK,WAAU,0BACb,UAAA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAA,CACxD;AAAA,MAAA,EAAA,CAEJ;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,mBAA8C;AAAA,EACrD;AAAA,EACA;AAAA,EACA,WAAW;AACb,GAIG;AACD,QAAM,QAAQ;AAAA;AAAA;AAAA;AAAA,IAIZ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,CAAC,MAAM;AACd,YAAE,gBAAA;AACF,mBAAS,IAAI;AAAA,QACf;AAAA,QACA,OAAM;AAAA,QACN,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QAAA;AAAA,QAGb,UAAA,KAAK;AAAA,MAAA;AAAA,IAAA;AAAA,MAGR,oBAAC,QAAA,EAAK,WAAU,yBAAyB,eAAK,OAAM;AAEtD,SACE,qBAAA,UAAA,EACG,UAAA;AAAA,IAAA;AAAA,IACA,KAAK,QAAQ,qBAAC,QAAA,EAAK,WAAU,4BAA2B,UAAA;AAAA,MAAA;AAAA,MAAE,KAAK;AAAA,IAAA,GAAK;AAAA,IACpE,KAAK,SAAS,OACb,oBAAC,UAAK,WAAU,6BAA6B,UAAA,OAAO,KAAK,KAAK,EAAA,CAAE,IAC9D,KAAK,OAAO,CAAC,KAAK,WACpB,oBAAC,UAAK,WAAU,6CAA6C,UAAA,KAAK,IAAA,CAAI,IACpE;AAAA,EAAA,GACN;AAEJ;"}
|
|
@@ -15,9 +15,9 @@ function detectMode() {
|
|
|
15
15
|
}
|
|
16
16
|
function getVersionInfo() {
|
|
17
17
|
return {
|
|
18
|
-
commit: read(() => "
|
|
19
|
-
tag: read(() => "clicky-ui@0.3.
|
|
20
|
-
date: read(() => "2026-
|
|
18
|
+
commit: read(() => "497ab24", ""),
|
|
19
|
+
tag: read(() => "clicky-ui@0.3.8", ""),
|
|
20
|
+
date: read(() => "2026-07-06T10:59:12.540Z", ""),
|
|
21
21
|
dirty: read(() => true, false),
|
|
22
22
|
mode: detectMode()
|
|
23
23
|
};
|
|
@@ -13,9 +13,9 @@ function detectMode() {
|
|
|
13
13
|
}
|
|
14
14
|
function getVersionInfo() {
|
|
15
15
|
return {
|
|
16
|
-
commit: read(() => "
|
|
17
|
-
tag: read(() => "clicky-ui@0.3.
|
|
18
|
-
date: read(() => "2026-
|
|
16
|
+
commit: read(() => "497ab24", ""),
|
|
17
|
+
tag: read(() => "clicky-ui@0.3.8", ""),
|
|
18
|
+
date: read(() => "2026-07-06T10:58:57.956Z", ""),
|
|
19
19
|
dirty: read(() => true, false),
|
|
20
20
|
mode: detectMode()
|
|
21
21
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flanksource/clicky-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.",
|
|
5
5
|
"homepage": "https://github.com/flanksource/clicky-ui#readme",
|
|
6
6
|
"bugs": "https://github.com/flanksource/clicky-ui/issues",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"@tanstack/react-query": "^5.66.8",
|
|
114
114
|
"class-variance-authority": "^0.7.1",
|
|
115
115
|
"clsx": "^2.1.1",
|
|
116
|
-
"dompurify": "^3.4.
|
|
116
|
+
"dompurify": "^3.4.11",
|
|
117
117
|
"jotai": "^2.20.1",
|
|
118
118
|
"tailwind-merge": "^2.6.0"
|
|
119
119
|
},
|
|
@@ -138,9 +138,9 @@
|
|
|
138
138
|
"tailwindcss": "^4.2.4",
|
|
139
139
|
"tsx": "^4.7.0",
|
|
140
140
|
"typescript": "^5.7.2",
|
|
141
|
-
"vite": "^6.
|
|
141
|
+
"vite": "^6.4.3",
|
|
142
142
|
"vite-plugin-dts": "^4.3.0",
|
|
143
|
-
"vitest": "^3.
|
|
143
|
+
"vitest": "^3.2.6"
|
|
144
144
|
},
|
|
145
145
|
"peerDependencies": {
|
|
146
146
|
"@ai-sdk/react": "^3.0.0",
|