@carlonicora/nextjs-jsonapi 1.97.1 → 1.98.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 (34) hide show
  1. package/dist/{BlockNoteEditor-7SXXGSJH.js → BlockNoteEditor-3SXAMY6O.js} +9 -9
  2. package/dist/{BlockNoteEditor-7SXXGSJH.js.map → BlockNoteEditor-3SXAMY6O.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-74GNMOST.mjs → BlockNoteEditor-HWQHTLEB.mjs} +2 -2
  4. package/dist/billing/index.js +299 -299
  5. package/dist/billing/index.mjs +1 -1
  6. package/dist/{chunk-XHCHSTAX.js → chunk-S5LH5422.js} +360 -262
  7. package/dist/chunk-S5LH5422.js.map +1 -0
  8. package/dist/{chunk-A4EZFGFA.mjs → chunk-TLTENUI6.mjs} +141 -43
  9. package/dist/chunk-TLTENUI6.mjs.map +1 -0
  10. package/dist/client/index.d.mts +4 -2
  11. package/dist/client/index.d.ts +4 -2
  12. package/dist/client/index.js +2 -2
  13. package/dist/client/index.mjs +1 -1
  14. package/dist/components/index.d.mts +5 -2
  15. package/dist/components/index.d.ts +5 -2
  16. package/dist/components/index.js +2 -2
  17. package/dist/components/index.mjs +1 -1
  18. package/dist/{content.fields-hzZvhlBd.d.mts → content.fields-xH3TGvVk.d.mts} +2 -0
  19. package/dist/{content.fields-hzZvhlBd.d.ts → content.fields-xH3TGvVk.d.ts} +2 -0
  20. package/dist/contexts/index.js +2 -2
  21. package/dist/contexts/index.mjs +1 -1
  22. package/dist/core/index.d.mts +1 -1
  23. package/dist/core/index.d.ts +1 -1
  24. package/dist/index.d.mts +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/package.json +1 -1
  27. package/src/components/editors/BlockNoteEditorSuggestionMenuController.tsx +1 -2
  28. package/src/components/forms/FormDate.tsx +27 -3
  29. package/src/components/forms/FormDateTime.tsx +40 -8
  30. package/src/hooks/useCustomD3Graph.tsx +91 -10
  31. package/src/interfaces/d3.node.interface.ts +2 -0
  32. package/dist/chunk-A4EZFGFA.mjs.map +0 -1
  33. package/dist/chunk-XHCHSTAX.js.map +0 -1
  34. /package/dist/{BlockNoteEditor-74GNMOST.mjs.map → BlockNoteEditor-HWQHTLEB.mjs.map} +0 -0
@@ -14,6 +14,7 @@ export function useCustomD3Graph(
14
14
  links: D3Link[],
15
15
  onNodeClick: (nodeId: string) => void,
16
16
  visibleNodeIds?: Set<string>,
17
+ options?: { directed?: boolean },
17
18
  loadingNodeIds?: Set<string>,
18
19
  containerKey?: string | number,
19
20
  ) {
@@ -154,6 +155,9 @@ export function useCustomD3Graph(
154
155
 
155
156
  const getNodeColor = useCallback(
156
157
  (node: D3Node) => {
158
+ if (node.color) {
159
+ return node.washedOut ? washOutColor(node.color) : node.color;
160
+ }
157
161
  const baseColor = colorScale.get(node.instanceType) || "gray";
158
162
  if (node.washedOut) {
159
163
  return washOutColor(baseColor);
@@ -190,6 +194,26 @@ export function useCustomD3Graph(
190
194
 
191
195
  const graphGroup = svg.append("g").attr("class", "graph-content");
192
196
 
197
+ const nodeRadius = 40;
198
+ const directed = options?.directed === true;
199
+
200
+ if (directed) {
201
+ const defs = svg.append("defs");
202
+ defs
203
+ .append("marker")
204
+ .attr("id", "narr8-arrow")
205
+ .attr("viewBox", "-10 -10 20 20")
206
+ .attr("markerWidth", 14)
207
+ .attr("markerHeight", 14)
208
+ .attr("markerUnits", "userSpaceOnUse")
209
+ .attr("orient", "auto")
210
+ .attr("refX", 0)
211
+ .attr("refY", 0)
212
+ .append("path")
213
+ .attr("d", "M-10,-10 L0,0 L-10,10 z")
214
+ .attr("fill", "#999");
215
+ }
216
+
193
217
  const zoom = d3
194
218
  .zoom<SVGSVGElement, unknown>()
195
219
  .scaleExtent([0.1, 4])
@@ -206,8 +230,6 @@ export function useCustomD3Graph(
206
230
  .on("wheel.zoom", null)
207
231
  .on("dblclick.zoom", null);
208
232
 
209
- const nodeRadius = 40;
210
-
211
233
  const childDistanceFromRoot = Math.min(width, height) * 0.4;
212
234
  const grandchildDistanceFromChild = nodeRadius * 10;
213
235
 
@@ -371,6 +393,23 @@ export function useCustomD3Graph(
371
393
  }
372
394
  });
373
395
 
396
+ // When directed, stop the line at the target node boundary so the
397
+ // arrowhead tip sits just outside the circle rather than inside it.
398
+ const linkX2 = (sx: number, sy: number, tx: number, ty: number): number => {
399
+ if (!directed) return tx;
400
+ const dx = tx - sx;
401
+ const dy = ty - sy;
402
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
403
+ return tx - (dx / dist) * nodeRadius;
404
+ };
405
+ const linkY2 = (sx: number, sy: number, tx: number, ty: number): number => {
406
+ if (!directed) return ty;
407
+ const dx = tx - sx;
408
+ const dy = ty - sy;
409
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
410
+ return ty - (dy / dist) * nodeRadius;
411
+ };
412
+
374
413
  const link = graphGroup
375
414
  .append("g")
376
415
  .attr("stroke", "#999")
@@ -380,9 +419,18 @@ export function useCustomD3Graph(
380
419
  .join("line")
381
420
  .attr("x1", (d) => (d.source as D3Node).x || 0)
382
421
  .attr("y1", (d) => (d.source as D3Node).y || 0)
383
- .attr("x2", (d) => (d.target as D3Node).x || 0)
384
- .attr("y2", (d) => (d.target as D3Node).y || 0)
385
- .attr("stroke-width", 1.5);
422
+ .attr("x2", (d) => {
423
+ const s = d.source as D3Node;
424
+ const t = d.target as D3Node;
425
+ return linkX2(s.x || 0, s.y || 0, t.x || 0, t.y || 0);
426
+ })
427
+ .attr("y2", (d) => {
428
+ const s = d.source as D3Node;
429
+ const t = d.target as D3Node;
430
+ return linkY2(s.x || 0, s.y || 0, t.x || 0, t.y || 0);
431
+ })
432
+ .attr("stroke-width", 1.5)
433
+ .attr("marker-end", directed ? "url(#narr8-arrow)" : null);
386
434
 
387
435
  const node = graphGroup
388
436
  .append("g")
@@ -423,12 +471,22 @@ export function useCustomD3Graph(
423
471
  return source.fy || source.y || 0;
424
472
  })
425
473
  .attr("x2", (l) => {
474
+ const source = l.source as D3Node;
426
475
  const target = l.target as D3Node;
427
- return target.fx || target.x || 0;
476
+ const sx = source.fx || source.x || 0;
477
+ const sy = source.fy || source.y || 0;
478
+ const tx = target.fx || target.x || 0;
479
+ const ty = target.fy || target.y || 0;
480
+ return linkX2(sx, sy, tx, ty);
428
481
  })
429
482
  .attr("y2", (l) => {
483
+ const source = l.source as D3Node;
430
484
  const target = l.target as D3Node;
431
- return target.fy || target.y || 0;
485
+ const sx = source.fx || source.x || 0;
486
+ const sy = source.fy || source.y || 0;
487
+ const tx = target.fx || target.x || 0;
488
+ const ty = target.fy || target.y || 0;
489
+ return linkY2(sx, sy, tx, ty);
432
490
  });
433
491
  })
434
492
  .on("end", function (event, d) {
@@ -489,8 +547,13 @@ export function useCustomD3Graph(
489
547
  .attr("r", nodeRadius)
490
548
  .attr("filter", null);
491
549
 
492
- // Return text to normal size with smooth transform
493
- const normalOffset = nodeRadius + 5;
550
+ // Return text to normal size with smooth transform. Two-line labels
551
+ // (when `d.subtitle` is set) sit one line-gap higher than the single
552
+ // line case — restoring to the bare `nodeRadius + 5` offset would
553
+ // shift the title down by that gap (visibly jumping after the first
554
+ // hover). The 16 here matches the `lineGap` used when the two-line
555
+ // text is first rendered (see the `d.subtitle` branch below).
556
+ const normalOffset = nodeRadius + 5 + (d.subtitle ? 16 : 0);
494
557
  currentNode
495
558
  .select("text")
496
559
  .transition()
@@ -607,6 +670,24 @@ export function useCustomD3Graph(
607
670
  .attr("dy", index === 0 ? `${startY}em` : `${lineHeight}em`)
608
671
  .text(word);
609
672
  });
673
+ } else if (d.subtitle) {
674
+ // Two-line label: name (bigger, bolder) on line 1, subtitle
675
+ // (smaller, dimmed) on line 2. Used by the scene graph to show
676
+ // the HAPPENS_AT location name beneath the scene title. The
677
+ // whole text block is lifted above the circle so the lower line
678
+ // sits at the same baseline the single-line case uses.
679
+ const titleSize = 16;
680
+ const subtitleSize = 11;
681
+ const lineGap = titleSize; // px between baselines
682
+ textElement.attr("dy", -nodeRadius - 5 - lineGap).attr("fill", "currentColor");
683
+ textElement.append("tspan").attr("x", 0).attr("font-size", titleSize).attr("font-weight", 700).text(d.name);
684
+ textElement
685
+ .append("tspan")
686
+ .attr("x", 0)
687
+ .attr("dy", lineGap)
688
+ .attr("font-size", subtitleSize)
689
+ .attr("fill-opacity", 0.7)
690
+ .text(d.subtitle);
610
691
  } else {
611
692
  // Non-root nodes: single line text above the circle. The
612
693
  // optional `bold` flag lets the consumer highlight a focal
@@ -625,7 +706,7 @@ export function useCustomD3Graph(
625
706
  return () => {
626
707
  simulation.stop();
627
708
  };
628
- }, [nodes, links, colorScale, visibleNodeIds, loadingNodeIds, onNodeClick]);
709
+ }, [nodes, links, colorScale, visibleNodeIds, options?.directed, loadingNodeIds, onNodeClick]);
629
710
 
630
711
  const zoomIn = useCallback(() => {
631
712
  if (!svgRef.current || !zoomBehaviorRef.current) return;
@@ -11,4 +11,6 @@ export interface D3Node extends d3.SimulationNodeDatum {
11
11
  visible?: boolean;
12
12
  washedOut?: boolean;
13
13
  bold?: boolean;
14
+ color?: string;
15
+ subtitle?: string;
14
16
  }