Skip to content

Commit

Permalink
Merge pull request #184 from dnbexperience/develop
Browse files Browse the repository at this point in the history
enhance #modal with new new props
  • Loading branch information
tujoworker authored May 21, 2019
2 parents f3faf80 + 85116dc commit 23e9c0d
Show file tree
Hide file tree
Showing 18 changed files with 218 additions and 44 deletions.
2 changes: 1 addition & 1 deletion packages/dnb-design-system-portal/src/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default class HTML extends PureComponent {
id="___gatsby"
dangerouslySetInnerHTML={{ __html: body }}
/>
<div id="dnb-modal-root" />
<div id="dnb-modal-root" className="dnb-core-style" />
{postBodyComponents}
</body>
</html>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Example extends PureComponent {
const [progress, setProgressIndicator] = useState(random(1, 100))
useEffect(() => {
const timer = setInterval(() => setProgressIndicator(random(1, 100)), 1e3)
return () => clearTimeout(timer)
return () => clearInterval(timer)
})
return (
<ProgressIndicator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class StateDemo extends PureComponent {
const [switchIsEnabled, setState] = useState(false)
useEffect(() => {
const timer = setInterval(() => setState(!switchIsEnabled), 1e3)
return () => clearTimeout(timer)
return () => clearInterval(timer)
})
return (<>
<FormLabel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const Component = () => {
const RenderHelper = () => {
useEffect(() => {
const timer = setInterval(() => render(<RenderHelper />), 1e3)
return () => clearTimeout(timer)
return () => clearInterval(timer)
}, [])
return <Component />
}
Expand Down
2 changes: 1 addition & 1 deletion packages/dnb-ui-lib/scripts/figma/version.lock
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"1a3caba565dddc0a936aaddc29a82887":"133043001"}
{"1a3caba565dddc0a936aaddc29a82887":"133380256"}
12 changes: 12 additions & 0 deletions packages/dnb-ui-lib/src/components/button/__tests__/Button.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ describe('Button component', () => {
expect(Comp.find('a').exists()).toBe(true)
})

it('has a disabled attribute, once we set disabled to true', () => {
const Comp = mount(<Component />)
Comp.setProps({
disabled: true
})
expect(
Comp.find('button')
.instance()
.hasAttribute('disabled')
).toBe(true)
})

it('should validate with ARIA rules as a button', async () => {
const Comp = mount(<Component {...props} />)
expect(await axeComponent(Comp)).toHaveNoViolations()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ export default class DatePickerInput extends PureComponent {
id={`${id}__input`}
input_state={focusState}
inputElement={this.renderInputElement}
disabled={disabled}
submitButton={
<SubmitButton
id={id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ describe('DatePicker component', () => {
expect(Comp.state().hidden).toBe(true)
})

it('has a disabled attribute, once we set disabled to true', () => {
const Comp = mount(<Component show_input />)
Comp.setProps({
disabled: true
})
expect(
Comp.find('input')
.first()
.instance()
.hasAttribute('disabled')
).toBe(true)
})

it('has correct state after "click" trigger', () => {
Comp.find('button.dnb-input__submit-button__button').simulate('click')
expect(Comp.state().opened).toBe(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ describe('Dropdown component', () => {
)
})

it('has a disabled attribute, once we set disabled to true', () => {
const Comp = mount(<Component data={mockData} />)
Comp.setProps({
disabled: true
})
expect(
Comp.find('button.dnb-dropdown__trigger')
.instance()
.hasAttribute('disabled')
).toBe(true)
})

it('should validate with ARIA rules as a tabs', async () => {
expect(await axeComponent(Comp)).toHaveNoViolations()
})
Expand Down
12 changes: 12 additions & 0 deletions packages/dnb-ui-lib/src/components/input/__tests__/Input.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ describe('Input component', () => {
expect(Comp.find('.dnb-form-status').text()).toBe('status')
})

it('has a disabled attribute, once we set disabled to true', () => {
const Comp = mount(<Component />)
Comp.setProps({
disabled: true
})
expect(
Comp.find('input')
.instance()
.hasAttribute('disabled')
).toBe(true)
})

it('has a submit button on prop type="search"', () => {
const Comp = mount(
<Component {...props} type="search" value={null}>
Expand Down
52 changes: 31 additions & 21 deletions packages/dnb-ui-lib/src/components/modal/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export const propTypes = {
id: PropTypes.string,
labelled_by: PropTypes.string,
title: PropTypes.string,
trigger_hidden: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
trigger_disabled: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool
]),
trigger_variant: ButtonPropTypes.variant,
trigger_text: PropTypes.string,
trigger_title: PropTypes.string,
Expand Down Expand Up @@ -79,6 +84,8 @@ export const defaultProps = {
id: null,
labelled_by: null,
title: null,
trigger_hidden: false,
trigger_disabled: false,
trigger_variant: 'secondary',
trigger_text: null,
trigger_title: 'Open Modal',
Expand Down Expand Up @@ -270,6 +277,8 @@ export default class Modal extends PureComponent {
id, // eslint-disable-line
preventSetTriggerRef, // eslint-disable-line
labelled_by,
trigger_hidden,
trigger_disabled,
trigger_variant,
trigger_text,
trigger_title,
Expand All @@ -283,23 +292,25 @@ export default class Modal extends PureComponent {

return (
<div className="dnb-modal">
{trigger_variant && (
<Button
id={this._id}
type="button"
variant={trigger_variant}
text={trigger_text}
title={trigger_title}
icon={
trigger_text && trigger_icon === defaultProps.trigger_icon
? null
: trigger_icon
}
on_click={this.toggleOpenClose}
className={classnames('dnb-modal__trigger', trigger_class)}
innerRef={this._triggerRef}
/>
)}
{Boolean(trigger_hidden) ||
(trigger_variant && (trigger_text || trigger_icon) && (
<Button
id={this._id}
type="button"
variant={trigger_variant}
text={trigger_text}
title={trigger_title}
disabled={Boolean(trigger_disabled)}
icon={
trigger_text && trigger_icon === defaultProps.trigger_icon
? null
: trigger_icon
}
on_click={this.toggleOpenClose}
className={classnames('dnb-modal__trigger', trigger_class)}
innerRef={this._triggerRef}
/>
))}

{modalActive && modal_content && (
<ModalRoot
Expand Down Expand Up @@ -589,10 +600,9 @@ class ModalContent extends PureComponent {
<div {...contentParams}>
<div ref={this._contentRef} {...innerParams}>
{title && <h1 className="dnb-h2 dnb-modal__title">{title}</h1>}
{hide_close_button !== true &&
hide_close_button !== 'true' && (
<CloseButton on_click={closeModal} title={close_title} />
)}
{Boolean(hide_close_button) !== true && (
<CloseButton on_click={closeModal} title={close_title} />
)}
{modal_content}
</div>
</div>
Expand Down
30 changes: 30 additions & 0 deletions packages/dnb-ui-lib/src/components/modal/__tests__/Modal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,36 @@ describe('Modal component', () => {
it('has to have the correct title', () => {
expect(Comp.find('h1').text()).toBe(props.title)
})
it('has no trigger button once we set trigger_hidden to true', () => {
Comp.setProps({
trigger_hidden: true
})
expect(Comp.find('button.dnb-modal__trigger').exists()).toBe(false)
Comp.setProps({
trigger_hidden: false
})
})
it('has a disabled trigger button once we set trigger_disabled to true', () => {
Comp.setProps({
trigger_disabled: true
})
expect(
Comp.find('button.dnb-modal__trigger')
.instance()
.hasAttribute('disabled')
).toBe(true)
})
it('has an opened modal if open_state is set to "opened"', () => {
const Comp = mount(<Component modal_content="unique_modal_content" />)
Comp.setProps({
open_state: 'opened'
})
expect(Comp.find('div.dnb-modal__content').exists()).toBe(true)
Comp.setProps({
open_state: 'closed'
})
expect(Comp.find('div.dnb-modal__content').exists()).toBe(false)
})
it('has to have the correct aria-describedby', () => {
expect(
Comp.find('[aria-describedby]').props()['aria-describedby']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ exports[`Modal component have to match snapshot 1`] = `
"prevent_close": "prevent_close",
"title": "title",
"trigger_class": "trigger_class",
"trigger_disabled": "trigger_disabled",
"trigger_hidden": "trigger_hidden",
"trigger_icon": "trigger_icon",
"trigger_text": "trigger_text",
"trigger_title": "trigger_title",
Expand Down Expand Up @@ -85,6 +87,8 @@ exports[`Modal component have to match snapshot 1`] = `
prevent_close={false}
title="modal_title"
trigger_class={null}
trigger_disabled={false}
trigger_hidden={false}
trigger_icon="question"
trigger_text={null}
trigger_title="Open Modal"
Expand Down Expand Up @@ -214,6 +218,8 @@ exports[`Modal component have to match snapshot 1`] = `
"prevent_close": "prevent_close",
"title": "title",
"trigger_class": "trigger_class",
"trigger_disabled": "trigger_disabled",
"trigger_hidden": "trigger_hidden",
"trigger_icon": "trigger_icon",
"trigger_text": "trigger_text",
"trigger_title": "trigger_title",
Expand Down Expand Up @@ -298,6 +304,8 @@ exports[`Modal component have to match snapshot 1`] = `
"prevent_close": "prevent_close",
"title": "title",
"trigger_class": "trigger_class",
"trigger_disabled": "trigger_disabled",
"trigger_hidden": "trigger_hidden",
"trigger_icon": "trigger_icon",
"trigger_text": "trigger_text",
"trigger_title": "trigger_title",
Expand Down
2 changes: 1 addition & 1 deletion packages/dnb-ui-lib/src/components/modal/description.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Modal dialogs appear on top of the main content changing the _mode_ of the syste

**NB:** If the wrapper is not set manually, a wrapper is inserted automatically as a child node to the body.

To make sure the HTML structure is decoupled from all the page content, You can optionally define a wrapper div like `<div class="dnb-modal-root" />`.
To make sure the HTML structure is decoupled from all the page content, You can optionally define a wrapper div like `<div class="dnb-modal-root" className="dnb-core-style" />`.

Just place this as a sibling of Your App root HTML element. This ensures that we always can stack the modal content above the App Content.

Expand Down
32 changes: 17 additions & 15 deletions packages/dnb-ui-lib/src/components/modal/details.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
| Properties | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title` | _(optional)_ the modal title. Displays on the very top of the content. |
| `trigger_variant` | _(optional)_ the modal triggering button variant. Defaults to `secondary`. |
| `trigger_text` | _(mandatory)_ if type is set to `text`, this will be the text which triggers the modal. If set to `button` it will be the `title` attribute of the button. |
| `trigger_title` | _(optional)_ the modal triggering button title. |
| `trigger_icon` | _(optional)_ the modal triggering button icon. Can be used instead of a `trigger_text` |
| `modal_content` | _(optional)_ the content which will appear when triggering the modal. |
| `content_id` | _(optional)_ defines an unique identifier to a modal. Use it in case you have to refer in some way to the modal content wrapper. |
| `close_title` | _(optional)_ the title of the close button. Defaults to _Close Modal Window_ |
| `hide_close_button` | _(optional)_ if set to true, the close button will now be shown |
| `prevent_close` | _(optional)_ if set to `true` (boolean or string), then the user can't close the modal. |
| `open_state` | _(optional)_ use this prop to control the open/close state by setting either: `opened` or `closed` |
| `open_modal` | _(optional)_ set a function to call the callback function, once the modal should open: `open_modal={(open) => open()}` |
| `close_modal` | _(optional)_ set a function to call the callback function, once the modal should close: `close_modal={(close) => close()}` |
| Properties | Description |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title` | _(optional)_ the modal title. Displays on the very top of the content. |
| `trigger_variant` | _(optional)_ the modal triggering button variant. Defaults to `secondary`. |
| `trigger_text` | _(optional)_ if type is set to `text`, this will be the text which triggers the modal. If set to `button` it will be the `title` attribute of the button. |
| `trigger_title` | _(optional)_ the modal triggering button title. |
| `trigger_icon` | _(optional)_ the modal triggering button icon. Can be used instead of a `trigger_text`. Defaults to `question` . |
| `trigger_hidden` | _(optional)_ if truthy, no trigger button will be show. This can be used in combination with `open_state="opened"`. |
| `trigger_disabled` | _(optional)_ if truthy, then the trigger button can't be opened. |
| `modal_content` | _(optional)_ the content which will appear when triggering the modal. |
| `content_id` | _(optional)_ defines an unique identifier to a modal. Use it in case you have to refer in some way to the modal content wrapper. |
| `close_title` | _(optional)_ the title of the close button. Defaults to _Close Modal Window_ |
| `hide_close_button` | _(optional)_ if truthy, the close button will now be shown |
| `prevent_close` | _(optional)_ if set to `true` (boolean or string), then the user can't close the modal. |
| `open_state` | _(optional)_ use this prop to control the open/close state by setting either: `opened` or `closed` |
| `open_modal` | _(optional)_ set a function to call the callback function, once the modal should open: `open_modal={(open) => open()}` |
| `close_modal` | _(optional)_ set a function to call the callback function, once the modal should close: `close_modal={(close) => close()}` |

| Events | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const props = fakeProps(require.resolve('../ProgressIndicator'), {
})

describe('Circular ProgressIndicator component', () => {
const mainLineSelector =
'svg.dnb-progress-indicator__circular__line.dark[style]'
const Comp = mount(
<Component {...props} type="circular" progress={50} />
)
Expand All @@ -34,7 +36,7 @@ describe('Circular ProgressIndicator component', () => {

it('has to have a stroke-dashoffset of 44 on 50%', () => {
expect(
Comp.find('svg.dnb-progress-indicator__circular__line.dark[style]')
Comp.find(mainLineSelector)
.instance()
.getAttribute('style')
).toBe('stroke-dashoffset: 44;')
Expand All @@ -48,6 +50,25 @@ describe('Circular ProgressIndicator component', () => {
).toBe('50%')
})

it('has to react to a progress value of 80%', () => {
Comp.setProps({
progress: 80
})
expect(
Comp.find('.dnb-progress-indicator__circular')
.instance()
.getAttribute('aria-label')
).toBe('80%')
expect(
Comp.find(mainLineSelector)
.instance()
.getAttribute('style')
).toBe('stroke-dashoffset: 17.599999999999994;')
Comp.setProps({
progress: 50
})
})

it('should validate with ARIA rules as a svg element', async () => {
expect(await axeComponent(Comp)).toHaveNoViolations()
})
Expand Down
12 changes: 12 additions & 0 deletions packages/dnb-ui-lib/src/components/switch/__tests__/Switch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ describe('Switch component', () => {
expect(Comp.find('input').props().value).toBe(value)
})

it('has a disabled attribute, once we set disabled to true', () => {
const Comp = mount(<Component />)
Comp.setProps({
disabled: true
})
expect(
Comp.find('input')
.instance()
.hasAttribute('disabled')
).toBe(true)
})

it('should validate with ARIA rules', async () => {
const Comp = mount(<Component {...props} />)
expect(await axeComponent(Comp)).toHaveNoViolations()
Expand Down
Loading

0 comments on commit 23e9c0d

Please sign in to comment.