@stoplight/elements-core 9.0.12 → 9.0.13
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/components/TableOfContents/types.d.ts +7 -0
- package/index.esm.js +64 -14
- package/index.js +64 -14
- package/index.mjs +64 -14
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ export declare type TableOfContentsGroup = {
|
|
|
21
21
|
title: string;
|
|
22
22
|
items: TableOfContentsGroupItem[];
|
|
23
23
|
itemsType?: 'article' | 'http_operation' | 'http_webhook' | 'model';
|
|
24
|
+
index: string;
|
|
24
25
|
};
|
|
25
26
|
export declare type TableOfContentsExternalLink = {
|
|
26
27
|
title: string;
|
|
@@ -33,5 +34,11 @@ export declare type TableOfContentsNode<T = 'http_service' | 'http_operation' |
|
|
|
33
34
|
type: T;
|
|
34
35
|
meta: string;
|
|
35
36
|
version?: string;
|
|
37
|
+
index: string;
|
|
36
38
|
};
|
|
37
39
|
export declare type TableOfContentsNodeGroup = TableOfContentsNode<'http_service'> & TableOfContentsGroup;
|
|
40
|
+
export declare type ActiveItemContextType = {
|
|
41
|
+
activeId: string | undefined;
|
|
42
|
+
lastActiveIndex: string;
|
|
43
|
+
setLastActiveIndex: React.Dispatch<React.SetStateAction<string>>;
|
|
44
|
+
};
|
package/index.esm.js
CHANGED
|
@@ -3496,7 +3496,7 @@ function findFirstNode(items) {
|
|
|
3496
3496
|
return;
|
|
3497
3497
|
}
|
|
3498
3498
|
function isDivider(item) {
|
|
3499
|
-
return Object.keys(item).length ===
|
|
3499
|
+
return Object.keys(item).length === 2 && 'title' in item && 'index' in item;
|
|
3500
3500
|
}
|
|
3501
3501
|
function isGroup(item) {
|
|
3502
3502
|
return Object.keys(item).length >= 2 && 'title' in item && 'items' in item;
|
|
@@ -3508,13 +3508,33 @@ function isNode(item) {
|
|
|
3508
3508
|
return 'title' in item && 'slug' in item && 'id' in item && 'meta' in item && 'type' in item;
|
|
3509
3509
|
}
|
|
3510
3510
|
function isExternalLink(item) {
|
|
3511
|
-
return Object.keys(item).length ===
|
|
3511
|
+
return Object.keys(item).length === 3 && 'title' in item && 'url' in item && 'index' in item;
|
|
3512
3512
|
}
|
|
3513
3513
|
|
|
3514
|
-
const
|
|
3514
|
+
const ActiveItemContext = React.createContext({
|
|
3515
|
+
activeId: undefined,
|
|
3516
|
+
lastActiveIndex: '',
|
|
3517
|
+
setLastActiveIndex: () => { },
|
|
3518
|
+
});
|
|
3515
3519
|
const LinkContext = React.createContext(undefined);
|
|
3516
3520
|
LinkContext.displayName = 'LinkContext';
|
|
3517
3521
|
const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefault, externalScrollbar = false, isInResponsiveMode = false, onLinkClick, }) => {
|
|
3522
|
+
const [lastActiveIndex, setLastActiveIndex] = useState('');
|
|
3523
|
+
const value = React.useMemo(() => ({
|
|
3524
|
+
lastActiveIndex,
|
|
3525
|
+
setLastActiveIndex,
|
|
3526
|
+
activeId,
|
|
3527
|
+
}), [lastActiveIndex, activeId]);
|
|
3528
|
+
const updateTocTree = React.useCallback((arr, parentId) => {
|
|
3529
|
+
return arr.map((item, key) => {
|
|
3530
|
+
let newItem = Object.assign(Object.assign({}, item), { index: parentId + key + '-' });
|
|
3531
|
+
if (isGroup(item) || isNodeGroup(item)) {
|
|
3532
|
+
newItem.items = updateTocTree(item.items, parentId + key + '-');
|
|
3533
|
+
}
|
|
3534
|
+
return newItem;
|
|
3535
|
+
});
|
|
3536
|
+
}, []);
|
|
3537
|
+
const updatedTree = updateTocTree(tree, '');
|
|
3518
3538
|
const container = React.useRef(null);
|
|
3519
3539
|
const child = React.useRef(null);
|
|
3520
3540
|
const firstRender = useFirstRender();
|
|
@@ -3534,18 +3554,30 @@ const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefaul
|
|
|
3534
3554
|
return (React.createElement(Box, { ref: container, w: "full", bg: isInResponsiveMode ? 'canvas' : 'canvas-100', overflowY: "auto" },
|
|
3535
3555
|
React.createElement(Box, { ref: child, my: 3 },
|
|
3536
3556
|
React.createElement(LinkContext.Provider, { value: Link },
|
|
3537
|
-
React.createElement(
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3557
|
+
React.createElement(ActiveItemContext.Provider, { value: value },
|
|
3558
|
+
React.createElement(TOCContainer, { updatedTree: updatedTree }, updatedTree.map((item, key) => {
|
|
3559
|
+
if (isDivider(item)) {
|
|
3560
|
+
return React.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
|
|
3561
|
+
}
|
|
3562
|
+
return (React.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
|
|
3563
|
+
})))))));
|
|
3543
3564
|
});
|
|
3544
3565
|
TableOfContents.displayName = 'TableOfContents';
|
|
3545
3566
|
const Divider = React.memo(({ item, isInResponsiveMode = false }) => {
|
|
3546
3567
|
return (React.createElement(Box, { pl: 4, mb: 2, mt: 6, textTransform: "uppercase", fontSize: isInResponsiveMode ? 'lg' : 'sm', lineHeight: "relaxed", letterSpacing: "wide", fontWeight: "bold" }, item.title));
|
|
3547
3568
|
});
|
|
3548
3569
|
Divider.displayName = 'Divider';
|
|
3570
|
+
const TOCContainer = React.memo(({ children, updatedTree }) => {
|
|
3571
|
+
const { setLastActiveIndex } = React.useContext(ActiveItemContext);
|
|
3572
|
+
React.useEffect(() => {
|
|
3573
|
+
const firstNode = findFirstNode(updatedTree);
|
|
3574
|
+
if (firstNode) {
|
|
3575
|
+
setLastActiveIndex(firstNode.index);
|
|
3576
|
+
}
|
|
3577
|
+
}, []);
|
|
3578
|
+
return React.createElement(Box, null, children);
|
|
3579
|
+
});
|
|
3580
|
+
TOCContainer.displayName = 'TOCContainer';
|
|
3549
3581
|
const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick }) => {
|
|
3550
3582
|
if (isExternalLink(item)) {
|
|
3551
3583
|
return (React.createElement(Box, { as: "a", href: item.url, target: "_blank", rel: "noopener noreferrer", display: "block" },
|
|
@@ -3563,9 +3595,24 @@ const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsi
|
|
|
3563
3595
|
});
|
|
3564
3596
|
GroupItem.displayName = 'GroupItem';
|
|
3565
3597
|
const Group = React.memo(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick = () => { } }) => {
|
|
3566
|
-
const activeId = React.useContext(
|
|
3598
|
+
const { activeId, lastActiveIndex } = React.useContext(ActiveItemContext);
|
|
3567
3599
|
const [isOpen, setIsOpen] = React.useState(() => isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault));
|
|
3568
|
-
const
|
|
3600
|
+
const isActiveGroup = React.useCallback((items, activeId, contextIndex) => {
|
|
3601
|
+
return items.some(element => {
|
|
3602
|
+
const hasSlugOrId = 'slug' in element || 'id' in element;
|
|
3603
|
+
const hasItems = 'items' in element && Array.isArray(element.items);
|
|
3604
|
+
if (!hasSlugOrId && !hasItems)
|
|
3605
|
+
return false;
|
|
3606
|
+
if (activeId &&
|
|
3607
|
+
'index' in element &&
|
|
3608
|
+
(element.slug === activeId || element.id === activeId) &&
|
|
3609
|
+
element.index === contextIndex) {
|
|
3610
|
+
return true;
|
|
3611
|
+
}
|
|
3612
|
+
return hasItems ? isActiveGroup(element.items, activeId, contextIndex) : false;
|
|
3613
|
+
});
|
|
3614
|
+
}, []);
|
|
3615
|
+
const hasActive = isActiveGroup(item.items, activeId, lastActiveIndex);
|
|
3569
3616
|
React.useEffect(() => {
|
|
3570
3617
|
const openByDefault = isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault);
|
|
3571
3618
|
if (isOpen !== openByDefault) {
|
|
@@ -3615,8 +3662,10 @@ const Item = React.memo(({ depth, isActive, id, title, meta, icon, isInResponsiv
|
|
|
3615
3662
|
});
|
|
3616
3663
|
Item.displayName = 'Item';
|
|
3617
3664
|
const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode, onClick, onLinkClick = () => { } }) => {
|
|
3618
|
-
const activeId = React.useContext(
|
|
3619
|
-
const
|
|
3665
|
+
const { activeId, lastActiveIndex, setLastActiveIndex } = React.useContext(ActiveItemContext);
|
|
3666
|
+
const { index } = item;
|
|
3667
|
+
const isSlugMatched = activeId === item.slug || activeId === item.id;
|
|
3668
|
+
const isActive = lastActiveIndex === index && isSlugMatched;
|
|
3620
3669
|
const LinkComponent = React.useContext(LinkContext);
|
|
3621
3670
|
const handleClick = (e) => {
|
|
3622
3671
|
if (isActive) {
|
|
@@ -3624,6 +3673,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
|
|
|
3624
3673
|
e.preventDefault();
|
|
3625
3674
|
}
|
|
3626
3675
|
else {
|
|
3676
|
+
setLastActiveIndex(index);
|
|
3627
3677
|
onLinkClick();
|
|
3628
3678
|
}
|
|
3629
3679
|
if (onClick) {
|
|
@@ -3631,7 +3681,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
|
|
|
3631
3681
|
}
|
|
3632
3682
|
};
|
|
3633
3683
|
return (React.createElement(Box, { as: LinkComponent, to: resolveRelativeLink(item.slug), display: "block", textDecoration: "no-underline", className: "ElementsTableOfContentsItem" },
|
|
3634
|
-
React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: handleClick })));
|
|
3684
|
+
React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: e => handleClick(e) })));
|
|
3635
3685
|
});
|
|
3636
3686
|
Node.displayName = 'Node';
|
|
3637
3687
|
const Version = ({ value }) => {
|
package/index.js
CHANGED
|
@@ -3517,7 +3517,7 @@ function findFirstNode(items) {
|
|
|
3517
3517
|
return;
|
|
3518
3518
|
}
|
|
3519
3519
|
function isDivider(item) {
|
|
3520
|
-
return Object.keys(item).length ===
|
|
3520
|
+
return Object.keys(item).length === 2 && 'title' in item && 'index' in item;
|
|
3521
3521
|
}
|
|
3522
3522
|
function isGroup(item) {
|
|
3523
3523
|
return Object.keys(item).length >= 2 && 'title' in item && 'items' in item;
|
|
@@ -3529,13 +3529,33 @@ function isNode(item) {
|
|
|
3529
3529
|
return 'title' in item && 'slug' in item && 'id' in item && 'meta' in item && 'type' in item;
|
|
3530
3530
|
}
|
|
3531
3531
|
function isExternalLink(item) {
|
|
3532
|
-
return Object.keys(item).length ===
|
|
3532
|
+
return Object.keys(item).length === 3 && 'title' in item && 'url' in item && 'index' in item;
|
|
3533
3533
|
}
|
|
3534
3534
|
|
|
3535
|
-
const
|
|
3535
|
+
const ActiveItemContext = React__namespace.createContext({
|
|
3536
|
+
activeId: undefined,
|
|
3537
|
+
lastActiveIndex: '',
|
|
3538
|
+
setLastActiveIndex: () => { },
|
|
3539
|
+
});
|
|
3536
3540
|
const LinkContext = React__namespace.createContext(undefined);
|
|
3537
3541
|
LinkContext.displayName = 'LinkContext';
|
|
3538
3542
|
const TableOfContents = React__namespace.memo(({ tree, activeId, Link, maxDepthOpenByDefault, externalScrollbar = false, isInResponsiveMode = false, onLinkClick, }) => {
|
|
3543
|
+
const [lastActiveIndex, setLastActiveIndex] = React.useState('');
|
|
3544
|
+
const value = React__namespace.useMemo(() => ({
|
|
3545
|
+
lastActiveIndex,
|
|
3546
|
+
setLastActiveIndex,
|
|
3547
|
+
activeId,
|
|
3548
|
+
}), [lastActiveIndex, activeId]);
|
|
3549
|
+
const updateTocTree = React__namespace.useCallback((arr, parentId) => {
|
|
3550
|
+
return arr.map((item, key) => {
|
|
3551
|
+
let newItem = Object.assign(Object.assign({}, item), { index: parentId + key + '-' });
|
|
3552
|
+
if (isGroup(item) || isNodeGroup(item)) {
|
|
3553
|
+
newItem.items = updateTocTree(item.items, parentId + key + '-');
|
|
3554
|
+
}
|
|
3555
|
+
return newItem;
|
|
3556
|
+
});
|
|
3557
|
+
}, []);
|
|
3558
|
+
const updatedTree = updateTocTree(tree, '');
|
|
3539
3559
|
const container = React__namespace.useRef(null);
|
|
3540
3560
|
const child = React__namespace.useRef(null);
|
|
3541
3561
|
const firstRender = useFirstRender();
|
|
@@ -3555,18 +3575,30 @@ const TableOfContents = React__namespace.memo(({ tree, activeId, Link, maxDepthO
|
|
|
3555
3575
|
return (React__namespace.createElement(mosaic.Box, { ref: container, w: "full", bg: isInResponsiveMode ? 'canvas' : 'canvas-100', overflowY: "auto" },
|
|
3556
3576
|
React__namespace.createElement(mosaic.Box, { ref: child, my: 3 },
|
|
3557
3577
|
React__namespace.createElement(LinkContext.Provider, { value: Link },
|
|
3558
|
-
React__namespace.createElement(
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3578
|
+
React__namespace.createElement(ActiveItemContext.Provider, { value: value },
|
|
3579
|
+
React__namespace.createElement(TOCContainer, { updatedTree: updatedTree }, updatedTree.map((item, key) => {
|
|
3580
|
+
if (isDivider(item)) {
|
|
3581
|
+
return React__namespace.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
|
|
3582
|
+
}
|
|
3583
|
+
return (React__namespace.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
|
|
3584
|
+
})))))));
|
|
3564
3585
|
});
|
|
3565
3586
|
TableOfContents.displayName = 'TableOfContents';
|
|
3566
3587
|
const Divider = React__namespace.memo(({ item, isInResponsiveMode = false }) => {
|
|
3567
3588
|
return (React__namespace.createElement(mosaic.Box, { pl: 4, mb: 2, mt: 6, textTransform: "uppercase", fontSize: isInResponsiveMode ? 'lg' : 'sm', lineHeight: "relaxed", letterSpacing: "wide", fontWeight: "bold" }, item.title));
|
|
3568
3589
|
});
|
|
3569
3590
|
Divider.displayName = 'Divider';
|
|
3591
|
+
const TOCContainer = React__namespace.memo(({ children, updatedTree }) => {
|
|
3592
|
+
const { setLastActiveIndex } = React__namespace.useContext(ActiveItemContext);
|
|
3593
|
+
React__namespace.useEffect(() => {
|
|
3594
|
+
const firstNode = findFirstNode(updatedTree);
|
|
3595
|
+
if (firstNode) {
|
|
3596
|
+
setLastActiveIndex(firstNode.index);
|
|
3597
|
+
}
|
|
3598
|
+
}, []);
|
|
3599
|
+
return React__namespace.createElement(mosaic.Box, null, children);
|
|
3600
|
+
});
|
|
3601
|
+
TOCContainer.displayName = 'TOCContainer';
|
|
3570
3602
|
const GroupItem = React__namespace.memo(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick }) => {
|
|
3571
3603
|
if (isExternalLink(item)) {
|
|
3572
3604
|
return (React__namespace.createElement(mosaic.Box, { as: "a", href: item.url, target: "_blank", rel: "noopener noreferrer", display: "block" },
|
|
@@ -3584,9 +3616,24 @@ const GroupItem = React__namespace.memo(({ item, depth, maxDepthOpenByDefault, i
|
|
|
3584
3616
|
});
|
|
3585
3617
|
GroupItem.displayName = 'GroupItem';
|
|
3586
3618
|
const Group = React__namespace.memo(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick = () => { } }) => {
|
|
3587
|
-
const activeId = React__namespace.useContext(
|
|
3619
|
+
const { activeId, lastActiveIndex } = React__namespace.useContext(ActiveItemContext);
|
|
3588
3620
|
const [isOpen, setIsOpen] = React__namespace.useState(() => isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault));
|
|
3589
|
-
const
|
|
3621
|
+
const isActiveGroup = React__namespace.useCallback((items, activeId, contextIndex) => {
|
|
3622
|
+
return items.some(element => {
|
|
3623
|
+
const hasSlugOrId = 'slug' in element || 'id' in element;
|
|
3624
|
+
const hasItems = 'items' in element && Array.isArray(element.items);
|
|
3625
|
+
if (!hasSlugOrId && !hasItems)
|
|
3626
|
+
return false;
|
|
3627
|
+
if (activeId &&
|
|
3628
|
+
'index' in element &&
|
|
3629
|
+
(element.slug === activeId || element.id === activeId) &&
|
|
3630
|
+
element.index === contextIndex) {
|
|
3631
|
+
return true;
|
|
3632
|
+
}
|
|
3633
|
+
return hasItems ? isActiveGroup(element.items, activeId, contextIndex) : false;
|
|
3634
|
+
});
|
|
3635
|
+
}, []);
|
|
3636
|
+
const hasActive = isActiveGroup(item.items, activeId, lastActiveIndex);
|
|
3590
3637
|
React__namespace.useEffect(() => {
|
|
3591
3638
|
const openByDefault = isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault);
|
|
3592
3639
|
if (isOpen !== openByDefault) {
|
|
@@ -3636,8 +3683,10 @@ const Item = React__namespace.memo(({ depth, isActive, id, title, meta, icon, is
|
|
|
3636
3683
|
});
|
|
3637
3684
|
Item.displayName = 'Item';
|
|
3638
3685
|
const Node = React__namespace.memo(({ item, depth, meta, showAsActive, isInResponsiveMode, onClick, onLinkClick = () => { } }) => {
|
|
3639
|
-
const activeId = React__namespace.useContext(
|
|
3640
|
-
const
|
|
3686
|
+
const { activeId, lastActiveIndex, setLastActiveIndex } = React__namespace.useContext(ActiveItemContext);
|
|
3687
|
+
const { index } = item;
|
|
3688
|
+
const isSlugMatched = activeId === item.slug || activeId === item.id;
|
|
3689
|
+
const isActive = lastActiveIndex === index && isSlugMatched;
|
|
3641
3690
|
const LinkComponent = React__namespace.useContext(LinkContext);
|
|
3642
3691
|
const handleClick = (e) => {
|
|
3643
3692
|
if (isActive) {
|
|
@@ -3645,6 +3694,7 @@ const Node = React__namespace.memo(({ item, depth, meta, showAsActive, isInRespo
|
|
|
3645
3694
|
e.preventDefault();
|
|
3646
3695
|
}
|
|
3647
3696
|
else {
|
|
3697
|
+
setLastActiveIndex(index);
|
|
3648
3698
|
onLinkClick();
|
|
3649
3699
|
}
|
|
3650
3700
|
if (onClick) {
|
|
@@ -3652,7 +3702,7 @@ const Node = React__namespace.memo(({ item, depth, meta, showAsActive, isInRespo
|
|
|
3652
3702
|
}
|
|
3653
3703
|
};
|
|
3654
3704
|
return (React__namespace.createElement(mosaic.Box, { as: LinkComponent, to: resolveRelativeLink(item.slug), display: "block", textDecoration: "no-underline", className: "ElementsTableOfContentsItem" },
|
|
3655
|
-
React__namespace.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React__namespace.createElement(mosaic.Box, { as: mosaic.Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: handleClick })));
|
|
3705
|
+
React__namespace.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React__namespace.createElement(mosaic.Box, { as: mosaic.Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: e => handleClick(e) })));
|
|
3656
3706
|
});
|
|
3657
3707
|
Node.displayName = 'Node';
|
|
3658
3708
|
const Version = ({ value }) => {
|
package/index.mjs
CHANGED
|
@@ -3496,7 +3496,7 @@ function findFirstNode(items) {
|
|
|
3496
3496
|
return;
|
|
3497
3497
|
}
|
|
3498
3498
|
function isDivider(item) {
|
|
3499
|
-
return Object.keys(item).length ===
|
|
3499
|
+
return Object.keys(item).length === 2 && 'title' in item && 'index' in item;
|
|
3500
3500
|
}
|
|
3501
3501
|
function isGroup(item) {
|
|
3502
3502
|
return Object.keys(item).length >= 2 && 'title' in item && 'items' in item;
|
|
@@ -3508,13 +3508,33 @@ function isNode(item) {
|
|
|
3508
3508
|
return 'title' in item && 'slug' in item && 'id' in item && 'meta' in item && 'type' in item;
|
|
3509
3509
|
}
|
|
3510
3510
|
function isExternalLink(item) {
|
|
3511
|
-
return Object.keys(item).length ===
|
|
3511
|
+
return Object.keys(item).length === 3 && 'title' in item && 'url' in item && 'index' in item;
|
|
3512
3512
|
}
|
|
3513
3513
|
|
|
3514
|
-
const
|
|
3514
|
+
const ActiveItemContext = React.createContext({
|
|
3515
|
+
activeId: undefined,
|
|
3516
|
+
lastActiveIndex: '',
|
|
3517
|
+
setLastActiveIndex: () => { },
|
|
3518
|
+
});
|
|
3515
3519
|
const LinkContext = React.createContext(undefined);
|
|
3516
3520
|
LinkContext.displayName = 'LinkContext';
|
|
3517
3521
|
const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefault, externalScrollbar = false, isInResponsiveMode = false, onLinkClick, }) => {
|
|
3522
|
+
const [lastActiveIndex, setLastActiveIndex] = useState('');
|
|
3523
|
+
const value = React.useMemo(() => ({
|
|
3524
|
+
lastActiveIndex,
|
|
3525
|
+
setLastActiveIndex,
|
|
3526
|
+
activeId,
|
|
3527
|
+
}), [lastActiveIndex, activeId]);
|
|
3528
|
+
const updateTocTree = React.useCallback((arr, parentId) => {
|
|
3529
|
+
return arr.map((item, key) => {
|
|
3530
|
+
let newItem = Object.assign(Object.assign({}, item), { index: parentId + key + '-' });
|
|
3531
|
+
if (isGroup(item) || isNodeGroup(item)) {
|
|
3532
|
+
newItem.items = updateTocTree(item.items, parentId + key + '-');
|
|
3533
|
+
}
|
|
3534
|
+
return newItem;
|
|
3535
|
+
});
|
|
3536
|
+
}, []);
|
|
3537
|
+
const updatedTree = updateTocTree(tree, '');
|
|
3518
3538
|
const container = React.useRef(null);
|
|
3519
3539
|
const child = React.useRef(null);
|
|
3520
3540
|
const firstRender = useFirstRender();
|
|
@@ -3534,18 +3554,30 @@ const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefaul
|
|
|
3534
3554
|
return (React.createElement(Box, { ref: container, w: "full", bg: isInResponsiveMode ? 'canvas' : 'canvas-100', overflowY: "auto" },
|
|
3535
3555
|
React.createElement(Box, { ref: child, my: 3 },
|
|
3536
3556
|
React.createElement(LinkContext.Provider, { value: Link },
|
|
3537
|
-
React.createElement(
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3557
|
+
React.createElement(ActiveItemContext.Provider, { value: value },
|
|
3558
|
+
React.createElement(TOCContainer, { updatedTree: updatedTree }, updatedTree.map((item, key) => {
|
|
3559
|
+
if (isDivider(item)) {
|
|
3560
|
+
return React.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
|
|
3561
|
+
}
|
|
3562
|
+
return (React.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
|
|
3563
|
+
})))))));
|
|
3543
3564
|
});
|
|
3544
3565
|
TableOfContents.displayName = 'TableOfContents';
|
|
3545
3566
|
const Divider = React.memo(({ item, isInResponsiveMode = false }) => {
|
|
3546
3567
|
return (React.createElement(Box, { pl: 4, mb: 2, mt: 6, textTransform: "uppercase", fontSize: isInResponsiveMode ? 'lg' : 'sm', lineHeight: "relaxed", letterSpacing: "wide", fontWeight: "bold" }, item.title));
|
|
3547
3568
|
});
|
|
3548
3569
|
Divider.displayName = 'Divider';
|
|
3570
|
+
const TOCContainer = React.memo(({ children, updatedTree }) => {
|
|
3571
|
+
const { setLastActiveIndex } = React.useContext(ActiveItemContext);
|
|
3572
|
+
React.useEffect(() => {
|
|
3573
|
+
const firstNode = findFirstNode(updatedTree);
|
|
3574
|
+
if (firstNode) {
|
|
3575
|
+
setLastActiveIndex(firstNode.index);
|
|
3576
|
+
}
|
|
3577
|
+
}, []);
|
|
3578
|
+
return React.createElement(Box, null, children);
|
|
3579
|
+
});
|
|
3580
|
+
TOCContainer.displayName = 'TOCContainer';
|
|
3549
3581
|
const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick }) => {
|
|
3550
3582
|
if (isExternalLink(item)) {
|
|
3551
3583
|
return (React.createElement(Box, { as: "a", href: item.url, target: "_blank", rel: "noopener noreferrer", display: "block" },
|
|
@@ -3563,9 +3595,24 @@ const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsi
|
|
|
3563
3595
|
});
|
|
3564
3596
|
GroupItem.displayName = 'GroupItem';
|
|
3565
3597
|
const Group = React.memo(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick = () => { } }) => {
|
|
3566
|
-
const activeId = React.useContext(
|
|
3598
|
+
const { activeId, lastActiveIndex } = React.useContext(ActiveItemContext);
|
|
3567
3599
|
const [isOpen, setIsOpen] = React.useState(() => isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault));
|
|
3568
|
-
const
|
|
3600
|
+
const isActiveGroup = React.useCallback((items, activeId, contextIndex) => {
|
|
3601
|
+
return items.some(element => {
|
|
3602
|
+
const hasSlugOrId = 'slug' in element || 'id' in element;
|
|
3603
|
+
const hasItems = 'items' in element && Array.isArray(element.items);
|
|
3604
|
+
if (!hasSlugOrId && !hasItems)
|
|
3605
|
+
return false;
|
|
3606
|
+
if (activeId &&
|
|
3607
|
+
'index' in element &&
|
|
3608
|
+
(element.slug === activeId || element.id === activeId) &&
|
|
3609
|
+
element.index === contextIndex) {
|
|
3610
|
+
return true;
|
|
3611
|
+
}
|
|
3612
|
+
return hasItems ? isActiveGroup(element.items, activeId, contextIndex) : false;
|
|
3613
|
+
});
|
|
3614
|
+
}, []);
|
|
3615
|
+
const hasActive = isActiveGroup(item.items, activeId, lastActiveIndex);
|
|
3569
3616
|
React.useEffect(() => {
|
|
3570
3617
|
const openByDefault = isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault);
|
|
3571
3618
|
if (isOpen !== openByDefault) {
|
|
@@ -3615,8 +3662,10 @@ const Item = React.memo(({ depth, isActive, id, title, meta, icon, isInResponsiv
|
|
|
3615
3662
|
});
|
|
3616
3663
|
Item.displayName = 'Item';
|
|
3617
3664
|
const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode, onClick, onLinkClick = () => { } }) => {
|
|
3618
|
-
const activeId = React.useContext(
|
|
3619
|
-
const
|
|
3665
|
+
const { activeId, lastActiveIndex, setLastActiveIndex } = React.useContext(ActiveItemContext);
|
|
3666
|
+
const { index } = item;
|
|
3667
|
+
const isSlugMatched = activeId === item.slug || activeId === item.id;
|
|
3668
|
+
const isActive = lastActiveIndex === index && isSlugMatched;
|
|
3620
3669
|
const LinkComponent = React.useContext(LinkContext);
|
|
3621
3670
|
const handleClick = (e) => {
|
|
3622
3671
|
if (isActive) {
|
|
@@ -3624,6 +3673,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
|
|
|
3624
3673
|
e.preventDefault();
|
|
3625
3674
|
}
|
|
3626
3675
|
else {
|
|
3676
|
+
setLastActiveIndex(index);
|
|
3627
3677
|
onLinkClick();
|
|
3628
3678
|
}
|
|
3629
3679
|
if (onClick) {
|
|
@@ -3631,7 +3681,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
|
|
|
3631
3681
|
}
|
|
3632
3682
|
};
|
|
3633
3683
|
return (React.createElement(Box, { as: LinkComponent, to: resolveRelativeLink(item.slug), display: "block", textDecoration: "no-underline", className: "ElementsTableOfContentsItem" },
|
|
3634
|
-
React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: handleClick })));
|
|
3684
|
+
React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: e => handleClick(e) })));
|
|
3635
3685
|
});
|
|
3636
3686
|
Node.displayName = 'Node';
|
|
3637
3687
|
const Version = ({ value }) => {
|