@sentropic/design-system-svelte 0.10.2 → 0.10.3

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.
@@ -54,6 +54,27 @@
54
54
  * animates the remainder unless reduced motion is requested.
55
55
  */
56
56
  iterations?: number;
57
+ /**
58
+ * IDs of currently selected nodes. Highlighted visually without
59
+ * re-running the layout. Defaults to [].
60
+ */
61
+ selectedIds?: string[];
62
+ /**
63
+ * ID of the node to focus/centre visually (ring highlight). Does not
64
+ * re-run the layout. Defaults to null.
65
+ */
66
+ focusId?: string | null;
67
+ /**
68
+ * Called when the user clicks (or presses Space/Enter) a node.
69
+ * Fires with the node's stable id.
70
+ */
71
+ onSelect?: (id: string) => void;
72
+ /**
73
+ * Called when the user activates a node (double-click or Enter key while
74
+ * keyboard-focused). Intended to open a detail panel.
75
+ * Fires with the node's stable id.
76
+ */
77
+ onOpenEntity?: (id: string) => void;
57
78
  class?: string;
58
79
  };
59
80
 
@@ -66,6 +87,10 @@
66
87
  nodeRadius = 7,
67
88
  showLabels = true,
68
89
  iterations = 300,
90
+ selectedIds = [],
91
+ focusId = null,
92
+ onSelect,
93
+ onOpenEntity,
69
94
  class: className
70
95
  }: ForceGraphProps = $props();
71
96
 
@@ -262,6 +287,21 @@
262
287
 
263
288
  let hoveredIndex: number | null = $state(null);
264
289
 
290
+ // Fast lookup sets — recomputed only when selectedIds/focusId props change,
291
+ // never when nodes/edges change.
292
+ const selectedSet = $derived(new Set<string>(selectedIds));
293
+
294
+ // Keyboard handler for a node circle: Space/Enter → onSelect, Enter → onOpenEntity.
295
+ function handleNodeKeydown(id: string, e: KeyboardEvent) {
296
+ if (e.key === "Enter" || e.key === " ") {
297
+ e.preventDefault();
298
+ onSelect?.(id);
299
+ }
300
+ if (e.key === "Enter") {
301
+ onOpenEntity?.(id);
302
+ }
303
+ }
304
+
265
305
  const classes = () =>
266
306
  ["st-forceGraph", prefersReducedMotion ? "st-forceGraph--static" : null, className]
267
307
  .filter(Boolean)
@@ -296,18 +336,24 @@
296
336
  <g
297
337
  class="st-forceGraph__node st-forceGraph__node--{p.tone}"
298
338
  class:st-forceGraph__node--dim={hoveredIndex !== null && hoveredIndex !== p.i}
339
+ class:st-forceGraph__node--selected={selectedSet.has(p.node.id)}
340
+ class:st-forceGraph__node--focus={focusId === p.node.id}
299
341
  transform="translate({p.x} {p.y})"
300
342
  >
301
343
  <circle
302
344
  class="st-forceGraph__dot"
303
345
  r={p.r}
304
346
  tabindex="0"
305
- role="img"
347
+ role="button"
306
348
  aria-label="{p.title}{p.node.group !== undefined ? ` — ${p.node.group}` : ''}"
349
+ aria-pressed={selectedSet.has(p.node.id)}
307
350
  onmouseenter={() => (hoveredIndex = p.i)}
308
351
  onmouseleave={() => (hoveredIndex = null)}
309
352
  onfocus={() => (hoveredIndex = p.i)}
310
353
  onblur={() => (hoveredIndex = null)}
354
+ onclick={() => onSelect?.(p.node.id)}
355
+ ondblclick={() => onOpenEntity?.(p.node.id)}
356
+ onkeydown={(e) => handleNodeKeydown(p.node.id, e)}
311
357
  />
312
358
  {#if showLabels}
313
359
  <text class="st-forceGraph__label" x={p.r + 3} y="0" dominant-baseline="middle">{p.title}</text>
@@ -380,6 +426,21 @@
380
426
  outline-offset: 1px;
381
427
  }
382
428
 
429
+ /* Selection highlight: slightly thicker stroke ring, full opacity. */
430
+ .st-forceGraph__node--selected .st-forceGraph__dot {
431
+ fill-opacity: 1;
432
+ stroke: var(--st-semantic-border-interactive, #0f62fe);
433
+ stroke-width: 2.5;
434
+ }
435
+
436
+ /* Focus (keyboard/programmatic focus): stronger ring + slight scale. */
437
+ .st-forceGraph__node--focus .st-forceGraph__dot {
438
+ fill-opacity: 1;
439
+ stroke: var(--st-semantic-border-interactive, #0f62fe);
440
+ stroke-width: 3.5;
441
+ filter: drop-shadow(0 0 4px var(--st-semantic-border-interactive, #0f62fe));
442
+ }
443
+
383
444
  .st-forceGraph__label {
384
445
  fill: var(--st-semantic-text-secondary);
385
446
  font-size: 0.6875rem;
@@ -46,6 +46,27 @@ type ForceGraphProps = {
46
46
  * animates the remainder unless reduced motion is requested.
47
47
  */
48
48
  iterations?: number;
49
+ /**
50
+ * IDs of currently selected nodes. Highlighted visually without
51
+ * re-running the layout. Defaults to [].
52
+ */
53
+ selectedIds?: string[];
54
+ /**
55
+ * ID of the node to focus/centre visually (ring highlight). Does not
56
+ * re-run the layout. Defaults to null.
57
+ */
58
+ focusId?: string | null;
59
+ /**
60
+ * Called when the user clicks (or presses Space/Enter) a node.
61
+ * Fires with the node's stable id.
62
+ */
63
+ onSelect?: (id: string) => void;
64
+ /**
65
+ * Called when the user activates a node (double-click or Enter key while
66
+ * keyboard-focused). Intended to open a detail panel.
67
+ * Fires with the node's stable id.
68
+ */
69
+ onOpenEntity?: (id: string) => void;
49
70
  class?: string;
50
71
  };
51
72
  declare const ForceGraph: import("svelte").Component<ForceGraphProps, {}, "">;
@@ -1 +1 @@
1
- {"version":3,"file":"ForceGraph.svelte.d.ts","sourceRoot":"","sources":["../src/lib/ForceGraph.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,cAAc,GACtB,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,gEAAgE;IAChE,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAoQJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ForceGraph.svelte.d.ts","sourceRoot":"","sources":["../src/lib/ForceGraph.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,cAAc,GACtB,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,gEAAgE;IAChE,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAuRJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentropic/design-system-svelte",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "dependencies": {
29
29
  "@lucide/svelte": "^0.562.0",
30
- "@sentropic/design-system-themes": "0.10.2"
30
+ "@sentropic/design-system-themes": "0.10.3"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "svelte": "^5.53.2"