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 dismissible prop to OuiCallOut #985

Merged
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 @@ -17,6 +17,7 @@
- Adds `SchemaItem` as an experimental component ([#974](https://github.com/opensearch-project/oui/pull/974))
- Make `CollapsibleNavGroup` background colors theme-able ([#968](https://github.com/opensearch-project/oui/pull/968))
- Update next light theme primary color to #07827E ([#981](https://github.com/opensearch-project/oui/pull/981))
- Add dismissible prop to OuiCallOut ([#985](https://github.com/opensearch-project/oui/pull/985))

### 🐛 Bug Fixes

Expand Down
95 changes: 59 additions & 36 deletions src-docs/src/views/call_out/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,65 @@
* GitHub history for details.
*/

import React from 'react';
import React, { useState } from 'react';

import { OuiCallOut, OuiLink, OuiSpacer } from '../../../../src/components';

export default () => (
<div>
<OuiCallOut
title="Check it out, here's a really long title that will wrap within a narrower browser"
iconType="search">
<p>
Here&rsquo;s some stuff that you need to know. We can make this text
really long so that, when viewed within a browser that&rsquo;s fairly
narrow, it will wrap, too.
</p>
<p>
When possible, its recommended to include links to product{' '}
<OuiLink href="https://opensearch.org/docs/latest/">
documentation
</OuiLink>
.
</p>
</OuiCallOut>

<OuiSpacer size="m" />

<OuiCallOut
title="Callouts can exist as just a title. Simply omit the child content."
iconType="visVisualBuilder"
/>

<OuiSpacer size="m" />

<OuiCallOut
size="s"
title="This is a small callout for more unintrusive but constant messages."
iconType="pin"
/>
</div>
);
export default () => {
const [isCallOutVisible, setIsCallOutVisible] = useState(true);

const closeCallOut = () => setIsCallOutVisible(false);

let callOut;

if (isCallOutVisible) {
callOut = (
<OuiCallOut
title="Callouts can be dismissed when dismissible is set to true unless the color is danger or warning. "
iconType="wrench"
dismissible
onDismissible={closeCallOut}
/>
);
}

return (
<div>
<OuiCallOut
title="Check it out, here's a really long title that will wrap within a narrower browser"
iconType="search">
<p>
Here&rsquo;s some stuff that you need to know. We can make this text
really long so that, when viewed within a browser that&rsquo;s fairly
narrow, it will wrap, too.
</p>
<p>
When possible, its recommended to include links to product{' '}
<OuiLink href="https://opensearch.org/docs/latest/">
documentation
</OuiLink>
.
</p>
</OuiCallOut>

<OuiSpacer size="m" />

<OuiCallOut
title="Callouts can exist as just a title. Simply omit the child content."
iconType="visVisualBuilder"
/>

<OuiSpacer size="m" />

{callOut}

<OuiSpacer size="m" />

<OuiCallOut
size="s"
title="This is a small callout for more unintrusive but constant messages."
iconType="pin"
/>
</div>
);
};
86 changes: 86 additions & 0 deletions src/components/call_out/__snapshots__/call_out.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,92 @@ exports[`OuiCallOut props color warning is rendered 1`] = `
/>
`;

exports[`OuiCallOut props dismissible close callout after click 1`] = `
<OuiCallOut
dismissible={true}
onDismissible={[MockFunction]}
title="This is a callout"
>
<div
className="ouiCallOut ouiCallOut--primary"
>
<div
className="ouiCallOutHeader"
>
<span
className="ouiCallOutHeader__title"
>
This is a callout
</span>
</div>
<OuiButtonIcon
aria-label="dismissible_icon"
className="ouiCallOut__closeIcon"
data-test-subj="closeCallOutButton"
iconType="cross"
onClick={[MockFunction]}
>
<button
aria-label="dismissible_icon"
className="ouiButtonIcon ouiButtonIcon--primary ouiButtonIcon--empty ouiButtonIcon--xSmall ouiCallOut__closeIcon"
data-test-subj="closeCallOutButton"
disabled={false}
onClick={[MockFunction]}
type="button"
>
<OuiIcon
aria-hidden="true"
className="ouiButtonIcon__icon"
color="inherit"
size="m"
type="cross"
>
<span
aria-hidden="true"
className="ouiButtonIcon__icon"
color="inherit"
data-ouiicon-type="cross"
size="m"
/>
</OuiIcon>
</button>
</OuiButtonIcon>
</div>
</OuiCallOut>
`;

exports[`OuiCallOut props dismissible is not rendered when in danger color 1`] = `
<div
class="ouiCallOut ouiCallOut--danger"
/>
`;

exports[`OuiCallOut props dismissible is not rendered when in warning color 1`] = `
<div
class="ouiCallOut ouiCallOut--warning"
/>
`;

exports[`OuiCallOut props dismissible is rendered when set to true 1`] = `
<div
class="ouiCallOut ouiCallOut--primary"
>
<button
aria-label="dismissible_icon"
class="ouiButtonIcon ouiButtonIcon--primary ouiButtonIcon--empty ouiButtonIcon--xSmall ouiCallOut__closeIcon"
data-test-subj="closeCallOutButton"
type="button"
>
<span
aria-hidden="true"
class="ouiButtonIcon__icon"
color="inherit"
data-ouiicon-type="cross"
/>
</button>
</div>
`;

exports[`OuiCallOut props heading h1 is rendered 1`] = `
<div
class="ouiCallOut ouiCallOut--primary"
Expand Down
11 changes: 11 additions & 0 deletions src/components/call_out/_call_out.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
.ouiCallOut {
padding: $ouiSize;
border-left: $ouiSizeXS / 2 solid transparent;
position: relative;

&.ouiCallOut--small {
padding: $ouiSizeS;
Expand All @@ -27,6 +28,12 @@
@include ouiCallOutTitle;
margin-bottom: 0; // In case it's nested inside OuiText
}

.ouiCallOut__closeIcon {
position: absolute;
right: $ouiSizeS / 2;
top: 0;
}
}

// smaller font size for headers in small callout
Expand All @@ -47,6 +54,10 @@
.ouiCallOutHeader__title {
color: ouiCallOutColor($name, 'foreground');
}

.ouiCallOut__closeIcon {
fill: ouiCallOutColor($name, 'foreground');
}
}
}

Expand Down
41 changes: 40 additions & 1 deletion src/components/call_out/call_out.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@
*/

import React from 'react';
import { render } from 'enzyme';
import { mount, render } from 'enzyme';
import { requiredProps } from '../../test/required_props';

import { OuiCallOut, COLORS, HEADINGS } from './call_out';
import { findTestSubject } from '../../test';

describe('OuiCallOut', () => {
test('is rendered', () => {
Expand Down Expand Up @@ -81,5 +82,43 @@ describe('OuiCallOut', () => {
});
});
});

describe('dismissible', () => {
it('is rendered when set to true', () => {
const component = render(<OuiCallOut dismissible={true} />);

expect(component).toMatchSnapshot();
});

it('is not rendered when in warning color', () => {
const component = render(
<OuiCallOut dismissible={true} color={'warning'} />
);

expect(component).toMatchSnapshot();
});

it('is not rendered when in danger color', () => {
const component = render(
<OuiCallOut dismissible={true} color={'danger'} />
);

expect(component).toMatchSnapshot();
});

it('close callout after click', () => {
const onDismissible = jest.fn();
const component = mount(
<OuiCallOut
dismissible={true}
onDismissible={onDismissible}
title="This is a callout"
/>
);
expect(component).toMatchSnapshot();
BSFishy marked this conversation as resolved.
Show resolved Hide resolved
findTestSubject(component, 'closeCallOutButton').simulate('click');
expect(onDismissible).toBeCalled();
});
});
});
});
25 changes: 25 additions & 0 deletions src/components/call_out/call_out.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { CommonProps, keysOf } from '../common';
import { IconType, OuiIcon } from '../icon';

import { OuiText } from '../text';
import { OuiButtonIcon } from '../button';

type Color = 'primary' | 'success' | 'warning' | 'danger';
type Size = 's' | 'm';
Expand All @@ -48,6 +49,12 @@ export type OuiCallOutProps = CommonProps &
color?: Color;
size?: Size;
heading?: Heading;
dismissible?: boolean;
onDismissible?: (
event?:
| React.KeyboardEvent<HTMLDivElement>
| React.MouseEvent<HTMLButtonElement>
) => void;
};

const colorToClassNameMap: { [color in Color]: string } = {
Expand Down Expand Up @@ -75,6 +82,8 @@ export const OuiCallOut = forwardRef<HTMLDivElement, OuiCallOutProps>(
children,
className,
heading,
dismissible = false,
onDismissible = () => {},
...rest
},
ref: Ref<HTMLDivElement>
Expand All @@ -100,6 +109,19 @@ export const OuiCallOut = forwardRef<HTMLDivElement, OuiCallOutProps>(
);
}

let dismissibleIcon;
if (dismissible && color !== 'warning' && color !== 'danger') {
dismissibleIcon = (
<OuiButtonIcon
iconType="cross"
onClick={onDismissible}
className="ouiCallOut__closeIcon"
aria-label="dismissible_icon"
data-test-subj="closeCallOutButton"
/>
);
}

let optionalChildren;
if (children && size === 's') {
optionalChildren = (
Expand All @@ -126,10 +148,13 @@ export const OuiCallOut = forwardRef<HTMLDivElement, OuiCallOutProps>(
</div>
);
}

return (
<div className={classes} ref={ref} {...rest}>
{header}

{dismissibleIcon}

{optionalChildren}
</div>
);
Expand Down
Loading