funda-ui 4.7.181 → 4.7.185

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/Tree/index.d.ts CHANGED
@@ -70,5 +70,9 @@ export declare type TreeProps = {
70
70
  onCollapse?: (e: React.MouseEvent<HTMLElement>, val: ItemConfig, updateData: UpdateDataFunction, isExpanded: boolean) => void;
71
71
  onCheck?: (val: any) => void;
72
72
  };
73
- declare const Tree: (props: TreeProps) => JSX.Element;
73
+ export interface TreeRef {
74
+ collapse: (slug: string) => void;
75
+ updateParentTreeHeights: (targetElement: HTMLElement) => Promise<void>;
76
+ }
77
+ declare const Tree: React.ForwardRefExoticComponent<TreeProps & React.RefAttributes<TreeRef>>;
74
78
  export default Tree;
package/Tree/index.js CHANGED
@@ -1139,8 +1139,8 @@ function TreeList(props) {
1139
1139
  expandedMap = props.expandedMap,
1140
1140
  onSelect = props.onSelect,
1141
1141
  onDoubleSelect = props.onDoubleSelect,
1142
- onCollapse = props.onCollapse,
1143
1142
  onCheck = props.onCheck,
1143
+ evCollapse = props.evCollapse,
1144
1144
  evInitValue = props.evInitValue;
1145
1145
  var rootRef = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useRef)(null);
1146
1146
  var mergedData = data === null ? [] : data.map(function (item) {
@@ -1321,7 +1321,7 @@ function TreeList(props) {
1321
1321
  }, _callee);
1322
1322
  })));
1323
1323
  if (disableArrow) {
1324
- onCollapse === null || onCollapse === void 0 ? void 0 : onCollapse(e);
1324
+ evCollapse === null || evCollapse === void 0 ? void 0 : evCollapse(e);
1325
1325
  }
1326
1326
  }
1327
1327
  function handleDoubleSelect(e) {
@@ -1358,7 +1358,7 @@ function TreeList(props) {
1358
1358
  }, _callee2);
1359
1359
  })));
1360
1360
  if (disableArrow) {
1361
- onCollapse === null || onCollapse === void 0 ? void 0 : onCollapse(e);
1361
+ evCollapse === null || evCollapse === void 0 ? void 0 : evCollapse(e);
1362
1362
  }
1363
1363
  }
1364
1364
  function titleArrowGenerator() {
@@ -1527,7 +1527,7 @@ function TreeList(props) {
1527
1527
  }, item.children && item.children.length || item.childrenAsync ? /*#__PURE__*/external_root_React_commonjs2_react_commonjs_react_amd_react_default().createElement("span", {
1528
1528
  "aria-expanded": JSON.parse(optiondata).isExpanded || item.active ? 'true' : 'false',
1529
1529
  className: item.active ? "arrow active ".concat(_async, " ").concat(_cusIcons) : "arrow ".concat(_async, " ").concat(_cusIcons),
1530
- onClick: onCollapse,
1530
+ onClick: evCollapse,
1531
1531
  "data-link": item.link,
1532
1532
  "data-slug": item.slug,
1533
1533
  "data-key": item.key,
@@ -1614,7 +1614,7 @@ function TreeList(props) {
1614
1614
  // Collapse
1615
1615
  ,
1616
1616
  expandedMap: expandedMap,
1617
- onCollapse: onCollapse
1617
+ evCollapse: evCollapse
1618
1618
  }));
1619
1619
  })));
1620
1620
  } else {
@@ -1622,7 +1622,7 @@ function TreeList(props) {
1622
1622
  }
1623
1623
  }
1624
1624
  ;// CONCATENATED MODULE: ./src/index.tsx
1625
- function src_createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = src_unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (_e2) { function e(_x9) { return _e2.apply(this, arguments); } e.toString = function () { return _e2.toString(); }; return e; }(function (e) { throw e; }), f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function (_e3) { function e(_x10) { return _e3.apply(this, arguments); } e.toString = function () { return _e3.toString(); }; return e; }(function (e) { didErr = true; err = e; }), f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
1625
+ function src_createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = src_unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (_e2) { function e(_x10) { return _e2.apply(this, arguments); } e.toString = function () { return _e2.toString(); }; return e; }(function (e) { throw e; }), f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function (_e3) { function e(_x11) { return _e3.apply(this, arguments); } e.toString = function () { return _e3.toString(); }; return e; }(function (e) { didErr = true; err = e; }), f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
1626
1626
  function src_typeof(obj) { "@babel/helpers - typeof"; return src_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, src_typeof(obj); }
1627
1627
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || src_unsupportedIterableToArray(arr) || _nonIterableSpread(); }
1628
1628
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
@@ -1649,7 +1649,7 @@ function src_arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
1649
1649
 
1650
1650
 
1651
1651
 
1652
- var Tree = function Tree(props) {
1652
+ var Tree = /*#__PURE__*/(0,external_root_React_commonjs2_react_commonjs_react_amd_react_.forwardRef)(function (props, ref) {
1653
1653
  var id = props.id,
1654
1654
  checkable = props.checkable,
1655
1655
  showLine = props.showLine,
@@ -1719,6 +1719,7 @@ var Tree = function Tree(props) {
1719
1719
  if (!rootRef.current) return;
1720
1720
  var observer = new MutationObserver(function (mutations) {
1721
1721
  // Check whether any new ul elements have been added
1722
+ // Changes of <li> are captured by changes in their parent <ul>
1722
1723
  var hasNewUL = mutations.some(function (mutation) {
1723
1724
  return Array.from(mutation.addedNodes).some(function (node) {
1724
1725
  return node.nodeName === 'UL';
@@ -1731,9 +1732,15 @@ var Tree = function Tree(props) {
1731
1732
  });
1732
1733
  observer.observe(rootRef.current, {
1733
1734
  childList: true,
1734
- subtree: true
1735
+ // Observe the addition or deletion of child nodes
1736
+ subtree: true,
1737
+ // Observe all descendant nodes
1738
+ attributes: false,
1739
+ // Do not observe attribute changes
1740
+ characterData: false // Do not observe text content changes
1735
1741
  });
1736
1742
  };
1743
+
1737
1744
  var updateTreeData = /*#__PURE__*/function () {
1738
1745
  var _ref = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee2(list, key, children) {
1739
1746
  var updatedList;
@@ -1820,11 +1827,23 @@ var Tree = function Tree(props) {
1820
1827
  // init <ul> height
1821
1828
  initUlHeight(ul);
1822
1829
  };
1823
- function handleCollapse(e) {
1830
+ function handleCollapse(e, slug) {
1824
1831
  if (disableCollapse) return;
1825
- e.preventDefault();
1826
- e.stopPropagation();
1827
- var hyperlink = e.currentTarget;
1832
+ if (e) {
1833
+ e.preventDefault();
1834
+ e.stopPropagation();
1835
+ }
1836
+ var hyperlink;
1837
+ if (e) {
1838
+ hyperlink = e.currentTarget;
1839
+ } else if (slug && rootRef.current) {
1840
+ // Find the hyperlink element by slug
1841
+ var linkElement = rootRef.current.querySelector("[data-slug=\"".concat(slug, "\"]"));
1842
+ if (!linkElement) return;
1843
+ hyperlink = linkElement;
1844
+ } else {
1845
+ return;
1846
+ }
1828
1847
  var url = hyperlink.dataset.href;
1829
1848
  var subElement = (0,dom.getNextSiblings)(hyperlink, 'ul');
1830
1849
  var asyncReqReady = hyperlink.classList.contains('async-ready');
@@ -1897,26 +1916,102 @@ var Tree = function Tree(props) {
1897
1916
  closeChild(hyperlink, subElement);
1898
1917
  }
1899
1918
  }
1900
- function fetchData(_x6, _x7) {
1919
+ var observeElement = function observeElement(ancestorNode) {
1920
+ return new Promise(function (resolve) {
1921
+ var observer = new MutationObserver(function (mutations) {
1922
+ // Check whether any new ul elements have been added
1923
+ // It is necessary to listen for <li> because <li> may be added dynamically in the business
1924
+ var hasNewUL = mutations.some(function (mutation) {
1925
+ return Array.from(mutation.addedNodes).some(function (node) {
1926
+ return node.nodeName === 'UL' || node.nodeName === 'LI';
1927
+ });
1928
+ });
1929
+ if (hasNewUL) {
1930
+ observer.disconnect();
1931
+ var ul = [].slice.call(ancestorNode.querySelectorAll('ul'));
1932
+ initAsyncItems(ul).then(function () {
1933
+ initUlHeight(ul);
1934
+ });
1935
+ resolve();
1936
+ }
1937
+ });
1938
+ observer.observe(ancestorNode, {
1939
+ childList: true,
1940
+ // Observe the addition or deletion of child nodes
1941
+ subtree: true,
1942
+ // Observe all descendant nodes
1943
+ attributes: false,
1944
+ // Do not observe attribute changes
1945
+ characterData: false // Do not observe text content changes
1946
+ });
1947
+ });
1948
+ };
1949
+
1950
+ // exposes the following methods
1951
+ (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useImperativeHandle)(ref, function () {
1952
+ return {
1953
+ collapse: function collapse(slug) {
1954
+ handleCollapse(undefined, slug);
1955
+ },
1956
+ updateParentTreeHeights: function () {
1957
+ var _updateParentTreeHeights = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee5(targetElement) {
1958
+ var _ancestorNode;
1959
+ return src_regeneratorRuntime().wrap(function _callee5$(_context5) {
1960
+ while (1) switch (_context5.prev = _context5.next) {
1961
+ case 0:
1962
+ if (!(targetElement !== null)) {
1963
+ _context5.next = 11;
1964
+ break;
1965
+ }
1966
+ // Find the topmost node, in order to fix the subtree height under this node
1967
+ _ancestorNode = targetElement.closest('.nav-item.first');
1968
+ if (!(_ancestorNode !== null)) {
1969
+ _context5.next = 11;
1970
+ break;
1971
+ }
1972
+ _context5.prev = 3;
1973
+ _context5.next = 6;
1974
+ return observeElement(_ancestorNode);
1975
+ case 6:
1976
+ _context5.next = 11;
1977
+ break;
1978
+ case 8:
1979
+ _context5.prev = 8;
1980
+ _context5.t0 = _context5["catch"](3);
1981
+ console.warn('Failed to update ul height:', _context5.t0);
1982
+ case 11:
1983
+ case "end":
1984
+ return _context5.stop();
1985
+ }
1986
+ }, _callee5, null, [[3, 8]]);
1987
+ }));
1988
+ function updateParentTreeHeights(_x6) {
1989
+ return _updateParentTreeHeights.apply(this, arguments);
1990
+ }
1991
+ return updateParentTreeHeights;
1992
+ }()
1993
+ };
1994
+ }, [rootRef.current, onCollapse]); // !Required "onCollapse"
1995
+ function fetchData(_x7, _x8) {
1901
1996
  return _fetchData.apply(this, arguments);
1902
1997
  }
1903
1998
  function _fetchData() {
1904
- _fetchData = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee5(fetch, params) {
1999
+ _fetchData = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee6(fetch, params) {
1905
2000
  var _fetch$fetchFuncAsync, response, _ORGIN_DATA;
1906
- return src_regeneratorRuntime().wrap(function _callee5$(_context5) {
1907
- while (1) switch (_context5.prev = _context5.next) {
2001
+ return src_regeneratorRuntime().wrap(function _callee6$(_context6) {
2002
+ while (1) switch (_context6.prev = _context6.next) {
1908
2003
  case 0:
1909
2004
  if (!(src_typeof(fetch.fetchFuncAsync) === 'object')) {
1910
- _context5.next = 14;
2005
+ _context6.next = 14;
1911
2006
  break;
1912
2007
  }
1913
- _context5.next = 3;
2008
+ _context6.next = 3;
1914
2009
  return (_fetch$fetchFuncAsync = fetch.fetchFuncAsync)["".concat(fetch.fetchFuncMethod)].apply(_fetch$fetchFuncAsync, _toConsumableArray(params.split(',')));
1915
2010
  case 3:
1916
- response = _context5.sent;
2011
+ response = _context6.sent;
1917
2012
  _ORGIN_DATA = response.data;
1918
2013
  if (!(Array.isArray(_ORGIN_DATA) && _ORGIN_DATA.length > 0)) {
1919
- _context5.next = 11;
2014
+ _context6.next = 11;
1920
2015
  break;
1921
2016
  }
1922
2017
  // reset data structure
@@ -1929,19 +2024,19 @@ var Tree = function Tree(props) {
1929
2024
  console.warn('The data structure does not match, please refer to the example in the component documentation.');
1930
2025
  _ORGIN_DATA = [];
1931
2026
  }
1932
- return _context5.abrupt("return", _ORGIN_DATA);
2027
+ return _context6.abrupt("return", _ORGIN_DATA);
1933
2028
  case 11:
1934
- return _context5.abrupt("return", []);
2029
+ return _context6.abrupt("return", []);
1935
2030
  case 12:
1936
- _context5.next = 15;
2031
+ _context6.next = 15;
1937
2032
  break;
1938
2033
  case 14:
1939
- return _context5.abrupt("return", []);
2034
+ return _context6.abrupt("return", []);
1940
2035
  case 15:
1941
2036
  case "end":
1942
- return _context5.stop();
2037
+ return _context6.stop();
1943
2038
  }
1944
- }, _callee5);
2039
+ }, _callee6);
1945
2040
  }));
1946
2041
  return _fetchData.apply(this, arguments);
1947
2042
  }
@@ -2010,11 +2105,11 @@ var Tree = function Tree(props) {
2010
2105
  }
2011
2106
  });
2012
2107
  }
2013
- function initDefaultValue(_x8) {
2108
+ function initDefaultValue(_x9) {
2014
2109
  return _initDefaultValue.apply(this, arguments);
2015
2110
  }
2016
2111
  function _initDefaultValue() {
2017
- _initDefaultValue = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee6(key) {
2112
+ _initDefaultValue = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee7(key) {
2018
2113
  var fetch,
2019
2114
  firstRender,
2020
2115
  retrieveData,
@@ -2025,15 +2120,16 @@ var Tree = function Tree(props) {
2025
2120
  _childrenData,
2026
2121
  findAndUpdateNode,
2027
2122
  _clone2,
2028
- _args6 = arguments;
2029
- return src_regeneratorRuntime().wrap(function _callee6$(_context6) {
2030
- while (1) switch (_context6.prev = _context6.next) {
2123
+ _findAndUpdateNode,
2124
+ _args7 = arguments;
2125
+ return src_regeneratorRuntime().wrap(function _callee7$(_context7) {
2126
+ while (1) switch (_context7.prev = _context7.next) {
2031
2127
  case 0:
2032
- fetch = _args6.length > 1 && _args6[1] !== undefined ? _args6[1] : null;
2033
- firstRender = _args6.length > 2 && _args6[2] !== undefined ? _args6[2] : false;
2034
- retrieveData = _args6.length > 3 && _args6[3] !== undefined ? _args6[3] : [];
2128
+ fetch = _args7.length > 1 && _args7[1] !== undefined ? _args7[1] : null;
2129
+ firstRender = _args7.length > 2 && _args7[2] !== undefined ? _args7[2] : false;
2130
+ retrieveData = _args7.length > 3 && _args7[3] !== undefined ? _args7[3] : [];
2035
2131
  if (!firstRender) {
2036
- _context6.next = 11;
2132
+ _context7.next = 11;
2037
2133
  break;
2038
2134
  }
2039
2135
  addKey(data, '', 0);
@@ -2057,27 +2153,27 @@ var Tree = function Tree(props) {
2057
2153
  // update retrive list
2058
2154
  _clone = (0,object.deepClone)(data);
2059
2155
  setFlatList((0,object.flatData)(_clone));
2060
- return _context6.abrupt("return", data);
2156
+ return _context7.abrupt("return", data);
2061
2157
  case 11:
2062
2158
  if (!(fetch && src_typeof(fetch.fetchFuncAsync) === 'object')) {
2063
- _context6.next = 31;
2159
+ _context7.next = 34;
2064
2160
  break;
2065
2161
  }
2066
2162
  _newData = list; //
2067
2163
  _params = fetch.fetchFuncMethodParams || [];
2068
- _context6.next = 16;
2164
+ _context7.next = 16;
2069
2165
  return fetchData(fetch, _params.join(','));
2070
2166
  case 16:
2071
- response = _context6.sent;
2167
+ response = _context7.sent;
2072
2168
  _childrenData = response;
2073
2169
  if (!(_childrenData.length > 0)) {
2074
- _context6.next = 29;
2170
+ _context7.next = 31;
2075
2171
  break;
2076
2172
  }
2077
- _context6.next = 21;
2173
+ _context7.next = 21;
2078
2174
  return updateTreeData(list, key ? key : '', _childrenData);
2079
2175
  case 21:
2080
- _newData = _context6.sent;
2176
+ _newData = _context7.sent;
2081
2177
  // set its childrenAsync property to false and active to true since we've successfully loaded its children
2082
2178
  if (key) {
2083
2179
  findAndUpdateNode = function findAndUpdateNode(nodes) {
@@ -2134,15 +2230,48 @@ var Tree = function Tree(props) {
2134
2230
  // update retrive list
2135
2231
  _clone2 = (0,object.deepClone)(_newData);
2136
2232
  setFlatList((0,object.flatData)(_clone2));
2137
- case 29:
2233
+ _context7.next = 32;
2234
+ break;
2235
+ case 31:
2236
+ // If empty response, remove loading state and set childrenAsync to false
2237
+ if (key) {
2238
+ _findAndUpdateNode = function _findAndUpdateNode(nodes) {
2239
+ var _iterator2 = src_createForOfIteratorHelper(nodes),
2240
+ _step2;
2241
+ try {
2242
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
2243
+ var node = _step2.value;
2244
+ if (node.key === key) {
2245
+ var _rootRef$current;
2246
+ node.childrenAsync = false;
2247
+ // Remove loading class from the hyperlink element
2248
+ var linkElement = (_rootRef$current = rootRef.current) === null || _rootRef$current === void 0 ? void 0 : _rootRef$current.querySelector("[data-key=\"".concat(key, "\"]"));
2249
+ if (linkElement) {
2250
+ activeClass(linkElement, 'remove', 'loading');
2251
+ }
2252
+ break;
2253
+ }
2254
+ if (node.children) {
2255
+ _findAndUpdateNode(node.children);
2256
+ }
2257
+ }
2258
+ } catch (err) {
2259
+ _iterator2.e(err);
2260
+ } finally {
2261
+ _iterator2.f();
2262
+ }
2263
+ };
2264
+ _findAndUpdateNode(_newData);
2265
+ }
2266
+ case 32:
2138
2267
  // dom init
2139
2268
  observeDOMChanges();
2140
- return _context6.abrupt("return", _newData);
2141
- case 31:
2269
+ return _context7.abrupt("return", _newData);
2270
+ case 34:
2142
2271
  case "end":
2143
- return _context6.stop();
2272
+ return _context7.stop();
2144
2273
  }
2145
- }, _callee6);
2274
+ }, _callee7);
2146
2275
  }));
2147
2276
  return _initDefaultValue.apply(this, arguments);
2148
2277
  }
@@ -2189,9 +2318,9 @@ var Tree = function Tree(props) {
2189
2318
  // Collapse
2190
2319
  ,
2191
2320
  expandedMap: expandedMap,
2192
- onCollapse: handleCollapse
2321
+ evCollapse: handleCollapse
2193
2322
  })));
2194
- };
2323
+ });
2195
2324
  /* harmony default export */ const src = (Tree);
2196
2325
  })();
2197
2326
 
@@ -70,5 +70,9 @@ export declare type TreeProps = {
70
70
  onCollapse?: (e: React.MouseEvent<HTMLElement>, val: ItemConfig, updateData: UpdateDataFunction, isExpanded: boolean) => void;
71
71
  onCheck?: (val: any) => void;
72
72
  };
73
- declare const Tree: (props: TreeProps) => JSX.Element;
73
+ export interface TreeRef {
74
+ collapse: (slug: string) => void;
75
+ updateParentTreeHeights: (targetElement: HTMLElement) => Promise<void>;
76
+ }
77
+ declare const Tree: React.ForwardRefExoticComponent<TreeProps & React.RefAttributes<TreeRef>>;
74
78
  export default Tree;
@@ -1139,8 +1139,8 @@ function TreeList(props) {
1139
1139
  expandedMap = props.expandedMap,
1140
1140
  onSelect = props.onSelect,
1141
1141
  onDoubleSelect = props.onDoubleSelect,
1142
- onCollapse = props.onCollapse,
1143
1142
  onCheck = props.onCheck,
1143
+ evCollapse = props.evCollapse,
1144
1144
  evInitValue = props.evInitValue;
1145
1145
  var rootRef = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useRef)(null);
1146
1146
  var mergedData = data === null ? [] : data.map(function (item) {
@@ -1321,7 +1321,7 @@ function TreeList(props) {
1321
1321
  }, _callee);
1322
1322
  })));
1323
1323
  if (disableArrow) {
1324
- onCollapse === null || onCollapse === void 0 ? void 0 : onCollapse(e);
1324
+ evCollapse === null || evCollapse === void 0 ? void 0 : evCollapse(e);
1325
1325
  }
1326
1326
  }
1327
1327
  function handleDoubleSelect(e) {
@@ -1358,7 +1358,7 @@ function TreeList(props) {
1358
1358
  }, _callee2);
1359
1359
  })));
1360
1360
  if (disableArrow) {
1361
- onCollapse === null || onCollapse === void 0 ? void 0 : onCollapse(e);
1361
+ evCollapse === null || evCollapse === void 0 ? void 0 : evCollapse(e);
1362
1362
  }
1363
1363
  }
1364
1364
  function titleArrowGenerator() {
@@ -1527,7 +1527,7 @@ function TreeList(props) {
1527
1527
  }, item.children && item.children.length || item.childrenAsync ? /*#__PURE__*/external_root_React_commonjs2_react_commonjs_react_amd_react_default().createElement("span", {
1528
1528
  "aria-expanded": JSON.parse(optiondata).isExpanded || item.active ? 'true' : 'false',
1529
1529
  className: item.active ? "arrow active ".concat(_async, " ").concat(_cusIcons) : "arrow ".concat(_async, " ").concat(_cusIcons),
1530
- onClick: onCollapse,
1530
+ onClick: evCollapse,
1531
1531
  "data-link": item.link,
1532
1532
  "data-slug": item.slug,
1533
1533
  "data-key": item.key,
@@ -1614,7 +1614,7 @@ function TreeList(props) {
1614
1614
  // Collapse
1615
1615
  ,
1616
1616
  expandedMap: expandedMap,
1617
- onCollapse: onCollapse
1617
+ evCollapse: evCollapse
1618
1618
  }));
1619
1619
  })));
1620
1620
  } else {
@@ -1622,7 +1622,7 @@ function TreeList(props) {
1622
1622
  }
1623
1623
  }
1624
1624
  ;// CONCATENATED MODULE: ./src/index.tsx
1625
- function src_createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = src_unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (_e2) { function e(_x9) { return _e2.apply(this, arguments); } e.toString = function () { return _e2.toString(); }; return e; }(function (e) { throw e; }), f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function (_e3) { function e(_x10) { return _e3.apply(this, arguments); } e.toString = function () { return _e3.toString(); }; return e; }(function (e) { didErr = true; err = e; }), f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
1625
+ function src_createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = src_unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (_e2) { function e(_x10) { return _e2.apply(this, arguments); } e.toString = function () { return _e2.toString(); }; return e; }(function (e) { throw e; }), f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function (_e3) { function e(_x11) { return _e3.apply(this, arguments); } e.toString = function () { return _e3.toString(); }; return e; }(function (e) { didErr = true; err = e; }), f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
1626
1626
  function src_typeof(obj) { "@babel/helpers - typeof"; return src_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, src_typeof(obj); }
1627
1627
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || src_unsupportedIterableToArray(arr) || _nonIterableSpread(); }
1628
1628
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
@@ -1649,7 +1649,7 @@ function src_arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
1649
1649
 
1650
1650
 
1651
1651
 
1652
- var Tree = function Tree(props) {
1652
+ var Tree = /*#__PURE__*/(0,external_root_React_commonjs2_react_commonjs_react_amd_react_.forwardRef)(function (props, ref) {
1653
1653
  var id = props.id,
1654
1654
  checkable = props.checkable,
1655
1655
  showLine = props.showLine,
@@ -1719,6 +1719,7 @@ var Tree = function Tree(props) {
1719
1719
  if (!rootRef.current) return;
1720
1720
  var observer = new MutationObserver(function (mutations) {
1721
1721
  // Check whether any new ul elements have been added
1722
+ // Changes of <li> are captured by changes in their parent <ul>
1722
1723
  var hasNewUL = mutations.some(function (mutation) {
1723
1724
  return Array.from(mutation.addedNodes).some(function (node) {
1724
1725
  return node.nodeName === 'UL';
@@ -1731,9 +1732,15 @@ var Tree = function Tree(props) {
1731
1732
  });
1732
1733
  observer.observe(rootRef.current, {
1733
1734
  childList: true,
1734
- subtree: true
1735
+ // Observe the addition or deletion of child nodes
1736
+ subtree: true,
1737
+ // Observe all descendant nodes
1738
+ attributes: false,
1739
+ // Do not observe attribute changes
1740
+ characterData: false // Do not observe text content changes
1735
1741
  });
1736
1742
  };
1743
+
1737
1744
  var updateTreeData = /*#__PURE__*/function () {
1738
1745
  var _ref = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee2(list, key, children) {
1739
1746
  var updatedList;
@@ -1820,11 +1827,23 @@ var Tree = function Tree(props) {
1820
1827
  // init <ul> height
1821
1828
  initUlHeight(ul);
1822
1829
  };
1823
- function handleCollapse(e) {
1830
+ function handleCollapse(e, slug) {
1824
1831
  if (disableCollapse) return;
1825
- e.preventDefault();
1826
- e.stopPropagation();
1827
- var hyperlink = e.currentTarget;
1832
+ if (e) {
1833
+ e.preventDefault();
1834
+ e.stopPropagation();
1835
+ }
1836
+ var hyperlink;
1837
+ if (e) {
1838
+ hyperlink = e.currentTarget;
1839
+ } else if (slug && rootRef.current) {
1840
+ // Find the hyperlink element by slug
1841
+ var linkElement = rootRef.current.querySelector("[data-slug=\"".concat(slug, "\"]"));
1842
+ if (!linkElement) return;
1843
+ hyperlink = linkElement;
1844
+ } else {
1845
+ return;
1846
+ }
1828
1847
  var url = hyperlink.dataset.href;
1829
1848
  var subElement = (0,dom.getNextSiblings)(hyperlink, 'ul');
1830
1849
  var asyncReqReady = hyperlink.classList.contains('async-ready');
@@ -1897,26 +1916,102 @@ var Tree = function Tree(props) {
1897
1916
  closeChild(hyperlink, subElement);
1898
1917
  }
1899
1918
  }
1900
- function fetchData(_x6, _x7) {
1919
+ var observeElement = function observeElement(ancestorNode) {
1920
+ return new Promise(function (resolve) {
1921
+ var observer = new MutationObserver(function (mutations) {
1922
+ // Check whether any new ul elements have been added
1923
+ // It is necessary to listen for <li> because <li> may be added dynamically in the business
1924
+ var hasNewUL = mutations.some(function (mutation) {
1925
+ return Array.from(mutation.addedNodes).some(function (node) {
1926
+ return node.nodeName === 'UL' || node.nodeName === 'LI';
1927
+ });
1928
+ });
1929
+ if (hasNewUL) {
1930
+ observer.disconnect();
1931
+ var ul = [].slice.call(ancestorNode.querySelectorAll('ul'));
1932
+ initAsyncItems(ul).then(function () {
1933
+ initUlHeight(ul);
1934
+ });
1935
+ resolve();
1936
+ }
1937
+ });
1938
+ observer.observe(ancestorNode, {
1939
+ childList: true,
1940
+ // Observe the addition or deletion of child nodes
1941
+ subtree: true,
1942
+ // Observe all descendant nodes
1943
+ attributes: false,
1944
+ // Do not observe attribute changes
1945
+ characterData: false // Do not observe text content changes
1946
+ });
1947
+ });
1948
+ };
1949
+
1950
+ // exposes the following methods
1951
+ (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useImperativeHandle)(ref, function () {
1952
+ return {
1953
+ collapse: function collapse(slug) {
1954
+ handleCollapse(undefined, slug);
1955
+ },
1956
+ updateParentTreeHeights: function () {
1957
+ var _updateParentTreeHeights = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee5(targetElement) {
1958
+ var _ancestorNode;
1959
+ return src_regeneratorRuntime().wrap(function _callee5$(_context5) {
1960
+ while (1) switch (_context5.prev = _context5.next) {
1961
+ case 0:
1962
+ if (!(targetElement !== null)) {
1963
+ _context5.next = 11;
1964
+ break;
1965
+ }
1966
+ // Find the topmost node, in order to fix the subtree height under this node
1967
+ _ancestorNode = targetElement.closest('.nav-item.first');
1968
+ if (!(_ancestorNode !== null)) {
1969
+ _context5.next = 11;
1970
+ break;
1971
+ }
1972
+ _context5.prev = 3;
1973
+ _context5.next = 6;
1974
+ return observeElement(_ancestorNode);
1975
+ case 6:
1976
+ _context5.next = 11;
1977
+ break;
1978
+ case 8:
1979
+ _context5.prev = 8;
1980
+ _context5.t0 = _context5["catch"](3);
1981
+ console.warn('Failed to update ul height:', _context5.t0);
1982
+ case 11:
1983
+ case "end":
1984
+ return _context5.stop();
1985
+ }
1986
+ }, _callee5, null, [[3, 8]]);
1987
+ }));
1988
+ function updateParentTreeHeights(_x6) {
1989
+ return _updateParentTreeHeights.apply(this, arguments);
1990
+ }
1991
+ return updateParentTreeHeights;
1992
+ }()
1993
+ };
1994
+ }, [rootRef.current, onCollapse]); // !Required "onCollapse"
1995
+ function fetchData(_x7, _x8) {
1901
1996
  return _fetchData.apply(this, arguments);
1902
1997
  }
1903
1998
  function _fetchData() {
1904
- _fetchData = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee5(fetch, params) {
1999
+ _fetchData = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee6(fetch, params) {
1905
2000
  var _fetch$fetchFuncAsync, response, _ORGIN_DATA;
1906
- return src_regeneratorRuntime().wrap(function _callee5$(_context5) {
1907
- while (1) switch (_context5.prev = _context5.next) {
2001
+ return src_regeneratorRuntime().wrap(function _callee6$(_context6) {
2002
+ while (1) switch (_context6.prev = _context6.next) {
1908
2003
  case 0:
1909
2004
  if (!(src_typeof(fetch.fetchFuncAsync) === 'object')) {
1910
- _context5.next = 14;
2005
+ _context6.next = 14;
1911
2006
  break;
1912
2007
  }
1913
- _context5.next = 3;
2008
+ _context6.next = 3;
1914
2009
  return (_fetch$fetchFuncAsync = fetch.fetchFuncAsync)["".concat(fetch.fetchFuncMethod)].apply(_fetch$fetchFuncAsync, _toConsumableArray(params.split(',')));
1915
2010
  case 3:
1916
- response = _context5.sent;
2011
+ response = _context6.sent;
1917
2012
  _ORGIN_DATA = response.data;
1918
2013
  if (!(Array.isArray(_ORGIN_DATA) && _ORGIN_DATA.length > 0)) {
1919
- _context5.next = 11;
2014
+ _context6.next = 11;
1920
2015
  break;
1921
2016
  }
1922
2017
  // reset data structure
@@ -1929,19 +2024,19 @@ var Tree = function Tree(props) {
1929
2024
  console.warn('The data structure does not match, please refer to the example in the component documentation.');
1930
2025
  _ORGIN_DATA = [];
1931
2026
  }
1932
- return _context5.abrupt("return", _ORGIN_DATA);
2027
+ return _context6.abrupt("return", _ORGIN_DATA);
1933
2028
  case 11:
1934
- return _context5.abrupt("return", []);
2029
+ return _context6.abrupt("return", []);
1935
2030
  case 12:
1936
- _context5.next = 15;
2031
+ _context6.next = 15;
1937
2032
  break;
1938
2033
  case 14:
1939
- return _context5.abrupt("return", []);
2034
+ return _context6.abrupt("return", []);
1940
2035
  case 15:
1941
2036
  case "end":
1942
- return _context5.stop();
2037
+ return _context6.stop();
1943
2038
  }
1944
- }, _callee5);
2039
+ }, _callee6);
1945
2040
  }));
1946
2041
  return _fetchData.apply(this, arguments);
1947
2042
  }
@@ -2010,11 +2105,11 @@ var Tree = function Tree(props) {
2010
2105
  }
2011
2106
  });
2012
2107
  }
2013
- function initDefaultValue(_x8) {
2108
+ function initDefaultValue(_x9) {
2014
2109
  return _initDefaultValue.apply(this, arguments);
2015
2110
  }
2016
2111
  function _initDefaultValue() {
2017
- _initDefaultValue = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee6(key) {
2112
+ _initDefaultValue = src_asyncToGenerator( /*#__PURE__*/src_regeneratorRuntime().mark(function _callee7(key) {
2018
2113
  var fetch,
2019
2114
  firstRender,
2020
2115
  retrieveData,
@@ -2025,15 +2120,16 @@ var Tree = function Tree(props) {
2025
2120
  _childrenData,
2026
2121
  findAndUpdateNode,
2027
2122
  _clone2,
2028
- _args6 = arguments;
2029
- return src_regeneratorRuntime().wrap(function _callee6$(_context6) {
2030
- while (1) switch (_context6.prev = _context6.next) {
2123
+ _findAndUpdateNode,
2124
+ _args7 = arguments;
2125
+ return src_regeneratorRuntime().wrap(function _callee7$(_context7) {
2126
+ while (1) switch (_context7.prev = _context7.next) {
2031
2127
  case 0:
2032
- fetch = _args6.length > 1 && _args6[1] !== undefined ? _args6[1] : null;
2033
- firstRender = _args6.length > 2 && _args6[2] !== undefined ? _args6[2] : false;
2034
- retrieveData = _args6.length > 3 && _args6[3] !== undefined ? _args6[3] : [];
2128
+ fetch = _args7.length > 1 && _args7[1] !== undefined ? _args7[1] : null;
2129
+ firstRender = _args7.length > 2 && _args7[2] !== undefined ? _args7[2] : false;
2130
+ retrieveData = _args7.length > 3 && _args7[3] !== undefined ? _args7[3] : [];
2035
2131
  if (!firstRender) {
2036
- _context6.next = 11;
2132
+ _context7.next = 11;
2037
2133
  break;
2038
2134
  }
2039
2135
  addKey(data, '', 0);
@@ -2057,27 +2153,27 @@ var Tree = function Tree(props) {
2057
2153
  // update retrive list
2058
2154
  _clone = (0,object.deepClone)(data);
2059
2155
  setFlatList((0,object.flatData)(_clone));
2060
- return _context6.abrupt("return", data);
2156
+ return _context7.abrupt("return", data);
2061
2157
  case 11:
2062
2158
  if (!(fetch && src_typeof(fetch.fetchFuncAsync) === 'object')) {
2063
- _context6.next = 31;
2159
+ _context7.next = 34;
2064
2160
  break;
2065
2161
  }
2066
2162
  _newData = list; //
2067
2163
  _params = fetch.fetchFuncMethodParams || [];
2068
- _context6.next = 16;
2164
+ _context7.next = 16;
2069
2165
  return fetchData(fetch, _params.join(','));
2070
2166
  case 16:
2071
- response = _context6.sent;
2167
+ response = _context7.sent;
2072
2168
  _childrenData = response;
2073
2169
  if (!(_childrenData.length > 0)) {
2074
- _context6.next = 29;
2170
+ _context7.next = 31;
2075
2171
  break;
2076
2172
  }
2077
- _context6.next = 21;
2173
+ _context7.next = 21;
2078
2174
  return updateTreeData(list, key ? key : '', _childrenData);
2079
2175
  case 21:
2080
- _newData = _context6.sent;
2176
+ _newData = _context7.sent;
2081
2177
  // set its childrenAsync property to false and active to true since we've successfully loaded its children
2082
2178
  if (key) {
2083
2179
  findAndUpdateNode = function findAndUpdateNode(nodes) {
@@ -2134,15 +2230,48 @@ var Tree = function Tree(props) {
2134
2230
  // update retrive list
2135
2231
  _clone2 = (0,object.deepClone)(_newData);
2136
2232
  setFlatList((0,object.flatData)(_clone2));
2137
- case 29:
2233
+ _context7.next = 32;
2234
+ break;
2235
+ case 31:
2236
+ // If empty response, remove loading state and set childrenAsync to false
2237
+ if (key) {
2238
+ _findAndUpdateNode = function _findAndUpdateNode(nodes) {
2239
+ var _iterator2 = src_createForOfIteratorHelper(nodes),
2240
+ _step2;
2241
+ try {
2242
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
2243
+ var node = _step2.value;
2244
+ if (node.key === key) {
2245
+ var _rootRef$current;
2246
+ node.childrenAsync = false;
2247
+ // Remove loading class from the hyperlink element
2248
+ var linkElement = (_rootRef$current = rootRef.current) === null || _rootRef$current === void 0 ? void 0 : _rootRef$current.querySelector("[data-key=\"".concat(key, "\"]"));
2249
+ if (linkElement) {
2250
+ activeClass(linkElement, 'remove', 'loading');
2251
+ }
2252
+ break;
2253
+ }
2254
+ if (node.children) {
2255
+ _findAndUpdateNode(node.children);
2256
+ }
2257
+ }
2258
+ } catch (err) {
2259
+ _iterator2.e(err);
2260
+ } finally {
2261
+ _iterator2.f();
2262
+ }
2263
+ };
2264
+ _findAndUpdateNode(_newData);
2265
+ }
2266
+ case 32:
2138
2267
  // dom init
2139
2268
  observeDOMChanges();
2140
- return _context6.abrupt("return", _newData);
2141
- case 31:
2269
+ return _context7.abrupt("return", _newData);
2270
+ case 34:
2142
2271
  case "end":
2143
- return _context6.stop();
2272
+ return _context7.stop();
2144
2273
  }
2145
- }, _callee6);
2274
+ }, _callee7);
2146
2275
  }));
2147
2276
  return _initDefaultValue.apply(this, arguments);
2148
2277
  }
@@ -2189,9 +2318,9 @@ var Tree = function Tree(props) {
2189
2318
  // Collapse
2190
2319
  ,
2191
2320
  expandedMap: expandedMap,
2192
- onCollapse: handleCollapse
2321
+ evCollapse: handleCollapse
2193
2322
  })));
2194
- };
2323
+ });
2195
2324
  /* harmony default export */ const src = (Tree);
2196
2325
  })();
2197
2326
 
@@ -47,8 +47,8 @@ export type TreeListProps = {
47
47
  val: ItemConfig,
48
48
  updateData: UpdateDataFunction
49
49
  ) => void;
50
- onCollapse?: (e: React.MouseEvent<HTMLElement>) => void;
51
50
  onCheck?: (val: any) => void;
51
+ evCollapse?: (e: React.MouseEvent<HTMLElement>) => void;
52
52
  evInitValue?: UpdateDataFunction;
53
53
  };
54
54
 
@@ -74,8 +74,8 @@ export default function TreeList(props: TreeListProps) {
74
74
  expandedMap,
75
75
  onSelect,
76
76
  onDoubleSelect,
77
- onCollapse,
78
77
  onCheck,
78
+ evCollapse,
79
79
  evInitValue
80
80
 
81
81
  } = props;
@@ -219,7 +219,7 @@ export default function TreeList(props: TreeListProps) {
219
219
  });
220
220
 
221
221
  if ( disableArrow ) {
222
- onCollapse?.(e);
222
+ evCollapse?.(e);
223
223
 
224
224
  }
225
225
  }
@@ -252,7 +252,7 @@ export default function TreeList(props: TreeListProps) {
252
252
  });
253
253
 
254
254
  if (disableArrow) {
255
- onCollapse?.(e);
255
+ evCollapse?.(e);
256
256
  }
257
257
  }
258
258
 
@@ -464,7 +464,7 @@ export default function TreeList(props: TreeListProps) {
464
464
  {(item.children && item.children.length) || item.childrenAsync ? <span
465
465
  aria-expanded={JSON.parse(optiondata as string).isExpanded || item.active ? 'true' : 'false'}
466
466
  className={item.active ? `arrow active ${_async} ${_cusIcons}` : `arrow ${_async} ${_cusIcons}`}
467
- onClick={onCollapse}
467
+ onClick={evCollapse}
468
468
  data-link={item.link}
469
469
  data-slug={item.slug}
470
470
  data-key={item.key}
@@ -577,7 +577,7 @@ export default function TreeList(props: TreeListProps) {
577
577
 
578
578
  // Collapse
579
579
  expandedMap={expandedMap}
580
- onCollapse={onCollapse}
580
+ evCollapse={evCollapse}
581
581
 
582
582
 
583
583
  />}
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useRef } from 'react';
1
+ import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
2
2
 
3
3
 
4
4
  import useComId from 'funda-utils/dist/cjs/useComId';
@@ -108,7 +108,12 @@ export type TreeProps = {
108
108
  onCheck?: (val: any) => void;
109
109
  };
110
110
 
111
- const Tree = (props: TreeProps) => {
111
+ export interface TreeRef {
112
+ collapse: (slug: string) => void;
113
+ updateParentTreeHeights: (targetElement: HTMLElement) => Promise<void>;
114
+ }
115
+
116
+ const Tree = forwardRef<TreeRef, TreeProps>((props, ref) => {
112
117
  const {
113
118
  id,
114
119
  checkable,
@@ -168,6 +173,7 @@ const Tree = (props: TreeProps) => {
168
173
 
169
174
  const observer = new MutationObserver((mutations) => {
170
175
  // Check whether any new ul elements have been added
176
+ // Changes of <li> are captured by changes in their parent <ul>
171
177
  const hasNewUL = mutations.some(mutation =>
172
178
  Array.from(mutation.addedNodes).some(node =>
173
179
  node.nodeName === 'UL'
@@ -181,8 +187,10 @@ const Tree = (props: TreeProps) => {
181
187
  });
182
188
 
183
189
  observer.observe(rootRef.current, {
184
- childList: true,
185
- subtree: true
190
+ childList: true, // Observe the addition or deletion of child nodes
191
+ subtree: true, // Observe all descendant nodes
192
+ attributes: false, // Do not observe attribute changes
193
+ characterData: false // Do not observe text content changes
186
194
  });
187
195
  };
188
196
 
@@ -234,38 +242,51 @@ const Tree = (props: TreeProps) => {
234
242
 
235
243
  };
236
244
 
237
- function handleCollapse(e: React.MouseEvent<HTMLElement>) {
245
+ function handleCollapse(e?: React.MouseEvent<HTMLElement>, slug?: string) {
246
+ if (disableCollapse) return;
238
247
 
239
- if ( disableCollapse ) return;
248
+ if (e) {
249
+ e.preventDefault();
250
+ e.stopPropagation();
251
+ }
240
252
 
241
- e.preventDefault();
242
- e.stopPropagation();
253
+ let hyperlink: HTMLElement;
243
254
 
244
- const hyperlink = e.currentTarget;
255
+ if (e) {
256
+ hyperlink = e.currentTarget;
257
+ } else if (slug && rootRef.current) {
258
+ // Find the hyperlink element by slug
259
+ const linkElement = rootRef.current.querySelector(`[data-slug="${slug}"]`);
260
+ if (!linkElement) return;
261
+ hyperlink = linkElement as HTMLElement;
262
+ } else {
263
+ return;
264
+ }
265
+
266
+
245
267
  const url = hyperlink.dataset.href;
246
268
  const subElement = getNextSiblings(hyperlink, 'ul');
247
269
  const asyncReqReady = hyperlink.classList.contains('async-ready');
248
270
 
249
271
  // loading
250
272
  //=====================
251
- if ( asyncReqReady ) {
273
+ if (asyncReqReady) {
252
274
  activeClass(hyperlink, 'add', 'loading');
253
275
  }
254
276
 
255
-
256
277
  // calback
257
278
  //=====================
258
279
  const fetchFunc: UpdateDataFunction = asyncReqReady ? (typeof initDefaultValue !== 'function' ? async () => void(0) : initDefaultValue) : async () => void(0);
259
-
280
+
281
+
260
282
  const optiondata = typeof hyperlink.dataset.optiondata !== 'undefined' ? hyperlink.dataset.optiondata : '{}';
261
- onCollapse?.(e, {
283
+ onCollapse?.(e as React.MouseEvent<HTMLElement>, {
262
284
  key: hyperlink.dataset.key as string,
263
285
  slug: hyperlink.dataset.slug as string,
264
286
  link: hyperlink.dataset.link as string,
265
287
  optiondata: optiondata as string
266
288
  }, fetchFunc, JSON.parse(optiondata as string).isExpanded);
267
289
 
268
-
269
290
  // update expanded status
270
291
  //=====================
271
292
  const isExpanded = hyperlink.getAttribute('aria-expanded') === 'true';
@@ -274,18 +295,14 @@ const Tree = (props: TreeProps) => {
274
295
  [hyperlink.dataset.key as string]: !isExpanded
275
296
  }));
276
297
 
277
-
278
298
  // hide child if expandedLink doesn't exist, on the contrary
279
299
  //=====================
280
- if ( hyperlink.classList.contains('loading') ) return;
281
-
282
- if ( hyperlink.getAttribute('aria-expanded') === 'false' || hyperlink.getAttribute('aria-expanded') === null ) {
283
-
300
+ if (hyperlink.classList.contains('loading')) return;
284
301
 
302
+ if (hyperlink.getAttribute('aria-expanded') === 'false' || hyperlink.getAttribute('aria-expanded') === null) {
285
303
  //Hide all other siblings of the selected <ul>
286
304
  if (alternateCollapse) {
287
305
  [].slice.call(rootRef.current.firstChild.children).forEach(function (li: any) {
288
-
289
306
  activeClass(li, 'remove');
290
307
 
291
308
  const _li = li.firstChild;
@@ -298,22 +315,64 @@ const Tree = (props: TreeProps) => {
298
315
  });
299
316
  }
300
317
 
301
-
302
318
  //open current
303
319
  openChild(hyperlink, subElement as never);
304
-
305
-
306
-
307
320
  } else {
308
-
309
321
  //close current
310
322
  closeChild(hyperlink, subElement as never);
311
-
312
323
  }
313
-
314
-
315
324
  }
316
325
 
326
+ const observeElement = (ancestorNode: HTMLElement) => {
327
+ return new Promise<void>((resolve) => {
328
+ const observer = new MutationObserver((mutations) => {
329
+ // Check whether any new ul elements have been added
330
+ // It is necessary to listen for <li> because <li> may be added dynamically in the business
331
+ const hasNewUL = mutations.some(mutation =>
332
+ Array.from(mutation.addedNodes).some(node =>
333
+ (node.nodeName === 'UL' || node.nodeName === 'LI')
334
+ )
335
+ );
336
+
337
+ if (hasNewUL) {
338
+ observer.disconnect();
339
+ const ul: any = [].slice.call(ancestorNode.querySelectorAll('ul'));
340
+ initAsyncItems(ul as never).then(() => {
341
+ initUlHeight(ul);
342
+ });
343
+ resolve();
344
+ }
345
+ });
346
+
347
+ observer.observe(ancestorNode, {
348
+ childList: true, // Observe the addition or deletion of child nodes
349
+ subtree: true, // Observe all descendant nodes
350
+ attributes: false, // Do not observe attribute changes
351
+ characterData: false // Do not observe text content changes
352
+ });
353
+ });
354
+ };
355
+
356
+ // exposes the following methods
357
+ useImperativeHandle(ref, () => ({
358
+ collapse: (slug: string) => {
359
+ handleCollapse(undefined, slug);
360
+ },
361
+ updateParentTreeHeights: async (targetElement: HTMLElement) => {
362
+
363
+ if (targetElement !== null) {
364
+ // Find the topmost node, in order to fix the subtree height under this node
365
+ const _ancestorNode = targetElement.closest('.nav-item.first') as HTMLElement;
366
+ if (_ancestorNode !== null) {
367
+ try {
368
+ await observeElement(_ancestorNode);
369
+ } catch (error) {
370
+ console.warn('Failed to update ul height:', error);
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }), [rootRef.current, onCollapse]); // !Required "onCollapse"
317
376
 
318
377
  async function fetchData(fetch: FetchConfig, params: any) {
319
378
 
@@ -512,6 +571,27 @@ const Tree = (props: TreeProps) => {
512
571
  setFlatList(flatData(_clone));
513
572
 
514
573
 
574
+ } else {
575
+ // If empty response, remove loading state and set childrenAsync to false
576
+ if (key) {
577
+ const findAndUpdateNode = (nodes: DataNode[]) => {
578
+ for (let node of nodes) {
579
+ if (node.key === key) {
580
+ node.childrenAsync = false;
581
+ // Remove loading class from the hyperlink element
582
+ const linkElement = rootRef.current?.querySelector(`[data-key="${key}"]`);
583
+ if (linkElement) {
584
+ activeClass(linkElement, 'remove', 'loading');
585
+ }
586
+ break;
587
+ }
588
+ if (node.children) {
589
+ findAndUpdateNode(node.children);
590
+ }
591
+ }
592
+ };
593
+ findAndUpdateNode(_newData as DataNode[]);
594
+ }
515
595
  }
516
596
 
517
597
  // dom init
@@ -568,7 +648,7 @@ const Tree = (props: TreeProps) => {
568
648
 
569
649
  // Collapse
570
650
  expandedMap={expandedMap}
571
- onCollapse={handleCollapse}
651
+ evCollapse={handleCollapse}
572
652
 
573
653
  />
574
654
 
@@ -576,6 +656,6 @@ const Tree = (props: TreeProps) => {
576
656
 
577
657
  </>
578
658
  )
579
- };
659
+ });
580
660
 
581
661
  export default Tree;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "UIUX Lab",
3
3
  "email": "uiuxlab@gmail.com",
4
4
  "name": "funda-ui",
5
- "version": "4.7.181",
5
+ "version": "4.7.185",
6
6
  "description": "React components using pure Bootstrap 5+ which does not contain any external style and script libraries.",
7
7
  "repository": {
8
8
  "type": "git",