@kanzo-tech/graph 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +60 -95
  2. package/dist/core/categories.d.ts +12 -0
  3. package/dist/core/categories.d.ts.map +1 -0
  4. package/dist/core/categories.js +14 -0
  5. package/dist/core/categories.js.map +1 -0
  6. package/dist/core/channels.d.ts +34 -0
  7. package/dist/core/channels.d.ts.map +1 -0
  8. package/dist/core/channels.js +19 -0
  9. package/dist/core/channels.js.map +1 -0
  10. package/dist/core/detail.d.ts +18 -0
  11. package/dist/core/detail.d.ts.map +1 -0
  12. package/dist/core/detail.js +20 -0
  13. package/dist/core/detail.js.map +1 -0
  14. package/dist/core/filter.d.ts +34 -0
  15. package/dist/core/filter.d.ts.map +1 -0
  16. package/dist/core/filter.js +99 -0
  17. package/dist/core/filter.js.map +1 -0
  18. package/dist/core/refine.d.ts +14 -0
  19. package/dist/core/refine.d.ts.map +1 -0
  20. package/dist/core/refine.js +20 -0
  21. package/dist/core/refine.js.map +1 -0
  22. package/dist/{resident.d.ts → core/resident.d.ts} +7 -7
  23. package/dist/core/resident.d.ts.map +1 -0
  24. package/dist/core/resident.js +44 -0
  25. package/dist/core/resident.js.map +1 -0
  26. package/dist/core/scheduler.d.ts +42 -0
  27. package/dist/core/scheduler.d.ts.map +1 -0
  28. package/dist/core/scheduler.js +77 -0
  29. package/dist/core/scheduler.js.map +1 -0
  30. package/dist/core/state.d.ts +132 -0
  31. package/dist/core/state.d.ts.map +1 -0
  32. package/dist/core/store.d.ts +6 -0
  33. package/dist/core/store.d.ts.map +1 -0
  34. package/dist/core/store.js +235 -0
  35. package/dist/core/store.js.map +1 -0
  36. package/dist/core/tile-matrix.d.ts +37 -0
  37. package/dist/core/tile-matrix.d.ts.map +1 -0
  38. package/dist/core/tile-matrix.js +49 -0
  39. package/dist/core/tile-matrix.js.map +1 -0
  40. package/dist/core/tile.d.ts +54 -0
  41. package/dist/core/tile.d.ts.map +1 -0
  42. package/dist/core/tile.js +76 -0
  43. package/dist/core/tile.js.map +1 -0
  44. package/dist/core/tileset.d.ts +59 -0
  45. package/dist/core/tileset.d.ts.map +1 -0
  46. package/dist/core/tileset.js +177 -0
  47. package/dist/core/tileset.js.map +1 -0
  48. package/dist/{types.d.ts → core/types.d.ts} +9 -0
  49. package/dist/core/types.d.ts.map +1 -0
  50. package/dist/index.d.ts +37 -70
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +32 -34
  53. package/dist/index.js.map +1 -1
  54. package/dist/{use-graph-selection.d.ts → parts/gesture.d.ts} +4 -4
  55. package/dist/parts/gesture.d.ts.map +1 -0
  56. package/dist/{use-graph-selection.js → parts/gesture.js} +17 -17
  57. package/dist/parts/gesture.js.map +1 -0
  58. package/dist/parts/graph-canvas.d.ts +17 -0
  59. package/dist/parts/graph-canvas.d.ts.map +1 -0
  60. package/dist/parts/graph-canvas.js +174 -0
  61. package/dist/parts/graph-canvas.js.map +1 -0
  62. package/dist/parts/graph-inspector.d.ts +18 -0
  63. package/dist/parts/graph-inspector.d.ts.map +1 -0
  64. package/dist/parts/graph-inspector.js +84 -0
  65. package/dist/parts/graph-inspector.js.map +1 -0
  66. package/dist/parts/graph-legend.d.ts +12 -0
  67. package/dist/parts/graph-legend.d.ts.map +1 -0
  68. package/dist/parts/graph-legend.js +61 -0
  69. package/dist/parts/graph-legend.js.map +1 -0
  70. package/dist/parts/graph-toolbar.d.ts +15 -0
  71. package/dist/parts/graph-toolbar.d.ts.map +1 -0
  72. package/dist/parts/graph-toolbar.js +94 -0
  73. package/dist/parts/graph-toolbar.js.map +1 -0
  74. package/dist/parts/overlays.d.ts +33 -0
  75. package/dist/parts/overlays.d.ts.map +1 -0
  76. package/dist/{use-graph-overlays.js → parts/overlays.js} +8 -8
  77. package/dist/parts/overlays.js.map +1 -0
  78. package/dist/{shape-glyph.d.ts → parts/shape-glyph.d.ts} +1 -1
  79. package/dist/parts/shape-glyph.d.ts.map +1 -0
  80. package/dist/{shape-glyph.js → parts/shape-glyph.js} +1 -1
  81. package/dist/parts/shape-glyph.js.map +1 -0
  82. package/dist/react/graph-root.d.ts +15 -0
  83. package/dist/react/graph-root.d.ts.map +1 -0
  84. package/dist/react/graph-root.js +23 -0
  85. package/dist/react/graph-root.js.map +1 -0
  86. package/dist/{use-graph-prefs.d.ts → react/use-graph-prefs.d.ts} +2 -2
  87. package/dist/react/use-graph-prefs.d.ts.map +1 -0
  88. package/dist/{use-graph-prefs.js → react/use-graph-prefs.js} +3 -3
  89. package/dist/react/use-graph-prefs.js.map +1 -0
  90. package/dist/react/use-graph-state.d.ts +11 -0
  91. package/dist/react/use-graph-state.d.ts.map +1 -0
  92. package/dist/react/use-graph-state.js +16 -0
  93. package/dist/react/use-graph-state.js.map +1 -0
  94. package/dist/react/use-graph.d.ts +38 -0
  95. package/dist/react/use-graph.d.ts.map +1 -0
  96. package/dist/react/use-graph.js +87 -0
  97. package/dist/react/use-graph.js.map +1 -0
  98. package/dist/{adaptive.d.ts → render/adaptive.d.ts} +1 -1
  99. package/dist/render/adaptive.d.ts.map +1 -0
  100. package/dist/render/adaptive.js.map +1 -0
  101. package/dist/render/compose.d.ts +51 -0
  102. package/dist/render/compose.d.ts.map +1 -0
  103. package/dist/render/compose.js +107 -0
  104. package/dist/render/compose.js.map +1 -0
  105. package/dist/render/css-color.d.ts.map +1 -0
  106. package/dist/render/css-color.js.map +1 -0
  107. package/dist/render/encode.d.ts +42 -0
  108. package/dist/render/encode.d.ts.map +1 -0
  109. package/dist/render/encode.js +68 -0
  110. package/dist/render/encode.js.map +1 -0
  111. package/dist/render/graph-looks.d.ts.map +1 -0
  112. package/dist/render/graph-looks.js.map +1 -0
  113. package/dist/render/graph-model.d.ts +44 -0
  114. package/dist/render/graph-model.d.ts.map +1 -0
  115. package/dist/render/graph-model.js +80 -0
  116. package/dist/render/graph-model.js.map +1 -0
  117. package/dist/{graph-sim.d.ts → render/graph-sim.d.ts} +1 -1
  118. package/dist/render/graph-sim.d.ts.map +1 -0
  119. package/dist/render/graph-sim.js.map +1 -0
  120. package/dist/{obligations.d.ts → render/obligations.d.ts} +1 -1
  121. package/dist/render/obligations.d.ts.map +1 -0
  122. package/dist/render/renderer.d.ts +38 -0
  123. package/dist/render/renderer.d.ts.map +1 -0
  124. package/dist/render/renderer.js +235 -0
  125. package/dist/render/renderer.js.map +1 -0
  126. package/dist/render/webgl.d.ts +14 -0
  127. package/dist/render/webgl.d.ts.map +1 -0
  128. package/dist/render/webgl.js +19 -0
  129. package/dist/render/webgl.js.map +1 -0
  130. package/dist/render/when-ready.d.ts.map +1 -0
  131. package/dist/render/when-ready.js.map +1 -0
  132. package/package.json +11 -21
  133. package/dist/adaptive.d.ts.map +0 -1
  134. package/dist/adaptive.js.map +0 -1
  135. package/dist/bounded.d.ts +0 -364
  136. package/dist/bounded.d.ts.map +0 -1
  137. package/dist/bounded.js +0 -18
  138. package/dist/bounded.js.map +0 -1
  139. package/dist/cluster-ring.d.ts +0 -25
  140. package/dist/cluster-ring.d.ts.map +0 -1
  141. package/dist/cluster-ring.js +0 -16
  142. package/dist/cluster-ring.js.map +0 -1
  143. package/dist/css-color.d.ts.map +0 -1
  144. package/dist/css-color.js.map +0 -1
  145. package/dist/duck-source.d.ts +0 -198
  146. package/dist/duck-source.d.ts.map +0 -1
  147. package/dist/duck-source.js +0 -320
  148. package/dist/duck-source.js.map +0 -1
  149. package/dist/graph-canvas.d.ts +0 -50
  150. package/dist/graph-canvas.d.ts.map +0 -1
  151. package/dist/graph-canvas.js +0 -35
  152. package/dist/graph-canvas.js.map +0 -1
  153. package/dist/graph-looks.d.ts.map +0 -1
  154. package/dist/graph-looks.js.map +0 -1
  155. package/dist/graph-model.d.ts +0 -130
  156. package/dist/graph-model.d.ts.map +0 -1
  157. package/dist/graph-model.js +0 -104
  158. package/dist/graph-model.js.map +0 -1
  159. package/dist/graph-sim.d.ts.map +0 -1
  160. package/dist/graph-sim.js.map +0 -1
  161. package/dist/obligations.d.ts.map +0 -1
  162. package/dist/resident.d.ts.map +0 -1
  163. package/dist/resident.js +0 -44
  164. package/dist/resident.js.map +0 -1
  165. package/dist/shape-glyph.d.ts.map +0 -1
  166. package/dist/shape-glyph.js.map +0 -1
  167. package/dist/slice-client.d.ts +0 -78
  168. package/dist/slice-client.d.ts.map +0 -1
  169. package/dist/slice-client.js +0 -98
  170. package/dist/slice-client.js.map +0 -1
  171. package/dist/types.d.ts.map +0 -1
  172. package/dist/use-graph-look.d.ts +0 -28
  173. package/dist/use-graph-look.d.ts.map +0 -1
  174. package/dist/use-graph-look.js +0 -28
  175. package/dist/use-graph-look.js.map +0 -1
  176. package/dist/use-graph-overlays.d.ts +0 -44
  177. package/dist/use-graph-overlays.d.ts.map +0 -1
  178. package/dist/use-graph-overlays.js.map +0 -1
  179. package/dist/use-graph-prefs.d.ts.map +0 -1
  180. package/dist/use-graph-prefs.js.map +0 -1
  181. package/dist/use-graph-selection.d.ts.map +0 -1
  182. package/dist/use-graph-selection.js.map +0 -1
  183. package/dist/use-graph.d.ts +0 -203
  184. package/dist/use-graph.d.ts.map +0 -1
  185. package/dist/use-graph.js +0 -102
  186. package/dist/use-graph.js.map +0 -1
  187. package/dist/use-query-loop.d.ts +0 -88
  188. package/dist/use-query-loop.d.ts.map +0 -1
  189. package/dist/use-query-loop.js +0 -148
  190. package/dist/use-query-loop.js.map +0 -1
  191. package/dist/use-renderer.d.ts +0 -86
  192. package/dist/use-renderer.d.ts.map +0 -1
  193. package/dist/use-renderer.js +0 -188
  194. package/dist/use-renderer.js.map +0 -1
  195. package/dist/when-ready.d.ts.map +0 -1
  196. package/dist/when-ready.js.map +0 -1
  197. /package/dist/{adaptive.js → render/adaptive.js} +0 -0
  198. /package/dist/{css-color.d.ts → render/css-color.d.ts} +0 -0
  199. /package/dist/{css-color.js → render/css-color.js} +0 -0
  200. /package/dist/{graph-looks.d.ts → render/graph-looks.d.ts} +0 -0
  201. /package/dist/{graph-looks.js → render/graph-looks.js} +0 -0
  202. /package/dist/{graph-sim.js → render/graph-sim.js} +0 -0
  203. /package/dist/{when-ready.d.ts → render/when-ready.d.ts} +0 -0
  204. /package/dist/{when-ready.js → render/when-ready.js} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,73 +1,40 @@
1
1
  /**
2
- * A GPU graph view, in the pieces a host actually composes.
3
- *
4
- * **`GraphCanvas` owns the three that never differ; the arrangement stays at the call site.** This
5
- * barrel said for a long time that there was no canvas component, on the argument that a graph
6
- * canvas is a toolbar, a legend, an inspector and a hover card — all of them per-product. That half
7
- * is still true and they are still yours. What the argument missed is that underneath them sit
8
- * three things that were identical everywhere and re-wired by hand each time: the renderer's
9
- * lifetime, the query loop that follows the camera, and the buffers a look implies.
10
- * `/docs/design/graph` has the measurement.
11
- *
12
- * **Why a package and not `@kanzo-tech/ui`.** The first admission rule is *domain-free —
13
- * nothing about RDF / SHACL / fossil / graphs / auth*. Graphs are excluded by name, deliberately:
14
- * `ui` is the generic vocabulary shared by every product. A sibling package is also the only place
15
- * a required WebGL peer belongs.
16
- *
17
- * **The measurements that shape it** are on `/docs/graph/benchmarks`: a live simulation is comfortable to
18
- * about 50,000 points and finished by 200,000, and past that the honest design is positions
19
- * precomputed once and stored as a column — which is why a simulation is opt-in here and off by
20
- * default, and why the render path is bounded rather than fast.
21
- */
22
- export { scaleOf, neighboursOf, type Channels } from './graph-model';
23
- export { lookFrom, type Look, type LookPatch, type Shape, } from './graph-looks';
24
- export { ShapeGlyph, type ShapeGlyphProps } from './shape-glyph';
25
- /**
26
- * The graph, in Ark's four pieces.
27
- *
28
- * `useGraph(props)` **creates** the api and `useGraphContext()` **reads** it, which is Ark's
29
- * convention and was inverted here: the reader was `useGraphCanvas` and there was no creator.
30
- * `GraphCanvas` is the shortcut that does both, and `GraphRootProvider` is what a host reaches for
31
- * when it has to call a hook *beside* the canvas — `useGraphOverlays` takes the api and the `events`
32
- * block reads `getGraph`/`getResident` off it, both from above the element where no context is
33
- * readable.
34
- *
35
- * That was not a symmetry we wanted for its own sake: it is what the workspace could not adopt
36
- * `GraphCanvas` without, and the `graphRef`/`residentRef` props that stood in for it are gone.
37
- */
38
- export { GraphCanvas, GraphRootProvider, useGraphContext, type GraphCanvasProps, type GraphRootProviderProps, } from './graph-canvas';
39
- export { useGraph, type GraphApi, type GraphEvents, type UseGraphProps } from './use-graph';
40
- export { useGraphOverlays, type GraphOverlays } from './use-graph-overlays';
41
- export { useGraphSelection, cursorChip } from './use-graph-selection';
42
- /**
43
- * Identity, and the map from it to the buffer index cosmos.gl draws at.
44
- *
45
- * The renderer addresses points by position in the arrays it was handed, and a resident set that
46
- * comes and goes reuses every position. So a vertex is the pair `(type_idx, dense_id)`, and
47
- * everything that outlives one answer is held as one and re-resolved through the `Resident` that
48
- * `useQueryLoop` rebuilds per answer. A host never builds its own: two maps of the same thing is
49
- * how one of them ends up describing buffers that are no longer on screen.
50
- */
51
- export { residentOf, vertexId, typeOf, denseOf, type Resident, type VertexId, } from './resident';
52
- /**
53
- * The bounded render path — a graph you never hold all of.
54
- *
55
- * A contract, not a format: anything that can answer "what is in this rectangle, at this zoom, in
56
- * at most this many marks" is a source. A tile fetched by a computed address is one; a relation
57
- * with `x`/`y` and a spatial predicate is another. This package renders and does not learn a storage layout,
58
- * which is what removed the ceiling rather than raising it.
59
- *
60
- * `useQueryLoop` is the loop that asks — it observes the camera, debounces, cancels what the
61
- * camera has already superseded, and pushes each answer into the renderer. **The source itself is
62
- * not here and there is one of it**: `openCorpus`, on `@kanzo-tech/graph/duckdb`, because a corpus
63
- * is read through a database and a database is an optional peer. What is left on this barrel is the
64
- * rendering surface — the hooks, the look, identity and the buffers a slice implies — and it draws
65
- * nothing on its own.
2
+ * The graph view over a fossil corpus. fossil reads and this package draws, and nothing crosses
3
+ * between them but the corpus contract: the host opens the corpus with fossil's `open` on the page's
4
+ * `engine()`, and `GraphRoot` draws it.
5
+ *
6
+ * Four layers, each the shape of a named reference — `/docs/design/graph`:
7
+ *
8
+ * - `core/` — a headless tileset in deck.gl's `Tileset2D` shape over `tileMatrix` and `scan`, and a
9
+ * store in TanStack Query's observer shape. No React, no cosmos.gl, no SQL.
10
+ * - `render/` — tiles to cosmos.gl buffers: encoded once per tile, uploaded by kind, rendered once a
11
+ * frame.
12
+ * - `react/` — `useGraph`, `GraphRoot`, `GraphRootProvider`, `useGraphContext`: Ark's four; and
13
+ * `useGraphState`, TanStack Store's selector, because the api is commands and the state moves at
14
+ * frame rate.
15
+ * - `parts/` — `GraphCanvas`, `GraphLegend`, `GraphToolbar`, `GraphInspector`: flat parts over the
16
+ * one context. They own the vocabulary; the root's callbacks are the host's policy.
17
+ *
18
+ * **Why a package and not `@kanzo-tech/ui`.** The first admission rule is *domain-free — nothing
19
+ * about RDF / SHACL / fossil / graphs / auth*. Graphs are excluded by name, and a sibling package is
20
+ * the only place a required WebGL peer belongs.
66
21
  */
67
- export { shouldSlice, type BoundedSource, type Slice, type SliceRequest, type Viewport, } from './bounded';
68
- export { adaptive } from './adaptive';
69
- export { resolveToken, toHex, type Rgba } from './css-color';
70
- export { type GraphCommands, type Motion, type Selection, type SelectionSource, type Tool, } from './types';
71
- export { simFrom, type Sim } from './graph-sim';
72
- export { useGraphPrefs } from './use-graph-prefs';
22
+ export { GraphRoot, GraphRootProvider, useGraphContext, type GraphRootProps, type GraphRootProviderProps, } from './react/graph-root';
23
+ export { useGraph, type GraphApi, type UseGraphProps } from './react/use-graph';
24
+ export { useGraphState } from './react/use-graph-state';
25
+ export { useGraphPrefs } from './react/use-graph-prefs';
26
+ export { GraphCanvas, type GraphCanvasProps } from './parts/graph-canvas';
27
+ export { GraphLegend, type GraphLegendProps } from './parts/graph-legend';
28
+ export { GraphToolbar, type GraphToolbarProps } from './parts/graph-toolbar';
29
+ export { GraphInspector, type GraphInspectorProps } from './parts/graph-inspector';
30
+ export { ShapeGlyph, type ShapeGlyphProps } from './parts/shape-glyph';
31
+ export { lookFrom, type Look, type LookPatch, type Shape } from './render/graph-looks';
32
+ export { simFrom, type Sim } from './render/graph-sim';
33
+ export { adaptive } from './render/adaptive';
34
+ export { scaleOf } from './render/graph-model';
35
+ export type { Channels } from './core/channels';
36
+ export { vertexId, typeOf, denseOf, type Resident, type VertexId } from './core/resident';
37
+ export type { GraphCommands, Motion, Selection, SelectionSource, Tool } from './core/types';
38
+ export type { Drawn, GraphState, GraphStatus } from './core/state';
39
+ export type { VertexDetail } from './core/detail';
73
40
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAqBrE,OAAO,EAIL,QAAQ,EACR,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,KAAK,GACX,MAAM,eAAe,CAAC;AAQvB,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAgC5F,OAAO,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEtE;;;;;;;;GAQG;AACH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,OAAO,EACP,KAAK,QAAQ,EACb,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC;AAuBpB;;;;;;;;;;;;;;GAcG;AAoBH,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,KAAK,QAAQ,GACd,MAAM,WAAW,CAAC;AAsBnB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,IAAI,GACV,MAAM,SAAS,CAAC;AASjB,OAAO,EAAE,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAIhD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAIvE,OAAO,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE1F,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC5F,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,37 +1,35 @@
1
- import { neighboursOf as e, scaleOf as p } from "./graph-model.js";
2
- import { lookFrom as f } from "./graph-looks.js";
3
- import { ShapeGlyph as s } from "./shape-glyph.js";
4
- import { GraphCanvas as a, GraphRootProvider as h, useGraphContext as i } from "./graph-canvas.js";
5
- import { useGraph as u } from "./use-graph.js";
6
- import { useGraphOverlays as n } from "./use-graph-overlays.js";
7
- import { cursorChip as v, useGraphSelection as O } from "./use-graph-selection.js";
8
- import { denseOf as y, residentOf as C, typeOf as S, vertexId as k } from "./resident.js";
9
- import { shouldSlice as P } from "./bounded.js";
10
- import { adaptive as g } from "./adaptive.js";
11
- import { resolveToken as I, toHex as R } from "./css-color.js";
12
- import { simFrom as j } from "./graph-sim.js";
13
- import { useGraphPrefs as w } from "./use-graph-prefs.js";
1
+ import { GraphRoot as e, GraphRootProvider as p, useGraphContext as t } from "./react/graph-root.js";
2
+ import { useGraph as f } from "./react/use-graph.js";
3
+ import { useGraphState as x } from "./react/use-graph-state.js";
4
+ import { useGraphPrefs as G } from "./react/use-graph-prefs.js";
5
+ import { GraphCanvas as d } from "./parts/graph-canvas.js";
6
+ import { GraphLegend as l } from "./parts/graph-legend.js";
7
+ import { GraphToolbar as v } from "./parts/graph-toolbar.js";
8
+ import { GraphInspector as O } from "./parts/graph-inspector.js";
9
+ import { ShapeGlyph as y } from "./parts/shape-glyph.js";
10
+ import { lookFrom as F } from "./render/graph-looks.js";
11
+ import { simFrom as P } from "./render/graph-sim.js";
12
+ import { adaptive as S } from "./render/adaptive.js";
13
+ import { scaleOf as g } from "./render/graph-model.js";
14
+ import { denseOf as L, typeOf as T, vertexId as j } from "./core/resident.js";
14
15
  export {
15
- a as GraphCanvas,
16
- h as GraphRootProvider,
17
- s as ShapeGlyph,
18
- g as adaptive,
19
- v as cursorChip,
20
- y as denseOf,
21
- f as lookFrom,
22
- e as neighboursOf,
23
- C as residentOf,
24
- I as resolveToken,
25
- p as scaleOf,
26
- P as shouldSlice,
27
- j as simFrom,
28
- R as toHex,
29
- S as typeOf,
30
- u as useGraph,
31
- i as useGraphContext,
32
- n as useGraphOverlays,
33
- w as useGraphPrefs,
34
- O as useGraphSelection,
35
- k as vertexId
16
+ d as GraphCanvas,
17
+ O as GraphInspector,
18
+ l as GraphLegend,
19
+ e as GraphRoot,
20
+ p as GraphRootProvider,
21
+ v as GraphToolbar,
22
+ y as ShapeGlyph,
23
+ S as adaptive,
24
+ L as denseOf,
25
+ F as lookFrom,
26
+ g as scaleOf,
27
+ P as simFrom,
28
+ T as typeOf,
29
+ f as useGraph,
30
+ t as useGraphContext,
31
+ G as useGraphPrefs,
32
+ x as useGraphState,
33
+ j as vertexId
36
34
  };
37
35
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
@@ -1,7 +1,7 @@
1
1
  import { default as React } from 'react';
2
2
  import { Graph } from '@cosmos.gl/graph';
3
- import { Resident, VertexId } from './resident';
4
- import { Selection, SelectionSource, Tool } from './types';
3
+ import { Resident, VertexId } from '../core/resident';
4
+ import { Selection, SelectionSource, Tool } from '../core/types';
5
5
  /**
6
6
  * Drawing a selection on the canvas: the marquee, the lasso, and the keys that modify them.
7
7
  *
@@ -55,5 +55,5 @@ export interface GraphSelectionOptions {
55
55
  tool: Tool;
56
56
  setTool: (tool: Tool) => void;
57
57
  }
58
- export declare function useGraphSelection(options: GraphSelectionOptions): GraphSelectionGesture;
59
- //# sourceMappingURL=use-graph-selection.d.ts.map
58
+ export declare function useGesture(options: GraphSelectionOptions): GraphSelectionGesture;
59
+ //# sourceMappingURL=gesture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gesture.d.ts","sourceRoot":"","sources":["../../src/parts/gesture.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGtE;;;;;;;;;;GAUG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAErC,wFAAwF;AACxF,MAAM,MAAM,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC;AAS/F,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,aAAa,CAIjE;AAED,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,oFAAoF;IACpF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,mFAAmF;IACnF,MAAM,EAAE,IAAI,CAAC;IACb,QAAQ,EAAE;QACR,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;QACnD,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;QACnD,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;QACjD,eAAe,EAAE,MAAM,IAAI,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,KAAK,GAAG,IAAI,CAAC;IAC7B;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,QAAQ,CAAC;IAC5B,wEAAwE;IACxE,YAAY,EAAE,MAAM,SAAS,GAAG,IAAI,CAAC;IACrC,MAAM,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzF,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CAC/B;AAOD,wBAAgB,UAAU,CAAC,OAAO,EAAE,qBAAqB,GAAG,qBAAqB,CA6IhF"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { useState as m, useRef as C, useCallback as P, useEffect as I } from "react";
3
- import { isReady as K } from "./when-ready.js";
2
+ import { useState as m, useRef as C, useCallback as S, useEffect as I } from "react";
3
+ import { isReady as K } from "../render/when-ready.js";
4
4
  const x = 3, _ = 4, q = 60;
5
5
  function N(l) {
6
6
  if (!l) return { display: "none" };
@@ -12,7 +12,7 @@ const z = {
12
12
  lasso: { source: "lasso", label: "Lasso" }
13
13
  };
14
14
  function U(l) {
15
- const { commit: i, getGraph: a, getResident: k, getSelection: v, setTool: y, tool: h } = l, [s, c] = m(null), [L, f] = m(null), [R, p] = m(!1), b = C(0), d = P(
15
+ const { commit: i, getGraph: a, getResident: k, getSelection: v, setTool: y, tool: h } = l, [s, c] = m(null), [L, f] = m(null), [R, d] = m(!1), b = C(0), p = S(
16
16
  (t) => {
17
17
  const e = a();
18
18
  if (!e) return [];
@@ -29,19 +29,19 @@ function U(l) {
29
29
  return t.path.length < 3 ? [] : Array.from(e.findPointsInPolygon(t.path));
30
30
  },
31
31
  [a]
32
- ), E = P(
32
+ ), E = S(
33
33
  (t) => {
34
34
  const e = performance.now();
35
- e - b.current < q || (b.current = e, f(d(t).length));
35
+ e - b.current < q || (b.current = e, f(p(t).length));
36
36
  },
37
- [d]
37
+ [p]
38
38
  );
39
39
  I(() => {
40
40
  const t = (n) => {
41
- n.key === "Shift" && p(!0), n.key === "Escape" && (c((r) => (r || (h ? y(null) : i(null, "node", "")), null)), f(null));
41
+ n.key === "Shift" && d(!0), n.key === "Escape" && (c((r) => (r || (h ? y(null) : i(null, "node", "")), null)), f(null));
42
42
  }, e = (n) => {
43
- n.key === "Shift" && p(!1);
44
- }, o = () => p(!1);
43
+ n.key === "Shift" && d(!1);
44
+ }, o = () => d(!1);
45
45
  return window.addEventListener("keydown", t), window.addEventListener("keyup", e), window.addEventListener("blur", o), () => {
46
46
  window.removeEventListener("keydown", t), window.removeEventListener("keyup", e), window.removeEventListener("blur", o);
47
47
  };
@@ -50,28 +50,28 @@ function U(l) {
50
50
  const e = t.currentTarget.getBoundingClientRect();
51
51
  return [t.clientX - e.left, t.clientY - e.top];
52
52
  }, T = (t, e) => {
53
- var g;
53
+ var P;
54
54
  if (c(null), f(null), !t) return;
55
- const o = new Set(k().verticesAt(d(t)));
55
+ const o = new Set(k().verticesAt(p(t)));
56
56
  if (o.size === 0 && !e.altKey) return;
57
- const { label: n, source: r } = z[t.tool], u = ((g = v()) == null ? void 0 : g.vertices) ?? [];
57
+ const { label: n, source: r } = z[t.tool], u = ((P = v()) == null ? void 0 : P.vertices) ?? [];
58
58
  if (e.altKey) {
59
59
  const w = new Set(u);
60
60
  for (const A of o) w.delete(A);
61
61
  i(w.size > 0 ? w : null, r, n);
62
62
  } else e.metaKey || e.ctrlKey ? i(/* @__PURE__ */ new Set([...u, ...o]), r, n) : i(o, r, n);
63
- }, S = h ?? (R ? "rect" : null);
63
+ }, g = h ?? (R ? "rect" : null);
64
64
  return {
65
65
  drag: s,
66
66
  preview: L,
67
- active: S,
67
+ active: g,
68
68
  handlers: {
69
69
  onPointerDown: (t) => {
70
70
  if (t.button !== 0) return;
71
71
  t.currentTarget.setPointerCapture(t.pointerId);
72
72
  const e = M(t);
73
73
  c(
74
- S === "rect" ? { tool: "rect", from: e, to: e } : { tool: "lasso", path: [e] }
74
+ g === "rect" ? { tool: "rect", from: e, to: e } : { tool: "lasso", path: [e] }
75
75
  );
76
76
  },
77
77
  onPointerMove: (t) => {
@@ -96,6 +96,6 @@ function U(l) {
96
96
  }
97
97
  export {
98
98
  N as cursorChip,
99
- U as useGraphSelection
99
+ U as useGesture
100
100
  };
101
- //# sourceMappingURL=use-graph-selection.js.map
101
+ //# sourceMappingURL=gesture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gesture.js","sources":["../../src/parts/gesture.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type React from \"react\";\nimport type { Graph } from \"@cosmos.gl/graph\";\nimport type { Resident, VertexId } from \"../core/resident\";\nimport type { Selection, SelectionSource, Tool } from \"../core/types\";\nimport { isReady } from \"../render/when-ready\";\n\n/**\n * Drawing a selection on the canvas: the marquee, the lasso, and the keys that modify them.\n *\n * The whole gesture lives here — what is being drawn, how many nodes it currently holds, and what\n * happens when the pointer comes up. The component gets handlers to spread onto an overlay and the\n * state to draw it with; it does not need to know that Shift borrows the marquee or that a hit test\n * costs a GPU readback.\n *\n * Modifiers are read at *release*, not at press, because that is when the reader has decided:\n * `Alt` removes what was drawn from the selection, `⌘`/`Ctrl` adds it, and neither replaces.\n */\nexport type Point = [number, number];\n\n/** A selection gesture in flight. The two tools differ only in what they accumulate. */\nexport type Drag = { tool: \"rect\"; from: Point; to: Point } | { tool: \"lasso\"; path: Point[] };\n\n/** Below this the hit test would be answering about a click, not a box. */\nconst MIN_RECT = 3;\n/** A raw pointer stream makes a polygon of near-duplicate vertices; the hit test walks every one. */\nconst PATH_STEP = 4;\n/** Slower than the hand, faster than the eye — and one GPU readback per gesture frame is plenty. */\nconst MEASURE_MS = 60;\n\n/** The running count rides just off the cursor, at the edge the gesture is growing from. */\nexport function cursorChip(drag: Drag | null): React.CSSProperties {\n if (!drag) return { display: \"none\" };\n const [x = 0, y = 0] = drag.tool === \"rect\" ? drag.to : (drag.path[drag.path.length - 1] ?? []);\n return { left: x + 14, top: y + 14 };\n}\n\nexport interface GraphSelectionGesture {\n /** The gesture being drawn, for the overlay to render. */\n drag: Drag | null;\n /** How many nodes it holds right now, so the number lands before the mouse does. */\n preview: number | null;\n /** The tool actually in force: the chosen one, or the marquee Shift is lending. */\n active: Tool;\n handlers: {\n onPointerDown: (event: React.PointerEvent) => void;\n onPointerMove: (event: React.PointerEvent) => void;\n onPointerUp: (event: React.PointerEvent) => void;\n onPointerCancel: () => void;\n };\n}\n\nexport interface GraphSelectionOptions {\n getGraph: () => Graph | null;\n /**\n * Who is drawn right now — the only thing that can turn a hit-test index into an identity.\n *\n * A gesture selects positions on screen, and a position is a buffer index, which the next\n * residency reuses for a different vertex. So the gesture resolves to identities here and now,\n * while the answer that produced them is still the one on screen.\n */\n getResident: () => Resident;\n /** The live selection, for the modifiers to add to or subtract from. */\n getSelection: () => Selection | null;\n commit: (vertices: Set<VertexId> | null, source: SelectionSource, label: string) => void;\n tool: Tool;\n setTool: (tool: Tool) => void;\n}\n\nconst NAME: Record<\"rect\" | \"lasso\", { source: SelectionSource; label: string }> = {\n rect: { source: \"marquee\", label: \"Marquee\" },\n lasso: { source: \"lasso\", label: \"Lasso\" },\n};\n\nexport function useGesture(options: GraphSelectionOptions): GraphSelectionGesture {\n const { commit, getGraph, getResident, getSelection, setTool, tool } = options;\n const [drag, setDrag] = useState<Drag | null>(null);\n const [preview, setPreview] = useState<number | null>(null);\n const [shift, setShift] = useState(false);\n const measured = useRef(0);\n\n const hitTest = useCallback(\n (shape: Drag): number[] => {\n const graph = getGraph();\n if (!graph) return [];\n // **Upstream's own words, on these two and on nothing else in its `.d.ts`:** *this method is\n // synchronous and must only be called when the graph is ready*. There is nothing to await in\n // a pointer handler, so the answer for a device that is not there is the honest one — a\n // gesture over a graph that has not drawn selects nothing, which is what it looks like.\n if (!isReady(graph)) return [];\n if (shape.tool === \"rect\") {\n const [[ax, ay], [bx, by]] = [shape.from, shape.to];\n if (Math.abs(bx - ax) < MIN_RECT || Math.abs(by - ay) < MIN_RECT) return [];\n return Array.from(\n graph.findPointsInRect([\n [Math.min(ax, bx), Math.min(ay, by)],\n [Math.max(ax, bx), Math.max(ay, by)],\n ]),\n );\n }\n if (shape.path.length < 3) return [];\n return Array.from(graph.findPointsInPolygon(shape.path));\n },\n [getGraph],\n );\n\n // Both hit tests are a GPU pass followed by a synchronous `readPixels`, so running one per\n // pointer event would stall the frame the gesture is being drawn into.\n const measure = useCallback(\n (shape: Drag) => {\n const now = performance.now();\n if (now - measured.current < MEASURE_MS) return;\n measured.current = now;\n setPreview(hitTest(shape).length);\n },\n [hitTest],\n );\n\n // Escape is the way out of everything, in layers: it abandons a drag in progress, then drops the\n // tool, then clears what is held. And a window that loses focus never delivers the Shift keyup,\n // which would leave the canvas unable to pan.\n useEffect(() => {\n const down = (event: KeyboardEvent) => {\n if (event.key === \"Shift\") setShift(true);\n if (event.key !== \"Escape\") return;\n setDrag((current) => {\n if (current) return null;\n if (tool) setTool(null);\n else commit(null, \"node\", \"\");\n return null;\n });\n setPreview(null);\n };\n const up = (event: KeyboardEvent) => {\n if (event.key === \"Shift\") setShift(false);\n };\n const blur = () => setShift(false);\n window.addEventListener(\"keydown\", down);\n window.addEventListener(\"keyup\", up);\n window.addEventListener(\"blur\", blur);\n return () => {\n window.removeEventListener(\"keydown\", down);\n window.removeEventListener(\"keyup\", up);\n window.removeEventListener(\"blur\", blur);\n };\n }, [commit, setTool, tool]);\n\n /** Screen coordinates inside the canvas — the space every cosmos.gl hit test speaks. */\n const at = (event: React.PointerEvent): Point => {\n const box = event.currentTarget.getBoundingClientRect();\n return [event.clientX - box.left, event.clientY - box.top];\n };\n\n const finish = (shape: Drag | null, event: React.PointerEvent) => {\n setDrag(null);\n setPreview(null);\n if (!shape) return;\n // The one line the whole gesture turns on: the hit test answers in buffer indices, and they stop\n // meaning anything the moment the resident set changes.\n const vertices = new Set(getResident().verticesAt(hitTest(shape)));\n // A gesture that caught nothing and asked for nothing is a misfire, not a request to clear —\n // clearing is what the corner's own button and Escape are for.\n if (vertices.size === 0 && !event.altKey) return;\n const { label, source } = NAME[shape.tool];\n const held = getSelection()?.vertices ?? [];\n if (event.altKey) {\n const next = new Set(held);\n for (const vertex of vertices) next.delete(vertex);\n commit(next.size > 0 ? next : null, source, label);\n } else if (event.metaKey || event.ctrlKey) {\n commit(new Set([...held, ...vertices]), source, label);\n } else {\n commit(vertices, source, label);\n }\n };\n\n const active: Tool = tool ?? (shift ? \"rect\" : null);\n\n return {\n drag,\n preview,\n active,\n handlers: {\n onPointerDown: (event) => {\n if (event.button !== 0) return;\n event.currentTarget.setPointerCapture(event.pointerId);\n const start = at(event);\n setDrag(\n active === \"rect\"\n ? { tool: \"rect\", from: start, to: start }\n : { tool: \"lasso\", path: [start] },\n );\n },\n onPointerMove: (event) => {\n if (!drag) return;\n const next = at(event);\n if (drag.tool === \"rect\") {\n const shape: Drag = { ...drag, to: next };\n setDrag(shape);\n measure(shape);\n return;\n }\n const last = drag.path[drag.path.length - 1] as Point;\n if (Math.hypot(next[0] - last[0], next[1] - last[1]) < PATH_STEP) return;\n const shape: Drag = { tool: \"lasso\", path: [...drag.path, next] };\n setDrag(shape);\n measure(shape);\n },\n onPointerUp: (event) => finish(drag, event),\n onPointerCancel: () => {\n setDrag(null);\n setPreview(null);\n },\n },\n };\n}\n"],"names":[],"mappings":";;;AA0BA;AAOO;AACL;AACA;AACA;AACF;AAkCA;AAAmF;AAC/C;AAEpC;AAEO;AACL;AAMgB;AAEZ;AACA;AAKA;AACA;AACE;AACA;AACa;AACY;AACc;AACA;AACpC;AAAA;AAGL;AACuD;AACzD;AACS;AAKK;AAEZ;AACA;AAEgC;AAClC;AACQ;AAMV;AACE;AAEE;AAOe;AAGf;AAAyC;AAG3C;AAIE;AAEuC;AACzC;AAIF;AACE;AACA;AAAyD;;AAMzD;AAGA;AAGA;AACA;AAEA;AACE;AACA;AACA;AAAiD;AAInB;AAMlC;AAAO;AACL;AACA;AACA;AACU;AAEN;AACA;AACA;AACA;AAAA;AAGmC;AAAE;AAEvC;AAEE;AACA;AACA;AACE;AACA;AAEA;AAAA;AAEF;AACA;AACA;AACA;AACa;AACf;AAC0C;AAExC;AACe;AACjB;AAAA;AAGN;;;;;"}
@@ -0,0 +1,17 @@
1
+ import { ReactNode } from 'react';
2
+ export interface GraphCanvasProps extends React.ComponentProps<"div"> {
3
+ /** The chrome — a toolbar, a legend, an inspector — positioned over the surface. */
4
+ children?: ReactNode;
5
+ }
6
+ /**
7
+ * **The element, and what the look declares over it** — the grid, the vignette, the labels and the
8
+ * hover card are fields of `Look`, so drawing them is the canvas's; the marquee and lasso gesture is
9
+ * too. Two layers: cosmos.gl fills the surface with a canvas of its own, so chrome parented there
10
+ * would be a sibling inside an element the renderer resizes. The frame is `isolate`, so a host's
11
+ * `z-index` on a child cannot escape into the page.
12
+ *
13
+ * The surface is never gated on the first answer: rendered behind a placeholder it deadlocks — no
14
+ * element, no renderer, no camera, no question. Waiting is an overlay over an empty canvas.
15
+ */
16
+ export declare function GraphCanvas({ children, className, slot, ...rest }: GraphCanvasProps): import("react").JSX.Element;
17
+ //# sourceMappingURL=graph-canvas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-canvas.d.ts","sourceRoot":"","sources":["../../src/parts/graph-canvas.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAa1F,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC;IACnE,oFAAoF;IACpF,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,gBAAgB,+BA0JnF"}
@@ -0,0 +1,174 @@
1
+ "use client";
2
+ import { jsxs as g, jsx as t } from "react/jsx-runtime";
3
+ import { useThemeTick as Q, categoricalCapacity as U, Show as v, cn as V } from "@kanzo-tech/ui";
4
+ import { useMemo as w, useCallback as L, useRef as X, useState as Y, useEffect as G } from "react";
5
+ import { nameOf as Z } from "../core/categories.js";
6
+ import { denseOf as ee } from "../core/resident.js";
7
+ import { useGraphContext as te } from "../react/graph-root.js";
8
+ import { internalsOf as re } from "../react/use-graph.js";
9
+ import { useGraphState as f } from "../react/use-graph-state.js";
10
+ import { resolveLook as oe } from "../render/graph-looks.js";
11
+ import { scaleOf as ne } from "../render/graph-model.js";
12
+ import { useGesture as se, cursorChip as ae } from "./gesture.js";
13
+ import { useOverlays as ie } from "./overlays.js";
14
+ import { ShapeGlyph as le } from "./shape-glyph.js";
15
+ const D = "var(--brand-a5)";
16
+ function ce(p, x, b) {
17
+ const y = p.titles;
18
+ if (!y || x <= 0) return [];
19
+ const n = Array.from({ length: p.vertices }, (l, c) => c), u = p.sizes;
20
+ u && n.sort((l, c) => (u[c] ?? 0) - (u[l] ?? 0));
21
+ const i = n.slice(0, x), s = b === null ? void 0 : p.resident.indexOf(b);
22
+ return s !== void 0 && !i.includes(s) && i.unshift(s), i.flatMap((l) => {
23
+ const c = p.resident.at(l), o = y[l];
24
+ return c === void 0 || !o ? [] : [{ vertex: c, text: o }];
25
+ });
26
+ }
27
+ const de = {
28
+ opening: "Opening the corpus…",
29
+ reading: "Reading the corpus…"
30
+ };
31
+ function Re({ children: p, className: x, slot: b, ...y }) {
32
+ const n = te(), { attach: u, renderer: i } = re(n), s = f((e) => e.hovered), l = f((e) => e.focus), c = f((e) => e.tool), o = f((e) => e.options), N = f((e) => {
33
+ var a;
34
+ return ((a = e.drawn) == null ? void 0 : a.domain) ?? e.domain;
35
+ }), _ = f((e) => e.drawn === null ? de[e.status] : void 0), h = w(() => oe(o.look), [o.look]), M = L(() => {
36
+ var e;
37
+ return ((e = i()) == null ? void 0 : e.graph) ?? null;
38
+ }, [i]), E = ie({ getGraph: M, getResident: n.getResident }), { cardRef: F, gridRef: q, hostRef: R, labelRef: B, schedule: k, setHovered: T, setLabelOrder: z, track: W } = E, j = X(null), [d, J] = Y(null);
39
+ G(() => {
40
+ const e = j.current;
41
+ if (e)
42
+ return u(e, { onFrame: k, onComposed: J });
43
+ }, [u, k]);
44
+ const K = Q();
45
+ G(() => {
46
+ var e;
47
+ (e = i()) == null || e.repaint();
48
+ }, [i, K]);
49
+ const O = w(
50
+ () => d ? ce(d, h.labels, l) : [],
51
+ [d, l, h.labels]
52
+ );
53
+ G(() => {
54
+ z(O.map((e) => e.vertex)), T(s), W(), k();
55
+ }, [s, O, k, T, z, W, h.grid]);
56
+ const A = se({
57
+ getGraph: M,
58
+ getResident: n.getResident,
59
+ getSelection: L(() => n.getState().selection, [n]),
60
+ commit: (e, a, C) => n.select(e ? [...e] : null, a, C),
61
+ setTool: n.setTool,
62
+ tool: c
63
+ }), { active: P, drag: r, preview: S } = A, I = R.current ? U(R.current) : void 0, $ = w(() => ne(o, I), [o, I]), m = w(() => {
64
+ var H;
65
+ if (s === null || !d) return null;
66
+ const e = d.resident.indexOf(s);
67
+ if (e === void 0) return null;
68
+ const a = d.categories[e] ?? 0, C = o.fill !== void 0 || o.symbol !== void 0;
69
+ return {
70
+ rank: a,
71
+ title: ((H = d.titles) == null ? void 0 : H[e]) || `#${ee(s)}`,
72
+ category: C && a < N.length ? Z(N[a], o.categories) : null
73
+ };
74
+ }, [d, N, s, o]);
75
+ return /* @__PURE__ */ g(
76
+ "div",
77
+ {
78
+ ...y,
79
+ className: V("relative isolate size-full overflow-hidden bg-background", x),
80
+ "data-slot": b ?? "graph-canvas",
81
+ ref: R,
82
+ children: [
83
+ /* @__PURE__ */ t("div", { className: "size-full", "data-slot": "graph-canvas-surface", ref: j }),
84
+ /* @__PURE__ */ t(v, { when: h.grid, children: /* @__PURE__ */ t(
85
+ "div",
86
+ {
87
+ className: "pointer-events-none absolute inset-0",
88
+ ref: q,
89
+ style: { backgroundImage: "radial-gradient(var(--border) 1px, transparent 1px)" }
90
+ }
91
+ ) }),
92
+ /* @__PURE__ */ t(v, { when: h.vignette, children: /* @__PURE__ */ t(
93
+ "div",
94
+ {
95
+ className: "pointer-events-none absolute inset-0",
96
+ style: { background: "radial-gradient(ellipse 75% 65% at 50% 45%, transparent 30%, var(--background) 100%)" }
97
+ }
98
+ ) }),
99
+ /* @__PURE__ */ g("div", { className: "pointer-events-none absolute inset-0 overflow-hidden", children: [
100
+ O.map((e) => /* @__PURE__ */ t(
101
+ "span",
102
+ {
103
+ className: "absolute top-0 left-0 whitespace-nowrap font-medium text-[10px] text-foreground leading-none opacity-0 transition-opacity [text-shadow:0_0_3px_var(--background),0_0_6px_var(--background)]",
104
+ ref: B(e.vertex),
105
+ children: e.text
106
+ },
107
+ String(e.vertex)
108
+ )),
109
+ m && /* @__PURE__ */ g(
110
+ "div",
111
+ {
112
+ className: "absolute top-0 left-0 flex w-max max-w-60 items-center gap-2 rounded-lg border bg-popover px-2.5 py-2 opacity-0 shadow-lg",
113
+ "data-slot": "graph-canvas-card",
114
+ ref: F,
115
+ children: [
116
+ /* @__PURE__ */ t(le, { className: "size-2.5 shrink-0", color: $.color(m.rank), shape: $.shape(m.rank) }),
117
+ /* @__PURE__ */ t("span", { className: "truncate font-medium text-popover-foreground text-sm leading-none", children: m.title }),
118
+ m.category !== null && /* @__PURE__ */ t("span", { className: "text-muted-foreground text-xs", children: m.category })
119
+ ]
120
+ }
121
+ )
122
+ ] }),
123
+ /* @__PURE__ */ t(v, { when: P !== null, children: /* @__PURE__ */ g("div", { className: "absolute inset-0 cursor-crosshair", "data-slot": "graph-canvas-gesture", ...A.handlers, children: [
124
+ r && /* @__PURE__ */ t("svg", { className: "pointer-events-none size-full", children: r.tool === "rect" ? /* @__PURE__ */ t(
125
+ "rect",
126
+ {
127
+ className: "stroke-primary",
128
+ height: Math.abs(r.to[1] - r.from[1]),
129
+ strokeDasharray: "4 3",
130
+ strokeWidth: 1,
131
+ style: { fill: D },
132
+ width: Math.abs(r.to[0] - r.from[0]),
133
+ x: Math.min(r.from[0], r.to[0]),
134
+ y: Math.min(r.from[1], r.to[1])
135
+ }
136
+ ) : r.path.length > 1 && /* @__PURE__ */ t(
137
+ "polygon",
138
+ {
139
+ className: "stroke-primary",
140
+ points: r.path.map(([e, a]) => `${e},${a}`).join(" "),
141
+ strokeWidth: 1,
142
+ style: { fill: D }
143
+ }
144
+ ) }),
145
+ /* @__PURE__ */ t(v, { when: S !== null, children: /* @__PURE__ */ g(
146
+ "span",
147
+ {
148
+ className: "pointer-events-none absolute rounded-sm bg-primary px-1.5 py-0.5 font-medium text-[10px] text-primary-foreground tabular-nums",
149
+ style: ae(r),
150
+ children: [
151
+ S,
152
+ " node",
153
+ S === 1 ? "" : "s"
154
+ ]
155
+ }
156
+ ) })
157
+ ] }) }),
158
+ /* @__PURE__ */ t(v, { when: _ !== void 0, children: /* @__PURE__ */ t(
159
+ "p",
160
+ {
161
+ className: "pointer-events-none absolute inset-0 grid place-items-center text-muted-foreground text-xs",
162
+ "data-slot": "graph-canvas-waiting",
163
+ children: _
164
+ }
165
+ ) }),
166
+ p
167
+ ]
168
+ }
169
+ );
170
+ }
171
+ export {
172
+ Re as GraphCanvas
173
+ };
174
+ //# sourceMappingURL=graph-canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-canvas.js","sources":["../../src/parts/graph-canvas.tsx"],"sourcesContent":["\"use client\";\n\nimport { categoricalCapacity, cn, Show, useThemeTick } from \"@kanzo-tech/ui\";\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { nameOf } from \"../core/categories\";\nimport { denseOf, type VertexId } from \"../core/resident\";\nimport { useGraphContext } from \"../react/graph-root\";\nimport { internalsOf } from \"../react/use-graph\";\nimport { useGraphState } from \"../react/use-graph-state\";\nimport type { Composition } from \"../render/compose\";\nimport { resolveLook } from \"../render/graph-looks\";\nimport { scaleOf } from \"../render/graph-model\";\nimport { cursorChip, useGesture } from \"./gesture\";\nimport { useOverlays } from \"./overlays\";\nimport { ShapeGlyph } from \"./shape-glyph\";\n\nexport interface GraphCanvasProps extends React.ComponentProps<\"div\"> {\n /** The chrome — a toolbar, a legend, an inspector — positioned over the surface. */\n children?: ReactNode;\n}\n\nconst WASH = \"var(--brand-a5)\";\n\ninterface Label {\n vertex: VertexId;\n text: string;\n}\n\n/** The biggest `budget` vertices by the ramp, the focused one first, each with its `title`. */\nfunction labelsOf(composition: Composition, budget: number, focus: VertexId | null): Label[] {\n const titles = composition.titles;\n if (!titles || budget <= 0) return [];\n const order = Array.from({ length: composition.vertices }, (_, i) => i);\n const ramp = composition.sizes;\n if (ramp) order.sort((a, b) => (ramp[b] ?? 0) - (ramp[a] ?? 0));\n const chosen = order.slice(0, budget);\n const focused = focus === null ? undefined : composition.resident.indexOf(focus);\n if (focused !== undefined && !chosen.includes(focused)) chosen.unshift(focused);\n return chosen.flatMap((i) => {\n const vertex = composition.resident.at(i);\n const text = titles[i];\n return vertex === undefined || !text ? [] : [{ vertex, text }];\n });\n}\n\nconst WAITING: Partial<Record<string, string>> = {\n opening: \"Opening the corpus…\",\n reading: \"Reading the corpus…\",\n};\n\n/**\n * **The element, and what the look declares over it** — the grid, the vignette, the labels and the\n * hover card are fields of `Look`, so drawing them is the canvas's; the marquee and lasso gesture is\n * too. Two layers: cosmos.gl fills the surface with a canvas of its own, so chrome parented there\n * would be a sibling inside an element the renderer resizes. The frame is `isolate`, so a host's\n * `z-index` on a child cannot escape into the page.\n *\n * The surface is never gated on the first answer: rendered behind a placeholder it deadlocks — no\n * element, no renderer, no camera, no question. Waiting is an overlay over an empty canvas.\n */\nexport function GraphCanvas({ children, className, slot, ...rest }: GraphCanvasProps) {\n const api = useGraphContext();\n const { attach, renderer } = internalsOf(api);\n const hovered = useGraphState((s) => s.hovered);\n const focus = useGraphState((s) => s.focus);\n const tool = useGraphState((s) => s.tool);\n const options = useGraphState((s) => s.options);\n const domain = useGraphState((s) => s.drawn?.domain ?? s.domain);\n const waiting = useGraphState((s) => (s.drawn === null ? WAITING[s.status] : undefined));\n const look = useMemo(() => resolveLook(options.look), [options.look]);\n const getGraph = useCallback(() => renderer()?.graph ?? null, [renderer]);\n const overlays = useOverlays({ getGraph, getResident: api.getResident });\n const { cardRef, gridRef, hostRef, labelRef, schedule, setHovered, setLabelOrder, track } = overlays;\n const surfaceRef = useRef<HTMLDivElement>(null);\n const [composition, setComposition] = useState<Composition | null>(null);\n\n useEffect(() => {\n const surface = surfaceRef.current;\n if (!surface) return;\n return attach(surface, { onFrame: schedule, onComposed: setComposition });\n }, [attach, schedule]);\n\n const themeTick = useThemeTick();\n useEffect(() => {\n renderer()?.repaint();\n }, [renderer, themeTick]);\n\n const labels = useMemo(\n () => (composition ? labelsOf(composition, look.labels, focus) : []),\n [composition, focus, look.labels],\n );\n useEffect(() => {\n setLabelOrder(labels.map((label) => label.vertex));\n setHovered(hovered);\n track();\n schedule();\n }, [hovered, labels, schedule, setHovered, setLabelOrder, track, look.grid]);\n\n const gesture = useGesture({\n getGraph,\n getResident: api.getResident,\n getSelection: useCallback(() => api.getState().selection, [api]),\n commit: (vertices, source, label) => api.select(vertices ? [...vertices] : null, source, label),\n setTool: api.setTool,\n tool,\n });\n const { active, drag, preview } = gesture;\n\n const capacity = hostRef.current ? categoricalCapacity(hostRef.current) : undefined;\n const scale = useMemo(() => scaleOf(options, capacity), [options, capacity]);\n const card = useMemo(() => {\n if (hovered === null || !composition) return null;\n const index = composition.resident.indexOf(hovered);\n if (index === undefined) return null;\n const rank = composition.categories[index] ?? 0;\n const bound = options.fill !== undefined || options.symbol !== undefined;\n return {\n rank,\n title: composition.titles?.[index] || `#${denseOf(hovered)}`,\n category: bound && rank < domain.length ? nameOf(domain[rank], options.categories) : null,\n };\n }, [composition, domain, hovered, options]);\n\n return (\n <div\n {...rest}\n className={cn(\"relative isolate size-full overflow-hidden bg-background\", className)}\n data-slot={slot ?? \"graph-canvas\"}\n ref={hostRef}\n >\n <div className=\"size-full\" data-slot=\"graph-canvas-surface\" ref={surfaceRef} />\n <Show when={look.grid}>\n <div\n className=\"pointer-events-none absolute inset-0\"\n ref={gridRef}\n style={{ backgroundImage: \"radial-gradient(var(--border) 1px, transparent 1px)\" }}\n />\n </Show>\n <Show when={look.vignette}>\n <div\n className=\"pointer-events-none absolute inset-0\"\n style={{ background: \"radial-gradient(ellipse 75% 65% at 50% 45%, transparent 30%, var(--background) 100%)\" }}\n />\n </Show>\n <div className=\"pointer-events-none absolute inset-0 overflow-hidden\">\n {labels.map((label) => (\n <span\n className=\"absolute top-0 left-0 whitespace-nowrap font-medium text-[10px] text-foreground leading-none opacity-0 transition-opacity [text-shadow:0_0_3px_var(--background),0_0_6px_var(--background)]\"\n key={String(label.vertex)}\n ref={labelRef(label.vertex)}\n >\n {label.text}\n </span>\n ))}\n {card && (\n <div\n className=\"absolute top-0 left-0 flex w-max max-w-60 items-center gap-2 rounded-lg border bg-popover px-2.5 py-2 opacity-0 shadow-lg\"\n data-slot=\"graph-canvas-card\"\n ref={cardRef}\n >\n <ShapeGlyph className=\"size-2.5 shrink-0\" color={scale.color(card.rank)} shape={scale.shape(card.rank)} />\n <span className=\"truncate font-medium text-popover-foreground text-sm leading-none\">{card.title}</span>\n {card.category !== null && <span className=\"text-muted-foreground text-xs\">{card.category}</span>}\n </div>\n )}\n </div>\n <Show when={active !== null}>\n <div className=\"absolute inset-0 cursor-crosshair\" data-slot=\"graph-canvas-gesture\" {...gesture.handlers}>\n {drag && (\n <svg className=\"pointer-events-none size-full\">\n {drag.tool === \"rect\" ? (\n <rect\n className=\"stroke-primary\"\n height={Math.abs(drag.to[1] - drag.from[1])}\n strokeDasharray=\"4 3\"\n strokeWidth={1}\n style={{ fill: WASH }}\n width={Math.abs(drag.to[0] - drag.from[0])}\n x={Math.min(drag.from[0], drag.to[0])}\n y={Math.min(drag.from[1], drag.to[1])}\n />\n ) : (\n drag.path.length > 1 && (\n <polygon\n className=\"stroke-primary\"\n points={drag.path.map(([x, y]) => `${x},${y}`).join(\" \")}\n strokeWidth={1}\n style={{ fill: WASH }}\n />\n )\n )}\n </svg>\n )}\n <Show when={preview !== null}>\n <span\n className=\"pointer-events-none absolute rounded-sm bg-primary px-1.5 py-0.5 font-medium text-[10px] text-primary-foreground tabular-nums\"\n style={cursorChip(drag)}\n >\n {preview} node{preview === 1 ? \"\" : \"s\"}\n </span>\n </Show>\n </div>\n </Show>\n <Show when={waiting !== undefined}>\n <p\n className=\"pointer-events-none absolute inset-0 grid place-items-center text-muted-foreground text-xs\"\n data-slot=\"graph-canvas-waiting\"\n >\n {waiting}\n </p>\n </Show>\n {children}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAqBA;AAQA;AACE;AACA;AACA;AAEA;AACA;AAEA;AAEE;AAEA;AAA6D;AAEjE;AAEA;AAAiD;AACtC;AAEX;AAYO;AACL;;AAMoC;AAAqB;;AAGtB;AAAqB;AAMxD;AACE;AACA;AACA;AAAwE;AAG1E;AACA;;AACE;AAAY;AAGd;AAAe;AACoD;AACjC;AAElC;AACE;AAGA;AAGF;AAA2B;AACzB;AACiB;AAC8C;AAC+B;AACjF;AACb;;AAOA;AACA;AACA;AACA;AAEA;AAAO;AACL;AAC0D;AAC2B;AAAA;AAIzF;AACE;AAAC;AAAA;AACK;AAC+E;AAChE;AACd;AAEL;AAA6E;AAE3E;AAAC;AAAA;AACW;AACL;AACqB;AAAsD;AAEpF;AAEE;AAAC;AAAA;AACW;AACW;AAAuF;AAEhH;AAEG;AACC;AAAC;AAAA;AACW;AAEgB;AAEnB;AAAA;AAHiB;AAK3B;AAEC;AAAC;AAAA;AACW;AACA;AACL;AAEL;AAAwG;AACR;AACN;AAAA;AAAA;AAAA;AAGhG;AAGK;AAGK;AAAC;AAAA;AACW;AACgC;AAC1B;AACH;AACE;AAC0B;AACL;AACA;AAAA;AAIpC;AAAC;AAAA;AACW;AAC6C;AAC1C;AACE;AAAK;AAI5B;AAGA;AAAC;AAAA;AACW;AACY;AAErB;AAAA;AAAQ;AAA2B;AAAA;AAAA;AAExC;AAEJ;AAEE;AAAC;AAAA;AACW;AACA;AAET;AAAA;AAEL;AACC;AAAA;AAAA;AAGP;;;;"}
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from 'react';
2
+ import { VertexDetail } from '../core/detail';
3
+ export interface GraphInspectorProps extends Omit<React.ComponentProps<"div">, "children"> {
4
+ /**
5
+ * More fields for the focused vertex, drawn inside its list after the corpus's own — a
6
+ * `DataListItem` each. A render prop rather than a table of formatters: what a product adds is
7
+ * markup, and the part never learns what any of it means.
8
+ */
9
+ children?: (detail: VertexDetail) => ReactNode;
10
+ }
11
+ /**
12
+ * **The focused vertex, fetched and laid out by the corpus's own types.** A tile carries what the
13
+ * channels project and nothing else, so the rest of the row is read when a reader focuses it — one
14
+ * payload tile, filtered to one `dense_id`, cancelled when the focus moves on. The fields are the
15
+ * type's, in the order the corpus declares them; the address and the position are the canvas's.
16
+ */
17
+ export declare function GraphInspector({ children, className, slot, ...rest }: GraphInspectorProps): import("react").JSX.Element;
18
+ //# sourceMappingURL=graph-inspector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-inspector.d.ts","sourceRoot":"","sources":["../../src/parts/graph-inspector.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrE,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ/D,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACxF;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,SAAS,CAAC;CAChD;AAWD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,mBAAmB,+BAoFzF"}