data-navigator 1.2.4 → 2.0.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.mjs CHANGED
@@ -1,4 +1,13 @@
1
1
  // src/consts.ts
2
+ var SemanticKeys = {
3
+ Escape: true,
4
+ Enter: true,
5
+ Backspace: true,
6
+ ArrowLeft: true,
7
+ ArrowRight: true,
8
+ ArrowUp: true,
9
+ ArrowDown: true
10
+ };
2
11
  var defaultKeyBindings = {
3
12
  ArrowLeft: "left",
4
13
  ArrowRight: "right",
@@ -9,44 +18,71 @@ var defaultKeyBindings = {
9
18
  Escape: "parent",
10
19
  Enter: "child"
11
20
  };
21
+ var TypicallyUnreservedKeys = ["KeyW", "KeyJ", "LeftBracket", "RightBracket", "Slash", "Backslash"];
22
+ var TypicallyUnreservedKeyPairs = [
23
+ ["LeftBracket", "RightBracket"],
24
+ ["Slash", "Backslash"]
25
+ ];
12
26
  var GenericFullNavigationRules = {
13
- down: {
14
- keyCode: "ArrowDown",
15
- direction: "target"
16
- },
17
27
  left: {
18
- keyCode: "ArrowLeft",
28
+ key: "ArrowLeft",
19
29
  direction: "source"
20
30
  },
21
31
  right: {
22
- keyCode: "ArrowRight",
32
+ key: "ArrowRight",
23
33
  direction: "target"
24
34
  },
25
35
  up: {
26
- keyCode: "ArrowUp",
36
+ key: "ArrowUp",
27
37
  direction: "source"
28
38
  },
29
- backward: {
30
- keyCode: "Comma",
31
- direction: "source"
39
+ down: {
40
+ key: "ArrowDown",
41
+ direction: "target"
32
42
  },
33
43
  child: {
34
- keyCode: "Enter",
44
+ key: "Enter",
35
45
  direction: "target"
36
46
  },
37
47
  parent: {
38
- keyCode: "Backspace",
48
+ key: "Backspace",
49
+ direction: "source"
50
+ },
51
+ backward: {
52
+ key: "Comma",
39
53
  direction: "source"
40
54
  },
41
55
  forward: {
42
- keyCode: "Period",
56
+ key: "Period",
57
+ direction: "target"
58
+ },
59
+ previous: {
60
+ key: "Semicolon",
61
+ direction: "source"
62
+ },
63
+ next: {
64
+ key: "Quote",
43
65
  direction: "target"
44
66
  },
45
67
  exit: {
46
- keyCode: "Escape",
68
+ key: "Escape",
69
+ direction: "target"
70
+ },
71
+ help: {
72
+ key: "KeyY",
73
+ direction: "target"
74
+ },
75
+ undo: {
76
+ key: "KeyZ",
47
77
  direction: "target"
48
78
  }
49
79
  };
80
+ var GenericFullNavigationDimensions = [
81
+ ["left", "right"],
82
+ ["up", "down"],
83
+ ["backward", "forward"],
84
+ ["previous", "next"]
85
+ ];
50
86
  var GenericLimitedNavigationRules = {
51
87
  right: {
52
88
  key: "ArrowRight",
@@ -87,7 +123,7 @@ var GenericLimitedNavigationRules = {
87
123
  };
88
124
  var NodeElementDefaults = {
89
125
  cssClass: "",
90
- dimensions: {
126
+ spatialProperties: {
91
127
  x: 0,
92
128
  y: 0,
93
129
  width: 0,
@@ -107,8 +143,8 @@ var NodeElementDefaults = {
107
143
  attributes: void 0
108
144
  },
109
145
  existingElement: {
110
- useForDimensions: false,
111
- dimensions: void 0
146
+ useForSpatialProperties: false,
147
+ spatialProperties: void 0
112
148
  }
113
149
  };
114
150
 
@@ -128,10 +164,7 @@ var structure_default = (options) => {
128
164
  if (options.dataType === "vega-lite" || options.dataType === "vl" || options.dataType === "Vega-Lite") {
129
165
  return buildNodeStructureFromVegaLite(options);
130
166
  } else {
131
- console.warn(
132
- "Apologies, we currently only have structure scaffolding for Vega-Lite, generic scaffolding coming soon!"
133
- );
134
- return;
167
+ return buildStructure(options);
135
168
  }
136
169
  };
137
170
  var buildNodeStructureFromVegaLite = (options) => {
@@ -252,11 +285,11 @@ var buildNodeStructureFromVegaLite = (options) => {
252
285
  nodes[id].parent = parent;
253
286
  elementData[renderId] = {};
254
287
  elementData[renderId].renderId = renderId;
255
- elementData[renderId].dimensions = {};
256
- elementData[renderId].dimensions.x = item.bounds.x1 + o[0];
257
- elementData[renderId].dimensions.y = item.bounds.y1 + o[1];
258
- elementData[renderId].dimensions.width = item.bounds.x2 - item.bounds.x1;
259
- elementData[renderId].dimensions.height = item.bounds.y2 - item.bounds.y1;
288
+ elementData[renderId].spatialProperties = {};
289
+ elementData[renderId].spatialProperties.x = item.bounds.x1 + o[0];
290
+ elementData[renderId].spatialProperties.y = item.bounds.y1 + o[1];
291
+ elementData[renderId].spatialProperties.width = item.bounds.x2 - item.bounds.x1;
292
+ elementData[renderId].spatialProperties.height = item.bounds.y2 - item.bounds.y1;
260
293
  elementData[renderId].cssClass = "dn-vega-lite-node";
261
294
  if (item.datum) {
262
295
  Object.keys(item.datum).forEach((key) => {
@@ -295,6 +328,647 @@ var buildNodeStructureFromVegaLite = (options) => {
295
328
  navigationRules
296
329
  };
297
330
  };
331
+ var createValidId = (s) => {
332
+ return "_" + s.replace(/[^a-zA-Z0-9_-]+/g, "_");
333
+ };
334
+ var addSimpleDataIDs = (options) => {
335
+ let i = 0;
336
+ let keyCounter = {};
337
+ options.data.forEach((d) => {
338
+ const id = typeof options.idKey === "function" ? options.idKey(d) : options.idKey;
339
+ d[id] = "_" + i;
340
+ if (options.keysForIdGeneration) {
341
+ options.keysForIdGeneration.forEach((k) => {
342
+ if (k in d) {
343
+ if (typeof d[k] === "string") {
344
+ if (!keyCounter[k]) {
345
+ keyCounter[k] = 0;
346
+ }
347
+ if (!keyCounter[d[k]]) {
348
+ keyCounter[d[k]] = 0;
349
+ }
350
+ d[id] += "_" + k + keyCounter[k] + "_" + d[k] + keyCounter[d[k]];
351
+ keyCounter[k]++;
352
+ keyCounter[d[k]]++;
353
+ } else {
354
+ if (!keyCounter[k]) {
355
+ keyCounter[k] = 0;
356
+ }
357
+ d[id] += "_" + k + keyCounter[k];
358
+ keyCounter[k]++;
359
+ }
360
+ }
361
+ });
362
+ }
363
+ i++;
364
+ });
365
+ };
366
+ var bulidNodes = (options) => {
367
+ let nodes = {};
368
+ options.data.forEach((d) => {
369
+ if (!options.idKey) {
370
+ console.error(
371
+ `Building nodes. A key string must be supplied in options.idKey to specify the id keys of every node.`
372
+ );
373
+ }
374
+ const idKey = typeof options.idKey === "function" ? options.idKey(d) : options.idKey;
375
+ const id = d[idKey];
376
+ if (!id) {
377
+ console.error(
378
+ `Building nodes. Each datum in options.data must contain an id. When matching the id key string ${idKey}, this datum has no id: ${JSON.stringify(
379
+ d
380
+ )}.`
381
+ );
382
+ return;
383
+ }
384
+ if (!nodes[id]) {
385
+ const renderIdKey = typeof options.renderIdKey === "function" ? options.renderIdKey(d) : options.renderIdKey;
386
+ nodes[id] = {
387
+ id,
388
+ edges: [],
389
+ renderId: renderIdKey ? d[renderIdKey] || "" : d.renderIdKey || "",
390
+ data: d
391
+ };
392
+ } else {
393
+ console.error(
394
+ `Building nodes. Each id for data in options.data must be unique. This id is not unique: ${id}.`
395
+ );
396
+ return;
397
+ }
398
+ });
399
+ return nodes;
400
+ };
401
+ var scaffoldDimensions = (options, nodes) => {
402
+ let dimensions = {};
403
+ if (options.dimensions?.parentOptions?.addLevel0) {
404
+ let level0 = options.dimensions.parentOptions.addLevel0;
405
+ nodes[level0.id] = { ...level0, dimensionLevel: 0 };
406
+ }
407
+ let rules = [...GenericFullNavigationDimensions];
408
+ const setExtents = (val, dim) => {
409
+ let min = dim.numericalExtents[0];
410
+ let max = dim.numericalExtents[1];
411
+ dim.numericalExtents[0] = min < val ? min : val;
412
+ dim.numericalExtents[1] = max > val ? max : val;
413
+ };
414
+ options.data.forEach((d) => {
415
+ let ods = options.dimensions.values || [];
416
+ let i = 0;
417
+ ods.forEach((dim) => {
418
+ if (!dim.dimensionKey) {
419
+ console.error(
420
+ `Building nodes, parsing dimensions. Each dimension in options.dimensions must contain a dimensionKey. This dimension has no key: ${JSON.stringify(
421
+ dim
422
+ )}.`
423
+ );
424
+ return;
425
+ }
426
+ if (dim.dimensionKey in d) {
427
+ let value = d[dim.dimensionKey];
428
+ let keepValue = typeof dim.operations?.filterFunction === "function" ? dim.operations.filterFunction(d, dim) : true;
429
+ if (value !== void 0 && keepValue) {
430
+ if (!dim.type) {
431
+ dim.type = typeof value === "bigint" || typeof value === "number" ? "numerical" : "categorical";
432
+ }
433
+ if (!dimensions[dim.dimensionKey]) {
434
+ let id2 = typeof dim.nodeId === "function" ? dim.nodeId(dim, options.data) : dim.nodeId || createValidId(dim.dimensionKey);
435
+ let renderId = typeof dim.renderId === "function" ? dim.renderId(dim, options.data) : dim.renderId || id2;
436
+ dimensions[dim.dimensionKey] = {
437
+ dimensionKey: dim.dimensionKey,
438
+ nodeId: id2,
439
+ divisions: {},
440
+ numericalExtents: [Infinity, -Infinity],
441
+ type: dim.type,
442
+ sortFunction: dim.operations?.sortFunction || void 0,
443
+ behavior: dim.behavior || {
444
+ extents: "circular"
445
+ },
446
+ navigationRules: dim.navigationRules || {
447
+ sibling_sibling: rules.length ? [...rules.shift()] : ["previous_" + dim.dimensionKey, "next_" + dim.dimensionKey],
448
+ parent_child: ["parent_" + dim.dimensionKey, "child"]
449
+ }
450
+ };
451
+ nodes[id2] = {
452
+ id: id2,
453
+ renderId,
454
+ derivedNode: dim.dimensionKey,
455
+ edges: [],
456
+ dimensionLevel: 1,
457
+ data: dimensions[dim.dimensionKey],
458
+ renderingStrategy: dim.renderingStrategy || "singleSquare"
459
+ // not sure what defaults we want yet
460
+ };
461
+ }
462
+ let dimension = dimensions[dim.dimensionKey];
463
+ let targetDivision = null;
464
+ if (dim.type === "categorical") {
465
+ let divisionId = typeof dim.divisionOptions?.divisionNodeIds === "function" ? dim.divisionOptions.divisionNodeIds(dim.dimensionKey, value, i) : dimension.nodeId + "_" + value;
466
+ targetDivision = dimension.divisions[divisionId];
467
+ if (!targetDivision) {
468
+ targetDivision = dimension.divisions[divisionId] = {
469
+ id: divisionId,
470
+ sortFunction: dim.divisionOptions?.sortFunction || void 0,
471
+ values: {}
472
+ };
473
+ let divisionRenderId = typeof dim.divisionOptions?.divisionRenderIds === "function" ? dim.divisionOptions.divisionRenderIds(dim.dimensionKey, value, i) : divisionId;
474
+ nodes[divisionId] = {
475
+ id: divisionId,
476
+ renderId: divisionRenderId,
477
+ derivedNode: dim.dimensionKey,
478
+ edges: [],
479
+ dimensionLevel: 2,
480
+ data: { ...targetDivision },
481
+ renderingStrategy: dim.divisionOptions?.renderingStrategy || "singleSquare"
482
+ // not sure what defaults we want yet
483
+ };
484
+ nodes[divisionId].data[dim.dimensionKey] = value;
485
+ }
486
+ } else {
487
+ targetDivision = dimension.divisions[dimension.nodeId];
488
+ if (!targetDivision) {
489
+ targetDivision = dimension.divisions[dimension.nodeId] = {
490
+ id: dimension.nodeId,
491
+ sortFunction: dim.divisionOptions?.sortFunction || void 0,
492
+ values: {}
493
+ };
494
+ }
495
+ if (!dim.operations) {
496
+ dim.operations = {};
497
+ }
498
+ let subdivs = dim.operations.createNumericalSubdivisions;
499
+ dimension.subdivisions = typeof subdivs === "number" && subdivs < 1 ? 1 : subdivs || 1;
500
+ if (subdivs !== 1) {
501
+ if (!dimension.divisionOptions) {
502
+ dimension.divisionOptions = dim.divisionOptions;
503
+ }
504
+ setExtents(value, dimension);
505
+ }
506
+ }
507
+ const id = typeof options.idKey === "function" ? options.idKey(d) : options.idKey;
508
+ targetDivision.values[d[id]] = d;
509
+ }
510
+ }
511
+ i++;
512
+ });
513
+ });
514
+ Object.keys(dimensions).forEach((s) => {
515
+ let dimension = dimensions[s];
516
+ let divisions = dimension.divisions;
517
+ if (dimension.type === "numerical") {
518
+ divisions[dimension.nodeId].values = Object.fromEntries(
519
+ Object.entries(divisions[dimension.nodeId].values).sort((a, b) => {
520
+ return typeof dimension.sortFunction === "function" ? dimension.sortFunction(a[1], b[1], dimension) : a[1][s] - b[1][s];
521
+ })
522
+ );
523
+ let values = divisions[dimension.nodeId].values;
524
+ if (dimension.numericalExtents[0] !== Infinity && dimension.subdivisions !== 1) {
525
+ let valueKeys = Object.keys(values);
526
+ let subDivisions = typeof dimension.subdivisions === "function" ? dimension.subdivisions(s, values) : dimension.subdivisions;
527
+ let range = dimension.numericalExtents[1] - dimension.numericalExtents[0];
528
+ let interval = range / subDivisions;
529
+ let i = dimension.numericalExtents[0] + interval;
530
+ let divisionCount = 0;
531
+ let index = 0;
532
+ for (i = dimension.numericalExtents[0] + interval; i <= dimension.numericalExtents[1]; i += interval) {
533
+ let divisionId = typeof dimension.divisionOptions?.divisionNodeIds === "function" ? dimension.divisionOptions.divisionNodeIds(s, i, i) : dimension.nodeId + "_" + i;
534
+ dimension.divisions[divisionId] = {
535
+ id: divisionId,
536
+ sortFunction: dimension.divisionOptions?.sortFunction || void 0,
537
+ values: {}
538
+ };
539
+ let divisionRenderId = typeof dimension.divisionOptions?.divisionRenderIds === "function" ? dimension.divisionOptions.divisionRenderIds(s, i, i) : divisionId;
540
+ nodes[divisionId] = {
541
+ id: divisionId,
542
+ renderId: divisionRenderId,
543
+ derivedNode: s,
544
+ edges: [],
545
+ data: dimension.divisions[divisionId],
546
+ dimensionLevel: 2,
547
+ renderingStrategy: dimension.divisionOptions?.renderingStrategy || "singleSquare"
548
+ // not sure what defaults we want yet
549
+ };
550
+ let limit = false;
551
+ while (!limit && index < valueKeys.length) {
552
+ let node = values[valueKeys[index]];
553
+ let value = node[s];
554
+ if (value <= i) {
555
+ dimension.divisions[divisionId].values[node.id] = node;
556
+ } else {
557
+ i += interval;
558
+ limit = true;
559
+ }
560
+ index++;
561
+ }
562
+ divisionCount++;
563
+ }
564
+ delete divisions[s];
565
+ }
566
+ } else if (typeof dimension.sortFunction === "function") {
567
+ dimension.divisions = Object.fromEntries(
568
+ Object.entries(divisions).sort((a, b) => {
569
+ return dimension.sortFunction(a[1], b[1], dimension);
570
+ })
571
+ );
572
+ }
573
+ let divisionKeys = Object.keys(dimension.divisions);
574
+ divisionKeys.forEach((d) => {
575
+ let division = dimension.divisions[d];
576
+ if (typeof division.sortFunction === "function") {
577
+ division.values = Object.fromEntries(
578
+ Object.entries(division.values).sort((a, b) => {
579
+ return dimension.sortFunction(a[1], b[1], division);
580
+ })
581
+ );
582
+ }
583
+ });
584
+ });
585
+ if (options.dimensions.adjustDimensions) {
586
+ dimensions = options.dimensions.adjustDimensions(dimensions);
587
+ }
588
+ return dimensions;
589
+ };
590
+ var buildEdges = (options, nodes, dimensions) => {
591
+ let edges = {};
592
+ const addEdgeToNode = (nodeId, edgeId) => {
593
+ if (nodes[nodeId].edges.indexOf(edgeId) === -1) {
594
+ nodes[nodeId].edges.push(edgeId);
595
+ }
596
+ };
597
+ const createEdge = (source, target, rules, addTo) => {
598
+ const id = `${source}-${target}`;
599
+ let targetId = !options.useDirectedEdges ? id : `${target}-${id}`;
600
+ let addToSource = !addTo || addTo === "source";
601
+ let addToTarget = !addTo || addTo === "target";
602
+ const checkEdgeRules = (eId) => {
603
+ if (edges[eId]) {
604
+ edges[eId].navigationRules.push(...rules || []);
605
+ } else {
606
+ edges[eId] = {
607
+ source,
608
+ target,
609
+ navigationRules: rules ? [...rules] : []
610
+ };
611
+ }
612
+ };
613
+ checkEdgeRules(id);
614
+ if (options.useDirectedEdges && addToTarget) {
615
+ checkEdgeRules(targetId);
616
+ }
617
+ if (addToSource) {
618
+ addEdgeToNode(source, id);
619
+ }
620
+ if (addToTarget) {
621
+ addEdgeToNode(target, targetId);
622
+ }
623
+ };
624
+ if (dimensions && Object.keys(dimensions).length) {
625
+ const dimensionKeys = Object.keys(dimensions);
626
+ const hasOrder = options.dimensions?.parentOptions?.level1Options?.order;
627
+ let order = hasOrder || dimensionKeys;
628
+ let l = 0;
629
+ let po = options.dimensions?.parentOptions || {};
630
+ let extents = po.level1Options?.behavior?.extents || "terminal";
631
+ let level0 = po.addLevel0;
632
+ let parentRules = level0 ? po.level1Options?.navigationRules?.parent_child || ["parent", "child"] : [];
633
+ let siblingRules = po.level1Options?.navigationRules?.sibling_sibling || ["left", "right"];
634
+ let firstLevel1Node = typeof order[0] === "string" ? hasOrder ? nodes[order[0]] : nodes[dimensions[order[0]].nodeId] : order[0];
635
+ if (level0) {
636
+ createEdge(level0.id, firstLevel1Node.id, parentRules, "source");
637
+ }
638
+ order.forEach((n) => {
639
+ let level1Node = typeof n === "string" ? hasOrder ? nodes[n] : nodes[dimensions[n].nodeId] : n;
640
+ if (level1Node === n && !nodes[level1Node.id]) {
641
+ nodes[level1Node.id] = level1Node;
642
+ }
643
+ if (level0) {
644
+ if (!options.useDirectedEdges) {
645
+ createEdge(level0.id, level1Node.id, parentRules, "target");
646
+ } else {
647
+ createEdge(level1Node.id, level0.id, parentRules, "source");
648
+ }
649
+ }
650
+ if (l === order.length - 1 && extents === "circular") {
651
+ createEdge(level1Node.id, firstLevel1Node.id, siblingRules);
652
+ } else if (l === order.length - 1 && extents === "bridgedCustom") {
653
+ createEdge(level1Node.id, po.level1Options.behavior.customBridgePost, siblingRules);
654
+ } else if (l < order.length - 1) {
655
+ let nextLevel1Node = typeof order[l + 1] === "string" ? hasOrder ? (
656
+ // @ts-ignore: for some reason the same use of conditional check works above for order[0] (firstLevel1Node) but not for l+1 here
657
+ nodes[order[l + 1]]
658
+ ) : (
659
+ // @ts-ignore: for some reason the same use of conditional check works above for order[0] (firstLevel1Node) but not for l+1 here
660
+ nodes[dimensions[order[l + 1]].nodeId]
661
+ ) : order[l + 1];
662
+ createEdge(level1Node.id, nextLevel1Node.id, siblingRules);
663
+ }
664
+ if (!l && extents === "bridgedCustom") {
665
+ createEdge(po.level1Options.behavior.customBridgePost, level1Node.id, siblingRules);
666
+ }
667
+ l++;
668
+ });
669
+ dimensionKeys.forEach((s) => {
670
+ const dimension = dimensions[s];
671
+ let extents2 = dimension.behavior?.extents || "circular";
672
+ if (!dimension.divisions) {
673
+ console.error(
674
+ `Parsing dimensions. The dimension using the key ${s} is missing the divisions property. dimension.divisions should be supplied. ${JSON.stringify(
675
+ dimension
676
+ )}.`
677
+ );
678
+ }
679
+ let divisionKeys = Object.keys(dimension.divisions);
680
+ const firstDivision = dimension.divisions[divisionKeys[0]];
681
+ if (divisionKeys.length !== 1) {
682
+ createEdge(dimension.nodeId, firstDivision.id, dimension.navigationRules.parent_child, "source");
683
+ } else {
684
+ let valueKeys = Object.keys(firstDivision.values);
685
+ let firstChildId = typeof options.idKey === "function" ? options.idKey(firstDivision.values[valueKeys[0]]) : options.idKey;
686
+ createEdge(
687
+ dimension.nodeId,
688
+ firstDivision.values[valueKeys[0]][firstChildId],
689
+ dimension.navigationRules.parent_child,
690
+ "source"
691
+ );
692
+ }
693
+ let j = 0;
694
+ divisionKeys.forEach((d) => {
695
+ let division = dimension.divisions[d];
696
+ if (j === divisionKeys.length - 1 && (extents2 === "circular" || extents2 === "bridgedCousins" || extents2 === "bridgedCustom")) {
697
+ createEdge(
698
+ division.id,
699
+ dimension.divisions[divisionKeys[0]].id,
700
+ dimension.navigationRules.sibling_sibling
701
+ );
702
+ } else if (j < divisionKeys.length - 1) {
703
+ createEdge(
704
+ division.id,
705
+ dimension.divisions[divisionKeys[j + 1]].id,
706
+ dimension.navigationRules.sibling_sibling
707
+ );
708
+ }
709
+ let valueKeys = Object.keys(division.values);
710
+ if (!options.useDirectedEdges) {
711
+ createEdge(dimension.nodeId, division.id, dimension.navigationRules.parent_child, "target");
712
+ } else {
713
+ createEdge(division.id, dimension.nodeId, dimension.navigationRules.parent_child, "source");
714
+ }
715
+ const firstChildId = typeof options.idKey === "function" ? options.idKey(division.values[valueKeys[0]]) : options.idKey;
716
+ createEdge(
717
+ division.id,
718
+ division.values[valueKeys[0]][firstChildId],
719
+ dimension.navigationRules.parent_child,
720
+ "source"
721
+ );
722
+ let i = 0;
723
+ if (valueKeys.length > 1) {
724
+ valueKeys.forEach((vk) => {
725
+ let v = division.values[vk];
726
+ const id = typeof options.idKey === "function" ? options.idKey(v) : options.idKey;
727
+ let parentId = divisionKeys.length !== 1 ? division.id : dimension.nodeId;
728
+ if (!options.useDirectedEdges) {
729
+ createEdge(parentId, v[id], dimension.navigationRules.parent_child, "target");
730
+ } else {
731
+ createEdge(v[id], parentId, dimension.navigationRules.parent_child, "source");
732
+ }
733
+ if (i === valueKeys.length - 1 && extents2 === "circular") {
734
+ const targetId = typeof options.idKey === "function" ? options.idKey(division.values[valueKeys[0]]) : options.idKey;
735
+ createEdge(
736
+ v[id],
737
+ division.values[valueKeys[0]][targetId],
738
+ dimension.navigationRules.sibling_sibling
739
+ );
740
+ } else if (i === valueKeys.length - 1 && extents2 === "bridgedCousins") {
741
+ if (j !== divisionKeys.length - 1) {
742
+ const targetId = typeof options.idKey === "function" ? options.idKey(dimension.divisions[divisionKeys[j + 1]].values[valueKeys[0]]) : options.idKey;
743
+ createEdge(
744
+ v[id],
745
+ dimension.divisions[divisionKeys[j + 1]].values[valueKeys[0]][targetId],
746
+ dimension.navigationRules.sibling_sibling
747
+ );
748
+ } else {
749
+ const targetId = typeof options.idKey === "function" ? options.idKey(dimension.divisions[divisionKeys[0]].values[valueKeys[0]]) : options.idKey;
750
+ createEdge(
751
+ v[id],
752
+ dimension.divisions[divisionKeys[0]].values[valueKeys[0]][targetId],
753
+ dimension.navigationRules.sibling_sibling
754
+ );
755
+ }
756
+ } else if (i === valueKeys.length - 1 && extents2 === "bridgedCustom") {
757
+ createEdge(
758
+ v[id],
759
+ dimension.behavior.customBridgePost,
760
+ dimension.navigationRules.sibling_sibling
761
+ );
762
+ } else if (i < valueKeys.length - 1) {
763
+ const targetId = typeof options.idKey === "function" ? options.idKey(division.values[valueKeys[i + 1]]) : options.idKey;
764
+ createEdge(
765
+ v[id],
766
+ division.values[valueKeys[i + 1]][targetId],
767
+ dimension.navigationRules.sibling_sibling
768
+ );
769
+ }
770
+ if (!i && extents2 === "bridgedCousins") {
771
+ if (j !== 0) {
772
+ const targetId = typeof options.idKey === "function" ? options.idKey(
773
+ dimension.divisions[divisionKeys[j - 1]].values[valueKeys[valueKeys.length - 1]]
774
+ ) : options.idKey;
775
+ createEdge(
776
+ dimension.divisions[divisionKeys[j - 1]].values[valueKeys[valueKeys.length - 1]][targetId],
777
+ v[id],
778
+ dimension.navigationRules.sibling_sibling
779
+ );
780
+ } else {
781
+ const targetId = typeof options.idKey === "function" ? options.idKey(
782
+ dimension.divisions[divisionKeys[divisionKeys.length - 1]].values[valueKeys[valueKeys.length - 1]]
783
+ ) : options.idKey;
784
+ createEdge(
785
+ dimension.divisions[divisionKeys[divisionKeys.length - 1]].values[valueKeys[valueKeys.length - 1]][targetId],
786
+ v[id],
787
+ dimension.navigationRules.sibling_sibling
788
+ );
789
+ }
790
+ } else if (!i && extents2 === "bridgedCustom") {
791
+ createEdge(
792
+ dimension.behavior.customBridgePrevious,
793
+ v[id],
794
+ dimension.navigationRules.sibling_sibling
795
+ );
796
+ }
797
+ i++;
798
+ });
799
+ }
800
+ j++;
801
+ });
802
+ });
803
+ }
804
+ Object.keys(nodes).forEach((nodeKey) => {
805
+ const node = nodes[nodeKey];
806
+ if (options.genericEdges?.length) {
807
+ options.genericEdges.forEach((e) => {
808
+ if (!edges[e.edgeId]) {
809
+ edges[e.edgeId] = e.edge;
810
+ }
811
+ if (!e.conditional || e.conditional && e.conditional(node, e)) {
812
+ node.edges.push(e.edgeId);
813
+ }
814
+ });
815
+ }
816
+ });
817
+ return edges;
818
+ };
819
+ var buildRules = (options, edges, dimensions) => {
820
+ let rules = options.navigationRules;
821
+ if (!rules) {
822
+ let dimKeys = Object.keys(dimensions || {});
823
+ if (dimKeys.length > 6) {
824
+ console.error(
825
+ `Building navigationRules. Dimension count is too high to automatically generate key commands. It is recommend you reduce your dimensions to 6 or fewer for end-user experience. If not, you must provide your own navigation rules in options.navigationRules. Details: Count is ${dimKeys.length}. Dimensions counted: ${dimKeys.join(", ")}.`
826
+ );
827
+ }
828
+ let importedRules = {};
829
+ let used = {};
830
+ let needsKeys = {};
831
+ let sparePairs = [...TypicallyUnreservedKeyPairs];
832
+ let spareKeys = [...TypicallyUnreservedKeys];
833
+ const checkKeys = (k1, k2) => {
834
+ let isPair = k1 && k2;
835
+ let k1Assigned = false;
836
+ let k2Assigned = false;
837
+ if (importedRules[k1] || used[k1]) {
838
+ used[k1] = { ...importedRules[k1] };
839
+ k1Assigned = true;
840
+ }
841
+ if (k2 && (importedRules[k2] || used[k2])) {
842
+ used[k2] = { ...importedRules[k2] };
843
+ k2Assigned = true;
844
+ }
845
+ if (isPair && !k1Assigned && !k2Assigned) {
846
+ if (!sparePairs.length) {
847
+ console.error(
848
+ `Building navigationRules. Dimension count is too high to automatically generate key commands, we have run out of keyboard key pairs to assign. You must either provide your own navigation rules in options.navigationRules, provide rules when generating dimensions, or reduce dimension count.`
849
+ );
850
+ }
851
+ let pair = [...sparePairs.shift()];
852
+ spareKeys.splice(spareKeys.indexOf(pair[0]), 1);
853
+ spareKeys.splice(spareKeys.indexOf(pair[1]), 1);
854
+ used[k1] = {
855
+ direction: options.useDirectedEdges ? "target" : "source",
856
+ key: pair[0]
857
+ };
858
+ used[k2] = {
859
+ direction: "target",
860
+ key: pair[1]
861
+ };
862
+ } else {
863
+ if (!used[k1] && spareKeys.length) {
864
+ let key = spareKeys.shift();
865
+ let newPairs = [];
866
+ sparePairs.forEach((p) => {
867
+ if (key !== p[0] && key !== p[1]) {
868
+ newPairs.push(p);
869
+ }
870
+ });
871
+ sparePairs = newPairs;
872
+ used[k1] = {
873
+ direction: options.useDirectedEdges ? "target" : "source",
874
+ key
875
+ };
876
+ }
877
+ if (k2 && !used[k2] && spareKeys.length) {
878
+ let key = spareKeys.shift();
879
+ let newPairs = [];
880
+ sparePairs.forEach((p) => {
881
+ if (key !== p[0] && key !== p[1]) {
882
+ newPairs.push(p);
883
+ }
884
+ });
885
+ sparePairs = newPairs;
886
+ used[k2] = {
887
+ direction: "target",
888
+ key
889
+ };
890
+ }
891
+ if (!spareKeys.length) {
892
+ if (!used[k1]) {
893
+ needsKeys[k1] = k1;
894
+ }
895
+ if (k2 && !used[k2]) {
896
+ needsKeys[k2] = k2;
897
+ }
898
+ }
899
+ }
900
+ };
901
+ Object.keys(GenericFullNavigationRules).forEach((r) => {
902
+ let rule = { ...GenericFullNavigationRules[r] };
903
+ if (options.useDirectedEdges) {
904
+ rule.direction = "target";
905
+ }
906
+ importedRules[r] = rule;
907
+ });
908
+ if (dimKeys.length) {
909
+ if (options.dimensions?.parentOptions?.addLevel0) {
910
+ let rules2 = options.dimensions.parentOptions.level1Options?.navigationRules?.parent_child || [
911
+ "parent",
912
+ "child"
913
+ ];
914
+ checkKeys(rules2[0], rules2[1]);
915
+ }
916
+ dimKeys.forEach((d) => {
917
+ let pc = dimensions[d].navigationRules.parent_child;
918
+ let ss = dimensions[d].navigationRules.sibling_sibling;
919
+ checkKeys(pc[0], pc[1]);
920
+ checkKeys(ss[0], ss[1]);
921
+ });
922
+ }
923
+ Object.keys(edges).forEach((e) => {
924
+ edges[e].navigationRules.forEach((rule) => {
925
+ if (!used[rule]) {
926
+ checkKeys(rule);
927
+ }
928
+ });
929
+ });
930
+ if (Object.keys(needsKeys).length) {
931
+ let usedKeys = {};
932
+ Object.keys(used).forEach((k) => {
933
+ usedKeys[used[k].key] = used[k].key;
934
+ });
935
+ Object.keys(importedRules).forEach((r) => {
936
+ if (!usedKeys[importedRules[r].key] && !SemanticKeys[importedRules[r].key]) {
937
+ spareKeys.push(importedRules[r].key);
938
+ }
939
+ });
940
+ let recheckKeys = { ...needsKeys };
941
+ needsKeys = {};
942
+ Object.keys(recheckKeys).forEach((key) => {
943
+ checkKeys(key);
944
+ });
945
+ if (Object.keys(needsKeys).length) {
946
+ console.error(
947
+ `Building navigationRules. There are no more keys left to assign automatically. Recommended fixes: use fewer dimensions, use fewer GenericEdges, or build your own navigationRules. Rules remaining without keyboard keys: ${Object.keys(
948
+ needsKeys
949
+ ).join(", ")}.`
950
+ );
951
+ }
952
+ }
953
+ rules = used;
954
+ }
955
+ return rules;
956
+ };
957
+ var buildStructure = (options) => {
958
+ if (options.addIds) {
959
+ addSimpleDataIDs(options);
960
+ }
961
+ let nodes = bulidNodes(options);
962
+ let dimensions = scaffoldDimensions(options, nodes);
963
+ let edges = buildEdges(options, nodes, dimensions);
964
+ let navigationRules = buildRules(options, edges, dimensions);
965
+ return {
966
+ nodes,
967
+ edges,
968
+ dimensions,
969
+ navigationRules
970
+ };
971
+ };
298
972
 
299
973
  // src/input.ts
300
974
  var input_default = (options) => {
@@ -403,14 +1077,14 @@ var rendering_default = (options) => {
403
1077
  let initialized = false;
404
1078
  let defaults = {
405
1079
  cssClass: NodeElementDefaults.cssClass,
406
- dimensions: { ...NodeElementDefaults.dimensions },
1080
+ spatialProperties: { ...NodeElementDefaults.spatialProperties },
407
1081
  semantics: { ...NodeElementDefaults.semantics },
408
1082
  parentSemantics: { ...NodeElementDefaults.parentSemantics },
409
1083
  existingElement: { ...NodeElementDefaults.existingElement }
410
1084
  };
411
1085
  if (options.defaults) {
412
1086
  defaults.cssClass = options.defaults.cssClass || defaults.cssClass;
413
- defaults.dimensions = options.defaults.dimensions ? { ...defaults.dimensions, ...options.defaults.dimensions } : defaults.dimensions;
1087
+ defaults.spatialProperties = options.defaults.spatialProperties ? { ...defaults.spatialProperties, ...options.defaults.spatialProperties } : defaults.spatialProperties;
414
1088
  defaults.semantics = options.defaults.semantics ? { ...defaults.semantics, ...options.defaults.semantics } : defaults.semantics;
415
1089
  defaults.parentSemantics = options.defaults.parentSemantics ? { ...defaults.parentSemantics, ...options.defaults.parentSemantics } : defaults.parentSemantics;
416
1090
  defaults.existingElement = options.defaults.existingElement ? { ...defaults.existingElement, ...options.defaults.existingElement } : defaults.existingElement;
@@ -499,19 +1173,19 @@ var rendering_default = (options) => {
499
1173
  return;
500
1174
  }
501
1175
  let useExisting = false;
502
- let existingDimensions = {};
1176
+ let existingSpatialProperties = {};
503
1177
  const resolveProp = (prop, subprop, checkExisting) => {
504
1178
  const p1 = d[prop] || defaults[prop];
505
- const s1 = !(checkExisting && useExisting) ? p1[subprop] : existingDimensions[subprop];
1179
+ const s1 = !(checkExisting && useExisting) ? p1[subprop] : existingSpatialProperties[subprop];
506
1180
  const s2 = defaults[prop][subprop];
507
1181
  return typeof p1 === "function" ? p1(d, nodeData.datum) : typeof s1 === "function" ? s1(d, nodeData.datum) : s1 || s2 || (!subprop ? p1 : void 0);
508
1182
  };
509
- useExisting = resolveProp("existingElement", "useForDimensions");
510
- existingDimensions = resolveProp("existingElement", "dimensions");
511
- const width = parseFloat(resolveProp("dimensions", "width", true) || 0);
512
- const height = parseFloat(resolveProp("dimensions", "height", true) || 0);
513
- const x = parseFloat(resolveProp("dimensions", "x", true) || 0);
514
- const y = parseFloat(resolveProp("dimensions", "y", true) || 0);
1183
+ useExisting = resolveProp("existingElement", "useForSpatialProperties");
1184
+ existingSpatialProperties = resolveProp("existingElement", "spatialProperties");
1185
+ const width = parseFloat(resolveProp("spatialProperties", "width", true) || 0);
1186
+ const height = parseFloat(resolveProp("spatialProperties", "height", true) || 0);
1187
+ const x = parseFloat(resolveProp("spatialProperties", "x", true) || 0);
1188
+ const y = parseFloat(resolveProp("spatialProperties", "y", true) || 0);
515
1189
  const node = document.createElement(resolveProp("parentSemantics", "elementType"));
516
1190
  const wrapperAttrs = resolveProp("parentSemantics", "attributes");
517
1191
  if (typeof wrapperAttrs === "object") {
@@ -550,7 +1224,7 @@ var rendering_default = (options) => {
550
1224
  }
551
1225
  nodeText.setAttribute("aria-label", label);
552
1226
  node.appendChild(nodeText);
553
- const hasPath = resolveProp("dimensions", "path");
1227
+ const hasPath = resolveProp("spatialProperties", "path");
554
1228
  if (hasPath) {
555
1229
  const totalWidth = width + x + 10;
556
1230
  const totalHeight = height + y + 10;