@atlaskit/charlie-hierarchy 0.1.0 → 0.1.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/charlie-hierarchy
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`806cfe1c4e6b7`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/806cfe1c4e6b7) -
8
+ Internal changes to how border radius is applied.
9
+
10
+ ## 0.1.1
11
+
12
+ ### Patch Changes
13
+
14
+ - [`d20026853a75b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d20026853a75b) -
15
+ [ux] Support basic stacking functionality
16
+
3
17
  ## 0.1.0
4
18
 
5
19
  ### Minor Changes
@@ -16,6 +16,7 @@ var _react = _interopRequireDefault(require("react"));
16
16
  var _group = require("@visx/group");
17
17
  var _hierarchy = require("@visx/hierarchy");
18
18
  var _shape = require("@visx/shape");
19
+ var _utils = require("./utils");
19
20
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
20
21
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /**
21
22
  * CharlieHierarchy is meant to be a generic reusable component for building SVG rendered trees.
@@ -31,7 +32,7 @@ var staticStyles = {
31
32
  zoom: "_1tktglyw"
32
33
  };
33
34
  var CharlieHierarchy = exports.CharlieHierarchy = function CharlieHierarchy(props) {
34
- var _props$size$, _props$size, _props$size$2, _props$size2, _props$nodeSize$, _props$nodeSize, _props$nodeSize$2, _props$nodeSize2, _props$top, _props$left, _props$renderDependen, _styles$transformMatr, _props$styles2;
35
+ var _props$size$, _props$size, _props$size$2, _props$size2, _props$nodeSize$, _props$nodeSize, _props$nodeSize$2, _props$nodeSize2, _props$top, _props$left, _props$renderDependen, _props$stackingSpacin, _styles$transformMatr, _props$styles2;
35
36
  var _React$useTransition = _react.default.useTransition(),
36
37
  _React$useTransition2 = (0, _slicedToArray2.default)(_React$useTransition, 2),
37
38
  isSuspending = _React$useTransition2[0],
@@ -56,6 +57,8 @@ var CharlieHierarchy = exports.CharlieHierarchy = function CharlieHierarchy(prop
56
57
  var cursor = zoom !== null && zoom !== void 0 && zoom.isDragging ? 'grabbing' : 'grab';
57
58
  var children = props.children;
58
59
  var renderDependencies = (_props$renderDependen = props.renderDependencies) !== null && _props$renderDependen !== void 0 ? _props$renderDependen : [];
60
+ var stackingThreshold = props.stackingThreshold;
61
+ var stackingSpacing = (_props$stackingSpacin = props.stackingSpacing) !== null && _props$stackingSpacin !== void 0 ? _props$stackingSpacin : 70;
59
62
 
60
63
  /**
61
64
  * If zoom is enabled, we need to apply the transform matrix to the SVG.
@@ -80,6 +83,15 @@ var CharlieHierarchy = exports.CharlieHierarchy = function CharlieHierarchy(prop
80
83
  }, function (tree) {
81
84
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, tree.links().map(function (link, linkIndex) {
82
85
  var _props$styles$lineAtt, _props$styles;
86
+ if (stackingThreshold) {
87
+ link.target.x = (0, _utils.calculateLinkTargetPosition)(link.target.x, link.source.children, stackingThreshold, nodeWidthWithPadding);
88
+
89
+ // For now, don't render links that are beyond the stacking threshold.
90
+ // In the future, we can render the links that are beyond the stacking threshold.
91
+ if (linkIndex > stackingThreshold - 1) {
92
+ return null;
93
+ }
94
+ }
83
95
  return /*#__PURE__*/_react.default.createElement(_shape.LinkVerticalStep, (0, _extends2.default)({
84
96
  key: "link-".concat(linkIndex),
85
97
  data: link,
@@ -104,9 +116,15 @@ var CharlieHierarchy = exports.CharlieHierarchy = function CharlieHierarchy(prop
104
116
  nodeSize: nodeSize
105
117
  }, function (tree) {
106
118
  var descendants = tree.descendants();
119
+ var stackLocations = [];
107
120
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, descendants.map(function (node, index) {
108
121
  var top = node.y - nodeHeight / 2;
109
122
  var left = node.x - nodeWidth / 2;
123
+ if (stackingThreshold) {
124
+ var layout = (0, _utils.updateNodeLayout)(index, stackingThreshold, nodeWidthWithPadding, stackLocations, stackingSpacing, top, left, node);
125
+ top = layout.top;
126
+ left = layout.left;
127
+ }
110
128
  return /*#__PURE__*/_react.default.createElement("div", {
111
129
  key: "tree-node-".concat(index),
112
130
  style: {
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.updateNodeLayout = exports.calculateStackingShift = exports.calculateNodePosition = exports.calculateLinkTargetPosition = void 0;
7
+ /**
8
+ * Utility functions for Charlie Hierarchy component
9
+ */
10
+
11
+ /**
12
+ * Calculates the horizontal shift needed to center nodes when some children are stacked vertically
13
+ * @param totalChildren - Total number of children for a parent node
14
+ * @param stackingThreshold - Maximum number of children to display horizontally
15
+ * @param nodeWidthWithPadding - Width of a node including padding
16
+ * @returns The horizontal offset to apply for centering
17
+ */
18
+ var calculateStackingShift = exports.calculateStackingShift = function calculateStackingShift(totalChildren, stackingThreshold, nodeWidthWithPadding) {
19
+ var stackedChildren = Math.max(0, totalChildren - stackingThreshold);
20
+ return stackedChildren * nodeWidthWithPadding / 2;
21
+ };
22
+
23
+ /**
24
+ * Calculates the adjusted position for a node when stacking is enabled
25
+ * @param originalLeft - The original left position of the node
26
+ * @param parentChildren - Array of parent's children (to get total count)
27
+ * @param stackingThreshold - Maximum number of children to display horizontally
28
+ * @param nodeWidthWithPadding - Width of a node including padding
29
+ * @returns The adjusted left position
30
+ */
31
+ var calculateNodePosition = exports.calculateNodePosition = function calculateNodePosition(originalLeft, parentChildren, stackingThreshold, nodeWidthWithPadding) {
32
+ if (!parentChildren || parentChildren.length <= stackingThreshold) {
33
+ return originalLeft;
34
+ }
35
+ var stackingShift = calculateStackingShift(parentChildren.length, stackingThreshold, nodeWidthWithPadding);
36
+ return originalLeft + stackingShift;
37
+ };
38
+
39
+ /**
40
+ * Calculates the adjusted x position for a link target when stacking is enabled
41
+ * @param originalX - The original x position of the link target
42
+ * @param sourceChildren - Array of source node's children (to get total count)
43
+ * @param stackingThreshold - Maximum number of children to display horizontally
44
+ * @param nodeWidthWithPadding - Width of a node including padding
45
+ * @returns The adjusted x position
46
+ */
47
+ var calculateLinkTargetPosition = exports.calculateLinkTargetPosition = function calculateLinkTargetPosition(originalX, sourceChildren, stackingThreshold, nodeWidthWithPadding) {
48
+ if (!sourceChildren || sourceChildren.length <= stackingThreshold) {
49
+ return originalX;
50
+ }
51
+ var stackingShift = calculateStackingShift(sourceChildren.length, stackingThreshold, nodeWidthWithPadding);
52
+ return originalX + stackingShift;
53
+ };
54
+
55
+ /**
56
+ * Updates the layout position for a single node in a hierarchical tree with stacking support
57
+ * @param index - The index of the current node in the descendants array (0-based)
58
+ * @param stackingThreshold - Maximum number of nodes to display horizontally before stacking
59
+ * @param nodeWidthWithPadding - Width of a node including its padding for spacing calculations
60
+ * @param stackLocations - Mutable array storing positions of horizontal nodes for stacked node reference
61
+ * @param stackingSpacing - Vertical spacing in pixels between stacked nodes
62
+ * @param top - Initial top position of the node (before stacking adjustments)
63
+ * @param left - Initial left position of the node (before centering/stacking adjustments)
64
+ * @param node - The hierarchy node object containing parent/children relationships
65
+ * @returns Object containing the final calculated { top, left } position for the node
66
+ */
67
+ var updateNodeLayout = exports.updateNodeLayout = function updateNodeLayout(index, stackingThreshold, nodeWidthWithPadding, stackLocations, stackingSpacing, top, left, node) {
68
+ if (index <= stackingThreshold) {
69
+ if (index > 0) {
70
+ var _node$parent;
71
+ left = calculateNodePosition(left, (_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.children, stackingThreshold, nodeWidthWithPadding);
72
+ }
73
+
74
+ // Add the stack location to the array so we can reference it later
75
+ stackLocations.push({
76
+ top: top,
77
+ left: left
78
+ });
79
+ } else {
80
+ var stackRefrencePoint = stackLocations[index - stackingThreshold];
81
+ top = stackRefrencePoint.top + stackingSpacing;
82
+ left = stackRefrencePoint.left;
83
+ stackLocations.push({
84
+ top: top,
85
+ left: left
86
+ });
87
+ }
88
+ return {
89
+ top: top,
90
+ left: left
91
+ };
92
+ };
@@ -13,6 +13,7 @@ import React from 'react';
13
13
  import { Group } from '@visx/group';
14
14
  import { Tree } from '@visx/hierarchy';
15
15
  import { LinkVerticalStep } from '@visx/shape';
16
+ import { calculateLinkTargetPosition, updateNodeLayout } from './utils';
16
17
  const staticStyles = {
17
18
  hierarchyWrapper: "_kqswh2mm",
18
19
  nodeGroupWrapper: "_kqswstnw",
@@ -21,7 +22,7 @@ const staticStyles = {
21
22
  zoom: "_1tktglyw"
22
23
  };
23
24
  export const CharlieHierarchy = props => {
24
- var _props$size$, _props$size, _props$size$2, _props$size2, _props$nodeSize$, _props$nodeSize, _props$nodeSize$2, _props$nodeSize2, _props$top, _props$left, _props$renderDependen, _styles$transformMatr, _props$styles2;
25
+ var _props$size$, _props$size, _props$size$2, _props$size2, _props$nodeSize$, _props$nodeSize, _props$nodeSize$2, _props$nodeSize2, _props$top, _props$left, _props$renderDependen, _props$stackingSpacin, _styles$transformMatr, _props$styles2;
25
26
  const [isSuspending, startSuspending] = React.useTransition();
26
27
  const styles = {
27
28
  ...{
@@ -46,6 +47,8 @@ export const CharlieHierarchy = props => {
46
47
  const cursor = zoom !== null && zoom !== void 0 && zoom.isDragging ? 'grabbing' : 'grab';
47
48
  const children = props.children;
48
49
  const renderDependencies = (_props$renderDependen = props.renderDependencies) !== null && _props$renderDependen !== void 0 ? _props$renderDependen : [];
50
+ const stackingThreshold = props.stackingThreshold;
51
+ const stackingSpacing = (_props$stackingSpacin = props.stackingSpacing) !== null && _props$stackingSpacin !== void 0 ? _props$stackingSpacin : 70;
49
52
 
50
53
  /**
51
54
  * If zoom is enabled, we need to apply the transform matrix to the SVG.
@@ -70,6 +73,15 @@ export const CharlieHierarchy = props => {
70
73
  }, tree => {
71
74
  return /*#__PURE__*/React.createElement(React.Fragment, null, tree.links().map((link, linkIndex) => {
72
75
  var _props$styles$lineAtt, _props$styles;
76
+ if (stackingThreshold) {
77
+ link.target.x = calculateLinkTargetPosition(link.target.x, link.source.children, stackingThreshold, nodeWidthWithPadding);
78
+
79
+ // For now, don't render links that are beyond the stacking threshold.
80
+ // In the future, we can render the links that are beyond the stacking threshold.
81
+ if (linkIndex > stackingThreshold - 1) {
82
+ return null;
83
+ }
84
+ }
73
85
  return /*#__PURE__*/React.createElement(LinkVerticalStep, _extends({
74
86
  key: `link-${linkIndex}`,
75
87
  data: link,
@@ -94,9 +106,15 @@ export const CharlieHierarchy = props => {
94
106
  nodeSize: nodeSize
95
107
  }, tree => {
96
108
  const descendants = tree.descendants();
109
+ const stackLocations = [];
97
110
  return /*#__PURE__*/React.createElement(React.Fragment, null, descendants.map((node, index) => {
98
- const top = node.y - nodeHeight / 2;
99
- const left = node.x - nodeWidth / 2;
111
+ let top = node.y - nodeHeight / 2;
112
+ let left = node.x - nodeWidth / 2;
113
+ if (stackingThreshold) {
114
+ const layout = updateNodeLayout(index, stackingThreshold, nodeWidthWithPadding, stackLocations, stackingSpacing, top, left, node);
115
+ top = layout.top;
116
+ left = layout.left;
117
+ }
100
118
  return /*#__PURE__*/React.createElement("div", {
101
119
  key: `tree-node-${index}`,
102
120
  style: {
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Utility functions for Charlie Hierarchy component
3
+ */
4
+
5
+ /**
6
+ * Calculates the horizontal shift needed to center nodes when some children are stacked vertically
7
+ * @param totalChildren - Total number of children for a parent node
8
+ * @param stackingThreshold - Maximum number of children to display horizontally
9
+ * @param nodeWidthWithPadding - Width of a node including padding
10
+ * @returns The horizontal offset to apply for centering
11
+ */
12
+ export const calculateStackingShift = (totalChildren, stackingThreshold, nodeWidthWithPadding) => {
13
+ const stackedChildren = Math.max(0, totalChildren - stackingThreshold);
14
+ return stackedChildren * nodeWidthWithPadding / 2;
15
+ };
16
+
17
+ /**
18
+ * Calculates the adjusted position for a node when stacking is enabled
19
+ * @param originalLeft - The original left position of the node
20
+ * @param parentChildren - Array of parent's children (to get total count)
21
+ * @param stackingThreshold - Maximum number of children to display horizontally
22
+ * @param nodeWidthWithPadding - Width of a node including padding
23
+ * @returns The adjusted left position
24
+ */
25
+ export const calculateNodePosition = (originalLeft, parentChildren, stackingThreshold, nodeWidthWithPadding) => {
26
+ if (!parentChildren || parentChildren.length <= stackingThreshold) {
27
+ return originalLeft;
28
+ }
29
+ const stackingShift = calculateStackingShift(parentChildren.length, stackingThreshold, nodeWidthWithPadding);
30
+ return originalLeft + stackingShift;
31
+ };
32
+
33
+ /**
34
+ * Calculates the adjusted x position for a link target when stacking is enabled
35
+ * @param originalX - The original x position of the link target
36
+ * @param sourceChildren - Array of source node's children (to get total count)
37
+ * @param stackingThreshold - Maximum number of children to display horizontally
38
+ * @param nodeWidthWithPadding - Width of a node including padding
39
+ * @returns The adjusted x position
40
+ */
41
+ export const calculateLinkTargetPosition = (originalX, sourceChildren, stackingThreshold, nodeWidthWithPadding) => {
42
+ if (!sourceChildren || sourceChildren.length <= stackingThreshold) {
43
+ return originalX;
44
+ }
45
+ const stackingShift = calculateStackingShift(sourceChildren.length, stackingThreshold, nodeWidthWithPadding);
46
+ return originalX + stackingShift;
47
+ };
48
+
49
+ /**
50
+ * Updates the layout position for a single node in a hierarchical tree with stacking support
51
+ * @param index - The index of the current node in the descendants array (0-based)
52
+ * @param stackingThreshold - Maximum number of nodes to display horizontally before stacking
53
+ * @param nodeWidthWithPadding - Width of a node including its padding for spacing calculations
54
+ * @param stackLocations - Mutable array storing positions of horizontal nodes for stacked node reference
55
+ * @param stackingSpacing - Vertical spacing in pixels between stacked nodes
56
+ * @param top - Initial top position of the node (before stacking adjustments)
57
+ * @param left - Initial left position of the node (before centering/stacking adjustments)
58
+ * @param node - The hierarchy node object containing parent/children relationships
59
+ * @returns Object containing the final calculated { top, left } position for the node
60
+ */
61
+ export const updateNodeLayout = (index, stackingThreshold, nodeWidthWithPadding, stackLocations, stackingSpacing, top, left, node) => {
62
+ if (index <= stackingThreshold) {
63
+ if (index > 0) {
64
+ var _node$parent;
65
+ left = calculateNodePosition(left, (_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.children, stackingThreshold, nodeWidthWithPadding);
66
+ }
67
+
68
+ // Add the stack location to the array so we can reference it later
69
+ stackLocations.push({
70
+ top: top,
71
+ left: left
72
+ });
73
+ } else {
74
+ const stackRefrencePoint = stackLocations[index - stackingThreshold];
75
+ top = stackRefrencePoint.top + stackingSpacing;
76
+ left = stackRefrencePoint.left;
77
+ stackLocations.push({
78
+ top: top,
79
+ left: left
80
+ });
81
+ }
82
+ return {
83
+ top,
84
+ left
85
+ };
86
+ };
@@ -18,6 +18,7 @@ import React from 'react';
18
18
  import { Group } from '@visx/group';
19
19
  import { Tree } from '@visx/hierarchy';
20
20
  import { LinkVerticalStep } from '@visx/shape';
21
+ import { calculateLinkTargetPosition, updateNodeLayout } from './utils';
21
22
  var staticStyles = {
22
23
  hierarchyWrapper: "_kqswh2mm",
23
24
  nodeGroupWrapper: "_kqswstnw",
@@ -26,7 +27,7 @@ var staticStyles = {
26
27
  zoom: "_1tktglyw"
27
28
  };
28
29
  export var CharlieHierarchy = function CharlieHierarchy(props) {
29
- var _props$size$, _props$size, _props$size$2, _props$size2, _props$nodeSize$, _props$nodeSize, _props$nodeSize$2, _props$nodeSize2, _props$top, _props$left, _props$renderDependen, _styles$transformMatr, _props$styles2;
30
+ var _props$size$, _props$size, _props$size$2, _props$size2, _props$nodeSize$, _props$nodeSize, _props$nodeSize$2, _props$nodeSize2, _props$top, _props$left, _props$renderDependen, _props$stackingSpacin, _styles$transformMatr, _props$styles2;
30
31
  var _React$useTransition = React.useTransition(),
31
32
  _React$useTransition2 = _slicedToArray(_React$useTransition, 2),
32
33
  isSuspending = _React$useTransition2[0],
@@ -51,6 +52,8 @@ export var CharlieHierarchy = function CharlieHierarchy(props) {
51
52
  var cursor = zoom !== null && zoom !== void 0 && zoom.isDragging ? 'grabbing' : 'grab';
52
53
  var children = props.children;
53
54
  var renderDependencies = (_props$renderDependen = props.renderDependencies) !== null && _props$renderDependen !== void 0 ? _props$renderDependen : [];
55
+ var stackingThreshold = props.stackingThreshold;
56
+ var stackingSpacing = (_props$stackingSpacin = props.stackingSpacing) !== null && _props$stackingSpacin !== void 0 ? _props$stackingSpacin : 70;
54
57
 
55
58
  /**
56
59
  * If zoom is enabled, we need to apply the transform matrix to the SVG.
@@ -75,6 +78,15 @@ export var CharlieHierarchy = function CharlieHierarchy(props) {
75
78
  }, function (tree) {
76
79
  return /*#__PURE__*/React.createElement(React.Fragment, null, tree.links().map(function (link, linkIndex) {
77
80
  var _props$styles$lineAtt, _props$styles;
81
+ if (stackingThreshold) {
82
+ link.target.x = calculateLinkTargetPosition(link.target.x, link.source.children, stackingThreshold, nodeWidthWithPadding);
83
+
84
+ // For now, don't render links that are beyond the stacking threshold.
85
+ // In the future, we can render the links that are beyond the stacking threshold.
86
+ if (linkIndex > stackingThreshold - 1) {
87
+ return null;
88
+ }
89
+ }
78
90
  return /*#__PURE__*/React.createElement(LinkVerticalStep, _extends({
79
91
  key: "link-".concat(linkIndex),
80
92
  data: link,
@@ -99,9 +111,15 @@ export var CharlieHierarchy = function CharlieHierarchy(props) {
99
111
  nodeSize: nodeSize
100
112
  }, function (tree) {
101
113
  var descendants = tree.descendants();
114
+ var stackLocations = [];
102
115
  return /*#__PURE__*/React.createElement(React.Fragment, null, descendants.map(function (node, index) {
103
116
  var top = node.y - nodeHeight / 2;
104
117
  var left = node.x - nodeWidth / 2;
118
+ if (stackingThreshold) {
119
+ var layout = updateNodeLayout(index, stackingThreshold, nodeWidthWithPadding, stackLocations, stackingSpacing, top, left, node);
120
+ top = layout.top;
121
+ left = layout.left;
122
+ }
105
123
  return /*#__PURE__*/React.createElement("div", {
106
124
  key: "tree-node-".concat(index),
107
125
  style: {
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Utility functions for Charlie Hierarchy component
3
+ */
4
+
5
+ /**
6
+ * Calculates the horizontal shift needed to center nodes when some children are stacked vertically
7
+ * @param totalChildren - Total number of children for a parent node
8
+ * @param stackingThreshold - Maximum number of children to display horizontally
9
+ * @param nodeWidthWithPadding - Width of a node including padding
10
+ * @returns The horizontal offset to apply for centering
11
+ */
12
+ export var calculateStackingShift = function calculateStackingShift(totalChildren, stackingThreshold, nodeWidthWithPadding) {
13
+ var stackedChildren = Math.max(0, totalChildren - stackingThreshold);
14
+ return stackedChildren * nodeWidthWithPadding / 2;
15
+ };
16
+
17
+ /**
18
+ * Calculates the adjusted position for a node when stacking is enabled
19
+ * @param originalLeft - The original left position of the node
20
+ * @param parentChildren - Array of parent's children (to get total count)
21
+ * @param stackingThreshold - Maximum number of children to display horizontally
22
+ * @param nodeWidthWithPadding - Width of a node including padding
23
+ * @returns The adjusted left position
24
+ */
25
+ export var calculateNodePosition = function calculateNodePosition(originalLeft, parentChildren, stackingThreshold, nodeWidthWithPadding) {
26
+ if (!parentChildren || parentChildren.length <= stackingThreshold) {
27
+ return originalLeft;
28
+ }
29
+ var stackingShift = calculateStackingShift(parentChildren.length, stackingThreshold, nodeWidthWithPadding);
30
+ return originalLeft + stackingShift;
31
+ };
32
+
33
+ /**
34
+ * Calculates the adjusted x position for a link target when stacking is enabled
35
+ * @param originalX - The original x position of the link target
36
+ * @param sourceChildren - Array of source node's children (to get total count)
37
+ * @param stackingThreshold - Maximum number of children to display horizontally
38
+ * @param nodeWidthWithPadding - Width of a node including padding
39
+ * @returns The adjusted x position
40
+ */
41
+ export var calculateLinkTargetPosition = function calculateLinkTargetPosition(originalX, sourceChildren, stackingThreshold, nodeWidthWithPadding) {
42
+ if (!sourceChildren || sourceChildren.length <= stackingThreshold) {
43
+ return originalX;
44
+ }
45
+ var stackingShift = calculateStackingShift(sourceChildren.length, stackingThreshold, nodeWidthWithPadding);
46
+ return originalX + stackingShift;
47
+ };
48
+
49
+ /**
50
+ * Updates the layout position for a single node in a hierarchical tree with stacking support
51
+ * @param index - The index of the current node in the descendants array (0-based)
52
+ * @param stackingThreshold - Maximum number of nodes to display horizontally before stacking
53
+ * @param nodeWidthWithPadding - Width of a node including its padding for spacing calculations
54
+ * @param stackLocations - Mutable array storing positions of horizontal nodes for stacked node reference
55
+ * @param stackingSpacing - Vertical spacing in pixels between stacked nodes
56
+ * @param top - Initial top position of the node (before stacking adjustments)
57
+ * @param left - Initial left position of the node (before centering/stacking adjustments)
58
+ * @param node - The hierarchy node object containing parent/children relationships
59
+ * @returns Object containing the final calculated { top, left } position for the node
60
+ */
61
+ export var updateNodeLayout = function updateNodeLayout(index, stackingThreshold, nodeWidthWithPadding, stackLocations, stackingSpacing, top, left, node) {
62
+ if (index <= stackingThreshold) {
63
+ if (index > 0) {
64
+ var _node$parent;
65
+ left = calculateNodePosition(left, (_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.children, stackingThreshold, nodeWidthWithPadding);
66
+ }
67
+
68
+ // Add the stack location to the array so we can reference it later
69
+ stackLocations.push({
70
+ top: top,
71
+ left: left
72
+ });
73
+ } else {
74
+ var stackRefrencePoint = stackLocations[index - stackingThreshold];
75
+ top = stackRefrencePoint.top + stackingSpacing;
76
+ left = stackRefrencePoint.left;
77
+ stackLocations.push({
78
+ top: top,
79
+ left: left
80
+ });
81
+ }
82
+ return {
83
+ top: top,
84
+ left: left
85
+ };
86
+ };
@@ -61,5 +61,15 @@ export interface CharlieHierarchyProps<Datum> extends Omit<TreeProps<Datum>, 'ch
61
61
  * Pass any dependencies that on change should trigger a re-render of the tree.
62
62
  */
63
63
  renderDependencies?: React.DependencyList;
64
+ /**
65
+ * When specified, enables vertical stacking of overflow children.
66
+ * Children beyond this threshold will be stacked vertically under the first child.
67
+ */
68
+ stackingThreshold?: number;
69
+ /**
70
+ * Vertical spacing between stacked nodes in pixels.
71
+ * @default 70
72
+ */
73
+ stackingSpacing?: number;
64
74
  }
65
75
  export declare const CharlieHierarchy: <Datum>(props: CharlieHierarchyProps<Datum>) => JSX.Element;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Utility functions for Charlie Hierarchy component
3
+ */
4
+ import type { HierarchyPointNode } from '@visx/hierarchy/lib/types';
5
+ /**
6
+ * Calculates the horizontal shift needed to center nodes when some children are stacked vertically
7
+ * @param totalChildren - Total number of children for a parent node
8
+ * @param stackingThreshold - Maximum number of children to display horizontally
9
+ * @param nodeWidthWithPadding - Width of a node including padding
10
+ * @returns The horizontal offset to apply for centering
11
+ */
12
+ export declare const calculateStackingShift: (totalChildren: number, stackingThreshold: number, nodeWidthWithPadding: number) => number;
13
+ /**
14
+ * Calculates the adjusted position for a node when stacking is enabled
15
+ * @param originalLeft - The original left position of the node
16
+ * @param parentChildren - Array of parent's children (to get total count)
17
+ * @param stackingThreshold - Maximum number of children to display horizontally
18
+ * @param nodeWidthWithPadding - Width of a node including padding
19
+ * @returns The adjusted left position
20
+ */
21
+ export declare const calculateNodePosition: (originalLeft: number, parentChildren: unknown[] | undefined, stackingThreshold: number, nodeWidthWithPadding: number) => number;
22
+ /**
23
+ * Calculates the adjusted x position for a link target when stacking is enabled
24
+ * @param originalX - The original x position of the link target
25
+ * @param sourceChildren - Array of source node's children (to get total count)
26
+ * @param stackingThreshold - Maximum number of children to display horizontally
27
+ * @param nodeWidthWithPadding - Width of a node including padding
28
+ * @returns The adjusted x position
29
+ */
30
+ export declare const calculateLinkTargetPosition: (originalX: number, sourceChildren: unknown[] | undefined, stackingThreshold: number, nodeWidthWithPadding: number) => number;
31
+ /**
32
+ * Updates the layout position for a single node in a hierarchical tree with stacking support
33
+ * @param index - The index of the current node in the descendants array (0-based)
34
+ * @param stackingThreshold - Maximum number of nodes to display horizontally before stacking
35
+ * @param nodeWidthWithPadding - Width of a node including its padding for spacing calculations
36
+ * @param stackLocations - Mutable array storing positions of horizontal nodes for stacked node reference
37
+ * @param stackingSpacing - Vertical spacing in pixels between stacked nodes
38
+ * @param top - Initial top position of the node (before stacking adjustments)
39
+ * @param left - Initial left position of the node (before centering/stacking adjustments)
40
+ * @param node - The hierarchy node object containing parent/children relationships
41
+ * @returns Object containing the final calculated { top, left } position for the node
42
+ */
43
+ export declare const updateNodeLayout: <Datum>(index: number, stackingThreshold: number, nodeWidthWithPadding: number, stackLocations: {
44
+ top: number;
45
+ left: number;
46
+ }[], stackingSpacing: number, top: number, left: number, node: HierarchyPointNode<Datum>) => {
47
+ top: number;
48
+ left: number;
49
+ };
@@ -61,5 +61,15 @@ export interface CharlieHierarchyProps<Datum> extends Omit<TreeProps<Datum>, 'ch
61
61
  * Pass any dependencies that on change should trigger a re-render of the tree.
62
62
  */
63
63
  renderDependencies?: React.DependencyList;
64
+ /**
65
+ * When specified, enables vertical stacking of overflow children.
66
+ * Children beyond this threshold will be stacked vertically under the first child.
67
+ */
68
+ stackingThreshold?: number;
69
+ /**
70
+ * Vertical spacing between stacked nodes in pixels.
71
+ * @default 70
72
+ */
73
+ stackingSpacing?: number;
64
74
  }
65
75
  export declare const CharlieHierarchy: <Datum>(props: CharlieHierarchyProps<Datum>) => JSX.Element;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Utility functions for Charlie Hierarchy component
3
+ */
4
+ import type { HierarchyPointNode } from '@visx/hierarchy/lib/types';
5
+ /**
6
+ * Calculates the horizontal shift needed to center nodes when some children are stacked vertically
7
+ * @param totalChildren - Total number of children for a parent node
8
+ * @param stackingThreshold - Maximum number of children to display horizontally
9
+ * @param nodeWidthWithPadding - Width of a node including padding
10
+ * @returns The horizontal offset to apply for centering
11
+ */
12
+ export declare const calculateStackingShift: (totalChildren: number, stackingThreshold: number, nodeWidthWithPadding: number) => number;
13
+ /**
14
+ * Calculates the adjusted position for a node when stacking is enabled
15
+ * @param originalLeft - The original left position of the node
16
+ * @param parentChildren - Array of parent's children (to get total count)
17
+ * @param stackingThreshold - Maximum number of children to display horizontally
18
+ * @param nodeWidthWithPadding - Width of a node including padding
19
+ * @returns The adjusted left position
20
+ */
21
+ export declare const calculateNodePosition: (originalLeft: number, parentChildren: unknown[] | undefined, stackingThreshold: number, nodeWidthWithPadding: number) => number;
22
+ /**
23
+ * Calculates the adjusted x position for a link target when stacking is enabled
24
+ * @param originalX - The original x position of the link target
25
+ * @param sourceChildren - Array of source node's children (to get total count)
26
+ * @param stackingThreshold - Maximum number of children to display horizontally
27
+ * @param nodeWidthWithPadding - Width of a node including padding
28
+ * @returns The adjusted x position
29
+ */
30
+ export declare const calculateLinkTargetPosition: (originalX: number, sourceChildren: unknown[] | undefined, stackingThreshold: number, nodeWidthWithPadding: number) => number;
31
+ /**
32
+ * Updates the layout position for a single node in a hierarchical tree with stacking support
33
+ * @param index - The index of the current node in the descendants array (0-based)
34
+ * @param stackingThreshold - Maximum number of nodes to display horizontally before stacking
35
+ * @param nodeWidthWithPadding - Width of a node including its padding for spacing calculations
36
+ * @param stackLocations - Mutable array storing positions of horizontal nodes for stacked node reference
37
+ * @param stackingSpacing - Vertical spacing in pixels between stacked nodes
38
+ * @param top - Initial top position of the node (before stacking adjustments)
39
+ * @param left - Initial left position of the node (before centering/stacking adjustments)
40
+ * @param node - The hierarchy node object containing parent/children relationships
41
+ * @returns Object containing the final calculated { top, left } position for the node
42
+ */
43
+ export declare const updateNodeLayout: <Datum>(index: number, stackingThreshold: number, nodeWidthWithPadding: number, stackLocations: {
44
+ top: number;
45
+ left: number;
46
+ }[], stackingSpacing: number, top: number, left: number, node: HierarchyPointNode<Datum>) => {
47
+ top: number;
48
+ left: number;
49
+ };
package/package.json CHANGED
@@ -23,14 +23,12 @@
23
23
  "*.compiled.css"
24
24
  ],
25
25
  "atlaskit:src": "src/index.ts",
26
- "af:exports": {
27
- ".": "./src/index.ts"
28
- },
29
26
  "dependencies": {
30
- "@atlaskit/button": "^23.3.0",
27
+ "@atlaskit/button": "^23.4.0",
31
28
  "@atlaskit/css": "^0.12.0",
32
- "@atlaskit/primitives": "^14.11.0",
33
- "@atlaskit/tokens": "^6.0.0",
29
+ "@atlaskit/primitives": "^14.12.0",
30
+ "@atlaskit/range": "^9.2.0",
31
+ "@atlaskit/tokens": "^6.1.0",
34
32
  "@babel/runtime": "^7.0.0",
35
33
  "@compiled/react": "^0.18.3",
36
34
  "@visx/group": "^1.7.0",
@@ -46,7 +44,6 @@
46
44
  "@af/integration-testing": "workspace:^",
47
45
  "@af/visual-regression": "workspace:^",
48
46
  "@atlaskit/ssr": "workspace:^",
49
- "@atlaskit/visual-regression": "workspace:^",
50
47
  "@testing-library/react": "^13.4.0",
51
48
  "react-dom": "^18.2.0"
52
49
  },
@@ -94,7 +91,7 @@
94
91
  ]
95
92
  },
96
93
  "name": "@atlaskit/charlie-hierarchy",
97
- "version": "0.1.0",
94
+ "version": "0.1.2",
98
95
  "description": "A component for building SVG-rendered trees, with support for custom node rendering, zooming, and panning.",
99
96
  "author": "Atlassian Pty Ltd",
100
97
  "license": "Apache-2.0",