@nesso-how/graph 0.1.0-alpha.26 → 0.1.0-alpha.28

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 CHANGED
@@ -13,8 +13,7 @@ npm install @nesso-how/graph
13
13
  ```tsx
14
14
  import { NessoGraph } from '@nesso-how/graph'
15
15
  import '@xyflow/react/dist/style.css'
16
-
17
- <NessoGraph
16
+ ;<NessoGraph
18
17
  nodes={nodes}
19
18
  edges={edges}
20
19
  display={{ edgeEncoding: 'full', curveStyle: 'straight' }}
@@ -23,19 +22,24 @@ import '@xyflow/react/dist/style.css'
23
22
  ```
24
23
 
25
24
  `nodes`/`edges` (or a full `graph: NessoGraphFile`) render read-only by default —
26
- no drag, connect, or selection. Pass `display`/`palette` to control how categories,
27
- glyphs, and curves are drawn; pass any other [`ReactFlow`](https://reactflow.dev/api-reference/react-flow)
28
- prop through `reactFlowProps`.
25
+ no drag, connect, or selection. Default `nodeTypes`/`edgeTypes` use `ConceptNode` and
26
+ `NessoEdge` from this package (display settings via `GraphDisplayContext`).
27
+
28
+ Pass `display`/`palette` to control categories, glyphs, and curves. Use
29
+ `categoryColorMode: 'css'` when `--cat-*` CSS variables are set on the page (the main
30
+ app); embeds default to `palette` (hex from `PALETTES`). Optional `getRelationLabel`
31
+ and `isItemSelected` customize labels and selection. Pass any other
32
+ [`ReactFlow`](https://reactflow.dev/api-reference/react-flow) prop through `reactFlowProps`.
29
33
 
30
34
  ### Interactivity
31
35
 
32
36
  Turn on `nodesDraggable`/`nodesConnectable`/`elementsSelectable` as needed. How you
33
37
  provide nodes determines who owns their state:
34
38
 
35
- - `nodes`/`edges` — *controlled*: you own the state and must also pass
39
+ - `nodes`/`edges` — _controlled_: you own the state and must also pass
36
40
  `onNodesChange`/`onEdgesChange`/`onConnect` to apply updates (e.g. the main app,
37
41
  where positions live in its own store).
38
- - `defaultNodes`/`defaultEdges` — *uncontrolled*: React Flow seeds its internal
42
+ - `defaultNodes`/`defaultEdges` — _uncontrolled_: React Flow seeds its internal
39
43
  state once and manages drag/connect/selection itself — no wiring needed, the
40
44
  right choice for decorative or one-off embeds.
41
45
 
@@ -1,5 +1,5 @@
1
1
  import type { Node, NodeProps } from '@xyflow/react';
2
2
  import type { ConceptNodeData } from '@nesso-how/types';
3
3
  type ConceptNodeType = Node<ConceptNodeData>;
4
- export declare function ReadOnlyConceptNode({ data, selected }: NodeProps<ConceptNodeType>): import("react/jsx-runtime").JSX.Element;
4
+ export declare function ConceptNode({ data, selected }: NodeProps<ConceptNodeType>): import("react/jsx-runtime").JSX.Element;
5
5
  export {};
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // SPDX-License-Identifier: MIT
3
+ import { Handle, Position } from '@xyflow/react';
4
+ import { ConceptNodeBody } from './ConceptNodeBody.js';
5
+ import { useGraphDisplay } from './context.js';
6
+ const HIDDEN_HANDLE = {
7
+ width: 1,
8
+ height: 1,
9
+ minWidth: 0,
10
+ background: 'transparent',
11
+ border: 'none',
12
+ borderRadius: 0,
13
+ opacity: 0,
14
+ pointerEvents: 'none',
15
+ };
16
+ export function ConceptNode({ data, selected }) {
17
+ const { showHeatmap, showConfidence } = useGraphDisplay();
18
+ return (_jsxs("div", { style: { position: 'relative' }, children: [_jsx(ConceptNodeBody, { text: data.text, selected: selected, showHeatmap: showHeatmap, showConfidence: showConfidence, lastRating: data.lastRating ?? 0, reps: data.reps, due: data.due }), _jsx(Handle, { id: "out", type: "source", position: Position.Right, style: HIDDEN_HANDLE }), _jsx(Handle, { id: "in", type: "target", position: Position.Left, style: HIDDEN_HANDLE })] }));
19
+ }
@@ -0,0 +1,20 @@
1
+ import type { CSSProperties, MouseEventHandler, ReactNode, Ref } from 'react';
2
+ export interface ConceptNodeBodyProps {
3
+ text: string;
4
+ selected: boolean;
5
+ showHeatmap: boolean;
6
+ showConfidence: boolean;
7
+ lastRating: number;
8
+ reps: number;
9
+ due: number;
10
+ cursor?: CSSProperties['cursor'];
11
+ userSelect?: CSSProperties['userSelect'];
12
+ className?: string;
13
+ connectionTarget?: boolean;
14
+ hideUnderline?: boolean;
15
+ rootRef?: Ref<HTMLDivElement>;
16
+ onDoubleClick?: MouseEventHandler<HTMLDivElement>;
17
+ /** Replaces the default label span (e.g. inline edit overlay). */
18
+ children?: ReactNode;
19
+ }
20
+ export declare function ConceptNodeBody({ text, selected, showHeatmap, showConfidence, lastRating, reps, due, cursor, userSelect, className, connectionTarget, hideUnderline, rootRef, onDoubleClick, children, }: ConceptNodeBodyProps): import("react/jsx-runtime").JSX.Element;
@@ -1,35 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // SPDX-License-Identifier: MIT
3
- import { Handle, Position } from '@xyflow/react';
4
- import { useGraphDisplay } from './context.js';
5
2
  import { ratingColor } from './ratingColor.js';
6
- const HIDDEN_HANDLE = {
7
- width: 1,
8
- height: 1,
9
- minWidth: 0,
10
- background: 'transparent',
11
- border: 'none',
12
- borderRadius: 0,
13
- opacity: 0,
14
- pointerEvents: 'none',
15
- };
16
- export function ReadOnlyConceptNode({ data, selected }) {
17
- const { showHeatmap, showConfidence } = useGraphDisplay();
18
- const heatTint = ratingColor(data.lastRating ?? 0);
3
+ export function ConceptNodeBody({ text, selected, showHeatmap, showConfidence, lastRating, reps, due, cursor = 'default', userSelect = 'none', className, connectionTarget = false, hideUnderline = false, rootRef, onDoubleClick, children, }) {
4
+ const heatTint = ratingColor(lastRating);
19
5
  const confColor = showConfidence ? heatTint : 'var(--ink, #1a1a1a)';
20
- const isStale = data.reps > 0 && data.due <= Date.now();
21
- return (_jsxs("div", { style: {
6
+ const isStale = reps > 0 && due <= Date.now();
7
+ return (_jsxs("div", { ref: rootRef, className: className, onDoubleClick: onDoubleClick, style: {
22
8
  position: 'relative',
23
9
  padding: '6px 14px',
24
10
  borderRadius: 999,
25
- background: selected || showHeatmap
26
- ? 'var(--bg-card, #f5f5f5)'
27
- : 'transparent',
28
- border: selected || showHeatmap
29
- ? '0.5px solid var(--line, #d0d0d0)'
30
- : '0.5px solid transparent',
31
- cursor: 'default',
32
- userSelect: 'none',
11
+ background: selected || showHeatmap ? 'var(--bg-card, #f5f5f5)' : 'transparent',
12
+ border: selected || showHeatmap ? '0.5px solid var(--line, #d0d0d0)' : '0.5px solid transparent',
13
+ cursor,
14
+ userSelect,
33
15
  minWidth: 60,
34
16
  }, children: [showHeatmap && (_jsx("div", { style: {
35
17
  position: 'absolute',
@@ -45,13 +27,19 @@ export function ReadOnlyConceptNode({ data, selected }) {
45
27
  border: '1px dashed var(--accent, #3b82f6)',
46
28
  opacity: 0.7,
47
29
  pointerEvents: 'none',
48
- } })), _jsx("span", { style: {
30
+ } })), connectionTarget && (_jsx("div", { style: {
31
+ position: 'absolute',
32
+ inset: -4,
33
+ borderRadius: 999,
34
+ border: '1.5px dotted color-mix(in srgb, var(--accent, #3b82f6) 65%, transparent)',
35
+ pointerEvents: 'none',
36
+ } })), children ?? (_jsx("span", { style: {
49
37
  font: '500 16px Fraunces, ui-serif, Georgia, serif',
50
38
  letterSpacing: '-0.005em',
51
39
  color: 'var(--ink, #1a1a1a)',
52
40
  display: 'block',
53
41
  whiteSpace: 'pre',
54
- }, children: data.text }), _jsx("div", { style: {
42
+ }, children: text })), !hideUnderline && (_jsx("div", { style: {
55
43
  position: 'absolute',
56
44
  bottom: 5,
57
45
  left: 16,
@@ -61,5 +49,5 @@ export function ReadOnlyConceptNode({ data, selected }) {
61
49
  ? `repeating-linear-gradient(90deg, ${confColor} 0, ${confColor} 4px, transparent 4px, transparent 8px)`
62
50
  : confColor,
63
51
  opacity: selected ? 0.9 : 0.55,
64
- } }), _jsx(Handle, { id: "out", type: "source", position: Position.Right, style: HIDDEN_HANDLE }), _jsx(Handle, { id: "in", type: "target", position: Position.Left, style: HIDDEN_HANDLE })] }));
52
+ } }))] }));
65
53
  }
@@ -1,5 +1,5 @@
1
1
  import type { Edge, EdgeProps } from '@xyflow/react';
2
2
  import type { NessoEdgeData } from '@nesso-how/types';
3
3
  type NessoFlowEdge = Edge<NessoEdgeData, 'nesso'>;
4
- export declare function ReadOnlyNessoEdge({ source, target, data, selected, }: EdgeProps<NessoFlowEdge>): import("react/jsx-runtime").JSX.Element | null;
4
+ export declare function NessoEdge({ id, source, target, data, selected }: EdgeProps<NessoFlowEdge>): import("react/jsx-runtime").JSX.Element | null;
5
5
  export {};
@@ -9,6 +9,11 @@ import { effectiveCurveFlip, flowNodeCenterX, flowNodeCenterY, nessoArcPath, rec
9
9
  function asEdgeTypeName(value, fallback = 'causes') {
10
10
  return typeof value === 'string' && value in RELATION_TYPES ? value : fallback;
11
11
  }
12
+ function categoryColor(cat, mode, palette) {
13
+ if (mode === 'css')
14
+ return `var(--cat-${cat})`;
15
+ return PALETTES[palette]?.[cat] ?? '#666666';
16
+ }
12
17
  function EdgePathElement({ d, color, lineStyle, width = 1.5, opacity = 0.78, }) {
13
18
  const base = {
14
19
  fill: 'none',
@@ -29,19 +34,21 @@ function EdgePathElement({ d, color, lineStyle, width = 1.5, opacity = 0.78, })
29
34
  return _jsx("path", { d: d, ...base, strokeDasharray: "0.1 5", strokeWidth: width * 1.4 });
30
35
  return _jsx("path", { d: d, ...base });
31
36
  }
32
- export function ReadOnlyNessoEdge({ source, target, data, selected, }) {
37
+ export function NessoEdge({ id, source, target, data, selected }) {
33
38
  const [hovered, setHovered] = useState(false);
34
- const { edgeEncoding, curveStyle, autoCurveFlip, palette } = useGraphDisplay();
39
+ const { edgeEncoding, curveStyle, autoCurveFlip, palette, categoryColorMode, getRelationLabel, isItemSelected, } = useGraphDisplay();
35
40
  const sourceNode = useStore((s) => s.nodeLookup.get(source));
36
41
  const targetNode = useStore((s) => s.nodeLookup.get(target));
37
42
  const edgeType = asEdgeTypeName(data?.type);
38
43
  const T = RELATION_TYPES[edgeType];
39
44
  const color = edgeEncoding === 'minimal'
40
45
  ? 'var(--ink-3, #888888)'
41
- : (PALETTES[palette]?.[T.cat] ?? '#666666');
46
+ : categoryColor(T.cat, categoryColorMode, palette);
42
47
  const lineStyle = edgeEncoding === 'minimal' ? 'solid' : T.line;
43
- const showLabel = edgeEncoding === 'full' || (edgeEncoding !== 'minimal' && (hovered || selected));
48
+ const isSelected = selected || isItemSelected?.('edge', id) === true;
49
+ const showLabel = edgeEncoding === 'full' || (edgeEncoding !== 'minimal' && (hovered || isSelected));
44
50
  const straight = curveStyle === 'straight';
51
+ const label = getRelationLabel?.(edgeType) ?? T.label;
45
52
  if (!sourceNode || !targetNode)
46
53
  return null;
47
54
  const sw = sourceNode.measured?.width ?? 80;
@@ -82,8 +89,8 @@ export function ReadOnlyNessoEdge({ source, target, data, selected, }) {
82
89
  const ay1 = b.y + Math.sin(a1) * arrowSize;
83
90
  const ax2 = b.x + Math.cos(a2) * arrowSize;
84
91
  const ay2 = b.y + Math.sin(a2) * arrowSize;
85
- const w = selected ? 2 : 1.4;
86
- const op = selected || hovered ? 1 : 0.78;
92
+ const w = isSelected ? 2 : 1.4;
93
+ const op = isSelected || hovered ? 1 : 0.78;
87
94
  const r = 11;
88
95
  return (_jsxs("g", { onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), style: { cursor: 'default' }, children: [_jsx("path", { d: path, stroke: "transparent", strokeWidth: 14, fill: "none" }), _jsx(EdgePathElement, { d: path, color: color, lineStyle: lineStyle, width: w, opacity: op }), T.inverse !== 'self' && edgeEncoding !== 'minimal' && (_jsx("polygon", { points: `${b.x},${b.y} ${ax1},${ay1} ${ax2},${ay2}`, fill: color, opacity: 0.85 })), edgeEncoding !== 'minimal' && (_jsxs("g", { style: { pointerEvents: 'all' }, children: [_jsx("circle", { cx: labelX, cy: labelY, r: r, fill: "var(--paper, #ffffff)", stroke: color, strokeWidth: 1.2 }), _jsx("g", { transform: `translate(${labelX - 7}, ${labelY - 7})`, children: _jsx(GlyphSVG, { kind: T.glyph, color: color, size: 14 }) })] })), showLabel && (_jsx("foreignObject", { x: labelX - 60, y: labelY + r + 2, width: 120, height: 20, style: { overflow: 'visible', pointerEvents: 'none' }, children: _jsx("div", { style: {
89
96
  display: 'inline-block',
@@ -96,5 +103,5 @@ export function ReadOnlyNessoEdge({ source, target, data, selected, }) {
96
103
  letterSpacing: '0.02em',
97
104
  whiteSpace: 'nowrap',
98
105
  lineHeight: '16px',
99
- }, children: T.label }) }))] }));
106
+ }, children: label }) }))] }));
100
107
  }
@@ -1,6 +1,8 @@
1
1
  import type { Node, Edge, NodeTypes, EdgeTypes, ReactFlowProps, Viewport, OnNodesChange, OnEdgesChange, OnConnect, OnConnectStart, OnConnectEnd, OnMoveEnd } from '@xyflow/react';
2
2
  import type { NessoGraphFile } from '@nesso-how/formats';
3
+ import type { EdgeTypeName } from '@nesso-how/relation-types';
3
4
  import type { ConceptNodeData, NessoEdgeData, GraphDisplaySettings, CategoryPalette } from '@nesso-how/types';
5
+ import { type CategoryColorMode } from './context.js';
4
6
  type PassthroughKeys = 'nodes' | 'defaultNodes' | 'edges' | 'defaultEdges' | 'nodeTypes' | 'edgeTypes' | 'nodesDraggable' | 'nodesConnectable' | 'elementsSelectable' | 'onNodesChange' | 'onEdgesChange' | 'onConnect' | 'onConnectStart' | 'onConnectEnd' | 'onSelectionChange' | 'onMoveEnd' | 'onNodeClick' | 'onEdgeClick' | 'fitView' | 'defaultViewport' | 'minZoom' | 'maxZoom' | 'panOnDrag' | 'zoomOnScroll';
5
7
  export interface NessoGraphProps {
6
8
  graph?: NessoGraphFile;
@@ -11,6 +13,10 @@ export interface NessoGraphProps {
11
13
  display?: Partial<GraphDisplaySettings>;
12
14
  palette?: CategoryPalette;
13
15
  showConfidence?: boolean;
16
+ /** `palette` (default) for embeds; `css` when `--cat-*` vars are set on the page. */
17
+ categoryColorMode?: CategoryColorMode;
18
+ getRelationLabel?: (type: EdgeTypeName) => string;
19
+ isItemSelected?: (kind: 'node' | 'edge', id: string) => boolean;
14
20
  nodeTypes?: NodeTypes;
15
21
  edgeTypes?: EdgeTypes;
16
22
  nodesDraggable?: boolean;
@@ -37,5 +43,5 @@ export interface NessoGraphProps {
37
43
  onDoubleClick?: React.MouseEventHandler<HTMLDivElement>;
38
44
  children?: React.ReactNode;
39
45
  }
40
- export declare function NessoGraph({ graph, nodes: nodesProp, defaultNodes, edges: edgesProp, defaultEdges, display, palette, showConfidence, nodeTypes, edgeTypes, nodesDraggable, nodesConnectable, elementsSelectable, panOnDrag, zoomOnScroll, onNodesChange, onEdgesChange, onConnect, onConnectStart, onConnectEnd, onSelectionChange, onMoveEnd, onNodeClick, onEdgeClick, fitView, defaultViewport, minZoom, maxZoom, reactFlowProps, style, className, onDoubleClick, children, }: NessoGraphProps): import("react/jsx-runtime").JSX.Element;
46
+ export declare function NessoGraph({ graph, nodes: nodesProp, defaultNodes, edges: edgesProp, defaultEdges, display, palette, showConfidence, categoryColorMode, getRelationLabel, isItemSelected, nodeTypes, edgeTypes, nodesDraggable, nodesConnectable, elementsSelectable, panOnDrag, zoomOnScroll, onNodesChange, onEdgesChange, onConnect, onConnectStart, onConnectEnd, onSelectionChange, onMoveEnd, onNodeClick, onEdgeClick, fitView, defaultViewport, minZoom, maxZoom, reactFlowProps, style, className, onDoubleClick, children, }: NessoGraphProps): import("react/jsx-runtime").JSX.Element;
41
47
  export {};
@@ -3,11 +3,11 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
3
3
  import { useMemo } from 'react';
4
4
  import { ReactFlow, Background, Controls } from '@xyflow/react';
5
5
  import { GraphDisplayContext } from './context.js';
6
- import { ReadOnlyConceptNode } from './ReadOnlyConceptNode.js';
7
- import { ReadOnlyNessoEdge } from './ReadOnlyNessoEdge.js';
8
- const DEFAULT_NODE_TYPES = { concept: ReadOnlyConceptNode };
9
- const DEFAULT_EDGE_TYPES = { nesso: ReadOnlyNessoEdge };
10
- export function NessoGraph({ graph, nodes: nodesProp, defaultNodes, edges: edgesProp, defaultEdges, display, palette = 'default', showConfidence = false, nodeTypes = DEFAULT_NODE_TYPES, edgeTypes = DEFAULT_EDGE_TYPES, nodesDraggable = false, nodesConnectable = false, elementsSelectable = true, panOnDrag = true, zoomOnScroll = true, onNodesChange, onEdgesChange, onConnect, onConnectStart, onConnectEnd, onSelectionChange, onMoveEnd, onNodeClick, onEdgeClick, fitView = true, defaultViewport, minZoom, maxZoom, reactFlowProps, style, className, onDoubleClick, children, }) {
6
+ import { ConceptNode } from './ConceptNode.js';
7
+ import { NessoEdge } from './NessoEdge.js';
8
+ const DEFAULT_NODE_TYPES = { concept: ConceptNode };
9
+ const DEFAULT_EDGE_TYPES = { nesso: NessoEdge };
10
+ export function NessoGraph({ graph, nodes: nodesProp, defaultNodes, edges: edgesProp, defaultEdges, display, palette = 'default', showConfidence = false, categoryColorMode = 'palette', getRelationLabel, isItemSelected, nodeTypes = DEFAULT_NODE_TYPES, edgeTypes = DEFAULT_EDGE_TYPES, nodesDraggable = false, nodesConnectable = false, elementsSelectable = true, panOnDrag = true, zoomOnScroll = true, onNodesChange, onEdgesChange, onConnect, onConnectStart, onConnectEnd, onSelectionChange, onMoveEnd, onNodeClick, onEdgeClick, fitView = true, defaultViewport, minZoom, maxZoom, reactFlowProps, style, className, onDoubleClick, children, }) {
11
11
  const controlledNodes = nodesProp ?? graph?.nodes;
12
12
  const controlledEdges = (edgesProp ?? graph?.edges);
13
13
  // Controlled (`nodes`/`graph`) takes precedence; otherwise fall back to ReactFlow's
@@ -25,10 +25,19 @@ export function NessoGraph({ graph, nodes: nodesProp, defaultNodes, edges: edges
25
25
  autoCurveFlip: display?.autoCurveFlip ?? graph?.display?.autoCurveFlip ?? true,
26
26
  palette,
27
27
  showConfidence,
28
- }), [display, graph?.display, palette, showConfidence]);
28
+ categoryColorMode,
29
+ getRelationLabel,
30
+ isItemSelected,
31
+ }), [
32
+ display,
33
+ graph?.display,
34
+ palette,
35
+ showConfidence,
36
+ categoryColorMode,
37
+ getRelationLabel,
38
+ isItemSelected,
39
+ ]);
29
40
  return (_jsx("div", { style: { width: '100%', height: '100%', ...style }, className: className, onDoubleClick: onDoubleClick, children: _jsx(GraphDisplayContext.Provider, { value: ctx, children: _jsx(ReactFlow, { ...nodesProps, ...edgesProps, nodeTypes: nodeTypes, edgeTypes: edgeTypes, nodesDraggable: nodesDraggable, nodesConnectable: nodesConnectable, elementsSelectable: elementsSelectable, panOnDrag: panOnDrag, zoomOnScroll: zoomOnScroll, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, onConnect: onConnect, onConnectStart: onConnectStart, onConnectEnd: onConnectEnd, onSelectionChange: onSelectionChange, onMoveEnd: onMoveEnd, fitView: fitView, defaultViewport: defaultViewport, minZoom: minZoom, maxZoom: maxZoom, onNodeClick: onNodeClick
30
41
  ? (_, node) => onNodeClick(node.id, node.data)
31
- : undefined, onEdgeClick: onEdgeClick
32
- ? (_, edge) => onEdgeClick(edge.id, edge.data)
33
- : undefined, ...reactFlowProps, children: children ?? (_jsxs(_Fragment, { children: [_jsx(Background, {}), _jsx(Controls, {})] })) }) }) }));
42
+ : undefined, onEdgeClick: onEdgeClick ? (_, edge) => onEdgeClick(edge.id, edge.data) : undefined, ...reactFlowProps, children: children ?? (_jsxs(_Fragment, { children: [_jsx(Background, {}), _jsx(Controls, {})] })) }) }) }));
34
43
  }
package/dist/context.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ import type { EdgeTypeName } from '@nesso-how/relation-types';
1
2
  import type { EdgeEncoding, CurveStyle, CategoryPalette } from '@nesso-how/types';
3
+ export type CategoryColorMode = 'palette' | 'css';
2
4
  export interface NessoGraphDisplayContext {
3
5
  edgeEncoding: EdgeEncoding;
4
6
  showHeatmap: boolean;
@@ -6,6 +8,10 @@ export interface NessoGraphDisplayContext {
6
8
  autoCurveFlip: boolean;
7
9
  palette: CategoryPalette;
8
10
  showConfidence: boolean;
11
+ /** `palette` uses hex from PALETTES; `css` uses `var(--cat-*)` (app with live palette switching). */
12
+ categoryColorMode: CategoryColorMode;
13
+ getRelationLabel?: (type: EdgeTypeName) => string;
14
+ isItemSelected?: (kind: 'node' | 'edge', id: string) => boolean;
9
15
  }
10
16
  export declare const GraphDisplayContext: import("react").Context<NessoGraphDisplayContext>;
11
17
  export declare function useGraphDisplay(): NessoGraphDisplayContext;
package/dist/context.js CHANGED
@@ -7,6 +7,7 @@ const defaultContext = {
7
7
  autoCurveFlip: true,
8
8
  palette: 'default',
9
9
  showConfidence: false,
10
+ categoryColorMode: 'palette',
10
11
  };
11
12
  export const GraphDisplayContext = createContext(defaultContext);
12
13
  export function useGraphDisplay() {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  export { NessoGraph } from './NessoGraph.js';
2
2
  export type { NessoGraphProps } from './NessoGraph.js';
3
+ export { ConceptNode } from './ConceptNode.js';
4
+ export { ConceptNodeBody } from './ConceptNodeBody.js';
5
+ export type { ConceptNodeBodyProps } from './ConceptNodeBody.js';
6
+ export { NessoEdge } from './NessoEdge.js';
7
+ export { useGraphDisplay, GraphDisplayContext } from './context.js';
8
+ export type { NessoGraphDisplayContext, CategoryColorMode } from './context.js';
3
9
  export { GlyphSVG } from './GlyphSVG.js';
4
10
  export { ratingColor } from './ratingColor.js';
5
11
  export { defaultCurveFlip, nodeCenterX, nodeCenterY, flowNodeCenterX, flowNodeCenterY, effectiveCurveFlip, rectExit, nessoArcPath, } from './geometry.js';
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  export { NessoGraph } from './NessoGraph.js';
3
+ export { ConceptNode } from './ConceptNode.js';
4
+ export { ConceptNodeBody } from './ConceptNodeBody.js';
5
+ export { NessoEdge } from './NessoEdge.js';
6
+ export { useGraphDisplay, GraphDisplayContext } from './context.js';
3
7
  // Shared canvas utilities — import from here to avoid duplication with the main app.
4
8
  export { GlyphSVG } from './GlyphSVG.js';
5
9
  export { ratingColor } from './ratingColor.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nesso-how/graph",
3
- "version": "0.1.0-alpha.26",
3
+ "version": "0.1.0-alpha.28",
4
4
  "description": "Embeddable read-only Nesso knowledge graph React component",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -21,15 +21,10 @@
21
21
  "import": "./dist/index.js"
22
22
  }
23
23
  },
24
- "scripts": {
25
- "build": "rm -rf dist && tsc",
26
- "prepublishOnly": "pnpm build",
27
- "dev": "tsc --watch"
28
- },
29
24
  "dependencies": {
30
- "@nesso-how/formats": "workspace:*",
31
- "@nesso-how/relation-types": "workspace:*",
32
- "@nesso-how/types": "workspace:*"
25
+ "@nesso-how/formats": "0.1.0-alpha.28",
26
+ "@nesso-how/types": "0.1.0-alpha.28",
27
+ "@nesso-how/relation-types": "0.1.0-alpha.28"
33
28
  },
34
29
  "peerDependencies": {
35
30
  "@xyflow/react": "^12.6.4",
@@ -40,5 +35,9 @@
40
35
  "@types/react": "^18.3.23",
41
36
  "@types/react-dom": "^18.3.7",
42
37
  "typescript": "~5.8.3"
38
+ },
39
+ "scripts": {
40
+ "build": "rm -rf dist && tsc",
41
+ "dev": "tsc --watch"
43
42
  }
44
- }
43
+ }