From 4c02449058e01948cd2bc93010450a395d0f7122 Mon Sep 17 00:00:00 2001 From: Jonathan Guardado Date: Fri, 2 Dec 2022 06:43:55 -0700 Subject: [PATCH] Restore navigation flow when closing the pace modal Fix focus loss when closing the pace modal, restoring the focus to the element that opened the modal closes LS-3625 flag=course_paces_redesign Test plan: - Go to the course pace landing page - Open the default course pace modal - Do some stuff and close it - Expect the focus to come back to the Edit default pace button - Repeat the process for section and student paces - Make sure the focus gets restored when closing the modal using the X , the Close button, or the Discard Changes button when attempting to close the modal without saving Change-Id: Ie3ee9374afecf813433495c1ef0fa313f8c4ec96 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/306475 Tested-by: Service Cloud Jenkins Reviewed-by: Jackson Howe QA-Review: Jackson Howe Product-Review: Jonathan Guardado --- .../react/components/header/header.tsx | 5 +++++ .../react/components/pace_contexts_table.tsx | 7 +++++- .../react/components/pace_modal/index.tsx | 8 +++++++ .../course_paces/react/utils/utils.tsx | 22 +++++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 ui/features/course_paces/react/utils/utils.tsx diff --git a/ui/features/course_paces/react/components/header/header.tsx b/ui/features/course_paces/react/components/header/header.tsx index 2ab4473021b..b27a83ea6b4 100644 --- a/ui/features/course_paces/react/components/header/header.tsx +++ b/ui/features/course_paces/react/components/header/header.tsx @@ -39,6 +39,7 @@ import {getCoursePace, isNewPace} from '../../reducers/course_paces' import {PaceContext, CoursePace, StoreState, ResponsiveSizes} from '../../types' import {actions} from '../../actions/ui' import {paceContextsActions} from '../../actions/pace_contexts' +import {generateModalLauncherId} from '../../utils/utils' const I18n = useI18nScope('course_paces_header') @@ -181,6 +182,10 @@ export const Header: React.FC = (props: HeaderProps) => { margin={props.responsiveSize === 'large' ? '0' : 'small 0 0'} > { diff --git a/ui/features/course_paces/react/components/pace_contexts_table.tsx b/ui/features/course_paces/react/components/pace_contexts_table.tsx index 729e2b57e4d..a31a80d55d2 100644 --- a/ui/features/course_paces/react/components/pace_contexts_table.tsx +++ b/ui/features/course_paces/react/components/pace_contexts_table.tsx @@ -36,6 +36,7 @@ import {Spinner} from '@instructure/ui-spinner' import Paginator from '@canvas/instui-bindings/react/Paginator' import {formatTimeAgoDate} from '../utils/date_stuff/date_helpers' import {paceContextsActions} from '../actions/pace_contexts' +import {generateModalLauncherId} from '../utils/utils' const I18n = useI18nScope('course_paces_app') @@ -143,7 +144,11 @@ const PaceContextsTable = ({ } const renderContextLink = (paceContext: PaceContext) => ( - handleContextSelect(paceContext)}> + handleContextSelect(paceContext)} + > {paceContext.name} ) diff --git a/ui/features/course_paces/react/components/pace_modal/index.tsx b/ui/features/course_paces/react/components/pace_modal/index.tsx index c10673b570e..5e10e836e86 100644 --- a/ui/features/course_paces/react/components/pace_modal/index.tsx +++ b/ui/features/course_paces/react/components/pace_modal/index.tsx @@ -62,6 +62,7 @@ import PaceModalHeading from './heading' import {getSelectedPaceContext} from '../../reducers/pace_contexts' import {getEnrolledSection} from '../../reducers/enrollments' import PaceModalStats from './stats' +import {generateModalLauncherId} from '../../utils/utils' const I18n = useI18nScope('course_paces_modal') @@ -116,12 +117,18 @@ export const PaceModal: React.FC = pro return `${title}: ${props.paceName}` } + const restoreFocus = () => { + const launcherId = generateModalLauncherId(props.selectedPaceContext) + document.getElementById(launcherId)?.focus() + } + const handleClose = () => { if (props.unappliedChangesExist) { setPendingContext(props.coursePace.context_type) } else { props.clearCategoryError('publish') props.onClose() + restoreFocus() } } @@ -223,6 +230,7 @@ export const PaceModal: React.FC = pro props.onResetPace() props.clearCategoryError('publish') props.onClose() + restoreFocus() }} contextType={props.coursePace.context_type} /> diff --git a/ui/features/course_paces/react/utils/utils.tsx b/ui/features/course_paces/react/utils/utils.tsx new file mode 100644 index 00000000000..e58881a6a23 --- /dev/null +++ b/ui/features/course_paces/react/utils/utils.tsx @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 - present Instructure, Inc. + * + * This file is part of Canvas. + * + * Canvas is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, version 3 of the License. + * + * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along + * with this program. If not, see . + */ + +import {PaceContext} from '../types' + +export const generateModalLauncherId = (paceContext: PaceContext) => + `pace-modal-launcher-${paceContext.type}-${paceContext.item_id}`