@cypress-design/react-docmenu 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import { createContext } from 'react';
2
3
  import clsx from 'clsx';
3
4
  import * as iconsRegistry from '@cypress-design/icon-registry';
4
5
  import { ICON_COLOR_PROP_NAMES } from '@cypress-design/icon-registry';
@@ -154,18 +155,23 @@ var IconChevronDownSmall = function (props) { return React.createElement('svg',
154
155
  /* <wind-keep class="filter icon-light-secondary icon-dark-secondary"> */
155
156
 
156
157
  const classes = {
158
+ expandedIcon: 'absolute left-0 transform transition-transform text-gray-400 dark:text-gray-700',
157
159
  button: 'flex leading-[24px] py-[10px] items-center relative w-full text-start',
158
160
  topButton: 'leading-[24px] text-[16px] pl-[24px] font-medium',
159
- leafButton: 'leading-[20px] text-[14px] pl-[40px]',
161
+ leafButton: 'leading-[20px] text-[14px] pl-[48px]',
162
+ openListBorderLeft: 'absolute left-[8px] top-0 w-[1px] h-full bg-gray-100 dark:bg-gray-900',
160
163
  };
161
164
 
165
+ var MarkerIsMovingContext = createContext({
166
+ setMarkerIsMoving: function () { },
167
+ markerIsMoving: false,
168
+ });
169
+
162
170
  var DocLink = React.forwardRef(function (_a, ref) {
163
171
  var item = _a.item, active = _a.active, collapsible = _a.collapsible, _b = _a.depth, depth = _b === void 0 ? -1 : _b, onActive = _a.onActive, _c = _a.LinkComponent, LinkComponent = _c === void 0 ? 'a' : _c;
164
172
  var activeLIRef = React.useRef(null);
165
- // on mount, if the item is active,
166
- // send the top position to the parent
167
- React.useEffect(setActiveMarkerPosition, [onActive, active]);
168
- function setActiveMarkerPosition() {
173
+ var markerIsMoving = React.useContext(MarkerIsMovingContext).markerIsMoving;
174
+ var setActiveMarkerPosition = function () {
169
175
  var _a;
170
176
  if (active) {
171
177
  var box = (_a = activeLIRef === null || activeLIRef === void 0 ? void 0 : activeLIRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
@@ -174,23 +180,27 @@ var DocLink = React.forwardRef(function (_a, ref) {
174
180
  height: (box === null || box === void 0 ? void 0 : box.height) || 0,
175
181
  });
176
182
  }
177
- }
183
+ };
184
+ // on mount, if the item is active,
185
+ // send the top position to the parent
186
+ React.useEffect(setActiveMarkerPosition, [onActive, active]);
178
187
  React.useImperativeHandle(ref, function () { return ({
179
188
  setActiveMarkerPosition: setActiveMarkerPosition,
180
189
  }); });
181
- return (React.createElement("li", { ref: activeLIRef, className: clsx('list-none p-0', {
182
- 'pl-[16px]': depth >= 0,
183
- }) },
184
- React.createElement(LinkComponent, { className: clsx('group relative inline-block pl-[24px]', {
190
+ return (React.createElement("li", { ref: activeLIRef, className: "list-none p-0" },
191
+ React.createElement(LinkComponent, { className: clsx('group relative block w-full pl-[24px]', {
185
192
  'text-indigo-500': active,
193
+ 'text-gray-700 dark:text-gray-500': !active,
186
194
  'py-[8px] text-[16px] leading-[24px]': depth < 0,
187
- 'py-[12px] leading-[20px] text-[14px]': depth >= 0,
188
- }), href: item.href },
189
- depth >= 0 ? (React.createElement("div", { className: clsx('absolute w-[4px] z-10 top-[4px] bottom-[4px] rounded-full hidden', {
195
+ 'leading-[20px] text-[14px] py-[12px]': depth >= 0,
196
+ }), href: item.href, style: {
197
+ paddingLeft: depth >= 0 ? "".concat(depth * 12 + 48, "px") : undefined,
198
+ } },
199
+ depth >= 0 ? (React.createElement("div", { className: clsx('left-[6.5px] absolute top-[4px] bottom-[4px] w-[4px] z-10 rounded-full', {
200
+ hidden: !markerIsMoving || !active,
190
201
  'group-hover:block bg-gray-300': !active && collapsible,
191
- }), style: {
192
- left: "-".concat(18.5 + depth * 8, "px"),
193
- } })) : null,
202
+ 'bg-indigo-500': active && markerIsMoving,
203
+ }) })) : null,
194
204
  item.label)));
195
205
  });
196
206
 
@@ -199,10 +209,13 @@ var DocGroup = React.forwardRef(function (_a, ref) {
199
209
  var group = _a.group, activePath = _a.activePath, collapsible = _a.collapsible, _c = _a.depth, depth = _c === void 0 ? 0 : _c, onActivePosition = _a.onActivePosition, updateMarkerPosition = _a.updateMarkerPosition, _d = _a.LinkComponent, LinkComponent = _d === void 0 ? 'a' : _d, hideMarker = _a.hideMarker;
200
210
  var _e = React.useState(group.collapsed !== true), open = _e[0], setOpen = _e[1];
201
211
  var $groupElements = React.useRef(null);
212
+ var $listWrapper = React.useRef(null);
202
213
  function toggleMenu(open) {
203
214
  if (!collapsible)
204
215
  return;
205
216
  setOpen(open);
217
+ hideShowAbsoluteMarker();
218
+ readjustMarkerPosition();
206
219
  }
207
220
  var hasActiveItemRecursively = React.useCallback(function (items) {
208
221
  if (items === void 0) { items = group.items; }
@@ -220,14 +233,32 @@ var DocGroup = React.forwardRef(function (_a, ref) {
220
233
  onActivePosition({ top: top, height: height });
221
234
  }
222
235
  }, [onActivePosition, open]);
223
- function reTriggerSetActiveGroup() {
236
+ var setMarkerIsMoving = React.useContext(MarkerIsMovingContext).setMarkerIsMoving;
237
+ function reTriggerSetActiveGroupParent() {
224
238
  var _a;
225
239
  (_a = $groupElements.current) === null || _a === void 0 ? void 0 : _a.reTriggerSetActiveGroup();
226
240
  }
227
- React.useEffect(function () {
241
+ /**
242
+ * To make the marker follow smooth open/close animation of the menu groups
243
+ * We replace the absolute marker by one in the link. After the transition, the
244
+ * marker is replaced by the absolute one again.
245
+ */
246
+ function hideShowAbsoluteMarker() {
247
+ var _a, _b;
248
+ (_a = $listWrapper.current) === null || _a === void 0 ? void 0 : _a.addEventListener('transitionstart', function () {
249
+ setMarkerIsMoving(true);
250
+ }, { once: true });
251
+ (_b = $listWrapper.current) === null || _b === void 0 ? void 0 : _b.addEventListener('transitionend', function () {
252
+ if (open || !hasActiveItemRecursively()) {
253
+ updateMarkerPosition === null || updateMarkerPosition === void 0 ? void 0 : updateMarkerPosition();
254
+ }
255
+ setMarkerIsMoving(false);
256
+ }, { once: true });
257
+ }
258
+ function readjustMarkerPosition() {
228
259
  if (hasActiveItemRecursively()) {
229
260
  if (open) {
230
- reTriggerSetActiveGroup();
261
+ reTriggerSetActiveGroupParent();
231
262
  }
232
263
  else {
233
264
  hideMarker();
@@ -236,13 +267,13 @@ var DocGroup = React.forwardRef(function (_a, ref) {
236
267
  else {
237
268
  updateMarkerPosition === null || updateMarkerPosition === void 0 ? void 0 : updateMarkerPosition();
238
269
  }
239
- }, [open, updateMarkerPosition, hideMarker, hasActiveItemRecursively]);
270
+ }
240
271
  React.useImperativeHandle(ref, function () { return ({
241
- reTriggerSetActiveGroup: reTriggerSetActiveGroup,
272
+ reTriggerSetActiveGroup: reTriggerSetActiveGroupParent,
242
273
  }); });
243
274
  var onUpdateMarkerPosition = React.useCallback(function () {
244
275
  if (hasActiveItemRecursively()) {
245
- reTriggerSetActiveGroup();
276
+ reTriggerSetActiveGroupParent();
246
277
  }
247
278
  else {
248
279
  updateMarkerPosition === null || updateMarkerPosition === void 0 ? void 0 : updateMarkerPosition();
@@ -254,13 +285,18 @@ var DocGroup = React.forwardRef(function (_a, ref) {
254
285
  _b[classes.leafButton] = depth,
255
286
  _b['text-indigo-500'] = activePath === group.href,
256
287
  _b)) },
257
- collapsible ? (React.createElement(IconChevronDownSmall, { "stroke-color": "gray-400", size: depth ? '8' : '16', className: clsx('absolute transform transition-transform left-0', {
288
+ collapsible ? (React.createElement(IconChevronDownSmall, { "stroke-color": "gray-400", size: depth ? '8' : '16', className: clsx(classes.expandedIcon, {
258
289
  'rotate-0': open,
259
290
  '-rotate-90': !open,
260
- 'ml-[16px]': depth,
291
+ 'ml-[28px]': depth,
261
292
  }) })) : null,
262
293
  group.label),
263
- React.createElement(DocGroupElements, { ref: $groupElements, className: !open ? 'hidden' : undefined, items: group.items, activePath: activePath, collapsible: collapsible, depth: depth, onActivePosition: setActivePosition, updateMarkerPosition: onUpdateMarkerPosition, LinkComponent: LinkComponent, hideMarker: hideMarker })));
294
+ React.createElement("div", { className: clsx('grid transition-all relative', {
295
+ 'grid-rows-[0fr]': !open && collapsible,
296
+ 'grid-rows-[1fr]': open || !collapsible,
297
+ }), ref: $listWrapper },
298
+ open && collapsible && depth === 0 ? (React.createElement("div", { className: classes.openListBorderLeft })) : null,
299
+ React.createElement(DocGroupElements, { ref: $groupElements, className: "overflow-hidden", items: group.items, activePath: activePath, collapsible: collapsible, depth: depth, onActivePosition: setActivePosition, updateMarkerPosition: onUpdateMarkerPosition, LinkComponent: LinkComponent, hideMarker: hideMarker }))));
264
300
  });
265
301
  var DocGroupElements = React.forwardRef(function (_a, ref) {
266
302
  var items = _a.items, activePath = _a.activePath, collapsible = _a.collapsible, _b = _a.depth, depth = _b === void 0 ? 0 : _b, onActivePosition = _a.onActivePosition, updateMarkerPosition = _a.updateMarkerPosition, LinkComponent = _a.LinkComponent, hideMarker = _a.hideMarker, className = _a.className, rest = __rest$1(_a, ["items", "activePath", "collapsible", "depth", "onActivePosition", "updateMarkerPosition", "LinkComponent", "hideMarker", "className"]);
@@ -275,35 +311,42 @@ var DocGroupElements = React.forwardRef(function (_a, ref) {
275
311
  return item.href === activePath;
276
312
  });
277
313
  }, [items, activePath]);
278
- function reTriggerSetActiveGroup() {
279
- $groups.current.forEach(function (group) {
280
- group === null || group === void 0 ? void 0 : group.reTriggerSetActiveGroup();
281
- });
314
+ var reTriggerSetActiveGroup = React.useCallback(function (index) {
315
+ if (index === void 0) { index = 0; }
282
316
  $items.current.forEach(function (item) {
283
317
  item === null || item === void 0 ? void 0 : item.setActiveMarkerPosition();
284
318
  });
285
- }
319
+ // calculate the index of the calling group in the list of groups
320
+ var indexGroup = index -
321
+ // remove all the items that are not groups from the array and count them
322
+ items.slice(0, index).filter(function (item) { return !('items' in item); }).length;
323
+ // only update groups that come after the toggled one
324
+ // others will not need to update the marker
325
+ // since they are "before" in the rendering tree
326
+ $groups.current.slice(indexGroup + 1).forEach(function (group) {
327
+ group === null || group === void 0 ? void 0 : group.reTriggerSetActiveGroup();
328
+ });
329
+ }, [items]);
286
330
  React.useImperativeHandle(ref, function () { return ({
287
331
  reTriggerSetActiveGroup: reTriggerSetActiveGroup,
288
332
  }); });
289
- var onUpdateMarkerPosition = React.useCallback(function () {
333
+ var onUpdateMarkerPosition = React.useCallback(function (index) {
290
334
  if (hasActiveItemRecursively()) {
291
- reTriggerSetActiveGroup();
335
+ reTriggerSetActiveGroup(index);
292
336
  }
293
337
  else {
294
338
  updateMarkerPosition === null || updateMarkerPosition === void 0 ? void 0 : updateMarkerPosition();
295
339
  }
296
- }, [hasActiveItemRecursively, updateMarkerPosition]);
297
- return (React.createElement("ul", __assign$1({}, rest, { className: clsx('list-none p-0', className, {
298
- 'border-l border-gray-100': depth === 0 && collapsible,
299
- 'ml-[8px]': depth >= 0,
300
- }) }), items.map(function (item, index) {
340
+ }, [hasActiveItemRecursively, updateMarkerPosition, reTriggerSetActiveGroup]);
341
+ return (React.createElement("ul", __assign$1({}, rest, { className: clsx('list-none p-0', className) }), items.map(function (item, index) {
301
342
  return 'items' in item ? (React.createElement("li", { key: index, className: "relative list-none p-0" },
302
343
  React.createElement(DocGroup, { ref: function (el) {
303
344
  $groups.current[index] = el;
304
- }, group: item, activePath: activePath, depth: depth + 1, collapsible: collapsible, LinkComponent: LinkComponent, hideMarker: hideMarker, onActivePosition: onActivePosition, updateMarkerPosition: onUpdateMarkerPosition }))) : (React.createElement(DocLink, { ref: function (el) {
345
+ }, group: item, activePath: activePath, depth: depth + 1, collapsible: collapsible, LinkComponent: LinkComponent, hideMarker: hideMarker, onActivePosition: onActivePosition, updateMarkerPosition: function () { return onUpdateMarkerPosition(index); } }))) : (React.createElement(DocLink, { ref: function (el) {
305
346
  $items.current[index] = el;
306
- }, key: index, item: item, active: item.href === activePath, collapsible: collapsible, depth: depth, onActive: onActivePosition, LinkComponent: LinkComponent }));
347
+ }, key: index, item: item, active: item.href === activePath, collapsible: collapsible, depth: depth, onActive: function (opts) {
348
+ return depth < 0 ? hideMarker() : onActivePosition(opts);
349
+ }, LinkComponent: LinkComponent }));
307
350
  })));
308
351
  });
309
352
 
@@ -312,6 +355,7 @@ var DocMenu = function (_a) {
312
355
  var _e = React.useState(0), activeTop = _e[0], setActiveTop = _e[1];
313
356
  var _f = React.useState(36), activeHeight = _f[0], setActiveHeight = _f[1];
314
357
  var _g = React.useState(false), showMarker = _g[0], setShowMarker = _g[1];
358
+ var _h = React.useState(false), markerIsMoving = _h[0], setMarkerIsMoving = _h[1];
315
359
  var container = React.useRef(null);
316
360
  var setActivePosition = React.useCallback(function (opts) {
317
361
  var _a;
@@ -320,15 +364,17 @@ var DocMenu = function (_a) {
320
364
  setActiveTop(opts.top - containerTop);
321
365
  setActiveHeight(opts.height);
322
366
  }, []);
323
- return (React.createElement("div", { ref: container, className: "relative" },
324
- showMarker && collapsible ? (React.createElement("div", { className: "absolute h-[36px] w-[4px] z-50 rounded-full bg-indigo-500 transition-all duration-300 ml-[6.5px] mt-[4px]", style: {
325
- top: "".concat(activeTop + 4, "px"),
326
- height: "".concat(activeHeight - 8, "px"),
327
- } })) : null,
328
- React.createElement(DocGroupElements, __assign$1({}, rest, { items: items, activePath: activePath, collapsible: collapsible, depth: -1, onActivePosition: setActivePosition, LinkComponent: LinkComponent, hideMarker: function () { return setShowMarker(false); } }))));
367
+ var setShowMarkerFalse = React.useCallback(function () { return setShowMarker(false); }, []);
368
+ return (React.createElement(MarkerIsMovingContext.Provider, { value: { markerIsMoving: markerIsMoving, setMarkerIsMoving: setMarkerIsMoving } },
369
+ React.createElement("div", { ref: container, className: "relative" },
370
+ showMarker && !markerIsMoving && collapsible ? (React.createElement("div", { className: "absolute h-[36px] w-[4px] z-50 rounded-full bg-indigo-500 transition-all duration-300 ml-[6.5px] mt-[4px]", style: {
371
+ top: "".concat(activeTop, "px"),
372
+ height: "".concat(activeHeight - 8, "px"),
373
+ } })) : null,
374
+ React.createElement(DocGroupElements, __assign$1({}, rest, { items: items, activePath: activePath, collapsible: collapsible, depth: -1, onActivePosition: setActivePosition, LinkComponent: LinkComponent, hideMarker: setShowMarkerFalse })))));
329
375
  };
330
376
 
331
377
  export { DocMenu as default };
332
378
  //# sourceMappingURL=index.es.mjs.map
333
379
 
334
- /* <wind-keep class="container relative absolute h-[36px] w-[4px] z-50 rounded-full bg-indigo-500 transition-all duration-300 ml-[6.5px] mt-[4px] text-indigo-500 transform transition-transform left-0 rotate-0 -rotate-90 ml-[16px] hidden list-none p-0 border-l border-gray-100 ml-[8px] pl-[16px] inline-block pl-[24px] py-[8px] text-[16px] leading-[24px] py-[12px] leading-[20px] text-[14px] z-10 top-[4px] bottom-[4px] group-hover:block bg-gray-300 flex py-[10px] items-center w-full text-start font-medium pl-[40px]"> */
380
+ /* <wind-keep class="container relative absolute h-[36px] w-[4px] z-50 rounded-full bg-indigo-500 transition-all duration-300 ml-[6.5px] mt-[4px] transition text-indigo-500 rotate-0 -rotate-90 ml-[28px] grid grid-rows-[0fr] grid-rows-[1fr] overflow-hidden filter list-none p-0 block w-full pl-[24px] text-gray-700 dark:text-gray-500 py-[8px] text-[16px] leading-[24px] leading-[20px] text-[14px] py-[12px] left-[6.5px] top-[4px] bottom-[4px] z-10 hidden group-hover:block bg-gray-300 text-gray-500 left-0 transform transition-transform text-gray-400 dark:text-gray-700 flex py-[10px] items-center text-start font-medium pl-[48px] left-[8px] top-0 w-[1px] h-full bg-gray-100 dark:bg-gray-900"> */