data-navigator 2.4.1 → 3.2.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.
package/dist/index.cjs CHANGED
@@ -32,6 +32,28 @@ var __copyProps = (to, from, except, desc) => {
32
32
  return to;
33
33
  };
34
34
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
+ var __accessCheck = (obj, member, msg) => {
36
+ if (!member.has(obj))
37
+ throw TypeError("Cannot " + msg);
38
+ };
39
+ var __privateGet = (obj, member, getter) => {
40
+ __accessCheck(obj, member, "read from private field");
41
+ return getter ? getter.call(obj) : member.get(obj);
42
+ };
43
+ var __privateAdd = (obj, member, value) => {
44
+ if (member.has(obj))
45
+ throw TypeError("Cannot add the same private member more than once");
46
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
47
+ };
48
+ var __privateSet = (obj, member, value, setter) => {
49
+ __accessCheck(obj, member, "write to private field");
50
+ setter ? setter.call(obj, value) : member.set(obj, value);
51
+ return value;
52
+ };
53
+ var __privateMethod = (obj, member, method) => {
54
+ __accessCheck(obj, member, "access private method");
55
+ return method;
56
+ };
35
57
  var __async = (__this, __arguments, generator) => {
36
58
  return new Promise((resolve, reject) => {
37
59
  var fulfilled = (value) => {
@@ -56,7 +78,19 @@ var __async = (__this, __arguments, generator) => {
56
78
  // src/index.ts
57
79
  var src_exports = {};
58
80
  __export(src_exports, {
59
- default: () => src_default
81
+ boundingRectPath: () => boundingRectPath,
82
+ convexHullOfCircles: () => convexHullOfCircles,
83
+ convexHullOfRects: () => convexHullOfRects,
84
+ convexHullPath: () => convexHullPath,
85
+ createValidId: () => createValidId,
86
+ default: () => src_default,
87
+ describeNode: () => describeNode,
88
+ expandHull: () => expandHull,
89
+ getGenericCommandsFromNavRules: () => getGenericCommandsFromNavRules,
90
+ grahamScan: () => grahamScan,
91
+ keyLabel: () => keyLabel,
92
+ offsetLinePath: () => offsetLinePath,
93
+ unionOfRectPaths: () => unionOfRectPaths
60
94
  });
61
95
  module.exports = __toCommonJS(src_exports);
62
96
 
@@ -77,12 +111,12 @@ var defaultKeyBindings = {
77
111
  ArrowDown: "down",
78
112
  Period: "forward",
79
113
  Comma: "backward",
80
- Escape: "parent",
81
- Enter: "child"
114
+ Escape: "drill-out",
115
+ Enter: "drill-in"
82
116
  };
83
- var TypicallyUnreservedKeys = ["KeyW", "KeyJ", "LeftBracket", "RightBracket", "Slash", "Backslash"];
117
+ var TypicallyUnreservedKeys = ["KeyW", "KeyJ", "BracketLeft", "BracketRight", "Slash", "Backslash"];
84
118
  var TypicallyUnreservedKeyPairs = [
85
- ["LeftBracket", "RightBracket"],
119
+ ["BracketLeft", "BracketRight"],
86
120
  ["Slash", "Backslash"]
87
121
  ];
88
122
  var GenericFullNavigationRules = {
@@ -102,11 +136,11 @@ var GenericFullNavigationRules = {
102
136
  key: "ArrowDown",
103
137
  direction: "target"
104
138
  },
105
- child: {
139
+ "drill-in": {
106
140
  key: "Enter",
107
141
  direction: "target"
108
142
  },
109
- parent: {
143
+ "drill-out": {
110
144
  key: "Backspace",
111
145
  direction: "source"
112
146
  },
@@ -162,11 +196,11 @@ var GenericLimitedNavigationRules = {
162
196
  key: "ArrowUp",
163
197
  direction: "source"
164
198
  },
165
- child: {
199
+ "drill-in": {
166
200
  key: "Enter",
167
201
  direction: "target"
168
202
  },
169
- parent: {
203
+ "drill-out": {
170
204
  key: "Backspace",
171
205
  direction: "source"
172
206
  },
@@ -209,6 +243,47 @@ var NodeElementDefaults = {
209
243
  spatialProperties: void 0
210
244
  }
211
245
  };
246
+ var KeyLabels = {
247
+ ArrowLeft: "\u2190",
248
+ ArrowRight: "\u2192",
249
+ ArrowUp: "\u2191",
250
+ ArrowDown: "\u2193",
251
+ Enter: "Enter",
252
+ Backspace: "Backspace",
253
+ Escape: "Esc",
254
+ Space: "Space",
255
+ Tab: "Tab",
256
+ BracketLeft: "[",
257
+ BracketRight: "]",
258
+ Backslash: "\\",
259
+ Slash: "/",
260
+ Comma: ",",
261
+ Period: ".",
262
+ Semicolon: ";",
263
+ Quote: "'",
264
+ Minus: "-",
265
+ Equal: "="
266
+ };
267
+ var GenericNavigationRuleCommands = {
268
+ "drill-in": { label: "Enter", description: "Drill in" },
269
+ "drill-out": { label: "Backspace", description: "Drill out" },
270
+ exit: { label: "Esc", description: "Exit" },
271
+ left: { label: "\u2190", description: "Previous data point" },
272
+ right: { label: "\u2192", description: "Next data point" },
273
+ up: { label: "\u2191", description: "Previous data point" },
274
+ down: { label: "\u2193", description: "Next data point" },
275
+ backward: { label: ",", description: "Move backward" },
276
+ forward: { label: ".", description: "Move forward" },
277
+ previous: { label: ";", description: "Previous" },
278
+ next: { label: "'", description: "Next" },
279
+ undo: { label: "Z", description: "Undo" },
280
+ help: { label: "Y", description: "Help" },
281
+ legend: { label: "L", description: "Legend" }
282
+ };
283
+ var commandsTableDefaultColumns = [
284
+ { label: "Command", id: "description" },
285
+ { label: "Key", id: "label" }
286
+ ];
212
287
 
213
288
  // src/utilities.ts
214
289
  var describeNode = (d, descriptionOptions) => {
@@ -223,6 +298,422 @@ var describeNode = (d, descriptionOptions) => {
223
298
  var createValidId = (s) => {
224
299
  return "_" + s.replace(/[^a-zA-Z0-9_-]+/g, "_");
225
300
  };
301
+ var keyLabel = (code) => {
302
+ if (!code)
303
+ return "";
304
+ return KeyLabels[code] || code.replace(/^Key/, "").replace(/^Digit/, "");
305
+ };
306
+ var humanizeRule = (navId) => {
307
+ const text = navId.replace(/[-_]+/g, " ").trim();
308
+ return text.charAt(0).toUpperCase() + text.slice(1);
309
+ };
310
+ function getGenericCommandsFromNavRules(navigationRules, descriptions) {
311
+ if (!navigationRules) {
312
+ return [];
313
+ }
314
+ return Object.keys(navigationRules).map((navId) => {
315
+ const rule = navigationRules[navId];
316
+ const generic = GenericNavigationRuleCommands[navId];
317
+ return {
318
+ label: (rule == null ? void 0 : rule.key) ? keyLabel(rule.key) : (generic == null ? void 0 : generic.label) || "",
319
+ description: (descriptions == null ? void 0 : descriptions[navId]) || (generic == null ? void 0 : generic.description) || humanizeRule(navId),
320
+ command: navId
321
+ };
322
+ });
323
+ }
324
+
325
+ // src/edge-utils.ts
326
+ var makeEdgeCreator = (nodes, edges, useDirectedEdges) => {
327
+ const addEdgeToNode = (nodeId, edgeId) => {
328
+ const node = nodes[nodeId];
329
+ if (!node) {
330
+ console.error(`Building edges. Node ${nodeId} does not exist, so edge ${edgeId} was not added to it.`);
331
+ return;
332
+ }
333
+ if (!node.edges) {
334
+ node.edges = [];
335
+ }
336
+ if (node.edges.indexOf(edgeId) === -1) {
337
+ node.edges.push(edgeId);
338
+ }
339
+ };
340
+ return (source, target, rules, addTo) => {
341
+ if (!source || !target || source === target) {
342
+ return;
343
+ }
344
+ const id = `${source}-${target}`;
345
+ const targetId = !useDirectedEdges ? id : `${target}-${id}`;
346
+ const addToSource = !addTo || addTo === "source";
347
+ const addToTarget = !addTo || addTo === "target";
348
+ const checkEdgeRules = (eId) => {
349
+ if (edges[eId]) {
350
+ (rules || []).forEach((r) => {
351
+ if (edges[eId].navigationRules.indexOf(r) === -1) {
352
+ edges[eId].navigationRules.push(r);
353
+ }
354
+ });
355
+ } else {
356
+ edges[eId] = {
357
+ source,
358
+ target,
359
+ navigationRules: rules ? [...rules] : []
360
+ };
361
+ }
362
+ };
363
+ checkEdgeRules(id);
364
+ if (useDirectedEdges && addToTarget) {
365
+ checkEdgeRules(targetId);
366
+ }
367
+ if (addToSource) {
368
+ addEdgeToNode(source, id);
369
+ }
370
+ if (addToTarget) {
371
+ addEdgeToNode(target, targetId);
372
+ }
373
+ };
374
+ };
375
+ var chain = (createEdge, ids, rules, extents = "terminal") => {
376
+ for (let i = 0; i < ids.length - 1; i++) {
377
+ createEdge(ids[i], ids[i + 1], rules);
378
+ }
379
+ if (extents === "circular" && ids.length > 1) {
380
+ createEdge(ids[ids.length - 1], ids[0], rules);
381
+ }
382
+ };
383
+
384
+ // src/frame.ts
385
+ var prepareFrameOptions = (options) => {
386
+ var _a, _b, _c;
387
+ const f = options.frame;
388
+ const dimCount = ((_b = (_a = options.dimensions) == null ? void 0 : _a.values) == null ? void 0 : _b.length) || 0;
389
+ if (!f || dimCount < 2 || ((_c = options.dimensions.parentOptions) == null ? void 0 : _c.addLevel0)) {
390
+ return options;
391
+ }
392
+ const data = f.data || { id: "data", edges: [], semantics: { label: "Data" } };
393
+ return __spreadProps(__spreadValues({}, options), {
394
+ dimensions: __spreadProps(__spreadValues({}, options.dimensions), {
395
+ parentOptions: __spreadProps(__spreadValues({}, options.dimensions.parentOptions || {}), {
396
+ addLevel0: __spreadProps(__spreadValues({}, data), { edges: data.edges || [] })
397
+ })
398
+ })
399
+ });
400
+ };
401
+ var buildFrame = (options, nodes, edges, topId) => {
402
+ var _a, _b, _c;
403
+ const f = options.frame;
404
+ if (!f)
405
+ return;
406
+ if (!topId || !nodes[topId]) {
407
+ console.error("Building frame. No top data node was found to place under the frame.");
408
+ return;
409
+ }
410
+ const createEdge = makeEdgeCreator(nodes, edges, options.useDirectedEdges);
411
+ const siblingRules = ((_a = f.navigationRules) == null ? void 0 : _a.sibling_sibling) || ["left", "right"];
412
+ const parentRules = ((_b = f.navigationRules) == null ? void 0 : _b.parent_child) || ["drill-out", "drill-in"];
413
+ const extents = ((_c = f.behavior) == null ? void 0 : _c.extents) || "circular";
414
+ const root = f.root;
415
+ nodes[root.id] = __spreadProps(__spreadValues({}, root), { edges: [...root.edges || []], depth: 0, frameRole: "root" });
416
+ const elementIds = (f.elements || []).map((e) => {
417
+ nodes[e.id] = __spreadProps(__spreadValues({}, e), {
418
+ edges: [...e.edges || []],
419
+ depth: 1,
420
+ parentId: root.id,
421
+ frameRole: "element"
422
+ });
423
+ return e.id;
424
+ });
425
+ let dataId = topId;
426
+ if (f.data && f.data.id !== topId) {
427
+ nodes[f.data.id] = __spreadProps(__spreadValues({}, f.data), { edges: [...f.data.edges || []] });
428
+ createEdge(f.data.id, topId, parentRules, "source");
429
+ createEdge(f.data.id, topId, parentRules, "target");
430
+ nodes[topId].parentId = f.data.id;
431
+ dataId = f.data.id;
432
+ }
433
+ const dataNode = nodes[dataId];
434
+ dataNode.frameRole = "data";
435
+ dataNode.depth = 1;
436
+ dataNode.parentId = root.id;
437
+ const children = [...elementIds, dataId];
438
+ createEdge(root.id, children[0], parentRules, "source");
439
+ children.forEach((c) => createEdge(root.id, c, parentRules, "target"));
440
+ chain(createEdge, children, siblingRules, extents);
441
+ return { rootId: root.id, elementIds, dataId, parentRules };
442
+ };
443
+
444
+ // src/spatial-grid.ts
445
+ var buildSpatialGrid = (options, nodes, edges) => {
446
+ var _a, _b, _c;
447
+ const g = options.spatialGrid;
448
+ if (!g)
449
+ return;
450
+ const createEdge = makeEdgeCreator(nodes, edges, options.useDirectedEdges);
451
+ const xRules = ((_a = g.navigationRules) == null ? void 0 : _a.x) || ["left", "right"];
452
+ const yRules = ((_b = g.navigationRules) == null ? void 0 : _b.y) || ["up", "down"];
453
+ const parentRules = ((_c = g.navigationRules) == null ? void 0 : _c.parent_child) || ["drill-out", "drill-in"];
454
+ const extents = g.extents || "terminal";
455
+ const across = g.levelNavigation !== "within";
456
+ const skipEmpty = g.skipEmpty !== false;
457
+ const leafMode = g.leaves || "points";
458
+ const idOf = (d) => d[typeof options.idKey === "function" ? options.idKey(d) : options.idKey];
459
+ const rows = options.data.filter((d) => typeof d[g.xKey] === "number" && typeof d[g.yKey] === "number");
460
+ const ext = (key, given) => {
461
+ if (given)
462
+ return given;
463
+ let min = Infinity;
464
+ let max = -Infinity;
465
+ rows.forEach((d) => {
466
+ min = Math.min(min, d[key]);
467
+ max = Math.max(max, d[key]);
468
+ });
469
+ return [min, max];
470
+ };
471
+ const xExtent = ext(g.xKey, g.xExtent);
472
+ const yExtent = ext(g.yKey, g.yExtent);
473
+ const indexOf = (v, [lo, hi], n) => {
474
+ if (hi === lo)
475
+ return 0;
476
+ return Math.max(0, Math.min(n - 1, Math.floor((v - lo) / (hi - lo) * n)));
477
+ };
478
+ const rootDefaults = { id: "grid", edges: [], semantics: { label: "Grid" } };
479
+ const root = __spreadValues(__spreadValues({}, rootDefaults), g.root || {});
480
+ root.edges = root.edges || [];
481
+ root.depth = 0;
482
+ root.data = __spreadProps(__spreadValues({}, root.data || {}), {
483
+ xKey: g.xKey,
484
+ yKey: g.yKey,
485
+ xExtent,
486
+ yExtent,
487
+ levels: g.levels,
488
+ count: rows.length
489
+ });
490
+ nodes[root.id] = root;
491
+ const cellId = (level, col, row) => g.cellIds ? g.cellIds(level, col, row) : createValidId(`${root.id}_L${level}_${col}_${row}`);
492
+ const cellsByLevel = [];
493
+ g.levels.forEach((n, level) => {
494
+ const cells = {};
495
+ const add = (col, row) => {
496
+ const key = `${col}_${row}`;
497
+ if (cells[key])
498
+ return cells[key];
499
+ const id = cellId(level, col, row);
500
+ const xStep = (xExtent[1] - xExtent[0]) / n;
501
+ const yStep = (yExtent[1] - yExtent[0]) / n;
502
+ let parent = root.id;
503
+ if (level > 0) {
504
+ const pn = g.levels[level - 1];
505
+ const parentCell = cellsByLevel[level - 1][`${Math.floor(col * pn / n)}_${Math.floor(row * pn / n)}`];
506
+ parent = parentCell == null ? void 0 : parentCell.id;
507
+ parentCell == null ? void 0 : parentCell.children.push(id);
508
+ }
509
+ cells[key] = { id, col, row, parent, children: [] };
510
+ nodes[id] = {
511
+ id,
512
+ renderId: id,
513
+ edges: [],
514
+ depth: level + 1,
515
+ parentId: parent,
516
+ data: {
517
+ level,
518
+ col,
519
+ row,
520
+ cellsPerAxis: n,
521
+ xExtent: [xExtent[0] + col * xStep, xExtent[0] + (col + 1) * xStep],
522
+ yExtent: [yExtent[0] + row * yStep, yExtent[0] + (row + 1) * yStep],
523
+ count: 0
524
+ }
525
+ };
526
+ return cells[key];
527
+ };
528
+ if (!skipEmpty) {
529
+ for (let c = 0; c < n; c++)
530
+ for (let r = 0; r < n; r++)
531
+ add(c, r);
532
+ }
533
+ rows.forEach((d) => add(indexOf(d[g.xKey], xExtent, n), indexOf(d[g.yKey], yExtent, n)));
534
+ cellsByLevel.push(cells);
535
+ });
536
+ const finest = cellsByLevel[cellsByLevel.length - 1];
537
+ const fn = g.levels[g.levels.length - 1];
538
+ const leafIds = [];
539
+ const leafParent = {};
540
+ rows.forEach((d) => {
541
+ const id = idOf(d);
542
+ if (!nodes[id])
543
+ return;
544
+ g.levels.forEach((n, level) => {
545
+ const c = cellsByLevel[level][`${indexOf(d[g.xKey], xExtent, n)}_${indexOf(d[g.yKey], yExtent, n)}`];
546
+ nodes[c.id].data.count++;
547
+ });
548
+ const cell = finest[`${indexOf(d[g.xKey], xExtent, fn)}_${indexOf(d[g.yKey], yExtent, fn)}`];
549
+ cell.children.push(id);
550
+ leafParent[id] = cell.id;
551
+ leafIds.push(id);
552
+ nodes[id].parentId = cell.id;
553
+ nodes[id].depth = g.levels.length + 1;
554
+ });
555
+ const topLeftFirst = (a, b) => b.row - a.row || a.col - b.col;
556
+ const rootChildren = Object.values(cellsByLevel[0]).sort(topLeftFirst);
557
+ if (rootChildren.length)
558
+ createEdge(root.id, rootChildren[0].id, parentRules, "source");
559
+ rootChildren.forEach((c) => createEdge(root.id, c.id, parentRules, "target"));
560
+ const pos = (id) => nodes[id].data;
561
+ cellsByLevel.forEach((cells, level) => {
562
+ Object.values(cells).forEach((c) => {
563
+ if (!c.children.length)
564
+ return;
565
+ let first;
566
+ if (level === cellsByLevel.length - 1) {
567
+ first = [...c.children].sort((a, b) => leafOrderX(a, b))[0];
568
+ } else {
569
+ first = [...c.children].sort((a, b) => topLeftFirst(pos(a), pos(b)))[0];
570
+ }
571
+ createEdge(c.id, first, parentRules, "source");
572
+ c.children.forEach((k) => createEdge(c.id, k, parentRules, "target"));
573
+ });
574
+ });
575
+ const linkCells = (ids) => {
576
+ const byRow = {};
577
+ const byCol = {};
578
+ ids.forEach((id) => {
579
+ const p = pos(id);
580
+ (byRow[p.row] = byRow[p.row] || []).push(id);
581
+ (byCol[p.col] = byCol[p.col] || []).push(id);
582
+ });
583
+ Object.values(byRow).forEach(
584
+ (r) => chain(
585
+ createEdge,
586
+ r.sort((a, b) => pos(a).col - pos(b).col),
587
+ xRules,
588
+ extents
589
+ )
590
+ );
591
+ Object.values(byCol).forEach(
592
+ (c) => chain(
593
+ createEdge,
594
+ c.sort((a, b) => pos(b).row - pos(a).row),
595
+ yRules,
596
+ extents
597
+ )
598
+ );
599
+ };
600
+ cellsByLevel.forEach((cells, level) => {
601
+ const list = Object.values(cells);
602
+ if (across || level === 0) {
603
+ linkCells(list.map((c) => c.id));
604
+ } else {
605
+ const groups = {};
606
+ list.forEach((c) => (groups[c.parent] = groups[c.parent] || []).push(c.id));
607
+ Object.values(groups).forEach(linkCells);
608
+ }
609
+ });
610
+ function leafOrderX(a, b) {
611
+ const da = nodes[a].data;
612
+ const db = nodes[b].data;
613
+ return da[g.xKey] - db[g.xKey] || db[g.yKey] - da[g.yKey];
614
+ }
615
+ const leafOrderY = (a, b) => {
616
+ const da = nodes[a].data;
617
+ const db = nodes[b].data;
618
+ return db[g.yKey] - da[g.yKey] || da[g.xKey] - db[g.xKey];
619
+ };
620
+ const linkLeaves = (ids) => {
621
+ if (leafMode === "cells") {
622
+ const byY = {};
623
+ const byX = {};
624
+ ids.forEach((id) => {
625
+ const d = nodes[id].data;
626
+ (byY[d[g.yKey]] = byY[d[g.yKey]] || []).push(id);
627
+ (byX[d[g.xKey]] = byX[d[g.xKey]] || []).push(id);
628
+ });
629
+ Object.values(byY).forEach((r) => chain(createEdge, r.sort(leafOrderX), xRules, extents));
630
+ Object.values(byX).forEach((c) => chain(createEdge, c.sort(leafOrderY), yRules, extents));
631
+ } else {
632
+ chain(createEdge, [...ids].sort(leafOrderX), xRules, extents);
633
+ chain(createEdge, [...ids].sort(leafOrderY), yRules, extents);
634
+ }
635
+ };
636
+ if (across) {
637
+ linkLeaves(leafIds);
638
+ } else {
639
+ Object.values(finest).forEach((c) => linkLeaves(c.children));
640
+ }
641
+ return {
642
+ rootId: root.id,
643
+ levels: g.levels,
644
+ cellsByLevel: cellsByLevel.map((cells) => Object.values(cells).map((c) => c.id)),
645
+ leafIds,
646
+ parentRules
647
+ };
648
+ };
649
+
650
+ // src/hierarchy.ts
651
+ var buildHierarchy = (options, nodes, edges) => {
652
+ var _a, _b;
653
+ const h = options.hierarchy;
654
+ if (!h)
655
+ return;
656
+ const createEdge = makeEdgeCreator(nodes, edges, options.useDirectedEdges);
657
+ const siblingRules = ((_a = h.navigationRules) == null ? void 0 : _a.sibling_sibling) || ["left", "right"];
658
+ const parentRules = ((_b = h.navigationRules) == null ? void 0 : _b.parent_child) || ["drill-out", "drill-in"];
659
+ const extents = h.extents || "circular";
660
+ const idOf = (d) => d[typeof options.idKey === "function" ? options.idKey(d) : options.idKey];
661
+ const children = {};
662
+ let rootId;
663
+ options.data.forEach((d) => {
664
+ const id = idOf(d);
665
+ const parent = d[h.parentKey];
666
+ if (parent === void 0 || parent === null || parent === "") {
667
+ if (rootId) {
668
+ console.error(
669
+ `Building hierarchy. More than one root was found: ${rootId} and ${id}. Using ${rootId}.`
670
+ );
671
+ return;
672
+ }
673
+ rootId = id;
674
+ } else {
675
+ if (!children[parent])
676
+ children[parent] = [];
677
+ children[parent].push(d);
678
+ }
679
+ });
680
+ if (!rootId) {
681
+ console.error("Building hierarchy. No root row was found. One row must have an empty parent.");
682
+ return;
683
+ }
684
+ const byDepth = [];
685
+ const visit = (id, parentId, depth) => {
686
+ const node = nodes[id];
687
+ if (!node) {
688
+ console.error(`Building hierarchy. Row ${id} has no node. Check idKey.`);
689
+ return;
690
+ }
691
+ node.depth = depth;
692
+ if (parentId)
693
+ node.parentId = parentId;
694
+ if (!byDepth[depth])
695
+ byDepth[depth] = [];
696
+ byDepth[depth].push(id);
697
+ let kids = children[id] || [];
698
+ if (h.sortFunction)
699
+ kids = [...kids].sort((a, b) => h.sortFunction(a, b));
700
+ const kidIds = kids.map(idOf);
701
+ node.childCount = kidIds.length;
702
+ if (kidIds.length) {
703
+ createEdge(id, kidIds[0], parentRules, "source");
704
+ kidIds.forEach((k) => createEdge(id, k, parentRules, "target"));
705
+ if (h.levelNavigation !== "across") {
706
+ chain(createEdge, kidIds, siblingRules, extents);
707
+ }
708
+ }
709
+ kidIds.forEach((k) => visit(k, id, depth + 1));
710
+ };
711
+ visit(rootId, void 0, 0);
712
+ if (h.levelNavigation === "across") {
713
+ byDepth.forEach((ids) => chain(createEdge, ids, siblingRules, extents));
714
+ }
715
+ return { rootId, depthCount: byDepth.length, parentRules };
716
+ };
226
717
 
227
718
  // src/structure.ts
228
719
  var structure_default = (options) => {
@@ -299,7 +790,7 @@ var buildNodeStructureFromVegaLite = (options) => {
299
790
  edges[firstChildEdge] = {
300
791
  source: node.id,
301
792
  target: firstChildId,
302
- navigationRules: ["parent", "child"]
793
+ navigationRules: ["drill-out", "drill-in"]
303
794
  };
304
795
  }
305
796
  }
@@ -312,7 +803,7 @@ var buildNodeStructureFromVegaLite = (options) => {
312
803
  edges[parentEdge] = {
313
804
  source: parentId,
314
805
  target: node.id,
315
- navigationRules: ["parent", "child"]
806
+ navigationRules: ["drill-out", "drill-in"]
316
807
  };
317
808
  }
318
809
  }
@@ -513,7 +1004,7 @@ var scaffoldDimensions = (options, nodes) => {
513
1004
  },
514
1005
  navigationRules: dim.navigationRules || {
515
1006
  sibling_sibling: rules.length ? [...rules.shift()] : ["previous_" + dim.dimensionKey, "next_" + dim.dimensionKey],
516
- parent_child: ["parent_" + dim.dimensionKey, "child"]
1007
+ parent_child: ["drill-out_" + dim.dimensionKey, "drill-in"]
517
1008
  }
518
1009
  };
519
1010
  nodes[id2] = {
@@ -700,9 +1191,9 @@ var scaffoldDimensions = (options, nodes) => {
700
1191
  }
701
1192
  return dimensions;
702
1193
  };
703
- var buildEdges = (options, nodes, dimensions) => {
1194
+ var buildEdges = (options, nodes, dimensions, existingEdges) => {
704
1195
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
705
- let edges = {};
1196
+ let edges = existingEdges || {};
706
1197
  const addEdgeToNode = (nodeId, edgeId) => {
707
1198
  if (nodes[nodeId].edges.indexOf(edgeId) === -1) {
708
1199
  nodes[nodeId].edges.push(edgeId);
@@ -743,7 +1234,7 @@ var buildEdges = (options, nodes, dimensions) => {
743
1234
  let po = ((_d = options.dimensions) == null ? void 0 : _d.parentOptions) || {};
744
1235
  let extents = ((_f = (_e = po.level1Options) == null ? void 0 : _e.behavior) == null ? void 0 : _f.extents) || "terminal";
745
1236
  let level0 = po.addLevel0;
746
- let parentRules = level0 ? ((_h = (_g = po.level1Options) == null ? void 0 : _g.navigationRules) == null ? void 0 : _h.parent_child) || ["parent", "child"] : [];
1237
+ let parentRules = level0 ? ((_h = (_g = po.level1Options) == null ? void 0 : _g.navigationRules) == null ? void 0 : _h.parent_child) || ["drill-out", "drill-in"] : [];
747
1238
  let siblingRules = ((_j = (_i = po.level1Options) == null ? void 0 : _i.navigationRules) == null ? void 0 : _j.sibling_sibling) || ["left", "right"];
748
1239
  let firstLevel1Node = typeof order[0] === "string" ? hasOrder ? nodes[order[0]] : nodes[dimensions[order[0]].nodeId] : order[0];
749
1240
  if (level0) {
@@ -776,7 +1267,7 @@ var buildEdges = (options, nodes, dimensions) => {
776
1267
  createEdge(level1Node.id, nextLevel1Node.id, siblingRules);
777
1268
  }
778
1269
  if (!l && extents === "bridgedCustom") {
779
- createEdge(po.level1Options.behavior.customBridgePost, level1Node.id, siblingRules);
1270
+ createEdge(po.level1Options.behavior.customBridgePrevious, level1Node.id, siblingRules);
780
1271
  }
781
1272
  l++;
782
1273
  });
@@ -963,7 +1454,7 @@ var buildEdges = (options, nodes, dimensions) => {
963
1454
  return edges;
964
1455
  };
965
1456
  var buildRules = (options, edges, dimensions) => {
966
- var _a, _b, _c, _d;
1457
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
967
1458
  let rules = options.navigationRules;
968
1459
  if (!rules) {
969
1460
  let dimKeys = Object.keys(dimensions || {});
@@ -1055,8 +1546,8 @@ var buildRules = (options, edges, dimensions) => {
1055
1546
  if (dimKeys.length) {
1056
1547
  if ((_b = (_a = options.dimensions) == null ? void 0 : _a.parentOptions) == null ? void 0 : _b.addLevel0) {
1057
1548
  let rules2 = ((_d = (_c = options.dimensions.parentOptions.level1Options) == null ? void 0 : _c.navigationRules) == null ? void 0 : _d.parent_child) || [
1058
- "parent",
1059
- "child"
1549
+ "drill-out",
1550
+ "drill-in"
1060
1551
  ];
1061
1552
  checkKeys(rules2[0], rules2[1]);
1062
1553
  }
@@ -1067,6 +1558,20 @@ var buildRules = (options, edges, dimensions) => {
1067
1558
  checkKeys(ss[0], ss[1]);
1068
1559
  });
1069
1560
  }
1561
+ const extraPairs = [
1562
+ (_f = (_e = options.frame) == null ? void 0 : _e.navigationRules) == null ? void 0 : _f.parent_child,
1563
+ (_h = (_g = options.frame) == null ? void 0 : _g.navigationRules) == null ? void 0 : _h.sibling_sibling,
1564
+ (_j = (_i = options.spatialGrid) == null ? void 0 : _i.navigationRules) == null ? void 0 : _j.x,
1565
+ (_l = (_k = options.spatialGrid) == null ? void 0 : _k.navigationRules) == null ? void 0 : _l.y,
1566
+ (_n = (_m = options.spatialGrid) == null ? void 0 : _m.navigationRules) == null ? void 0 : _n.parent_child,
1567
+ (_p = (_o = options.hierarchy) == null ? void 0 : _o.navigationRules) == null ? void 0 : _p.parent_child,
1568
+ (_r = (_q = options.hierarchy) == null ? void 0 : _q.navigationRules) == null ? void 0 : _r.sibling_sibling
1569
+ ];
1570
+ extraPairs.forEach((pair) => {
1571
+ if (pair && !used[pair[0]] && !used[pair[1]]) {
1572
+ checkKeys(pair[0], pair[1]);
1573
+ }
1574
+ });
1070
1575
  Object.keys(edges).forEach((e) => {
1071
1576
  edges[e].navigationRules.forEach((rule) => {
1072
1577
  if (!used[rule]) {
@@ -1101,20 +1606,38 @@ var buildRules = (options, edges, dimensions) => {
1101
1606
  }
1102
1607
  return rules;
1103
1608
  };
1104
- var buildStructure = (options) => {
1105
- if (options.addIds) {
1106
- addSimpleDataIDs(options);
1609
+ var buildStructure = (inputOptions) => {
1610
+ var _a, _b, _c;
1611
+ if (inputOptions.addIds) {
1612
+ addSimpleDataIDs(inputOptions);
1107
1613
  }
1614
+ const options = prepareFrameOptions(inputOptions);
1108
1615
  let nodes = buildNodes(options);
1109
1616
  let dimensions = scaffoldDimensions(options, nodes);
1110
- let edges = buildEdges(options, nodes, dimensions);
1617
+ let edges = {};
1618
+ const spatialGrid = buildSpatialGrid(options, nodes, edges);
1619
+ const hierarchy = buildHierarchy(options, nodes, edges);
1620
+ let frame;
1621
+ if (options.frame) {
1622
+ const dimKeys = Object.keys(dimensions || {});
1623
+ const topId = (spatialGrid == null ? void 0 : spatialGrid.rootId) || (hierarchy == null ? void 0 : hierarchy.rootId) || ((_c = (_b = (_a = options.dimensions) == null ? void 0 : _a.parentOptions) == null ? void 0 : _b.addLevel0) == null ? void 0 : _c.id) || (dimKeys.length === 1 ? dimensions[dimKeys[0]].nodeId : void 0);
1624
+ frame = buildFrame(options, nodes, edges, topId);
1625
+ }
1626
+ edges = buildEdges(options, nodes, dimensions, edges);
1111
1627
  let navigationRules = buildRules(options, edges, dimensions);
1112
- return {
1628
+ const structure = {
1113
1629
  nodes,
1114
1630
  edges,
1115
1631
  dimensions,
1116
1632
  navigationRules
1117
1633
  };
1634
+ if (frame)
1635
+ structure.frame = frame;
1636
+ if (spatialGrid)
1637
+ structure.spatialGrid = spatialGrid;
1638
+ if (hierarchy)
1639
+ structure.hierarchy = hierarchy;
1640
+ return structure;
1118
1641
  };
1119
1642
 
1120
1643
  // src/input.ts
@@ -1212,6 +1735,124 @@ var input_default = (options) => {
1212
1735
  return inputHandler;
1213
1736
  };
1214
1737
 
1738
+ // src/commands-table.ts
1739
+ var _commands, _columns, _kbdColumn, _connected, _render, render_fn;
1740
+ var CommandsTable = class extends HTMLElement {
1741
+ constructor() {
1742
+ super(...arguments);
1743
+ __privateAdd(this, _render);
1744
+ __privateAdd(this, _commands, []);
1745
+ __privateAdd(this, _columns, commandsTableDefaultColumns);
1746
+ __privateAdd(this, _kbdColumn, "label");
1747
+ __privateAdd(this, _connected, false);
1748
+ }
1749
+ static get observedAttributes() {
1750
+ return ["title"];
1751
+ }
1752
+ set commands(value) {
1753
+ __privateSet(this, _commands, value);
1754
+ if (!__privateGet(this, _connected))
1755
+ return;
1756
+ __privateMethod(this, _render, render_fn).call(this);
1757
+ }
1758
+ get commands() {
1759
+ return __privateGet(this, _commands);
1760
+ }
1761
+ set columns(value) {
1762
+ __privateSet(this, _columns, value);
1763
+ if (!__privateGet(this, _connected))
1764
+ return;
1765
+ __privateMethod(this, _render, render_fn).call(this);
1766
+ }
1767
+ get columns() {
1768
+ return __privateGet(this, _columns);
1769
+ }
1770
+ /** Column id whose cells are wrapped in <kbd>. Defaults to 'label'. Set to null to disable. */
1771
+ set kbdColumn(value) {
1772
+ __privateSet(this, _kbdColumn, value);
1773
+ if (!__privateGet(this, _connected))
1774
+ return;
1775
+ __privateMethod(this, _render, render_fn).call(this);
1776
+ }
1777
+ get kbdColumn() {
1778
+ return __privateGet(this, _kbdColumn);
1779
+ }
1780
+ attributeChangedCallback() {
1781
+ if (!__privateGet(this, _connected))
1782
+ return;
1783
+ __privateMethod(this, _render, render_fn).call(this);
1784
+ }
1785
+ connectedCallback() {
1786
+ __privateSet(this, _connected, true);
1787
+ __privateMethod(this, _render, render_fn).call(this);
1788
+ }
1789
+ disconnectedCallback() {
1790
+ __privateSet(this, _connected, false);
1791
+ }
1792
+ };
1793
+ _commands = new WeakMap();
1794
+ _columns = new WeakMap();
1795
+ _kbdColumn = new WeakMap();
1796
+ _connected = new WeakMap();
1797
+ _render = new WeakSet();
1798
+ render_fn = function() {
1799
+ this.replaceChildren();
1800
+ const headerCells = [];
1801
+ for (const column of __privateGet(this, _columns)) {
1802
+ const headerCell = document.createElement("th");
1803
+ headerCell.classList.add("dn-commands-table-th");
1804
+ headerCell.textContent = column.label;
1805
+ headerCells.push(headerCell);
1806
+ }
1807
+ const headerRow = document.createElement("tr");
1808
+ headerRow.classList.add("dn-commands-table-thead-tr");
1809
+ for (const headerCell of headerCells) {
1810
+ headerRow.appendChild(headerCell);
1811
+ }
1812
+ const thead = document.createElement("thead");
1813
+ thead.classList.add("dn-commands-table-thead");
1814
+ thead.appendChild(headerRow);
1815
+ const tbody = document.createElement("tbody");
1816
+ tbody.classList.add("dn-commands-table-tbody");
1817
+ for (const command of __privateGet(this, _commands)) {
1818
+ const rowCells = [];
1819
+ for (const column of __privateGet(this, _columns)) {
1820
+ const cellValue = command[column.id];
1821
+ const rowCell = document.createElement("td");
1822
+ rowCell.classList.add("dn-commands-table-td");
1823
+ if (__privateGet(this, _kbdColumn) !== null && column.id === __privateGet(this, _kbdColumn) && cellValue) {
1824
+ const kbd = document.createElement("kbd");
1825
+ kbd.classList.add("dn-commands-table-td-kbd");
1826
+ kbd.textContent = cellValue;
1827
+ rowCell.append(kbd);
1828
+ } else {
1829
+ rowCell.textContent = cellValue;
1830
+ }
1831
+ rowCells.push(rowCell);
1832
+ }
1833
+ const row = document.createElement("tr");
1834
+ row.classList.add("dn-commands-table-tbody-tr");
1835
+ for (const rowCell of rowCells) {
1836
+ row.appendChild(rowCell);
1837
+ }
1838
+ tbody.appendChild(row);
1839
+ }
1840
+ const table = document.createElement("table");
1841
+ table.classList.add("dn-commands-table");
1842
+ const title = this.getAttribute("title");
1843
+ if (title) {
1844
+ const caption = document.createElement("caption");
1845
+ caption.classList.add("dn-commands-table-caption");
1846
+ caption.textContent = title;
1847
+ table.appendChild(caption);
1848
+ } else {
1849
+ table.setAttribute("aria-label", "Commands table");
1850
+ }
1851
+ table.appendChild(thead);
1852
+ table.appendChild(tbody);
1853
+ this.appendChild(table);
1854
+ };
1855
+
1215
1856
  // src/rendering.ts
1216
1857
  var rendering_default = (options) => {
1217
1858
  const setActiveDescendant = (e) => {
@@ -1237,7 +1878,7 @@ var rendering_default = (options) => {
1237
1878
  defaults.existingElement = options.defaults.existingElement ? __spreadValues(__spreadValues({}, defaults.existingElement), options.defaults.existingElement) : defaults.existingElement;
1238
1879
  }
1239
1880
  renderer.initialize = () => {
1240
- var _a;
1881
+ var _a, _b;
1241
1882
  if (initialized) {
1242
1883
  console.error(
1243
1884
  `The renderer wrapper has already been initialized successfully, RenderingOptions.suffixId is: ${options.suffixId}. No further action was taken.`
@@ -1268,6 +1909,9 @@ var rendering_default = (options) => {
1268
1909
  if (options.root && options.root.height) {
1269
1910
  renderer.wrapper.style.height = options.root.height;
1270
1911
  }
1912
+ if ((_a = options.commandsElement) == null ? void 0 : _a.include) {
1913
+ renderer.initializeCommands(options.commandsElement);
1914
+ }
1271
1915
  if (options.entryButton && options.entryButton.include) {
1272
1916
  renderer.entryButton = document.createElement("button");
1273
1917
  renderer.entryButton.id = "dn-entry-button-" + options.suffixId;
@@ -1282,7 +1926,7 @@ var rendering_default = (options) => {
1282
1926
  renderer.wrapper.appendChild(renderer.entryButton);
1283
1927
  }
1284
1928
  renderer.root.appendChild(renderer.wrapper);
1285
- if ((_a = options.exitElement) == null ? void 0 : _a.include) {
1929
+ if ((_b = options.exitElement) == null ? void 0 : _b.include) {
1286
1930
  renderer.exitElement = document.createElement("div");
1287
1931
  renderer.exitElement.id = "dn-exit-" + options.suffixId;
1288
1932
  renderer.exitElement.classList.add("dn-exit-position");
@@ -1292,17 +1936,17 @@ var rendering_default = (options) => {
1292
1936
  renderer.exitElement.setAttribute("tabindex", "-1");
1293
1937
  renderer.exitElement.style.display = "none";
1294
1938
  renderer.exitElement.addEventListener("focus", (e) => {
1295
- var _a2, _b;
1939
+ var _a2, _b2;
1296
1940
  renderer.exitElement.style.display = "block";
1297
1941
  renderer.clearStructure();
1298
- if ((_b = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b.focus) {
1942
+ if ((_b2 = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b2.focus) {
1299
1943
  options.exitElement.callbacks.focus(e);
1300
1944
  }
1301
1945
  });
1302
1946
  renderer.exitElement.addEventListener("blur", (e) => {
1303
- var _a2, _b;
1947
+ var _a2, _b2;
1304
1948
  renderer.exitElement.style.display = "none";
1305
- if ((_b = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b.blur) {
1949
+ if ((_b2 = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b2.blur) {
1306
1950
  options.exitElement.callbacks.blur(e);
1307
1951
  }
1308
1952
  });
@@ -1359,15 +2003,15 @@ var rendering_default = (options) => {
1359
2003
  const attributes = resolveProp("semantics", "attributes");
1360
2004
  if (typeof attributes === "object") {
1361
2005
  Object.keys(attributes).forEach((attribute) => {
1362
- node.setAttribute(attribute, attributes[attribute]);
2006
+ nodeText.setAttribute(attribute, attributes[attribute]);
1363
2007
  });
1364
2008
  }
1365
2009
  nodeText.setAttribute("role", resolveProp("semantics", "role"));
1366
2010
  nodeText.classList.add("dn-node-text");
2011
+ const label = resolveProp("semantics", "label");
1367
2012
  if (d.showText) {
1368
- nodeText.innerText = d.semantics.label;
2013
+ nodeText.innerText = label;
1369
2014
  }
1370
- const label = resolveProp("semantics", "label");
1371
2015
  if (!label) {
1372
2016
  console.error(
1373
2017
  "Accessibility error: a label must be supplied to every rendered element using semantics.label."
@@ -1415,6 +2059,34 @@ var rendering_default = (options) => {
1415
2059
  }
1416
2060
  });
1417
2061
  };
2062
+ renderer.initializeCommands = (commandOptions) => {
2063
+ const root = document.getElementById(commandOptions == null ? void 0 : commandOptions.rootId);
2064
+ if (!root) {
2065
+ console.error("Commands root element not found in document.");
2066
+ return;
2067
+ }
2068
+ const optionsCommands = commandOptions.commands;
2069
+ const genericCommandsFromRules = getGenericCommandsFromNavRules(
2070
+ commandOptions.navigationRules,
2071
+ commandOptions.descriptions
2072
+ );
2073
+ const commands = optionsCommands ? typeof optionsCommands === "function" ? optionsCommands(genericCommandsFromRules) : optionsCommands : genericCommandsFromRules;
2074
+ if (!customElements.get("dn-commands-table")) {
2075
+ customElements.define("dn-commands-table", CommandsTable);
2076
+ }
2077
+ const commandsElement = document.createElement("dn-commands-table");
2078
+ if (commandOptions == null ? void 0 : commandOptions.title) {
2079
+ commandsElement.setAttribute("title", commandOptions.title);
2080
+ }
2081
+ commandsElement.commands = commands;
2082
+ if (commandOptions.columns) {
2083
+ commandsElement.columns = commandOptions.columns;
2084
+ }
2085
+ root.appendChild(commandsElement);
2086
+ return commandsElement;
2087
+ };
2088
+ renderer.getGenericCommandsFromNavRules = getGenericCommandsFromNavRules;
2089
+ renderer.CommandsTable = CommandsTable;
1418
2090
  return renderer;
1419
2091
  };
1420
2092
 
@@ -1589,7 +2261,7 @@ var searchNodes = (query, structure, describeFn, limit = 10) => {
1589
2261
  return results;
1590
2262
  };
1591
2263
  var text_chat_default = (options) => {
1592
- var _a;
2264
+ var _a, _b, _c, _d;
1593
2265
  const {
1594
2266
  structure,
1595
2267
  container,
@@ -1607,7 +2279,9 @@ var text_chat_default = (options) => {
1607
2279
  if (!rootEl) {
1608
2280
  throw new Error(`textChat: container "${container}" not found`);
1609
2281
  }
1610
- const resolvedEntryPoint = entryPoint || (structure.dimensions ? (_a = structure.dimensions[Object.keys(structure.dimensions)[0]]) == null ? void 0 : _a.nodeId : Object.keys(structure.nodes)[0]);
2282
+ const level0Id = Object.keys(structure.nodes).find((id) => structure.nodes[id].dimensionLevel === 0);
2283
+ const firstDimensionId = structure.dimensions ? (_a = structure.dimensions[Object.keys(structure.dimensions)[0]]) == null ? void 0 : _a.nodeId : void 0;
2284
+ const resolvedEntryPoint = entryPoint || ((_b = structure.frame) == null ? void 0 : _b.rootId) || level0Id || ((_c = structure.spatialGrid) == null ? void 0 : _c.rootId) || ((_d = structure.hierarchy) == null ? void 0 : _d.rootId) || firstDimensionId || Object.keys(structure.nodes)[0];
1611
2285
  const inputHandler = input_default({
1612
2286
  structure,
1613
2287
  navigationRules: structure.navigationRules || {},
@@ -1971,5 +2645,203 @@ var text_chat_default = (options) => {
1971
2645
  };
1972
2646
  };
1973
2647
 
2648
+ // src/geometry.ts
2649
+ function grahamScan(points) {
2650
+ if (points.length < 3)
2651
+ return [...points];
2652
+ let pivot = points[0];
2653
+ for (const p of points) {
2654
+ if (p.y < pivot.y || p.y === pivot.y && p.x < pivot.x)
2655
+ pivot = p;
2656
+ }
2657
+ const sorted = [...points].sort((a, b) => {
2658
+ const ax = a.x - pivot.x, ay = a.y - pivot.y;
2659
+ const bx = b.x - pivot.x, by = b.y - pivot.y;
2660
+ const cross2 = ax * by - ay * bx;
2661
+ if (cross2 !== 0)
2662
+ return -cross2;
2663
+ return ax * ax + ay * ay - (bx * bx + by * by);
2664
+ });
2665
+ const hull = [];
2666
+ for (const p of sorted) {
2667
+ while (hull.length >= 2 && cross(hull[hull.length - 2], hull[hull.length - 1], p) <= 0) {
2668
+ hull.pop();
2669
+ }
2670
+ hull.push(p);
2671
+ }
2672
+ return hull;
2673
+ }
2674
+ function cross(O, A, B) {
2675
+ return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
2676
+ }
2677
+ function convexHullPath(points) {
2678
+ if (points.length === 0)
2679
+ return "";
2680
+ if (points.length === 1) {
2681
+ const p = points[0];
2682
+ return `M${p.x},${p.y}Z`;
2683
+ }
2684
+ const hull = grahamScan(points);
2685
+ if (hull.length === 0)
2686
+ return "";
2687
+ const [first, ...rest] = hull;
2688
+ return `M${fmt(first.x)},${fmt(first.y)}` + rest.map((p) => `L${fmt(p.x)},${fmt(p.y)}`).join("") + "Z";
2689
+ }
2690
+ function expandHull(hullPoints, padPx) {
2691
+ if (padPx === 0 || hullPoints.length === 0)
2692
+ return hullPoints;
2693
+ const cx = hullPoints.reduce((s, p) => s + p.x, 0) / hullPoints.length;
2694
+ const cy = hullPoints.reduce((s, p) => s + p.y, 0) / hullPoints.length;
2695
+ return hullPoints.map((p) => {
2696
+ const dx = p.x - cx;
2697
+ const dy = p.y - cy;
2698
+ const dist = Math.hypot(dx, dy);
2699
+ if (dist === 0)
2700
+ return p;
2701
+ return { x: p.x + dx / dist * padPx, y: p.y + dy / dist * padPx };
2702
+ });
2703
+ }
2704
+ function rectCorners(r) {
2705
+ return [
2706
+ { x: r.x, y: r.y },
2707
+ { x: r.x + r.width, y: r.y },
2708
+ { x: r.x + r.width, y: r.y + r.height },
2709
+ { x: r.x, y: r.y + r.height }
2710
+ ];
2711
+ }
2712
+ function padRect(r, pad) {
2713
+ return { x: r.x - pad, y: r.y - pad, width: r.width + pad * 2, height: r.height + pad * 2 };
2714
+ }
2715
+ function convexHullOfRects(rects, padPx = 0) {
2716
+ if (rects.length === 0)
2717
+ return "";
2718
+ const corners = rects.flatMap(rectCorners);
2719
+ const hull = grahamScan(corners);
2720
+ const expanded = padPx > 0 ? expandHull(hull, padPx) : hull;
2721
+ return hullToPath(expanded);
2722
+ }
2723
+ function unionOfRectPaths(rects, padPx = 0) {
2724
+ if (rects.length === 0)
2725
+ return "";
2726
+ return rects.map((r) => {
2727
+ const pr = padPx > 0 ? padRect(r, padPx) : r;
2728
+ const { x, y, width: w, height: h } = pr;
2729
+ return `M${fmt(x)},${fmt(y)}L${fmt(x + w)},${fmt(y)}L${fmt(x + w)},${fmt(y + h)}L${fmt(x)},${fmt(y + h)}Z`;
2730
+ }).join("");
2731
+ }
2732
+ function boundingRectPath(rects, padPx = 0) {
2733
+ if (rects.length === 0)
2734
+ return "";
2735
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
2736
+ for (const r of rects) {
2737
+ minX = Math.min(minX, r.x);
2738
+ minY = Math.min(minY, r.y);
2739
+ maxX = Math.max(maxX, r.x + r.width);
2740
+ maxY = Math.max(maxY, r.y + r.height);
2741
+ }
2742
+ minX -= padPx;
2743
+ minY -= padPx;
2744
+ maxX += padPx;
2745
+ maxY += padPx;
2746
+ return `M${fmt(minX)},${fmt(minY)}L${fmt(maxX)},${fmt(minY)}L${fmt(maxX)},${fmt(maxY)}L${fmt(minX)},${fmt(maxY)}Z`;
2747
+ }
2748
+ function convexHullOfCircles(circles, padPx = 0) {
2749
+ if (circles.length === 0)
2750
+ return "";
2751
+ const SAMPLES = 16;
2752
+ const points = [];
2753
+ for (const { x, y, r } of circles) {
2754
+ const effectiveR = r + padPx;
2755
+ for (let i = 0; i < SAMPLES; i++) {
2756
+ const angle = 2 * Math.PI * i / SAMPLES;
2757
+ points.push({
2758
+ x: x + effectiveR * Math.cos(angle),
2759
+ y: y + effectiveR * Math.sin(angle)
2760
+ });
2761
+ }
2762
+ }
2763
+ return convexHullPath(points);
2764
+ }
2765
+ function offsetLinePath(points, offsetPx) {
2766
+ if (points.length < 2) {
2767
+ if (points.length === 1) {
2768
+ const p = points[0];
2769
+ return convexHullOfCircles([{ x: p.x, y: p.y, r: offsetPx }]);
2770
+ }
2771
+ return "";
2772
+ }
2773
+ const normals = [];
2774
+ for (let i = 0; i < points.length - 1; i++) {
2775
+ const dx = points[i + 1].x - points[i].x;
2776
+ const dy = points[i + 1].y - points[i].y;
2777
+ const len = Math.hypot(dx, dy);
2778
+ normals.push(len === 0 ? { x: 0, y: -1 } : { x: -dy / len, y: dx / len });
2779
+ }
2780
+ const vertexNormals = [];
2781
+ for (let i = 0; i < points.length; i++) {
2782
+ if (i === 0) {
2783
+ vertexNormals.push(normals[0]);
2784
+ } else if (i === points.length - 1) {
2785
+ vertexNormals.push(normals[normals.length - 1]);
2786
+ } else {
2787
+ const n1 = normals[i - 1];
2788
+ const n2 = normals[i];
2789
+ const avg = { x: (n1.x + n2.x) / 2, y: (n1.y + n2.y) / 2 };
2790
+ const len = Math.hypot(avg.x, avg.y);
2791
+ vertexNormals.push(len === 0 ? n1 : { x: avg.x / len, y: avg.y / len });
2792
+ }
2793
+ }
2794
+ const left = points.map((p, i) => ({
2795
+ x: p.x + vertexNormals[i].x * offsetPx,
2796
+ y: p.y + vertexNormals[i].y * offsetPx
2797
+ }));
2798
+ const right = points.map((p, i) => ({
2799
+ x: p.x - vertexNormals[i].x * offsetPx,
2800
+ y: p.y - vertexNormals[i].y * offsetPx
2801
+ })).reverse();
2802
+ const firstLeft = left[0];
2803
+ let d = `M${fmt(firstLeft.x)},${fmt(firstLeft.y)}`;
2804
+ for (let i = 1; i < left.length; i++) {
2805
+ d += `L${fmt(left[i].x)},${fmt(left[i].y)}`;
2806
+ }
2807
+ const lastLeft = left[left.length - 1];
2808
+ const firstRight = right[0];
2809
+ d += arcCap(lastLeft, firstRight, offsetPx);
2810
+ for (let i = 1; i < right.length; i++) {
2811
+ d += `L${fmt(right[i].x)},${fmt(right[i].y)}`;
2812
+ }
2813
+ const lastRight = right[right.length - 1];
2814
+ d += arcCap(lastRight, firstLeft, offsetPx);
2815
+ d += "Z";
2816
+ return d;
2817
+ }
2818
+ function arcCap(from, to, r) {
2819
+ return `A${fmt(r)},${fmt(r)},0,0,0,${fmt(to.x)},${fmt(to.y)}`;
2820
+ }
2821
+ function fmt(n) {
2822
+ return Math.round(n * 100) / 100 + "";
2823
+ }
2824
+ function hullToPath(hull) {
2825
+ if (hull.length === 0)
2826
+ return "";
2827
+ const [first, ...rest] = hull;
2828
+ return `M${fmt(first.x)},${fmt(first.y)}` + rest.map((p) => `L${fmt(p.x)},${fmt(p.y)}`).join("") + "Z";
2829
+ }
2830
+
1974
2831
  // src/index.ts
1975
2832
  var src_default = { structure: structure_default, input: input_default, rendering: rendering_default, textChat: text_chat_default };
2833
+ // Annotate the CommonJS export names for ESM import in node:
2834
+ 0 && (module.exports = {
2835
+ boundingRectPath,
2836
+ convexHullOfCircles,
2837
+ convexHullOfRects,
2838
+ convexHullPath,
2839
+ createValidId,
2840
+ describeNode,
2841
+ expandHull,
2842
+ getGenericCommandsFromNavRules,
2843
+ grahamScan,
2844
+ keyLabel,
2845
+ offsetLinePath,
2846
+ unionOfRectPaths
2847
+ });