diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f785c21..53c253159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [5.7.0](https://github.com/dequelabs/cauldron/compare/v5.6.2...v5.7.0) (2023-08-02) + + +### Features + +* **react:** allow for NavBar to include additional props for html div elements. ([#1144](https://github.com/dequelabs/cauldron/issues/1144)) ([b103453](https://github.com/dequelabs/cauldron/commit/b103453db0f59b2498de2653c5c5d88328c5bb99)) +* **react,styles:** add Notice component ([#1136](https://github.com/dequelabs/cauldron/issues/1136)) ([14bfe32](https://github.com/dequelabs/cauldron/commit/14bfe32d8763a2a64e821823e5bd3a2befa76cf6)) + + +### Bug Fixes + +* fixes overflow bug on text-field and text-area ([#1143](https://github.com/dequelabs/cauldron/issues/1143)) ([10f53c9](https://github.com/dequelabs/cauldron/commit/10f53c90fe2466f913bb00c49fc0b8e1aad501b1)) + ### [5.6.2](https://github.com/dequelabs/cauldron/compare/v5.6.1...v5.6.2) (2023-07-28) diff --git a/docs/pages/components/NavBar.mdx b/docs/pages/components/NavBar.mdx new file mode 100644 index 000000000..5c04fb237 --- /dev/null +++ b/docs/pages/components/NavBar.mdx @@ -0,0 +1,119 @@ +--- +title: NavBar +description: A navigation bar that contains links to other sections of the website. +source: https://github.com/dequelabs/cauldron/tree/develop/packages/react/src/components/NavBar/NavBar.tsx +--- + +import { NavBar, NavItem } from '@deque/cauldron-react' + +```js +import { NavBar, NavItem } from '@deque/cauldron-react' +``` + +The `NavBar` component is intended to be placed directly below the `TopBar` component to display an additional section of navigational links for the current area. + +Under the hood, `NavBar` renders inside of a `nav` element. If there are multiple `nav` elements present on the page be sure to include `aria-label` or `aria-labelledby` to help uniquely identify each nav region. + +## Examples + +### Default + +```jsx example + + + One + + + Two + + + Three + + +``` + +### NavBar with Active NavItem + +```jsx example + + + One + + + Two + + + Three + + +``` + +### Collapsed + +```jsx example + + + One + + + Two + + + Three + + +``` + +## Props + +### NavBar + + + +### NavItem + + + +## Related Components + +- [TopBar](./TopBar) \ No newline at end of file diff --git a/docs/pages/components/Notice.mdx b/docs/pages/components/Notice.mdx new file mode 100644 index 000000000..17dff9348 --- /dev/null +++ b/docs/pages/components/Notice.mdx @@ -0,0 +1,152 @@ +--- +title: Notice +description: A notification banner - similar to a Toast, but allows for more flexibile positioning and control. +source: https://github.com/dequelabs/cauldron/blob/develop/packages/react/src/components/Notice/Notice.tsx +--- + +import { useState } from 'react'; +import { Notice, Icon, Button } from '@deque/cauldron-react'; + +```js +import { Notice } from '@deque/cauldron-react'; +``` + +The `Notice` component is used to display a notification banner. It is similar to the [Toast](./Toast) component, +but can be used in more flexible ways. + +For example, the `Notice` component can be used to display a notification banner within a [Panel](./Panel) component +or anywhere else in the DOM without needing to be absolutely/statically positioned. + +## Examples + +There are two variants of the `Notice` component: `info` and `caution`. The `info` variant is used to display general +information, while the `caution` variant is used to display a warning. Depending on the variant, the background color +and icon will change (can be overwritten). + +### Info + +```jsx example + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at porttitor + sem. Aliquam erat volutpat. Donec placerat nisl magna, et faucibus arcu + condimentum sed. + +``` + +### Caution + +```jsx example + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at porttitor + sem. Aliquam erat volutpat. Donec placerat nisl magna, et faucibus arcu + condimentum sed. + +``` + +### Danger + +```jsx example + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at porttitor + sem. Aliquam erat volutpat. Donec placerat nisl magna, et faucibus arcu + condimentum sed. + +``` + +### Thin + +Rendering a `Notice` that appears as a thin bar can be accomplished by only passing a `title` prop, or only passing a child. + +```jsx example + +``` + +### Notice Title + +```jsx example +Information}> + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at porttitor + sem. Aliquam erat volutpat. Donec placerat nisl magna, et faucibus arcu + condimentum sed. + +``` + +### Customizing Icon + +If you would like to customize the preset icon/type variants, the `icon` prop can be used with any [Cauldron +Icon Type](/components/icon). + +```jsx example + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at porttitor + sem. Aliquam erat volutpat. Donec placerat nisl magna, et faucibus arcu + condimentum sed. + +``` + +### Dismissable + +```jsx example +function DismissableNotice() { + const [dismissed, setDismissed] = useState(false); + const handleDismiss = () => { + setDismissed(true); + setTimeout(() => setDismissed(false), 2000); + }; + + return dismissed ? null : ( + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at + porttitor sem. Aliquam erat volutpat. Donec placerat nisl magna, et + faucibus arcu condimentum sed. +

+ +
+ ); +} +``` + +## Props + + + +## Related Components + +- [Toast](./Toast) diff --git a/docs/pages/components/Toast.mdx b/docs/pages/components/Toast.mdx index 1a3d484f6..fd6d6e797 100644 --- a/docs/pages/components/Toast.mdx +++ b/docs/pages/components/Toast.mdx @@ -4,41 +4,35 @@ description: A banner with text positioned at the top of the page. source: https://github.com/dequelabs/cauldron/tree/develop/packages/react/src/components/Toast/index.tsx --- -import { useState } from 'react' -import { Toast, Button } from '@deque/cauldron-react' +import { useState } from 'react'; +import { Toast, Button } from '@deque/cauldron-react'; ```js -import { Toast } from '@deque/cauldron-react' +import { Toast } from '@deque/cauldron-react'; ``` ## Examples - Only a single toast should be rendered at a given moment as additional toasts will stack on top of each other. + Only a single toast should be rendered at a given moment as additional toasts + will stack on top of each other. ### Confirmation ```jsx example function ConfirmationToastExample() { - const [show, setShow] = useState(false) + const [show, setShow] = useState(false); return ( <> - setShow(false)} - > + setShow(false)}> Your toast is ready! - - ) + ); } ``` @@ -46,24 +40,17 @@ function ConfirmationToastExample() { ```jsx example function CautionToastExample() { - const [show, setShow] = useState(false) + const [show, setShow] = useState(false); return ( <> - setShow(false)} - > + setShow(false)}> Your toast is getting toasty... - - ) + ); } ``` @@ -71,24 +58,20 @@ function CautionToastExample() { ```jsx example function ActionNeededToastExample() { - const [show, setShow] = useState(false) + const [show, setShow] = useState(false); return ( <> - + You burnt the toast! Check yourself before you wreck yourself... - + - - ) + ); } ``` @@ -96,24 +79,17 @@ function ActionNeededToastExample() { ```jsx example function InfoToastExample() { - const [show, setShow] = useState(false) + const [show, setShow] = useState(false); return ( <> - setShow(false)} - > + setShow(false)}> It is getting toasty in here! - - ) + ); } ``` @@ -121,24 +97,17 @@ function InfoToastExample() { ```jsx example function ErrorToastExample() { - const [show, setShow] = useState(false) + const [show, setShow] = useState(false); return ( <> - setShow(false)} - > + setShow(false)}> This toast tastes like toast! - - ) + ); } ``` @@ -146,31 +115,25 @@ function ErrorToastExample() { Non-dismissable toasts are shown inline to prevent clipping of content. - ```jsx example function NonDismissibleToastExample() { - const [show, setShow] = useState(true) + const [show, setShow] = useState(true); return ( <> - - This toast is not dismissible by normal methods. - But you can . + + This toast is not dismissible by normal methods. But you can{' '} + + . {!show && ( - )} - ) + ); } ``` @@ -189,13 +152,14 @@ function NonDismissibleToastExample() { name: 'show', type: 'boolean', defaultValue: 'false', - description: 'Whether or not to show the toast.', + description: 'Whether or not to show the toast.' }, { name: 'focus', type: 'boolean', defaultValue: 'true', - description: 'Whether or not to focus the toast. This will also set the toast to `role="alert"` when set to true.' + description: + 'Whether or not to focus the toast. This will also set the toast to `role="alert"` when set to true.' }, { name: 'onDismiss', @@ -221,3 +185,7 @@ function NonDismissibleToastExample() { } ]} /> + +## Related + +- [Notice](./Notice) diff --git a/docs/pages/components/Tooltip.mdx b/docs/pages/components/Tooltip.mdx index f20858425..b8ddcb9e3 100644 --- a/docs/pages/components/Tooltip.mdx +++ b/docs/pages/components/Tooltip.mdx @@ -15,6 +15,12 @@ import { Tooltip } from '@deque/cauldron-react' Cauldron's tooltip relies on [Popper](https://popper.js.org/) to position tooltips dynamically. Tooltips can be triggered from any focusable element via a `target` attribute pointed to an HTMLElement or React ref object. + + +`Tooltip` is intended to be used with elements that are interactive or are keyboard accessible such as buttons or links. For non-interactive elements such as informational tooltips attached to an icon, consider using [TooltipTabstop](./TooltipTabstop) instead. + + + ### Text Tooltips Text Tooltips are the default variant and are intended to show short single-line text hints. diff --git a/docs/pages/components/TopBar.mdx b/docs/pages/components/TopBar.mdx index daef6027a..ff6373558 100644 --- a/docs/pages/components/TopBar.mdx +++ b/docs/pages/components/TopBar.mdx @@ -153,3 +153,4 @@ In addition to navigational items, the `MenuBar` can also contain a dropdown men ## Related Components - [OptionsMenu](./OptionsMenu) +- [NavBar](./NavBar) diff --git a/docs/patterns/components/NavBar/index.css b/docs/patterns/components/NavBar/index.css deleted file mode 100644 index e0f57602a..000000000 --- a/docs/patterns/components/NavBar/index.css +++ /dev/null @@ -1,7 +0,0 @@ -.NavBarButton { - margin-top: var(--space-large); -} - -.NavBar--collapsed { - width: 20rem; -} diff --git a/docs/patterns/components/NavBar/index.js b/docs/patterns/components/NavBar/index.js deleted file mode 100644 index 3646f2607..000000000 --- a/docs/patterns/components/NavBar/index.js +++ /dev/null @@ -1,98 +0,0 @@ -import React, { useState } from 'react'; -import { NavBar, NavItem, Code, Button } from '@deque/cauldron-react'; -import './index.css'; -import { className } from '../../../props'; -import PropDocs from '../../../Demo/PropDocs'; - -const Demo = () => { - const [isMobile, setIsMobile] = useState(false); - const componentsList = new Array(5).fill('NavItem'); - const handleToggle = () => { - setIsMobile(!isMobile); - }; - return ( -
-

NavBar

-

Component Description

-

- A navigation bar that contains links to other sections of the website. -

-

Demo

- - {componentsList.map((name, index) => { - return ( - - {`${name} ${index + 1}`} - - ); - })} - - -

Code Sample

- - {` -import React, { useState } from 'react'; -import { NavBar, NavItem, Code, Button } from '@deque/cauldron-react'; -import './index.css'; - -const Demo = () => { - const [isMobile, setIsMobile] = useState(false); - const componentsList = new Array(5).fill('NavItem'); - const handleToggle = () => { - setIsMobile(!isMobile); - }; - return ( -
-

NavBar

-

Demo

-

Basic NavBar

- - {componentsList.map((name, index) => { - return ( - - {\`\${name} \${index + 1}\`} - - ); - })} - - -
- `} -
-
- -
-
- ); -}; - -export default Demo; diff --git a/package.json b/package.json index 6de845898..a1b3838ec 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cauldron", "private": true, - "version": "5.6.2", + "version": "5.7.0", "license": "MPL-2.0", "scripts": { "clean": "rimraf dist docs/dist", diff --git a/packages/react/__tests__/src/components/Notice/index.js b/packages/react/__tests__/src/components/Notice/index.js new file mode 100644 index 000000000..a0e309b58 --- /dev/null +++ b/packages/react/__tests__/src/components/Notice/index.js @@ -0,0 +1,95 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import Notice from 'src/components/Notice'; +import axe from '../../../axe'; + +test('handles rendering without errors', done => { + const wrapper = mount(); + expect(wrapper.find('Notice').length).toBe(1); + done(); +}); + +test('should render with defaults when no props passed in', async () => { + const wrapper = mount(child); + + expect(wrapper.find('.Notice').length).toBe(1); +}); +test('should render the correct default icon for a given `type`', async () => { + const cautionNotice = mount(); + + expect(cautionNotice.find('Icon').prop('type')).toBe('caution'); +}); + +test('should return no axe violations', async () => { + const info = mount( + + bar + + ); + + const caution = mount( + + bar + + ); + + const danger = mount( + + bar + + ); + + const infoAxeResults = await axe(info.html()); + const cautionAxeResults = await axe(caution.html()); + const dangerAxeResults = await axe(danger.html()); + expect(infoAxeResults).toHaveNoViolations(); + expect(cautionAxeResults).toHaveNoViolations(); + expect(dangerAxeResults).toHaveNoViolations(); +}); + +test('should return correctly with props passed in', async () => { + const wrapper = mount( + + bar + + ); + + expect(wrapper.find('Notice').length).toBe(1); + expect(wrapper.prop('title')).toBe('foo'); + expect(wrapper.prop('type')).toBe('info'); + expect(wrapper.prop('children')).toBe('bar'); +}); + +test('should render with the correct icon when a valid icon `type` string is passed in', async () => { + const wrapper = mount(); + + expect(wrapper.find('Notice').length).toBe(1); + expect(wrapper.find('Icon').prop('type')).toBe('bolt'); + expect(wrapper.find('.Icon--bolt').length).toBe(1); +}); + +test('should render only a `title` when no children are passed in', async () => { + const wrapper = mount(); + + expect(wrapper.find('Notice').length).toBe(1); + expect(wrapper.find('.Notice__title').contains('foo')).toBeTruthy(); +}); + +test('`title` prop should allow for any valid ContentNode element', async () => { + const wrapper = mount( + foo}> + bar + + ); + + expect(wrapper.find('Notice').length).toBe(1); + expect(wrapper.contains(

foo

)).toBeTruthy(); +}); + +test('should allow a ref to be forwarded', async () => { + const ref = React.createRef(); + const wrapper = mount(); + + expect(wrapper.find('Notice').length).toBe(1); + expect(ref.current).toBeTruthy(); +}); diff --git a/packages/react/package.json b/packages/react/package.json index e8e072555..2c52b19f4 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@deque/cauldron-react", - "version": "5.6.2", + "version": "5.7.0", "description": "Fully accessible react components library for Deque Cauldron", "homepage": "https://cauldron.dequelabs.com/", "publishConfig": { diff --git a/packages/react/src/components/NavBar/NavBar.tsx b/packages/react/src/components/NavBar/NavBar.tsx index 5ecfdb7fd..64118132d 100644 --- a/packages/react/src/components/NavBar/NavBar.tsx +++ b/packages/react/src/components/NavBar/NavBar.tsx @@ -9,9 +9,8 @@ import PropTypes from 'prop-types'; import Icon from '../Icon'; import { useId } from 'react-id-generator'; -interface NavBarProps { +interface NavBarProps extends React.HTMLAttributes { children: React.ReactNode; - initialActiveIndex?: number; className?: string; collapsed?: boolean; navTriggerLabel?: string; @@ -23,7 +22,8 @@ const NavBar = ({ className, collapsed = false, navTriggerLabel = 'MAIN MENU', - propId + propId, + ...props }: NavBarProps) => { const navRef = useRef(null); const triggerRef = useRef(null); @@ -69,6 +69,7 @@ const NavBar = ({ 'NavBar--collapsed': collapsed })} ref={navRef} + {...props} > {collapsed && (