Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to
- ♿️(frontend) improve language picker accessibility #2069
- ♿️(frontend) add aria-hidden to decorative icons in dropdown menu #2093
- 🐛(backend) move lock table closer to the insert operation targeted
- ♿️(frontend) replace ARIA grid pattern with list in docs grid #2131

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ test.describe('Doc grid dnd mobile', () => {
await expect(page.getByTestId('docs-grid')).toBeVisible();
await expect(page.getByTestId('grid-loader')).toBeHidden();

await expect(docsGrid.getByRole('row').first()).toBeVisible();
await expect(docsGrid.getByRole('listitem').first()).toBeVisible();
await expect(docsGrid.locator('.--docs--grid-droppable')).toHaveCount(0);

await createDoc(page, 'Draggable doc mobile', browserName, 1, true);
Expand Down
25 changes: 24 additions & 1 deletion src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ test.describe('Documents Grid mobile', () => {
await expect(docsGrid).toBeVisible();
await expect(page.getByTestId('grid-loader')).toBeHidden();

const rows = docsGrid.getByRole('row');
const rows = docsGrid.getByRole('listitem');
const row = rows.filter({
hasText: 'My mocked document',
});
Expand Down Expand Up @@ -289,6 +289,29 @@ test.describe('Documents Grid', () => {
);
});

test('opens a document with keyboard (Tab + Enter)', async ({
page,
browserName,
}) => {
await page.goto('/');

const [docTitle] = await createDoc(page, 'keyboard-nav-test', browserName);

await page.goto('/');
await expect(page.getByTestId('grid-loader')).toBeHidden();

const row = await getGridRow(page, docTitle);
const link = row.getByRole('link').first();

await link.focus();
await expect(link).toBeFocused();

await page.keyboard.press('Enter');

await expect(page).toHaveURL(/\/docs\//);
await verifyDocName(page, docTitle);
});

test('checks the infinite scroll', async ({ page }) => {
let docs: SmallDoc[];
const responsePromisePage1 = page.waitForResponse((response) => {
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,11 @@ export const verifyDocName = async (page: Page, docName: string) => {
};

export const getGridRow = async (page: Page, title: string) => {
const docsGrid = page.getByRole('grid');
const docsGrid = page.getByTestId('docs-grid');
await expect(docsGrid).toBeVisible();
await expect(page.getByTestId('grid-loader')).toBeHidden();

const rows = docsGrid.getByRole('row');
const rows = docsGrid.getByRole('listitem');

const row = rows
.filter({
Expand Down Expand Up @@ -215,7 +215,7 @@ export const goToGridDoc = async (
await expect(docsGrid).toBeVisible();
await expect(page.getByTestId('grid-loader')).toBeHidden();

const rows = docsGrid.getByRole('row');
const rows = docsGrid.getByRole('listitem');

const row = title
? rows.filter({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { DndContext, DragOverlay, Modifier } from '@dnd-kit/core';
import {
DndContext,
DragOverlay,
Modifier,
UniqueIdentifier,
} from '@dnd-kit/core';
import { getEventCoordinates } from '@dnd-kit/utilities';
import { useModal } from '@gouvfr-lasuite/cunningham-react';
import { TreeViewMoveModeEnum } from '@gouvfr-lasuite/ui-kit';
Expand Down Expand Up @@ -107,6 +112,59 @@ export const DraggableDocGridContentList = ({

const { t } = useTranslation();

const dndAccessibility = useMemo(
() => ({
screenReaderInstructions: {
draggable: t(
'To pick up a draggable item, press space or enter. While dragging, use the arrow keys to move the item. Press space or enter again to drop the item in its new position, or press escape to cancel.',
),
},
announcements: {
onDragStart({ active }: { active: { id: UniqueIdentifier } }) {
return t('Picked up document {{id}}.', { id: active.id });
},
onDragOver({
active,
over,
}: {
active: { id: UniqueIdentifier };
over: { id: UniqueIdentifier } | null;
}) {
if (over) {
return t('Document {{activeId}} is over document {{overId}}.', {
activeId: active.id,
overId: over.id,
});
}
return t('Document {{id}} is no longer over a droppable area.', {
id: active.id,
});
},
onDragEnd({
active,
over,
}: {
active: { id: UniqueIdentifier };
over: { id: UniqueIdentifier } | null;
}) {
if (over) {
return t(
'Document {{activeId}} was dropped over document {{overId}}.',
{ activeId: active.id, overId: over.id },
);
}
return t('Document {{id}} was dropped.', { id: active.id });
},
onDragCancel({ active }: { active: { id: UniqueIdentifier } }) {
return t('Dragging was cancelled. Document {{id}} was dropped.', {
id: active.id,
});
},
},
}),
[t],
);

const overlayText = useMemo(() => {
if (!canDrag) {
return t('You must be the owner to move the document');
Expand Down Expand Up @@ -147,6 +205,7 @@ export const DraggableDocGridContentList = ({
modifiers={[snapToTopLeft]}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
accessibility={dndAccessibility}
>
{docs.map((doc) => (
<DraggableDocGridItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,36 +140,30 @@ export const DocsGrid = ({
$overflow="auto"
$padding={{ vertical: 'sm', horizontal: isDesktop ? 'md' : 'xs' }}
>
<Box role="grid" aria-label={t('Documents grid')}>
<Box role="rowgroup">
<Box
$direction="row"
$padding={{ horizontal: 'xs' }}
$gap="10px"
data-testid="docs-grid-header"
role="row"
>
<Box $flex={flexLeft} $padding="3xs" role="columnheader">
<Text $size="xs" $variation="secondary" $weight="500">
{t('Name')}
<Box aria-label={t('Documents grid')}>
<Box
$direction="row"
$padding={{ horizontal: 'xs' }}
$gap="10px"
data-testid="docs-grid-header"
aria-hidden="true"
>
<Box $flex={flexLeft} $padding="3xs">
<Text $size="xs" $variation="secondary" $weight="500">
{t('Name')}
</Text>
</Box>
{isDesktop && (
<Box $flex={flexRight} $padding={{ vertical: '3xs' }}>
<Text $size="xs" $weight="500" $variation="secondary">
{DocDefaultFilter.TRASHBIN === target
? t('Days remaining')
: t('Updated at')}
</Text>
</Box>
{isDesktop && (
<Box
$flex={flexRight}
$padding={{ vertical: '3xs' }}
role="columnheader"
>
<Text $size="xs" $weight="500" $variation="secondary">
{DocDefaultFilter.TRASHBIN === target
? t('Days remaining')
: t('Updated at')}
</Text>
</Box>
)}
</Box>
)}
</Box>
<Box role="rowgroup">
<Box role="list">
<DocGridContentList docs={docs} />
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
const { isDesktop } = useResponsiveStore();
const { flexLeft, flexRight } = useResponsiveDocGrid();
const { spacingsTokens } = useCunninghamTheme();
const dateToDisplay = useDateToDisplay(doc, isInTrashbin);

const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
Expand All @@ -46,7 +47,7 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
$direction="row"
$width="100%"
$align="center"
role="row"
role="listitem"
$gap="20px"
$padding={{ vertical: '4xs', horizontal: isDesktop ? 'base' : 'xs' }}
$css={css`
Expand All @@ -65,7 +66,6 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
>
<Box
$flex={flexLeft}
role="gridcell"
$css={css`
align-items: center;
min-width: 0;
Expand All @@ -90,9 +90,15 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
$align="center"
$justify={isDesktop ? 'space-between' : 'flex-end'}
$gap="32px"
role="gridcell"
>
<StyledLink href={`/docs/${doc.id}`} tabIndex={-1}>
<StyledLink
href={`/docs/${doc.id}`}
tabIndex={-1}
aria-label={t('{{title}}, updated {{date}}', {
title: doc.title || untitledDocument,
date: dateToDisplay,
})}
>
<DocsGridItemDate
doc={doc}
isDesktop={isDesktop}
Expand Down Expand Up @@ -196,23 +202,11 @@ const IconPublic = ({ isPublic }: { isPublic: boolean }) => {
);
};

export const DocsGridItemDate = ({
doc,
isDesktop,
isInTrashbin,
}: {
doc: Doc;
isDesktop: boolean;
isInTrashbin: boolean;
}) => {
const useDateToDisplay = (doc: Doc, isInTrashbin: boolean) => {
const { data: config } = useConfig();
const { t } = useTranslation();
const { relativeDate, calculateDaysLeft } = useDate();

if (!isDesktop) {
return null;
}

let dateToDisplay = relativeDate(doc.updated_at);

if (isInTrashbin && config?.TRASHBIN_CUTOFF_DAYS && doc.deleted_at) {
Expand All @@ -224,6 +218,24 @@ export const DocsGridItemDate = ({
dateToDisplay = `${daysLeft} ${t('days', { count: daysLeft })}`;
}

return dateToDisplay;
};

export const DocsGridItemDate = ({
doc,
isDesktop,
isInTrashbin,
}: {
doc: Doc;
isDesktop: boolean;
isInTrashbin: boolean;
}) => {
const dateToDisplay = useDateToDisplay(doc, isInTrashbin);

if (!isDesktop) {
return null;
}

return (
<Text
$size="xs"
Expand Down
Loading