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

Feature/rui modal #51

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
24bff5e
Initial template setup
jnelssonsmith Jul 23, 2019
27c3221
Initial focus trap implementation
jnelssonsmith Jul 24, 2019
62e4aea
Fix bug with focus restore
jnelssonsmith Jul 24, 2019
d577df2
Add role=dialog
jnelssonsmith Jul 24, 2019
86880e5
Back to basic # href
jnelssonsmith Jul 24, 2019
c2b77e9
Adds examples with enable/disbaling of esc close and click outside close
jnelssonsmith Jul 25, 2019
ffa08db
Added a11y-utils package and added partial code documentation for foc…
jnelssonsmith Jul 25, 2019
6f9cf73
Update test
jnelssonsmith Jul 25, 2019
150adcb
disable tests for now
jnelssonsmith Jul 25, 2019
01643ee
Finalise code docs of focus trap
jnelssonsmith Jul 25, 2019
10f5271
Add destruction handler
jnelssonsmith Jul 25, 2019
01b1dfe
Adds slotted structure to modal, adds some basic styling, adds some d…
jnelssonsmith Aug 1, 2019
a0b5a2e
Adds different sizes to modal
jnelssonsmith Aug 2, 2019
d806eeb
Further variable work, documentation and refactor
jnelssonsmith Aug 2, 2019
31f9d1e
Adds new utils package with generateUUID in it
jnelssonsmith Aug 2, 2019
326b3fb
Final unit tests and custom close example
jnelssonsmith Aug 3, 2019
f105fa0
Adds react adapter for rui modal
jnelssonsmith Aug 3, 2019
f578397
Adds code documentation to ruimodal react adapter
jnelssonsmith Aug 3, 2019
dc4ce20
Add react readme
jnelssonsmith Aug 3, 2019
59415eb
Adds storybook examples for modal
jnelssonsmith Aug 4, 2019
7a91583
Fixed casting issue
jennasalau Aug 7, 2019
b43fbf6
Merge branch 'master' into feature/rui-modal
ricominten Sep 11, 2019
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
3 changes: 3 additions & 0 deletions adapters/react/RuiModalReact/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["babel-preset-rhythm-ui-react"]
}
124 changes: 124 additions & 0 deletions adapters/react/RuiModalReact/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Modal
Modals are used for situations where you need to interupt the user's workflow and bring their attention to something that may
or may not require their response.

## Basic Usage
Modal content is provided via the `RuiModal.Heading` and `RuiModal.Detail` slots. This will render a modal with a top right close button by default.
The modal can also be exited via esc key press or clicking outside the modal

```jsx
<RuiModal>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
```

## Sizes
You can configure the size of the modal via the `size` prop (size is small by default)

```jsx
<RuiModal size={RuiModal.SIZE.SMALL}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
<RuiModal size={RuiModal.SIZE.MEDIUM}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
<RuiModal size={RuiModal.SIZE.FULLSCREEN}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
```

## Custom close button
You can change the default close button via the `customClose` prop

```jsx
<RuiModal customClose={<button>x</button>}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
```

## Custom Actions
If you wish to provide some actions to the modal, it supports supplying cancel and confirm actions via the `confirmTrigger` and `cancelTrigger` props.

```jsx
<RuiModal
size={RuiModal.SIZE.MEDIUM}
confirmTrigger={<button>Confirm</button>}
cancelTrigger={<button>Cancel</button>}
>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail as="div">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis. <a href="#">A focusable element</a></p>
<p><a href="#">Test</a>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
<p><a href="#">Test test</a>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
</RuiModal.Detail>
</RuiModal>
```

## Responding to Modal actions
The `onCancel` and `onConfirm` props should be used to respond to modal actions. `onConfirm` is called if the user clicks the `confirmTrigger` and `onCancel` is called if the modal closes for any other reason.

```jsx
<RuiModal
size={RuiModal.SIZE.MEDIUM}
confirmTrigger={<button>Confirm</button>}
cancelTrigger={<button>Cancel</button>}
onConfirm={() => { alert('User confirmed'); }}
onCancel={() => { alert('User canceled'); }}
>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
```

## Changing Close Conditions
By default the user can close a modal by esc key press or by clicking outside the modal. If you wish to disable either of these you can
via the `noClickOutsideClose` and `noEscBtnClose` props

```jsx
<RuiModal noClickOutsideClose>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
```

```jsx
<RuiModal noEscBtnClose>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
```

## Customising First Focused Element
By default, the modal will focus the first focusable element found within it, if this is not wanted, you can specify what element to focus first via the `initiallyFocused` prop, which expects a selector.

```jsx
<RuiModal initiallyFocused="#focus-here">
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail as="div">
<p id="focus-here" tabindex="0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
</RuiModal.Detail>
</RuiModal>
```
125 changes: 125 additions & 0 deletions adapters/react/RuiModalReact/RuiModal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React from 'react';
import {storiesOf} from '@storybook/react';
import RuiModal from './src';
import Readme from './README.md';

storiesOf('RuiModal', module)
.addParameters({
readme: {
sidebar: Readme,
},
})
.add('Basic Usage', () => (
<>
<button type="button" onClick={(): void => {document.getElementById('modal').open = true; }}>Open Modal</button>
<RuiModal id="modal">
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
</>
))
.add('Sizes', () => (
<>
<button type="button" onClick={(): void => {document.getElementById('small').open = true; }}>Small (Default)</button>
<RuiModal id="small" size={RuiModal.SIZE.SMALL}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
<button type="button" onClick={(): void => {document.getElementById('medium').open = true; }}>Medium</button>
<RuiModal id="medium" size={RuiModal.SIZE.MEDIUM}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
<button type="button" onClick={(): void => {document.getElementById('fullscreen').open = true; }}>Fullscreen</button>
<RuiModal id="fullscreen" size={RuiModal.SIZE.FULLSCREEN}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
</>
))
.add('Custom Close Button', () => (
<>
<button type="button" onClick={(): void => {document.getElementById('modal').open = true; }}>Open Modal</button>
<RuiModal id="modal" customClose={<button type="button">x</button>}>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
</>
))
.add('Custom Actions', () => (
<>
<button type="button" onClick={(): void => {document.getElementById('modal').open = true; }}>Open Modal</button>
<RuiModal
id="modal"
size={RuiModal.SIZE.MEDIUM}
confirmTrigger={<button type="button">Confirm</button>}
cancelTrigger={<button type="button">Cancel</button>}
>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail as="div">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis. <a href="#">A focusable element</a></p>
<p><a href="#">Test</a>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
<p><a href="#">Test test</a>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
</RuiModal.Detail>
</RuiModal>
</>
))
.add('Responding to Modal Actions', () => (
<>
<button type="button" onClick={(): void => {document.getElementById('modal').open = true; }}>Open Modal</button>
<RuiModal
id="modal"
size={RuiModal.SIZE.MEDIUM}
confirmTrigger={<button type="button">Confirm</button>}
cancelTrigger={<button type="button">Cancel</button>}
onConfirm={(): void => { alert('User confirmed'); }}
onCancel={(): void => { alert('User canceled'); }}
>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
</>
))
.add('Changing Close Conditions', () => (
<>
<button type="button" onClick={(): void => {document.getElementById('no-outside').open = true; }}>Click outside close disabled</button>
<RuiModal id="no-outside" noClickOutsideClose>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
<button type="button" onClick={(): void => {document.getElementById('no-esc').open = true; }}>Esc press close disabled</button>
<RuiModal id="no-esc" noEscBtnClose>
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.
</RuiModal.Detail>
</RuiModal>
</>
))
.add('Customising First Focused Element', () => (
<>
<button type="button" onClick={(): void => {document.getElementById('modal').open = true; }}>Open Modal</button>
<RuiModal id="modal" initiallyFocused="#focus-here">
<RuiModal.Heading>Modal Heading</RuiModal.Heading>
<RuiModal.Detail as="div">
<p>Lorem ipsum dolor sit amet, <a href="#" id="focus-here">Focus here</a>consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.</p>
</RuiModal.Detail>
</RuiModal>
</>
));
28 changes: 28 additions & 0 deletions adapters/react/RuiModalReact/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

{
"name": "@rhythm-ui/modal-react",
"version": "1.0.0",
"main": "lib/index.js",
"scripts": {
"start": "yarn clean && concurrently \"yarn start:babel\" \"yarn start:declarations\"",
"start:babel": "babel -w -s -d lib src --extensions \".ts,.tsx\" --ignore *.spec.ts --copy-files",
"start:declarations": "tsc --declaration --emitDeclarationOnly --watch",
"build": "yarn build:babel && yarn build:declarations",
"build:babel": "babel -s -d lib src --extensions \".ts,.tsx\" --ignore *.spec.ts --ignore *.d.ts --copy-files",
"build:declarations": "tsc --declaration --emitDeclarationOnly",
"clean": "rimraf lib"
},
"files": [
"lib/"
],
"devDependencies": {
"babel-preset-rhythm-ui-react": "^1.0.0",
"react": "^16.8.6"
},
"dependencies": {
"@rhythm-ui/modal": "^1.0.0"
},
"peerDependencies": {
"react": ">= 16"
}
}
40 changes: 40 additions & 0 deletions adapters/react/RuiModalReact/src/IRuiModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright Deloitte Digital 2019
*
* This source code is licensed under the BSD-3-Clause license found in the
* LICENSE file in the root directory of this source tree.
*/
/* eslint import/prefer-default-export: 0 */

import {ReactNode, ReactElement} from 'react';

declare global {
namespace JSX {
interface IntrinsicElements { // eslint-disable-line @typescript-eslint/interface-name-prefix
'rui-modal': any;
}
}
}

export interface IRuiModalProps {
children: ReactNode,
noClickOutsideClose: boolean,
noEscBtnClose: boolean,
size: 'small' | 'medium' | 'fullscreen',
initiallyFocused: string,
onCancel: Function,
onConfirm: Function,
cancelTrigger?: ReactElement,
confirmTrigger?: ReactElement,
customClose?: ReactElement,
}

export interface IRuiModalDetailProps {
as?: string,
children: React.ReactNode | React.ReactNodeArray
}

export interface IRuiModalHeadingProps {
as?: string,
children: React.ReactNode | React.ReactNodeArray
}
Loading