Skip to content

Commit 720b591

Browse files
authored
feat: display only one card action overflow menu (#2427)
Instead of stopping whole click event propagation from actions to card element, specifically stop click event if the source target is actions menu.
1 parent 87239ab commit 720b591

File tree

7 files changed

+121
-93
lines changed

7 files changed

+121
-93
lines changed

src/course-outline/data/thunk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ import {
6262
* @param {string} courseId - ID of the course
6363
* @returns {Object} - Object containing fetch course outline index query success or failure status
6464
*/
65-
export function fetchCourseOutlineIndexQuery(courseId: string): object {
65+
export function fetchCourseOutlineIndexQuery(courseId: string): (dispatch: any) => Promise<void> {
6666
return async (dispatch) => {
6767
dispatch(updateOutlineIndexLoadingStatus({ status: RequestStatus.IN_PROGRESS }));
6868

src/library-authoring/components/BaseCard.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import {
77
Stack,
88
} from '@openedx/paragon';
99
import { useIntl } from '@edx/frontend-platform/i18n';
10+
import { getItemIcon, getComponentStyleColor } from '@src/generic/block-type-utils';
11+
import ComponentCount from '@src/generic/component-count';
12+
import TagCount from '@src/generic/tag-count';
13+
import { BlockTypeLabel, type ContentHitTags, Highlight } from '@src/search-manager';
14+
import { skipIfUnwantedTarget } from '@src/utils';
1015
import messages from './messages';
11-
import { getItemIcon, getComponentStyleColor } from '../../generic/block-type-utils';
12-
import ComponentCount from '../../generic/component-count';
13-
import TagCount from '../../generic/tag-count';
14-
import { BlockTypeLabel, type ContentHitTags, Highlight } from '../../search-manager';
1516

1617
type BaseCardProps = {
1718
itemType: string;
@@ -52,7 +53,7 @@ const BaseCard = ({
5253
<Container className="library-item-card selected">
5354
<Card
5455
isClickable
55-
onClick={onSelect}
56+
onClick={(e: React.MouseEvent) => skipIfUnwantedTarget(e, onSelect)}
5657
onKeyDown={(e: React.KeyboardEvent) => {
5758
if (['Enter', ' '].includes(e.key)) {
5859
onSelect();
@@ -65,12 +66,13 @@ const BaseCard = ({
6566
title={
6667
<Icon src={itemIcon} className="library-item-header-icon" />
6768
}
68-
actions={
69-
// Wrap the actions in a div to prevent the card from being clicked when the actions are clicked
70-
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,
71-
jsx-a11y/no-static-element-interactions */
72-
<div onClick={(e) => e.stopPropagation()}>{actions}</div>
73-
}
69+
actions={(
70+
<div
71+
// Prevent card being clicked when actions menu are clicked
72+
className="stop-event-propagation"
73+
>{actions}
74+
</div>
75+
)}
7476
/>
7577
<Card.Body className="w-100">
7678
<Card.Section>

src/library-authoring/section-subsections/LibraryContainerChildren.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { ToastContext } from '../../generic/toast-context';
2424
import TagCount from '../../generic/tag-count';
2525
import { useLibraryRoutes } from '../routes';
2626
import { SidebarActions, SidebarBodyItemId, useSidebarContext } from '../common/context/SidebarContext';
27-
import { useRunOnNextRender } from '../../utils';
27+
import { skipIfUnwantedTarget, useRunOnNextRender } from '../../utils';
2828
import { ContainerMenu } from '../containers/ContainerCard';
2929

3030
interface LibraryContainerChildrenProps {
@@ -76,7 +76,7 @@ const ContainerRow = ({ containerKey, container, readOnly }: ContainerRowProps)
7676
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
7777
<div
7878
// Prevent parent card from being clicked.
79-
onClick={(e) => e.stopPropagation()}
79+
className="stop-event-propagation"
8080
>
8181
<InplaceTextEditor
8282
onSave={handleSaveDisplayName}
@@ -90,8 +90,7 @@ const ContainerRow = ({ containerKey, container, readOnly }: ContainerRowProps)
9090
direction="horizontal"
9191
gap={3}
9292
// Prevent parent card from being clicked.
93-
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
94-
onClick={(e) => e.stopPropagation()}
93+
className="stop-event-propagation"
9594
>
9695
{!showOnlyPublished && container.hasUnpublishedChanges && (
9796
<Badge
@@ -230,7 +229,7 @@ export const LibraryContainerChildren = ({ containerKey, readOnly }: LibraryCont
230229
borderLeft: '8px solid #E1DDDB',
231230
}}
232231
isClickable={!readOnly}
233-
onClick={(e) => handleChildClick(child, e.detail)}
232+
onClick={(e) => skipIfUnwantedTarget(e, (event) => handleChildClick(child, event.detail))}
234233
onKeyDown={(e) => {
235234
if (e.key === 'Enter') {
236235
handleChildClick(child, 1);

src/library-authoring/units/LibraryUnitBlocks.tsx

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,18 @@ import classNames from 'classnames';
77
import {
88
useCallback, useContext, useEffect, useState,
99
} from 'react';
10-
import { blockTypes } from '../../editors/data/constants/app';
11-
import DraggableList, { SortableItem } from '../../generic/DraggableList';
10+
import { blockTypes } from '@src/editors/data/constants/app';
11+
import DraggableList, { SortableItem } from '@src/generic/DraggableList';
1212

13-
import ErrorAlert from '../../generic/alert-error';
14-
import { getItemIcon } from '../../generic/block-type-utils';
15-
import { COMPONENT_TYPES } from '../../generic/block-type-utils/constants';
16-
import { IframeProvider } from '../../generic/hooks/context/iFrameContext';
17-
import { InplaceTextEditor } from '../../generic/inplace-text-editor';
18-
import Loading from '../../generic/Loading';
19-
import TagCount from '../../generic/tag-count';
13+
import ErrorAlert from '@src/generic/alert-error';
14+
import { getItemIcon } from '@src/generic/block-type-utils';
15+
import { COMPONENT_TYPES } from '@src/generic/block-type-utils/constants';
16+
import { IframeProvider } from '@src/generic/hooks/context/iFrameContext';
17+
import { InplaceTextEditor } from '@src/generic/inplace-text-editor';
18+
import Loading from '@src/generic/Loading';
19+
import TagCount from '@src/generic/tag-count';
20+
import { ToastContext } from '@src/generic/toast-context';
21+
import { skipIfUnwantedTarget, useRunOnNextRender } from '@src/utils';
2022
import { useLibraryContext } from '../common/context/LibraryContext';
2123
import ComponentMenu from '../components';
2224
import { LibraryBlockMetadata } from '../data/api';
@@ -28,9 +30,7 @@ import {
2830
import { LibraryBlock } from '../LibraryBlock';
2931
import messages from './messages';
3032
import { SidebarActions, SidebarBodyItemId, useSidebarContext } from '../common/context/SidebarContext';
31-
import { ToastContext } from '../../generic/toast-context';
3233
import { canEditComponent } from '../components/ComponentEditorModal';
33-
import { useRunOnNextRender } from '../../utils';
3434

3535
/** Components that need large min height in preview */
3636
const LARGE_COMPONENTS = [
@@ -91,9 +91,7 @@ const BlockHeader = ({ block, readOnly }: ComponentBlockProps) => {
9191
<Stack
9292
direction="horizontal"
9393
gap={2}
94-
className="font-weight-bold"
95-
// Prevent parent card from being clicked.
96-
onClick={(e) => e.stopPropagation()}
94+
className="font-weight-bold stop-event-propagation"
9795
>
9896
<Icon src={getItemIcon(block.blockType)} />
9997
<InplaceTextEditor
@@ -106,8 +104,7 @@ const BlockHeader = ({ block, readOnly }: ComponentBlockProps) => {
106104
<Stack
107105
direction="horizontal"
108106
gap={3}
109-
// Prevent parent card from being clicked.
110-
onClick={(e) => e.stopPropagation()}
107+
className="stop-event-propagation"
111108
>
112109
{!showOnlyPublished && block.hasUnpublishedChanges && (
113110
<Badge
@@ -185,7 +182,7 @@ const ComponentBlock = ({ block, readOnly, isDragging }: ComponentBlockProps) =>
185182
borderBottom: 'solid 1px #E1DDDB',
186183
}}
187184
isClickable={!readOnly}
188-
onClick={(e) => handleComponentSelection(e.detail)}
185+
onClick={(e) => skipIfUnwantedTarget(e, (event) => handleComponentSelection(event.detail))}
189186
onKeyDown={(e) => {
190187
if (e.key === 'Enter') {
191188
handleComponentSelection(e.detail);

src/pages-and-resources/PagesAndResourcesProvider.jsx

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React, { useMemo } from 'react';
2+
3+
interface PagesAndResourcesContextData {
4+
courseId?: string;
5+
path?: string;
6+
}
7+
export const PagesAndResourcesContext = React.createContext<PagesAndResourcesContextData>({});
8+
9+
interface PagesAndResourcesProviderProps {
10+
courseId: string;
11+
children: React.ReactNode,
12+
}
13+
14+
const PagesAndResourcesProvider = ({ courseId, children }: PagesAndResourcesProviderProps) => {
15+
const contextValue = useMemo(() => ({
16+
courseId,
17+
path: `/course/${courseId}/pages-and-resources`,
18+
}), []);
19+
return (
20+
<PagesAndResourcesContext.Provider
21+
value={contextValue}
22+
>
23+
{children}
24+
</PagesAndResourcesContext.Provider>
25+
);
26+
};
27+
28+
export default PagesAndResourcesProvider;

0 commit comments

Comments
 (0)