Skip to content

Commit 4921830

Browse files
committed
Auto-expand/collapse nav items
1 parent 145e78b commit 4921830

File tree

7 files changed

+273
-190
lines changed

7 files changed

+273
-190
lines changed

website/src/HomePage.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,7 @@ export default function HomePage({ supportedNetworks }: { supportedNetworks: Sup
200200
!['boba-bnb', 'eos-evm', 'polygon-zkevm', 'solana-accounts'].includes(network.id),
201201
)
202202
// Filter out networks that don't have a proper monochrome logo
203-
.filter((network) => {
204-
return network.id !== 'zora'
205-
})
203+
.filter((network) => network.id !== 'zora')
206204
.map((network) => (
207205
<li key={network.id} className="-mb-px -mr-px">
208206
<Tooltip content={network.shortName}>

website/src/components/Image.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
import NextImage from 'next/image'
21
import type { ComponentProps } from 'react'
32

43
import { classNames } from '@edgeandnode/gds'
54

6-
export interface ImageProps extends Omit<ComponentProps<'img'>, 'src'> {
7-
src?: ComponentProps<typeof NextImage>['src']
8-
}
5+
interface ImageProps extends ComponentProps<'img'> {}
96

10-
export const Image = ({ src: passedSrc, alt, className, ...props }: ImageProps) => {
11-
const src =
12-
typeof passedSrc === 'object' ? ('default' in passedSrc ? passedSrc.default.src : passedSrc.src) : passedSrc
7+
export const Image = ({ src, alt, className, ...props }: ImageProps) => {
138
return (
149
<figure
1510
className={classNames([

website/src/components/Navigation.tsx

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,33 @@ export const NavigationList = ({ className, children, ...props }: ComponentProps
3434
)
3535
}
3636

37+
// TODO: Use GDS's `useControlled` when the `OnChangeArgs` generic is added
38+
function useControlled<T, OnChangeValue extends T = T, OnChangeArgs extends any[] = []>(
39+
controlledValue: T | undefined,
40+
defaultValue: T,
41+
onChange?: (value: OnChangeValue, ...args: OnChangeArgs) => void,
42+
) {
43+
const [uncontrolledValue, setUncontrolledValue] = useState(
44+
controlledValue !== undefined ? controlledValue : defaultValue,
45+
)
46+
const value = controlledValue !== undefined ? controlledValue : uncontrolledValue
47+
const setValue = (newValue: OnChangeValue, ...args: OnChangeArgs) => {
48+
if (newValue === value) return
49+
onChange?.(newValue, ...args)
50+
if (controlledValue === undefined) {
51+
setUncontrolledValue(newValue)
52+
}
53+
}
54+
return [value, setValue] as const
55+
}
56+
3757
declare namespace NavigationItemProps {
3858
interface BaseProps {
3959
title: string
4060
icon?: ReactNode
4161
selected?: boolean | 'partially'
62+
expanded?: boolean
63+
onExpandedChange?: (expanded: boolean, manual: boolean) => void
4264
}
4365
type OmittedButtonOrLinkProps = 'title' | 'selected'
4466
interface ButtonProps extends BaseProps, Omit<ButtonOrLinkProps.ButtonProps, OmittedButtonOrLinkProps> {}
@@ -55,14 +77,16 @@ export const NavigationItem = ({
5577
title,
5678
icon,
5779
selected,
80+
expanded: controlledExpanded,
81+
onExpandedChange,
5882
onClick,
5983
className,
6084
children,
6185
...props
6286
}: NavigationItemProps) => {
6387
const navigationListContext = useContext(NavigationListContext)
6488
const depth = navigationListContext?.depth ?? 0
65-
const [expandedIfChildren, setExpanded] = useState(false)
89+
const [expandedIfChildren, setExpanded] = useControlled(controlledExpanded, false, onExpandedChange)
6690
const expanded = children ? expandedIfChildren : false
6791

6892
return (
@@ -85,7 +109,7 @@ export const NavigationItem = ({
85109
<ButtonOrLink
86110
selected={selected === true}
87111
onClick={(event: MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {
88-
setExpanded(true)
112+
setExpanded(true, false)
89113
onClick?.(event)
90114
}}
91115
className={`
@@ -140,7 +164,7 @@ export const NavigationItem = ({
140164
variant="naked"
141165
size="xsmall"
142166
aria-expanded={expanded}
143-
onClick={() => setExpanded((expanded) => !expanded)}
167+
onClick={() => setExpanded(!expanded, true)}
144168
>
145169
<CaretDown
146170
alt={expanded ? 'Collapse' : 'Expand'}
@@ -160,12 +184,12 @@ export const NavigationItem = ({
160184
duration={300}
161185
mode="exit-enter"
162186
className={`
163-
not-safari:group-data-[depth=1]/navigation-list:[--gds-transition-enter-translate-x:-16px]
164-
not-safari:group-data-[depth=1]/navigation-list:[--gds-transition-exit-translate-x:-16px]
187+
group-data-[depth=1]/navigation-list:[--gds-transition-enter-translate-x:-16px]
188+
group-data-[depth=1]/navigation-list:[--gds-transition-exit-translate-x:-16px]
165189
not-in-group-data-[depth=1]/navigation-list:[--gds-transition-enter-opacity:1]
166190
not-in-group-data-[depth=1]/navigation-list:[--gds-transition-exit-opacity:1]
167-
rtl:not-safari:group-data-[depth=1]/navigation-list:[--gds-transition-enter-translate-x:16px]
168-
rtl:not-safari:group-data-[depth=1]/navigation-list:[--gds-transition-exit-translate-x:16px]
191+
rtl:group-data-[depth=1]/navigation-list:[--gds-transition-enter-translate-x:16px]
192+
rtl:group-data-[depth=1]/navigation-list:[--gds-transition-exit-translate-x:16px]
169193
`}
170194
>
171195
<NavigationList
@@ -190,9 +214,7 @@ export const NavigationItem = ({
190214
data-expanded={expanded || undefined}
191215
className={`
192216
absolute -top-2 start-0 z-10 aspect-square w-full origin-[start] bg-space-1800 fill-none stroke-space-1500 transition duration-150
193-
safari:delay-150
194217
not-data-[expanded]:opacity-0
195-
not-data-[expanded]:safari:delay-0
196218
rtl:-scale-x-100
197219
`}
198220
>
@@ -232,9 +254,7 @@ export const NavigationItem = ({
232254
data-expanded={expanded || undefined}
233255
className={`
234256
absolute -bottom-2 start-0 aspect-square w-full origin-[start] bg-space-1800 fill-none stroke-space-1500 transition duration-150
235-
safari:delay-150
236257
not-data-[expanded]:opacity-0
237-
not-data-[expanded]:safari:delay-0
238258
nearest-group-[:has(ul:not(:scope_ul_*,[inert]_*)>li:last-child[data-expanded])]/navigation-item:opacity-0
239259
nearest-group-[:has(ul:not(:scope_ul_*,[inert]_*)>li:last-child[data-expanded])]/navigation-item:delay-150
240260
@style-[--docs-navigation-item-last=1]:opacity-0

website/src/components/TimeIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { HourglassDynamic } from '@edgeandnode/gds/icons'
55

66
import { useI18n } from '@/i18n'
77

8-
export interface TimeIconProps extends ComponentProps<'div'> {
8+
interface TimeIconProps extends ComponentProps<'div'> {
99
variant: 'reading' | 'duration'
1010
minutes: number
1111
}

0 commit comments

Comments
 (0)