diff --git a/.changeset/sharp-eggs-crash.md b/.changeset/sharp-eggs-crash.md new file mode 100644 index 00000000000..3e64d1a28c1 --- /dev/null +++ b/.changeset/sharp-eggs-crash.md @@ -0,0 +1,7 @@ +--- +"@primer/react": patch +--- + +`TreeView` is now SSR-compatible. + +Warning: In this new implementation, `TreeView.LeadingVisual` and `TreeView.TrailingView` must be direct children of `TreeView.Item`. diff --git a/generated/components.json b/generated/components.json index a4ce8d3884f..73d9ef09355 100644 --- a/generated/components.json +++ b/generated/components.json @@ -5121,4 +5121,4 @@ "subcomponents": [] } } -} +} \ No newline at end of file diff --git a/src/TreeView/TreeView.tsx b/src/TreeView/TreeView.tsx index d70195cfa90..e0891177373 100644 --- a/src/TreeView/TreeView.tsx +++ b/src/TreeView/TreeView.tsx @@ -7,16 +7,16 @@ import { import classnames from 'classnames' import React from 'react' import styled, {keyframes} from 'styled-components' -import {get} from '../constants' import {ConfirmationDialog} from '../Dialog/ConfirmationDialog' +import Spinner from '../Spinner' +import Text from '../Text' +import VisuallyHidden from '../_VisuallyHidden' +import {get} from '../constants' import {useControllableState} from '../hooks/useControllableState' import {useId} from '../hooks/useId' import useSafeTimeout from '../hooks/useSafeTimeout' -import Spinner from '../Spinner' +import {useSlots} from '../hooks/useSlots' import sx, {SxProp} from '../sx' -import Text from '../Text' -import createSlots from '../utils/create-slots' -import VisuallyHidden from '../_VisuallyHidden' import {getAccessibleName} from './shared' import {getFirstChildElement, useRovingTabIndex} from './useRovingTabIndex' import {useTypeahead} from './useTypeahead' @@ -302,8 +302,6 @@ export type TreeViewItemProps = { onSelect?: (event: React.MouseEvent | React.KeyboardEvent) => void } -const {Slots, Slot} = createSlots(['LeadingVisual', 'TrailingVisual']) - const Item = React.forwardRef( ( { @@ -318,6 +316,7 @@ const Item = React.forwardRef( }, ref, ) => { + const [slots, rest] = useSlots(children, {leadingVisual: LeadingVisual, trailingVisual: TrailingVisual}) const {expandedStateCache} = React.useContext(RootContext) const labelId = useId() const leadingVisualId = useId() @@ -333,7 +332,7 @@ const Item = React.forwardRef( onChange: onExpandedChange, }) const {level} = React.useContext(ItemContext) - const {hasSubTree, subTree, childrenWithoutSubTree} = useSubTree(children) + const {hasSubTree, subTree, childrenWithoutSubTree} = useSubTree(rest) const [isSubTreeEmpty, setIsSubTreeEmpty] = React.useState(!hasSubTree) const [isFocused, setIsFocused] = React.useState(false) @@ -462,15 +461,9 @@ const Item = React.forwardRef( ) : null}
- - {slots => ( - <> - {slots.LeadingVisual} - {childrenWithoutSubTree} - {slots.TrailingVisual} - - )} - + {slots.leadingVisual} + {childrenWithoutSubTree} + {slots.trailingVisual}
{subTree} @@ -757,14 +750,14 @@ const LeadingVisual: React.FC = props => { const {isExpanded, leadingVisualId} = React.useContext(ItemContext) const children = typeof props.children === 'function' ? props.children({isExpanded}) : props.children return ( - + <>
{props.label}
{children}
-
+ ) } @@ -774,14 +767,14 @@ const TrailingVisual: React.FC = props => { const {isExpanded, trailingVisualId} = React.useContext(ItemContext) const children = typeof props.children === 'function' ? props.children({isExpanded}) : props.children return ( - + <>
{props.label}
{children}
-
+ ) } diff --git a/src/hooks/useSlots.ts b/src/hooks/useSlots.ts index 6c1de73a3dd..e9df43bc449 100644 --- a/src/hooks/useSlots.ts +++ b/src/hooks/useSlots.ts @@ -1,7 +1,8 @@ import React from 'react' import {warning} from '../utils/warning' -export type SlotConfig = Record +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type SlotConfig = Record> type SlotElements = { [Property in keyof Type]: React.ReactElement