Skip to content

Commit 411cc38

Browse files
Merge pull request #131 from linked-planet/dev
Dev
2 parents 4434f3d + a1b3d3a commit 411cc38

File tree

9 files changed

+499
-288
lines changed

9 files changed

+499
-288
lines changed

library/src/components/Modal.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ type ModalDialogProps = {
3333
triggerTestId?: string
3434
/** The accessible description for the dialog, is visually hidden but announced by screen readers */
3535
accessibleDialogDescription: string
36+
role?: RDialog.DialogContentProps["role"]
37+
tabIndex?: RDialog.DialogContentProps["tabIndex"]
3638
}
3739

3840
const blanketStyles =
@@ -55,7 +57,9 @@ function Container({
5557
triggerId,
5658
testId,
5759
triggerTestId,
60+
role = "dialog",
5861
accessibleDialogDescription,
62+
tabIndex = 0,
5963
}: ModalDialogProps) {
6064
const content = useMemo(
6165
() => (
@@ -94,6 +98,8 @@ function Container({
9498
onWheel={(e) => {
9599
e.stopPropagation() // this is necessary or scrolling will not work in the select dropdown menu in the modal
96100
}}
101+
role={role}
102+
tabIndex={tabIndex}
97103
>
98104
<VisuallyHidden>
99105
<RDialog.DialogDescription>
@@ -115,6 +121,8 @@ function Container({
115121
testId,
116122
useModal,
117123
accessibleDialogDescription,
124+
role,
125+
tabIndex,
118126
],
119127
)
120128

library/src/components/SlideOpen.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
import type { CSSProperties, RefObject } from "react"
22
import { twMerge } from "tailwind-merge"
33

4+
type SlideOpenProps = /*ComponentPropsWithRef<"div"> &*/ {
5+
open: boolean
6+
containerClassName?: string
7+
containerStyle?: CSSProperties
8+
contentClassName?: string
9+
contentStyle?: CSSProperties
10+
tabIndex?: number
11+
ariaLabel?: string
12+
ariaExpanded?: boolean
13+
children: React.ReactNode
14+
ref?: RefObject<HTMLDivElement>
15+
}
16+
417
export function SlideOpen({
518
children,
619
containerClassName,
720
containerStyle,
821
contentStyle,
922
contentClassName,
1023
open,
24+
ariaLabel,
25+
ariaExpanded,
26+
tabIndex,
1127
ref,
12-
}: {
13-
children: React.ReactNode
14-
containerClassName?: string
15-
containerStyle?: CSSProperties
16-
contentClassName?: string
17-
contentStyle?: CSSProperties
18-
open: boolean
19-
ref?: RefObject<HTMLDivElement>
20-
}) {
28+
...props
29+
}: SlideOpenProps) {
2130
return (
2231
<div
2332
className={twMerge(
@@ -27,6 +36,10 @@ export function SlideOpen({
2736
style={containerStyle}
2837
data-open={open}
2938
ref={ref}
39+
aria-label={ariaLabel}
40+
aria-expanded={ariaExpanded ?? open}
41+
tabIndex={tabIndex}
42+
{...props}
3043
>
3144
<div
3245
className={twMerge(

library/src/components/sidenavigation/SideNavigation.tsx

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ function Container({
4747
return (
4848
<nav
4949
className={twMerge(
50-
"bg-surface text-text-subtle relative flex size-full flex-col overflow-hidden truncate py-4",
50+
"bg-surface text-text-subtle relative flex size-full flex-col overflow-hidden truncate",
5151
className,
5252
)}
5353
role={role}
@@ -66,12 +66,10 @@ function Content({
6666
children,
6767
className,
6868
style,
69-
storeIdent = "side-nav-store",
7069
}: {
7170
children: React.ReactNode
7271
className?: string
7372
style?: React.CSSProperties
74-
storeIdent?: string
7573
}) {
7674
const ref = useRef<HTMLDivElement>(null)
7775

@@ -455,6 +453,7 @@ type _NestingItemProps = {
455453
style?: React.CSSProperties
456454
title: string // title is used to identify the item and as a key
457455
sideNavStoreIdent?: string
456+
id: string
458457
}
459458

460459
function NestingItem({
@@ -464,6 +463,7 @@ function NestingItem({
464463
sideNavStoreIdent = "default",
465464
title,
466465
_isOpen,
466+
id,
467467
}: _NestingItemProps & { _isOpen?: boolean }) {
468468
const {
469469
getCurrentPathElement,
@@ -488,7 +488,7 @@ function NestingItem({
488488
return (
489489
<ButtonItem
490490
onClick={() => {
491-
pushPathElement(title)
491+
pushPathElement(id)
492492
setTransitioning(true)
493493
window.setTimeout(() => setTransitioning(null), animTime * 1000)
494494
}}
@@ -498,6 +498,7 @@ function NestingItem({
498498
className="rounded-full p-1 box-border bg-neutral-full size-5.5 text-text-inverse"
499499
/>
500500
}
501+
id={id}
501502
>
502503
{title}
503504
</ButtonItem>
@@ -510,24 +511,26 @@ type _NestableNavigationContentProps = {
510511
className?: string
511512
style?: React.CSSProperties
512513
sideNavStoreIdent?: string
514+
onAnimationStart?: () => void
515+
onAnimationComplete?: () => void
513516
}
514517

515518
function searchChild(
516519
children: React.ReactNode,
517-
currentOpenedTitle: string | undefined,
520+
currentOpenedId: string | undefined,
518521
) {
519522
let renderChild: React.ReactElement<_NestingItemProps> | null = null
520523
React.Children.forEach(children, (child) => {
521524
if (renderChild) return
522525
if (
523526
React.isValidElement<_NestingItemProps>(child) &&
524-
child.props.title === currentOpenedTitle
527+
child.props.id === currentOpenedId
525528
) {
526529
renderChild = child
527530
return
528531
}
529532
if (React.isValidElement(child)) {
530-
const ret = searchChild(child.props.children, currentOpenedTitle)
533+
const ret = searchChild(child.props.children, currentOpenedId)
531534
if (ret) renderChild = ret
532535
}
533536
})
@@ -542,14 +545,16 @@ function NestableNavigationContent({
542545
sideNavStoreIdent = "default",
543546
className,
544547
style,
548+
onAnimationStart,
549+
onAnimationComplete,
545550
}: _NestableNavigationContentProps) {
546-
const { popPathElement, getCurrentPathElement, setTransitioning } =
551+
const { popPathElement, getCurrentPathElement, setTransitioning, path } =
547552
useSideNavigationStore(sideNavStoreIdent)
548553

549-
const currentOpenedTitle = getCurrentPathElement()
554+
const currentOpenedId = getCurrentPathElement()
550555

551-
const renderChild = currentOpenedTitle
552-
? searchChild(children, currentOpenedTitle)
556+
const renderChild = currentOpenedId
557+
? searchChild(children, currentOpenedId)
553558
: null
554559

555560
const [isBack, setIsBack] = useState(false)
@@ -561,7 +566,7 @@ function NestableNavigationContent({
561566
>
562567
<AnimatePresence initial={false} mode="popLayout">
563568
{/* root level elements */}
564-
{!renderChild && (
569+
{!currentOpenedId && (
565570
<motion.div
566571
key="outside"
567572
//layout
@@ -574,13 +579,19 @@ function NestableNavigationContent({
574579
duration: animTime,
575580
ease: "easeInOut",
576581
}}
582+
onAnimationStart={() => {
583+
onAnimationStart?.()
584+
}}
585+
onAnimationComplete={() => {
586+
onAnimationComplete?.()
587+
}}
577588
>
578589
{children}
579590
</motion.div>
580591
)}
581592
</AnimatePresence>
582593
<AnimatePresence initial={false} mode="popLayout">
583-
{renderChild && (
594+
{currentOpenedId && (
584595
<motion.div
585596
key="go-back-btn"
586597
initial={{ x: "100%" }}
@@ -615,12 +626,14 @@ function NestableNavigationContent({
615626
<AnimatePresence
616627
initial={false}
617628
mode="popLayout"
618-
onExitComplete={() => setIsBack(false)}
629+
onExitComplete={() => {
630+
setIsBack(false)
631+
}}
619632
>
620633
{/* followed by the lower level elements */}
621-
{renderChild && (
634+
{renderChild != null && (
622635
<motion.div
623-
key={`inside-${currentOpenedTitle}`}
636+
key={`inside-${currentOpenedId}`}
624637
initial={{
625638
x: isBack ? "-100%" : "100%",
626639
}}
@@ -635,7 +648,13 @@ function NestableNavigationContent({
635648
ease: "easeInOut",
636649
//delay: animTime * 0.5,
637650
}}
638-
className="border-b-border-separator border-t-border-separator box-border flex size-full border-b-2 border-t-2 border-solid py-2"
651+
className="border-b-border-separator border-t-border-separator box-border flex size-full border-b-2 border-t-2 border-solid"
652+
onAnimationStart={() => {
653+
onAnimationStart?.()
654+
}}
655+
onAnimationComplete={() => {
656+
onAnimationComplete?.()
657+
}}
639658
>
640659
{React.cloneElement(renderChild, { _isOpen: true })}
641660
</motion.div>

library/src/components/sidenavigation/SideNavigationStore.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,20 @@ const store = proxy<Record<string, SideNavigationStore>>({})
1010

1111
export function useSideNavigationStore(sideNavStoreIdent: string) {
1212
if (!store[sideNavStoreIdent]) {
13-
store[sideNavStoreIdent] = {
13+
store[sideNavStoreIdent] = proxy<SideNavigationStore>({
1414
path: [],
1515
transitioning: null,
16-
}
16+
})
1717
}
1818

1919
const path = useSnapshot(store[sideNavStoreIdent])
20-
console.info(
21-
"SideNavigationStore -",
22-
sideNavStoreIdent,
23-
path.path.map((e) => e),
24-
)
25-
2620
const setPath = useCallback(
2721
(path: string[]) =>
28-
store[sideNavStoreIdent].path.splice(0, path.length, ...path),
22+
store[sideNavStoreIdent].path.splice(
23+
0,
24+
Number.POSITIVE_INFINITY,
25+
...path,
26+
),
2927
[sideNavStoreIdent],
3028
)
3129

0 commit comments

Comments
 (0)