diff --git a/docs/decisions/0014-removal-of-custom-responsive-components.rst b/docs/decisions/0014-removal-of-custom-responsive-components.rst new file mode 100644 index 0000000000..dbf34f4f24 --- /dev/null +++ b/docs/decisions/0014-removal-of-custom-responsive-components.rst @@ -0,0 +1,49 @@ +14. Removal of Custom Responsive Components +------------------------------------------- + +Status +------ + +Accepted + +Context +_______ + +Paragon utilizes the `react-responsive `_ +NPM package in some components, as well as providing some helper components from +react-responsive. However, often consumers of Paragon require additional responsive +functionality than is offered through Paragon itself and as such resort to installing +react-responsive as a standalone dependency in microfrontends. + +If Paragon instead makes react-responsive a passthrough library, consumers of Paragon will +be able to use react-responsive directly (by importing it from Paragon) rather than needing +to install it separately. This shouldn’t necessarily have any impact on Paragon’s bundle +size since react-bootstrap already ships with Paragon; just not all its functionality is +importable by its consumers. + +Decision +________ + +We will remove the following components: + +- ExtraSmall +- Small +- Medium +- Large +- ExtraLarge +- ExtraExtraLarge +- LargerThanExtraSmall + +We will pass through the following components and functionality from react-responsive: + +- MediaQuery +- useMediaQuery +- Context (as ResponsiveContext) + +Consequences +------------ + +- Consumers of the current `Responsive` components will need to refactor to the passthrough + components from react-responsive. +- Consumers of Paragon will be able to use components from react-responsive directly, without + having to install it separately. diff --git a/src/Alert/Alert.test.jsx b/src/Alert/Alert.test.jsx index 5c1437edca..b8743c801c 100644 --- a/src/Alert/Alert.test.jsx +++ b/src/Alert/Alert.test.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { mount } from 'enzyme'; import renderer, { act } from 'react-test-renderer'; import { Context as ResponsiveContext } from 'react-responsive'; -import { breakpoints } from '../Responsive'; +import breakpoints from '../utils/breakpoints'; import Button from '../Button'; import Alert from './index'; import { Info } from '../../icons'; diff --git a/src/Alert/index.jsx b/src/Alert/index.jsx index 8f14425fff..fbcffd6980 100644 --- a/src/Alert/index.jsx +++ b/src/Alert/index.jsx @@ -5,8 +5,8 @@ import BaseAlert from 'react-bootstrap/Alert'; import divWithClassName from 'react-bootstrap/divWithClassName'; import { useMediaQuery } from 'react-responsive'; import { Icon } from '..'; +import breakpoints from '../utils/breakpoints'; import Button from '../Button'; -import { breakpoints } from '../Responsive'; import ActionRow from '../ActionRow'; const Alert = React.forwardRef(({ diff --git a/src/Pagination/Pagination.test.jsx b/src/Pagination/Pagination.test.jsx index 625c209865..e4790af543 100644 --- a/src/Pagination/Pagination.test.jsx +++ b/src/Pagination/Pagination.test.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { mount } from 'enzyme'; import { Context as ResponsiveContext } from 'react-responsive'; -import { breakpoints } from '../Responsive'; +import breakpoints from '../utils/breakpoints'; import Pagination from './index'; const baseProps = { diff --git a/src/Pagination/index.jsx b/src/Pagination/index.jsx index ad288fd21c..af5c188f49 100644 --- a/src/Pagination/index.jsx +++ b/src/Pagination/index.jsx @@ -3,10 +3,11 @@ import { between } from 'airbnb-prop-types'; import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; +import MediaQuery from 'react-responsive'; import { Button } from '..'; -import { ExtraSmall, LargerThanExtraSmall } from '../Responsive'; import Icon from '../Icon'; +import breakpoints from '../utils/breakpoints'; import newId from '../utils/newId'; import { ELLIPSIS } from './constants'; import getPaginationRange from './getPaginationRange'; @@ -286,12 +287,12 @@ class Pagination extends React.Component { {this.renderScreenReaderSection()} diff --git a/src/Responsive/README.md b/src/Responsive/README.md deleted file mode 100644 index d2c1f1d8a8..0000000000 --- a/src/Responsive/README.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: 'Responsive Components' -type: 'component' -components: -- ExtraSmall -- Small -- Medium -- Large -- ExtraLarge -- ExtraExtraLarge -- LargerThanExtraSmall -categories: -- Layout -status: 'Reassessing' -designStatus: 'Done' -devStatus: 'TBD' -notes: | - Consider a different strategy: export breakpoint constants and a passthrough to react-responsive. Current components are less flexible than needed ( from x-small to medium is not possible without strange repetition). ---- - -### Props -Provides several wrapper components that support hiding/showing components for specific screen sizes based on [Bootstrap's responsive breakpoints](https://getbootstrap.com/docs/4.0/layout/overview/#responsive-breakpoints). This enables `Paragon` components to create mobile-specific UIs (e.g., simplifying the UX of `Pagination` for mobile devices). - -The following responsive components are available: - -1. `ExtraSmall` (max-width: 575) -2. `Small` (min-width: 576; max-width: 767) -3. `Medium` (min-width: 768; max-width: 991) -4. `Large` (min-width: 992; max-width: 1199) -5. `ExtraLarge` (min-width: 1200; max-width: 1399) -6. `ExtraExtraLarge` (min-width: 1400) -7. `LargerThanExtraSmall` (min-width: 576) - -## Example Usage - -```jsx - -

This text will only show on extra small screens.

-
- - -

This text will only show on large screens.

-
- - -

This text will only show on screens larger than extra small.

-
-``` diff --git a/src/Responsive/Responsive.test.jsx b/src/Responsive/Responsive.test.jsx deleted file mode 100644 index 7339274b3f..0000000000 --- a/src/Responsive/Responsive.test.jsx +++ /dev/null @@ -1,228 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import { Context as ResponsiveContext } from 'react-responsive'; - -import { - breakpoints, - ExtraSmall, - Small, - Medium, - Large, - ExtraLarge, - ExtraExtraLarge, - LargerThanExtraSmall, -} from './index'; - -describe('', () => { - it('should render children for extra small displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(1); - }); - - it('should not render children for larger than extra small displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); -}); - -describe('', () => { - it('should render children for small displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(1); - }); - - it('should not render children for smaller than small displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); - - it('should not render children for larger than small displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); -}); - -describe('', () => { - it('should render children for medium displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(1); - }); - - it('should not render children for smaller than medium displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); - - it('should not render children for larger than medium displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); -}); - -describe('', () => { - it('should render children for large displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(1); - }); - - it('should not render children for smaller than large displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); - - it('should not render children for larger than large displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); -}); - -describe('', () => { - it('should render children for extra large displays', () => { - // global.innerWidth = breakpoints.extraLarge.maxWidth; - - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(1); - }); - - it('should not render children for smaller than extra large displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); - - it('should not render children for larger than extra large displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); -}); - -describe('', () => { - it('should render children for extra large displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(1); - }); - - it('should not render children for smaller than extra large displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); -}); - -describe('', () => { - it('should render children for larger than extra small displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(1); - }); - - it('should not render children for extra small displays', () => { - const wrapper = mount(( - - -

Hello world

-
-
- )); - expect(wrapper.find('p')).toHaveLength(0); - }); -}); diff --git a/src/Responsive/index.jsx b/src/Responsive/index.jsx deleted file mode 100644 index 14ed5995bd..0000000000 --- a/src/Responsive/index.jsx +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react'; -import Responsive from 'react-responsive'; - -// NOTE: These are the breakpoints used in Bootstrap v4.0.0 as seen in -// the documentation (https://getbootstrap.com/docs/4.0/layout/overview/#responsive-breakpoints) -const breakpoints = { - extraSmall: { - maxWidth: 575.98, - }, - small: { - minWidth: 576, - maxWidth: 767.98, - }, - medium: { - minWidth: 768, - maxWidth: 991.98, - }, - large: { - minWidth: 992, - maxWidth: 1199.98, - }, - extraLarge: { - minWidth: 1200, - maxWidth: 1399.98, - }, - extraExtraLarge: { - minWidth: 1400, - }, -}; - -// Extra small devices (portrait phones) -const ExtraSmall = props => ( - -); - -// Small devices (landscape phones) -const Small = props => ( - -); - -// Medium devices (tablets) -const Medium = props => ( - -); - -// Large devices (desktops) -const Large = props => ( - -); - -// Extra large devices (large desktops) -const ExtraLarge = props => ( - -); - -// Extra Extra large devices -const ExtraExtraLarge = props => ( - -); - -const LargerThanExtraSmall = props => ( - -); - -export { - breakpoints, - ExtraSmall, - Small, - Medium, - Large, - ExtraLarge, - ExtraExtraLarge, - LargerThanExtraSmall, -}; diff --git a/src/index.js b/src/index.js index b2246a4739..5a439f5cd5 100644 --- a/src/index.js +++ b/src/index.js @@ -88,16 +88,6 @@ export { default as Pagination } from './Pagination'; export { default as Popover, PopoverTitle, PopoverContent } from './Popover'; export { default as ProgressBar } from './ProgressBar'; export { default as RadioButtonGroup, RadioButton } from './RadioButtonGroup'; -export { - breakpoints, - ExtraSmall, - Small, - Medium, - Large, - ExtraLarge, - ExtraExtraLarge, - LargerThanExtraSmall, -} from './Responsive'; export { default as ResponsiveEmbed } from './ResponsiveEmbed'; export { default as SearchField } from './SearchField'; export { default as Sheet } from './Sheet'; @@ -137,6 +127,7 @@ export { default as TableControlBar } from './DataTable/TableControlBar'; export { default as TableFooter } from './DataTable/TableFooter'; export { default as CardView } from './DataTable/CardView'; export { default as ToggleButton, ToggleButtonGroup } from './ToggleButton'; +export { default as breakpoints } from './utils/breakpoints'; export { default as Variant } from './utils/constants'; export { default as useWindowSize } from './hooks/useWindowSize'; export { default as useToggle } from './hooks/useToggle'; @@ -145,6 +136,12 @@ export { default as useToggle } from './hooks/useToggle'; // useTable for example is needed to use the DataTable component seamlessly // rather than setting a peer dependency in this project, we opt to tightly // couple these dependencies by passing through needed functionality. +export { + default as MediaQuery, + useMediaQuery, + Context as ResponsiveContext, +} from 'react-responsive'; + export { useTable, useFilters, diff --git a/src/utils/breakpoints.js b/src/utils/breakpoints.js new file mode 100644 index 0000000000..7490068a55 --- /dev/null +++ b/src/utils/breakpoints.js @@ -0,0 +1,28 @@ +// NOTE: These are the breakpoints used in Bootstrap v4.0.0 as seen in +// the documentation (https://getbootstrap.com/docs/4.0/layout/overview/#responsive-breakpoints) +const breakpoints = { + extraSmall: { + maxWidth: 575.98, + }, + small: { + minWidth: 576, + maxWidth: 767.98, + }, + medium: { + minWidth: 768, + maxWidth: 991.98, + }, + large: { + minWidth: 992, + maxWidth: 1199.98, + }, + extraLarge: { + minWidth: 1200, + maxWidth: 1399.98, + }, + extraExtraLarge: { + minWidth: 1400, + }, +}; + +export default breakpoints;