data-navigator 3.0.0 → 3.2.1

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
@@ -86,7 +86,9 @@ __export(src_exports, {
86
86
  default: () => src_default,
87
87
  describeNode: () => describeNode,
88
88
  expandHull: () => expandHull,
89
+ getGenericCommandsFromNavRules: () => getGenericCommandsFromNavRules,
89
90
  grahamScan: () => grahamScan,
91
+ keyLabel: () => keyLabel,
90
92
  offsetLinePath: () => offsetLinePath,
91
93
  unionOfRectPaths: () => unionOfRectPaths
92
94
  });
@@ -112,9 +114,9 @@ var defaultKeyBindings = {
112
114
  Escape: "drill-out",
113
115
  Enter: "drill-in"
114
116
  };
115
- var TypicallyUnreservedKeys = ["KeyW", "KeyJ", "LeftBracket", "RightBracket", "Slash", "Backslash"];
117
+ var TypicallyUnreservedKeys = ["KeyW", "KeyJ", "BracketLeft", "BracketRight", "Slash", "Backslash"];
116
118
  var TypicallyUnreservedKeyPairs = [
117
- ["LeftBracket", "RightBracket"],
119
+ ["BracketLeft", "BracketRight"],
118
120
  ["Slash", "Backslash"]
119
121
  ];
120
122
  var GenericFullNavigationRules = {
@@ -241,6 +243,27 @@ var NodeElementDefaults = {
241
243
  spatialProperties: void 0
242
244
  }
243
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
+ };
244
267
  var GenericNavigationRuleCommands = {
245
268
  "drill-in": { label: "Enter", description: "Drill in" },
246
269
  "drill-out": { label: "Backspace", description: "Drill out" },
@@ -275,13 +298,423 @@ var describeNode = (d, descriptionOptions) => {
275
298
  var createValidId = (s) => {
276
299
  return "_" + s.replace(/[^a-zA-Z0-9_-]+/g, "_");
277
300
  };
278
- function getGenericCommandsFromNavRules(navigationRules) {
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) {
279
311
  if (!navigationRules) {
280
312
  return [];
281
313
  }
282
- return Object.keys(navigationRules).map((navId) => GenericNavigationRuleCommands[navId]).filter(Boolean);
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
+ });
283
323
  }
284
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
+ };
717
+
285
718
  // src/structure.ts
286
719
  var structure_default = (options) => {
287
720
  if (options.dataType === "vega-lite" || options.dataType === "vl" || options.dataType === "Vega-Lite") {
@@ -758,9 +1191,9 @@ var scaffoldDimensions = (options, nodes) => {
758
1191
  }
759
1192
  return dimensions;
760
1193
  };
761
- var buildEdges = (options, nodes, dimensions) => {
1194
+ var buildEdges = (options, nodes, dimensions, existingEdges) => {
762
1195
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
763
- let edges = {};
1196
+ let edges = existingEdges || {};
764
1197
  const addEdgeToNode = (nodeId, edgeId) => {
765
1198
  if (nodes[nodeId].edges.indexOf(edgeId) === -1) {
766
1199
  nodes[nodeId].edges.push(edgeId);
@@ -834,7 +1267,7 @@ var buildEdges = (options, nodes, dimensions) => {
834
1267
  createEdge(level1Node.id, nextLevel1Node.id, siblingRules);
835
1268
  }
836
1269
  if (!l && extents === "bridgedCustom") {
837
- createEdge(po.level1Options.behavior.customBridgePost, level1Node.id, siblingRules);
1270
+ createEdge(po.level1Options.behavior.customBridgePrevious, level1Node.id, siblingRules);
838
1271
  }
839
1272
  l++;
840
1273
  });
@@ -1021,7 +1454,7 @@ var buildEdges = (options, nodes, dimensions) => {
1021
1454
  return edges;
1022
1455
  };
1023
1456
  var buildRules = (options, edges, dimensions) => {
1024
- 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;
1025
1458
  let rules = options.navigationRules;
1026
1459
  if (!rules) {
1027
1460
  let dimKeys = Object.keys(dimensions || {});
@@ -1125,6 +1558,20 @@ var buildRules = (options, edges, dimensions) => {
1125
1558
  checkKeys(ss[0], ss[1]);
1126
1559
  });
1127
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
+ });
1128
1575
  Object.keys(edges).forEach((e) => {
1129
1576
  edges[e].navigationRules.forEach((rule) => {
1130
1577
  if (!used[rule]) {
@@ -1159,20 +1606,38 @@ var buildRules = (options, edges, dimensions) => {
1159
1606
  }
1160
1607
  return rules;
1161
1608
  };
1162
- var buildStructure = (options) => {
1163
- if (options.addIds) {
1164
- addSimpleDataIDs(options);
1609
+ var buildStructure = (inputOptions) => {
1610
+ var _a, _b, _c;
1611
+ if (inputOptions.addIds) {
1612
+ addSimpleDataIDs(inputOptions);
1165
1613
  }
1614
+ const options = prepareFrameOptions(inputOptions);
1166
1615
  let nodes = buildNodes(options);
1167
1616
  let dimensions = scaffoldDimensions(options, nodes);
1168
- 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);
1169
1627
  let navigationRules = buildRules(options, edges, dimensions);
1170
- return {
1628
+ const structure = {
1171
1629
  nodes,
1172
1630
  edges,
1173
1631
  dimensions,
1174
1632
  navigationRules
1175
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;
1176
1641
  };
1177
1642
 
1178
1643
  // src/input.ts
@@ -1405,11 +1870,12 @@ var rendering_default = (options) => {
1405
1870
  parentSemantics: __spreadValues({}, NodeElementDefaults.parentSemantics),
1406
1871
  existingElement: __spreadValues({}, NodeElementDefaults.existingElement)
1407
1872
  };
1873
+ const mergeDefault = (base, o) => typeof o === "function" ? o : __spreadValues(__spreadValues({}, base), o);
1408
1874
  if (options.defaults) {
1409
1875
  defaults.cssClass = options.defaults.cssClass || defaults.cssClass;
1410
- defaults.spatialProperties = options.defaults.spatialProperties ? __spreadValues(__spreadValues({}, defaults.spatialProperties), options.defaults.spatialProperties) : defaults.spatialProperties;
1411
- defaults.semantics = options.defaults.semantics ? __spreadValues(__spreadValues({}, defaults.semantics), options.defaults.semantics) : defaults.semantics;
1412
- defaults.parentSemantics = options.defaults.parentSemantics ? __spreadValues(__spreadValues({}, defaults.parentSemantics), options.defaults.parentSemantics) : defaults.parentSemantics;
1876
+ defaults.spatialProperties = options.defaults.spatialProperties ? mergeDefault(defaults.spatialProperties, options.defaults.spatialProperties) : defaults.spatialProperties;
1877
+ defaults.semantics = options.defaults.semantics ? mergeDefault(defaults.semantics, options.defaults.semantics) : defaults.semantics;
1878
+ defaults.parentSemantics = options.defaults.parentSemantics ? mergeDefault(defaults.parentSemantics, options.defaults.parentSemantics) : defaults.parentSemantics;
1413
1879
  defaults.existingElement = options.defaults.existingElement ? __spreadValues(__spreadValues({}, defaults.existingElement), options.defaults.existingElement) : defaults.existingElement;
1414
1880
  }
1415
1881
  renderer.initialize = () => {
@@ -1503,12 +1969,16 @@ var rendering_default = (options) => {
1503
1969
  }
1504
1970
  let useExisting = false;
1505
1971
  let existingSpatialProperties = {};
1506
- const resolveProp = (prop, subprop, checkExisting) => {
1972
+ const resolve = (v) => {
1507
1973
  var _a;
1508
- const p1 = d[prop] || defaults[prop];
1974
+ return typeof v === "function" ? v(d, (_a = nodeData.datum) != null ? _a : nodeData.data) : v;
1975
+ };
1976
+ const resolveProp = (prop, subprop, checkExisting) => {
1977
+ var _a, _b, _c;
1978
+ const p1 = resolve(d[prop] || defaults[prop]);
1509
1979
  const s1 = !(checkExisting && useExisting) ? p1 == null ? void 0 : p1[subprop] : existingSpatialProperties[subprop];
1510
- const s2 = (_a = defaults[prop]) == null ? void 0 : _a[subprop];
1511
- return typeof p1 === "function" ? p1(d, nodeData.datum) : typeof s1 === "function" ? s1(d, nodeData.datum) : s1 || s2 || (!subprop ? p1 : void 0);
1980
+ const s2 = (_c = (_a = resolve(defaults[prop])) == null ? void 0 : _a[subprop]) != null ? _c : (_b = NodeElementDefaults[prop]) == null ? void 0 : _b[subprop];
1981
+ return resolve(s1) || resolve(s2) || (!subprop ? p1 : void 0);
1512
1982
  };
1513
1983
  useExisting = resolveProp("existingElement", "useForSpatialProperties");
1514
1984
  existingSpatialProperties = resolveProp("existingElement", "spatialProperties");
@@ -1538,15 +2008,15 @@ var rendering_default = (options) => {
1538
2008
  const attributes = resolveProp("semantics", "attributes");
1539
2009
  if (typeof attributes === "object") {
1540
2010
  Object.keys(attributes).forEach((attribute) => {
1541
- node.setAttribute(attribute, attributes[attribute]);
2011
+ nodeText.setAttribute(attribute, attributes[attribute]);
1542
2012
  });
1543
2013
  }
1544
2014
  nodeText.setAttribute("role", resolveProp("semantics", "role"));
1545
2015
  nodeText.classList.add("dn-node-text");
2016
+ const label = resolveProp("semantics", "label");
1546
2017
  if (d.showText) {
1547
- nodeText.innerText = d.semantics.label;
2018
+ nodeText.innerText = label;
1548
2019
  }
1549
- const label = resolveProp("semantics", "label");
1550
2020
  if (!label) {
1551
2021
  console.error(
1552
2022
  "Accessibility error: a label must be supplied to every rendered element using semantics.label."
@@ -1601,7 +2071,10 @@ var rendering_default = (options) => {
1601
2071
  return;
1602
2072
  }
1603
2073
  const optionsCommands = commandOptions.commands;
1604
- const genericCommandsFromRules = getGenericCommandsFromNavRules(commandOptions.navigationRules);
2074
+ const genericCommandsFromRules = getGenericCommandsFromNavRules(
2075
+ commandOptions.navigationRules,
2076
+ commandOptions.descriptions
2077
+ );
1605
2078
  const commands = optionsCommands ? typeof optionsCommands === "function" ? optionsCommands(genericCommandsFromRules) : optionsCommands : genericCommandsFromRules;
1606
2079
  if (!customElements.get("dn-commands-table")) {
1607
2080
  customElements.define("dn-commands-table", CommandsTable);
@@ -1793,7 +2266,7 @@ var searchNodes = (query, structure, describeFn, limit = 10) => {
1793
2266
  return results;
1794
2267
  };
1795
2268
  var text_chat_default = (options) => {
1796
- var _a;
2269
+ var _a, _b, _c, _d;
1797
2270
  const {
1798
2271
  structure,
1799
2272
  container,
@@ -1811,7 +2284,9 @@ var text_chat_default = (options) => {
1811
2284
  if (!rootEl) {
1812
2285
  throw new Error(`textChat: container "${container}" not found`);
1813
2286
  }
1814
- const resolvedEntryPoint = entryPoint || (structure.dimensions ? (_a = structure.dimensions[Object.keys(structure.dimensions)[0]]) == null ? void 0 : _a.nodeId : Object.keys(structure.nodes)[0]);
2287
+ const level0Id = Object.keys(structure.nodes).find((id) => structure.nodes[id].dimensionLevel === 0);
2288
+ const firstDimensionId = structure.dimensions ? (_a = structure.dimensions[Object.keys(structure.dimensions)[0]]) == null ? void 0 : _a.nodeId : void 0;
2289
+ 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];
1815
2290
  const inputHandler = input_default({
1816
2291
  structure,
1817
2292
  navigationRules: structure.navigationRules || {},
@@ -2369,7 +2844,9 @@ var src_default = { structure: structure_default, input: input_default, renderin
2369
2844
  createValidId,
2370
2845
  describeNode,
2371
2846
  expandHull,
2847
+ getGenericCommandsFromNavRules,
2372
2848
  grahamScan,
2849
+ keyLabel,
2373
2850
  offsetLinePath,
2374
2851
  unionOfRectPaths
2375
2852
  });