Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Skip to content" button #5773

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
d86309c
Disable ripple effect
fzaninotto Nov 27, 2020
e46c682
Merge pull request #5598 from marmelab/improve-perfo-disableripple
djhi Nov 30, 2020
766997d
Upgrade "@testing-library/react" to v11.2.2
Luwangel Dec 16, 2020
cfe998d
Cleanup is automatically called in the new testing library version
Luwangel Dec 16, 2020
2850e63
Fix <Responsive> unit tests
Luwangel Dec 16, 2020
fd7fa4d
Fix <ReferenceField> unit tests
Luwangel Dec 16, 2020
5934893
Fix <AutocompleteInput> unit tests
Luwangel Dec 16, 2020
d0683ef
Fix <AutocompleteArrayInput> unit tests
Luwangel Dec 16, 2020
82408e6
Fix deprecated usage of waitForElement in unit tests
Luwangel Dec 16, 2020
a24ee8c
Fix <SingleFieldList> unit tests
Luwangel Dec 16, 2020
9dcb54f
Prevent an error when cleaning the <RichTextInput> input
Luwangel Dec 16, 2020
f2bcad1
Upgrade jest and ts-jest to v26.4.4
Luwangel Dec 16, 2020
e1e2b60
Merge pull request #5679 from marmelab/upgrade-test-dependencies
djhi Dec 16, 2020
5781f4a
Add container prop to SimpleForm
Dec 21, 2020
140876b
Renamed container prop to component
Dec 22, 2020
e392680
Add success to NotificationType type
Dec 22, 2020
1f22c38
Add success styling to Notification component
Dec 22, 2020
710c018
Added missing info styling to Notification component
Dec 22, 2020
8127a41
Fix warning type styling for Notification component
Dec 22, 2020
df3892d
Merge pull request #5710 from WiXSL/fix-notification-colors
fzaninotto Dec 23, 2020
6cbfa2b
Merge pull request #5703 from WiXSL/add-simplefor-container
fzaninotto Dec 23, 2020
87e0e55
Allow MenuItemLink to receive TooltipPops
Dec 23, 2020
69bd082
Change Notification's error color from dark to main
Dec 28, 2020
8b4029d
Merge pull request #5724 from WiXSL/fix-error-color
fzaninotto Jan 3, 2021
b355a9d
Merge pull request #5714 from WiXSL/allow-tooltip-props
fzaninotto Jan 3, 2021
6574709
List - Optional Sync With Location
djhi Jan 5, 2021
b90ecd7
Don't sync with redux either
djhi Jan 5, 2021
14736f2
Add tests
djhi Jan 5, 2021
e11f389
Missing tests
djhi Jan 6, 2021
d2b3036
Merge pull request #5741 from marmelab/list-optional-sync-with-location
fzaninotto Jan 11, 2021
6a21dc1
menu bar is now tabbable
Jan 14, 2021
e8ef9bb
add skip navigation button
Jan 14, 2021
e18393a
pass tabindex attribute through MenuItem component
Jan 14, 2021
6a49d2c
add navigation test
Jan 15, 2021
a631f64
remove use of hash link package
Jan 15, 2021
9b1eac4
Merge pull request #5772 from andrico1234/feature/a11y-improvements
fzaninotto Jan 15, 2021
39798a8
Merge branch 'next' into feature/skip-to-content-button
Jan 16, 2021
0867839
add test for navigation button
Jan 18, 2021
ee7b452
add skip navigation button
Jan 14, 2021
5cf84df
remove use of hash link package
Jan 15, 2021
e1143cd
add test for navigation button
Jan 18, 2021
37a8214
Merge branch 'feature/skip-to-content-button' of github.com:andrico12…
Jan 20, 2021
3a3b865
add skip navigation button
Jan 14, 2021
e5a055e
remove use of hash link package
Jan 15, 2021
b30a639
add test for navigation button
Jan 18, 2021
aa712da
add skip navigation button
Jan 14, 2021
6cea064
remove use of hash link package
Jan 15, 2021
1411b59
Merge branch 'feature/skip-to-content-button' of github.com:andrico12…
Jan 20, 2021
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
32 changes: 32 additions & 0 deletions cypress/integration/navigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import listPageFactory from '../support/ListPage';

describe('Navigation', () => {
const ListPage = listPageFactory('/#/posts');

describe('Sidebar', () => {
it('should have tabbable menu items', () => {
ListPage.navigate();

ListPage.waitUntilVisible();

cy.get('body').tab().tab().tab().tab();

cy.get(`${ListPage.elements.menuItems}:first-child`).should(
'have.class',
'Mui-focusVisible'
);
});
});

describe('Skip Navigation Button', () => {
it('should appear when a user immediately tabs on the homepage', () => {
ListPage.navigate();

ListPage.waitUntilVisible();

cy.get('body').tab();

cy.get(ListPage.elements.skipNavButton).should('exist');
});
});
});
1 change: 1 addition & 0 deletions cypress/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"devDependencies": {
"@cypress/webpack-preprocessor": "^5.4.5",
"cypress": "^5.1.0",
"cypress-plugin-tab": "^1.0.5",
"cypress-skip-and-only-ui": "^1.2.7"
}
}
3 changes: 2 additions & 1 deletion cypress/support/ListPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default url => ({
displayedRecords: '.displayed-records',
filter: name => `.filter-field[data-source='${name}'] input`,
filterMenuItems: `.new-filter-item`,
menuItems: `[role=menuitem`,
menuItems: `[role=menuitem]`,
filterMenuItem: source => `.new-filter-item[data-key="${source}"]`,
hideFilterButton: source =>
`.filter-field[data-source="${source}"] .hide-filter`,
Expand All @@ -31,6 +31,7 @@ export default url => ({
title: '#react-admin-title',
headroomUnfixed: '.headroom--unfixed',
headroomUnpinned: '.headroom--unpinned',
skipNavButton: '.skip-nav-button',
},

navigate() {
Expand Down
1 change: 1 addition & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
require('cypress-skip-and-only-ui/support');
require('cypress-plugin-tab');
24 changes: 24 additions & 0 deletions docs/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Here are all the props accepted by the `<List>` component:
* [`pagination`](#pagination)
* [`aside`](#aside-component)
* [`empty`](#empty-page)
- [`syncWithLocation`](#synchronize-with-url)

Here is the minimal code necessary to display a list of posts:

Expand Down Expand Up @@ -721,6 +722,29 @@ const PostList = props => (

The default value for the `component` prop is `Card`.

## Synchronize With URL

When a List based component (eg: `PostList`) is passed to the `list` prop of a `<Resource>`, it will automatically synchronize its parameters with the browser URL (using react-router location). However, when used anywhere outside of a `<Resource>`, it won't synchronize, which can be useful when you have multiple lists on a single page for example.

In order to enable the synchronization with the URL, you can set the `syncWithLocation` prop. For example, adding a `List` to an `Edit` page:

```jsx
const TagsEdit = (props) => (
<>
<Edit {...props}>
// ...
</Edit>
<ResourceProviderContext resource="posts">
<List syncWithLocation basePath="/posts" filter={{ tags: [id]}}>
<Datagri>
<TextField source="title" />
</Datagrid>
</List>
</ResourceProviderContext>
</>
)
```

### CSS API

The `List` component accepts the usual `className` prop but you can override many class names injected to the inner components by React-admin thanks to the `classes` property (as most Material UI components, see their [documentation about it](https://material-ui.com/customization/components/#overriding-styles-with-classes)). This property accepts the following keys:
Expand Down
2 changes: 1 addition & 1 deletion examples/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"devDependencies": {
"@types/fetch-mock": "^7.3.2",
"@types/classnames": "^2.2.9",
"@types/jest": "^24.0.23",
"@types/jest": "^26.0.19",
"@types/node": "^12.12.14",
"@types/query-string": "5.1.0",
"@types/react": "^16.9.13",
Expand Down
52 changes: 52 additions & 0 deletions examples/demo/src/layout/themes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,32 @@ export const darkTheme = {
backgroundColor: '#616161e6',
},
},
MuiButtonBase: {
root: {
'&:hover:active::after': {
// recreate a static ripple color
// use the currentColor to make it work both for outlined and contained buttons
// but to dim the background without dimming the text,
// put another element on top with a limited opacity
content: '""',
display: 'block',
width: '100%',
height: '100%',
position: 'absolute',
top: 0,
right: 0,
backgroundColor: 'currentColor',
opacity: 0.3,
borderRadius: 'inherit',
},
},
},
},
props: {
MuiButtonBase: {
// disable ripple for perf reasons
disableRipple: true,
},
},
};

Expand Down Expand Up @@ -62,6 +88,26 @@ export const lightTheme = {
boxShadow: 'none',
},
},
MuiButtonBase: {
root: {
'&:hover:active::after': {
// recreate a static ripple color
// use the currentColor to make it work both for outlined and contained buttons
// but to dim the background without dimming the text,
// put another element on top with a limited opacity
content: '""',
display: 'block',
width: '100%',
height: '100%',
position: 'absolute',
top: 0,
right: 0,
backgroundColor: 'currentColor',
opacity: 0.3,
borderRadius: 'inherit',
},
},
},
MuiAppBar: {
colorSecondary: {
color: '#808080',
Expand All @@ -85,4 +131,10 @@ export const lightTheme = {
},
},
},
props: {
MuiButtonBase: {
// disable ripple for perf reasons
disableRipple: true,
},
},
};
45 changes: 37 additions & 8 deletions examples/simple/src/tags/TagEdit.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
/* eslint react/jsx-key: off */
import * as React from 'react';
import { Edit, SimpleForm, TextField, TextInput, required } from 'react-admin';
import {
Edit,
SimpleForm,
TextField,
TextInput,
required,
List,
Datagrid,
ResourceContextProvider,
EditButton,
} from 'react-admin';

const TagEdit = props => (
<Edit {...props}>
<SimpleForm redirect="list">
<TextField source="id" />
<TextInput source="name" validate={[required()]} />
</SimpleForm>
</Edit>
<>
<Edit {...props}>
<SimpleForm redirect="list">
<TextField source="id" />
<TextInput source="name" validate={[required()]} />
</SimpleForm>
</Edit>
<ResourceContextProvider resource="posts">
<List
hasCreate={false}
hasShow
hasEdit
hasList
basePath="/posts"
resource="posts"
filter={{ tags: [props.id] }}
title=" "
>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<EditButton />
</Datagrid>
</List>
</ResourceContextProvider>
</>
);

export default TagEdit;
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
}
},
"devDependencies": {
"@types/jest": "^24.0.13",
"@types/jest": "^26.0.19",
"@types/react": "^16.9.0",
"@types/react-redux": "^7.1.1",
"@typescript-eslint/eslint-plugin": "^3.10.1",
Expand All @@ -63,14 +63,14 @@
"express": "~4.16.3",
"full-icu": "~1.3.1",
"husky": "^2.3.0",
"jest": "^24.7.0",
"jest": "^26.6.3",
"lerna": "~2.9.1",
"lint-staged": "^8.1.7",
"lolex": "~2.3.2",
"mutationobserver-shim": "^0.3.3",
"prettier": "~2.1.1",
"raf": "~3.4.1",
"ts-jest": "^24.0.0",
"ts-jest": "^26.4.4",
"wait-on": "^3.2.0",
"whatwg-fetch": "^3.0.0"
},
Expand All @@ -82,4 +82,4 @@
"dependencies": {
"typescript": "^4.0.2"
}
}
}
2 changes: 1 addition & 1 deletion packages/ra-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"redux-saga": "^1.0.0"
},
"dependencies": {
"@testing-library/react": "^8.0.7",
"@testing-library/react": "^11.2.2",
"classnames": "~2.2.5",
"date-fns": "^1.29.0",
"eventemitter3": "^3.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/actions/notificationActions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const SHOW_NOTIFICATION = 'RA/SHOW_NOTIFICATION';

export type NotificationType = 'info' | 'warning' | 'error';
export type NotificationType = 'success' | 'info' | 'warning' | 'error';

interface NotificationOptions {
// The duration in milliseconds the notification is shown
Expand Down
4 changes: 1 addition & 3 deletions packages/ra-core/src/auth/Authenticated.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import expect from 'expect';
import { cleanup, wait } from '@testing-library/react';
import { wait } from '@testing-library/react';

import Authenticated from './Authenticated';
import AuthContext from './AuthContext';
Expand All @@ -10,8 +10,6 @@ import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';

describe('<Authenticated>', () => {
afterEach(cleanup);

const Foo = () => <div>Foo</div>;

it('should render its child by default', async () => {
Expand Down
4 changes: 1 addition & 3 deletions packages/ra-core/src/auth/useAuthState.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import expect from 'expect';
import { cleanup, wait } from '@testing-library/react';
import { wait } from '@testing-library/react';

import useAuthState from './useAuthState';
import AuthContext from './AuthContext';
Expand All @@ -20,8 +20,6 @@ const stateInpector = state => (
);

describe('useAuthState', () => {
afterEach(cleanup);

it('should return a loading state on mount', () => {
const { queryByText } = renderWithRedux(
<UseAuth>{stateInpector}</UseAuth>
Expand Down
4 changes: 1 addition & 3 deletions packages/ra-core/src/auth/useAuthenticated.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import expect from 'expect';
import { cleanup, wait } from '@testing-library/react';
import { wait } from '@testing-library/react';

import Authenticated from './Authenticated';
import AuthContext from './AuthContext';
Expand All @@ -10,8 +10,6 @@ import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';

describe('useAuthenticated', () => {
afterEach(cleanup);

const Foo = () => <div>Foo</div>;

it('should call authProvider on mount', () => {
Expand Down
3 changes: 1 addition & 2 deletions packages/ra-core/src/auth/useCheckAuth.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import expect from 'expect';
import { render, cleanup, wait } from '@testing-library/react';
import { render, wait } from '@testing-library/react';

import useCheckAuth from './useCheckAuth';
import AuthContext from './AuthContext';
Expand Down Expand Up @@ -60,7 +60,6 @@ describe('useCheckAuth', () => {
afterEach(() => {
logout.mockClear();
notify.mockClear();
cleanup();
});

it('should not logout if has credentials', async () => {
Expand Down
3 changes: 1 addition & 2 deletions packages/ra-core/src/auth/useLogoutIfAccessDenied.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import expect from 'expect';
import { render, cleanup, wait } from '@testing-library/react';
import { render, wait } from '@testing-library/react';

import useLogoutIfAccessDenied from './useLogoutIfAccessDenied';
import AuthContext from './AuthContext';
Expand Down Expand Up @@ -55,7 +55,6 @@ describe('useLogoutIfAccessDenied', () => {
afterEach(() => {
logout.mockClear();
notify.mockClear();
cleanup();
});

it('should not logout if passed no error', async () => {
Expand Down
4 changes: 1 addition & 3 deletions packages/ra-core/src/auth/usePermissions.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import expect from 'expect';
import { cleanup, wait } from '@testing-library/react';
import { wait } from '@testing-library/react';

import usePermissions from './usePermissions';
import AuthContext from './AuthContext';
Expand All @@ -21,8 +21,6 @@ const stateInpector = state => (
);

describe('usePermissions', () => {
afterEach(cleanup);

it('should return a loading state on mount', () => {
const { queryByText } = renderWithRedux(
<UsePermissions>{stateInpector}</UsePermissions>
Expand Down
Loading