Skip to content

Commit ab61553

Browse files
committed
centralize don't animate logic for side modals
1 parent 111646f commit ab61553

File tree

12 files changed

+45
-81
lines changed

12 files changed

+45
-81
lines changed

app/components/form/ReadOnlySideModalForm.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88
import type { ReactNode } from 'react'
99

10+
import { useShouldAnimateModal } from '~/hooks/use-should-animate-modal'
1011
import { Button } from '~/ui/lib/Button'
1112
import { SideModal } from '~/ui/lib/SideModal'
1213

@@ -15,11 +16,7 @@ type ReadOnlySideModalFormProps = {
1516
subtitle?: ReactNode
1617
onDismiss: () => void
1718
children: ReactNode
18-
/**
19-
* Whether to animate the modal opening. Defaults to true. Used to prevent
20-
* modal from animating in on a fresh pageload where it should already be
21-
* open.
22-
*/
19+
/** Pass `true` for state-driven modals. Omit for route-driven modals to use nav type. */
2320
animate?: boolean
2421
}
2522

@@ -34,13 +31,14 @@ export function ReadOnlySideModalForm({
3431
children,
3532
animate,
3633
}: ReadOnlySideModalFormProps) {
34+
const animateDefault = useShouldAnimateModal()
3735
return (
3836
<SideModal
3937
isOpen
4038
onDismiss={onDismiss}
4139
title={title}
4240
subtitle={subtitle}
43-
animate={animate}
41+
animate={animate ?? animateDefault}
4442
>
4543
<SideModal.Body>
4644
<div className="ox-form">{children}</div>

app/components/form/SideModalForm.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88

99
import { useEffect, useId, useState, type ReactNode } from 'react'
1010
import type { FieldValues, UseFormReturn } from 'react-hook-form'
11-
import { NavigationType, useNavigationType } from 'react-router'
1211

1312
import type { ApiError } from '@oxide/api'
1413

14+
import { useShouldAnimateModal } from '~/hooks/use-should-animate-modal'
1515
import { Button } from '~/ui/lib/Button'
1616
import { Modal } from '~/ui/lib/Modal'
1717
import { SideModal } from '~/ui/lib/SideModal'
@@ -49,16 +49,6 @@ type SideModalFormProps<TFieldValues extends FieldValues> = {
4949
onSubmit?: (values: TFieldValues) => void
5050
} & (CreateFormProps | EditFormProps)
5151

52-
/**
53-
* Only animate the modal in when we're navigating by a client-side click.
54-
* Don't animate on a fresh pageload or on back/forward. The latter may be
55-
* slightly awkward but it also makes some sense. I do not believe there is
56-
* any way to distinguish between fresh pageload and back/forward.
57-
*/
58-
function useShouldAnimateModal() {
59-
return useNavigationType() === NavigationType.Push
60-
}
61-
6252
export function SideModalForm<TFieldValues extends FieldValues>({
6353
form,
6454
formType,

app/forms/idp/edit.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@
66
* Copyright Oxide Computer Company
77
*/
88
import { useForm } from 'react-hook-form'
9-
import {
10-
NavigationType,
11-
useNavigate,
12-
useNavigationType,
13-
type LoaderFunctionArgs,
14-
} from 'react-router'
9+
import { useNavigate, type LoaderFunctionArgs } from 'react-router'
1510

1611
import { api, q, queryClient, usePrefetchedQuery } from '@oxide/api'
1712
import { Access16Icon } from '@oxide/design-system/icons/react'
@@ -45,15 +40,13 @@ export default function EditIdpSideModalForm() {
4540

4641
const navigate = useNavigate()
4742
const onDismiss = () => navigate(pb.silo({ silo }))
48-
const animate = useNavigationType() === NavigationType.Push
4943

5044
const form = useForm({ defaultValues: idp })
5145

5246
return (
5347
<ReadOnlySideModalForm
5448
title="Identity provider"
5549
onDismiss={onDismiss}
56-
animate={animate}
5750
subtitle={
5851
<ResourceLabel>
5952
<Access16Icon /> {idp.name}

app/forms/image-edit.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,10 @@ export function EditImageSideModalForm({
2424
image,
2525
dismissLink,
2626
type,
27-
animate,
2827
}: {
2928
image: Image
3029
dismissLink: string
3130
type: 'Project' | 'Silo'
32-
animate?: boolean
3331
}) {
3432
const navigate = useNavigate()
3533
const form = useForm({ defaultValues: image })
@@ -40,7 +38,6 @@ export function EditImageSideModalForm({
4038
<ReadOnlySideModalForm
4139
title={capitalize(resourceName)}
4240
onDismiss={onDismiss}
43-
animate={animate}
4441
subtitle={
4542
<ResourceLabel>
4643
<Images16Icon /> {image.name}

app/forms/ssh-key-edit.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@
66
* Copyright Oxide Computer Company
77
*/
88
import { useForm } from 'react-hook-form'
9-
import {
10-
NavigationType,
11-
useNavigate,
12-
useNavigationType,
13-
type LoaderFunctionArgs,
14-
} from 'react-router'
9+
import { useNavigate, type LoaderFunctionArgs } from 'react-router'
1510

1611
import { api, q, queryClient, usePrefetchedQuery } from '@oxide/api'
1712
import { Key16Icon } from '@oxide/design-system/icons/react'
@@ -47,13 +42,11 @@ export default function EditSSHKeySideModalForm() {
4742

4843
const form = useForm({ defaultValues: data })
4944
const onDismiss = () => navigate(pb.sshKeys())
50-
const animate = useNavigationType() === NavigationType.Push
5145

5246
return (
5347
<ReadOnlySideModalForm
5448
title="View SSH key"
5549
onDismiss={onDismiss}
56-
animate={animate}
5750
subtitle={
5851
<ResourceLabel>
5952
<Key16Icon /> {data.name}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright Oxide Computer Company
7+
*/
8+
import { NavigationType, useNavigationType } from 'react-router'
9+
10+
/**
11+
* Only animate the modal in when we're navigating by a client-side click.
12+
* Don't animate on a fresh pageload or on back/forward. The latter may be
13+
* slightly awkward but it also makes some sense. I do not believe there is
14+
* any way to distinguish between fresh pageload and back/forward.
15+
*/
16+
export function useShouldAnimateModal() {
17+
const navType = useNavigationType()
18+
return navType === NavigationType.Push || navType === NavigationType.Replace
19+
}

app/pages/SiloImageEdit.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Copyright Oxide Computer Company
77
*/
8-
import { NavigationType, useNavigationType, type LoaderFunctionArgs } from 'react-router'
8+
import type { LoaderFunctionArgs } from 'react-router'
99

1010
import { api, q, queryClient, usePrefetchedQuery } from '@oxide/api'
1111

@@ -28,14 +28,6 @@ export const handle = titleCrumb('Edit Image')
2828
export default function SiloImageEdit() {
2929
const selector = useSiloImageSelector()
3030
const { data } = usePrefetchedQuery(imageView(selector))
31-
const animate = useNavigationType() === NavigationType.Push
3231

33-
return (
34-
<EditImageSideModalForm
35-
image={data}
36-
dismissLink={pb.siloImages()}
37-
type="Silo"
38-
animate={animate}
39-
/>
40-
)
32+
return <EditImageSideModalForm image={data} dismissLink={pb.siloImages()} type="Silo" />
4133
}

app/pages/project/disks/DiskDetailSideModal.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55
*
66
* Copyright Oxide Computer Company
77
*/
8-
import {
9-
NavigationType,
10-
useNavigate,
11-
useNavigationType,
12-
type LoaderFunctionArgs,
13-
} from 'react-router'
8+
import { useNavigate, type LoaderFunctionArgs } from 'react-router'
149

1510
import { api, q, queryClient, usePrefetchedQuery, type Disk } from '@oxide/api'
1611
import { Storage16Icon } from '@oxide/design-system/icons/react'
@@ -41,14 +36,9 @@ export default function DiskDetailSideModalRoute() {
4136
const { project, disk } = useDiskSelector()
4237
const navigate = useNavigate()
4338
const { data } = usePrefetchedQuery(diskView({ project, disk }))
44-
const animate = useNavigationType() === NavigationType.Push
4539

4640
return (
47-
<DiskDetailSideModal
48-
disk={data}
49-
onDismiss={() => navigate(pb.disks({ project }))}
50-
animate={animate}
51-
/>
41+
<DiskDetailSideModal disk={data} onDismiss={() => navigate(pb.disks({ project }))} />
5242
)
5343
}
5444

@@ -60,14 +50,14 @@ export default function DiskDetailSideModalRoute() {
6050
type DiskDetailSideModalProps = {
6151
disk: Disk
6252
onDismiss: () => void
63-
/** Default true because when used outside a route (e.g., StorageTab), it's always a click action */
53+
/** Pass `true` for state-driven usage (e.g., StorageTab). Omit for route usage. */
6454
animate?: boolean
6555
}
6656

6757
export function DiskDetailSideModal({
6858
disk,
6959
onDismiss,
70-
animate = true,
60+
animate,
7161
}: DiskDetailSideModalProps) {
7262
return (
7363
<ReadOnlySideModalForm

app/pages/project/images/ProjectImageEdit.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Copyright Oxide Computer Company
77
*/
8-
import { NavigationType, useNavigationType, type LoaderFunctionArgs } from 'react-router'
8+
import type { LoaderFunctionArgs } from 'react-router'
99

1010
import { api, q, queryClient, usePrefetchedQuery } from '@oxide/api'
1111

@@ -29,15 +29,7 @@ export const handle = titleCrumb('Edit Image')
2929
export default function ProjectImageEdit() {
3030
const selector = useProjectImageSelector()
3131
const { data } = usePrefetchedQuery(imageView(selector))
32-
const animate = useNavigationType() === NavigationType.Push
3332

3433
const dismissLink = pb.projectImages({ project: selector.project })
35-
return (
36-
<EditImageSideModalForm
37-
image={data}
38-
dismissLink={dismissLink}
39-
type="Project"
40-
animate={animate}
41-
/>
42-
)
34+
return <EditImageSideModalForm image={data} dismissLink={dismissLink} type="Project" />
4335
}

app/pages/project/instances/StorageTab.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,11 @@ export default function StorageTab() {
420420
/>
421421
)}
422422
{selectedDisk && (
423-
<DiskDetailSideModal disk={selectedDisk} onDismiss={() => setSelectedDisk(null)} />
423+
<DiskDetailSideModal
424+
disk={selectedDisk}
425+
onDismiss={() => setSelectedDisk(null)}
426+
animate
427+
/>
424428
)}
425429
</div>
426430
)

0 commit comments

Comments
 (0)