diff --git a/README.md b/README.md index f519ff76..284c9850 100644 --- a/README.md +++ b/README.md @@ -161,9 +161,5 @@ Thanks to the internet world. * [How to create an npm library from react components](https://dev.to/jimjunior/how-to-create-an-npm-library-from-react-components-2m2) ### TODO -* components v1.4 - * bouton tertiaire - * bouton FranceConnect - * retour en haut de page * Limit usage of colors to colorFamilies * Add StoryBook diff --git a/example/src/App.js b/example/src/App.js index 9734a67e..25435e4e 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -10,7 +10,7 @@ import ButtonGroupExample from './components/Button/ButtonGroup'; import CalloutExample from './components/Callout/Callout'; import CardExample from './components/Card/Card'; import CheckboxExample from './components/Checkbox/Checkbox'; -// import ConsentManagerExample from './components/ConsentManager/ConsentManager'; +import ConsentManagerExample from './components/ConsentManager/ConsentManager'; import FooterExample from './components/Footer/Footer'; import FileExample from './components/File/File'; import HeaderExample from './components/Header/Header'; @@ -36,6 +36,7 @@ import DownloadExample from './components/Download/Download'; import Element from './Element'; import Page1 from './Page-1'; import Page2 from './Page-2'; +import ShareExample from './components/Share/Share'; const App = () => { const elements = [ @@ -49,6 +50,7 @@ const App = () => { { title: 'Callout', component: }, { title: 'Card', component: }, { title: 'Checkbox', component: }, + { title: 'Consent', component: }, { title: 'Download', component: }, { title: 'File', component: }, { title: 'Highlight', component: }, @@ -68,6 +70,7 @@ const App = () => { { title: 'TextInput', component: }, { title: 'Tile - Tuile', component: }, { title: 'Toggle', component: }, + { title: 'Share', component: }, ]; return ( diff --git a/example/src/components/Share/Share.jsx b/example/src/components/Share/Share.jsx new file mode 100644 index 00000000..8f62e9b1 --- /dev/null +++ b/example/src/components/Share/Share.jsx @@ -0,0 +1,66 @@ +import React from 'react'; + +import { + Share, ShareButton, +} from '@dataesr/react-dsfr'; + +const ShareExampla = () => { + const onClickFacebook = () => { + window.open( + 'https://www.facebook.com/sharer.php', + 'Partager sur Facebook', + 'toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=450', + ); + }; + + const onClickTwitter = () => { + window.open( + 'https://twitter.com/intent/tweet', + 'Partager sur Twitter', + 'toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=420', + ); + }; + + const onClickLinkedin = () => { + window.open( + 'https://www.linkedin.com/shareArticle', + 'Partager sur Linkedin', + 'toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=420', + ); + }; + + const onCopy = () => { + navigator.clipboard.writeText(window.location); + }; + + return ( + + + + + + + + ); +}; + +export default ShareExampla; diff --git a/src/components/interface/Share/Share.d.ts b/src/components/interface/Share/Share.d.ts new file mode 100644 index 00000000..38629f18 --- /dev/null +++ b/src/components/interface/Share/Share.d.ts @@ -0,0 +1,16 @@ +import * as React from 'react'; + +export type ShareChildren = React.ReactNode[] | React.ReactNode; + +export type ShareClassName = string | Object | any[]; + +export interface ShareProps { + title: string; + children: ShareChildren; + className?: ShareClassName; +} + +declare const Share: React.FC; + +export default Share; + diff --git a/src/components/interface/Share/Share.js b/src/components/interface/Share/Share.js new file mode 100644 index 00000000..878e5788 --- /dev/null +++ b/src/components/interface/Share/Share.js @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import dataAttributes from '../../../utils/data-attributes'; + +/* +* DSFR v1.5.0 +*/ +import '@gouvfr/dsfr/dist/component/share/share.css'; + +const Share = ({ + children, className, title, ...remainingProps +}) => { + const _className = classNames('fr-share', className); + + return ( +
+

{title}

+
    + {children} +
+
+ ); +}; + +Share.defaultProps = { + className: '', + title: '', +}; + +Share.propTypes = { + children: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, + title: PropTypes.string, + className: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object, + PropTypes.array, + ]), +}; + +export default Share; diff --git a/src/components/interface/Share/Share.md b/src/components/interface/Share/Share.md new file mode 100644 index 00000000..af23b9b6 --- /dev/null +++ b/src/components/interface/Share/Share.md @@ -0,0 +1,16 @@ +# Méta données +cf [Confluences](https://gouvfr.atlassian.net/wiki/spaces/DB/pages/771555355/Partage+-+Share) + + + + + + + + + + + + + + diff --git a/src/components/interface/Share/ShareButton.d.ts b/src/components/interface/Share/ShareButton.d.ts new file mode 100644 index 00000000..acda4372 --- /dev/null +++ b/src/components/interface/Share/ShareButton.d.ts @@ -0,0 +1,16 @@ +import * as React from 'react'; + +export type ShareButtonClassName = string | Object | any[]; + +export interface ShareButtonProps { + type: string; + label: string; + href?: string; + onClick?: (...args: any[]) => any; + className?: ShareButtonClassName; +} + +declare const ShareButton: React.FC; + +export default ShareButton; + diff --git a/src/components/interface/Share/ShareButton.js b/src/components/interface/Share/ShareButton.js new file mode 100644 index 00000000..ff16ad17 --- /dev/null +++ b/src/components/interface/Share/ShareButton.js @@ -0,0 +1,85 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import dataAttributes from '../../../utils/data-attributes'; + +/* +* DSFR v1.5.0 +*/ +import '@gouvfr/dsfr/dist/component/share/share.css'; + +const ShareButton = ({ + label, href, className, type, onClick, ...remainingProps +}) => { + const _className = classNames('fr-share', className); + + const _onClick = (e) => { + e.preventDefault(); + onClick(e); + }; + + const renderLink = () => { + let link = ( + + {label} + + ); + + if (type === 'mail') { + link = ( + + {label} + + ); + } + + return link; + }; + + return ( +
  • + {type === 'copy' ? ( + + ) : ( + renderLink() + )} +
  • + ); +}; + +ShareButton.defaultProps = { + className: '', + href: '', + onClick: undefined, +}; + +ShareButton.propTypes = { + href: PropTypes.string, + label: PropTypes.string.isRequired, + onClick: PropTypes.func, + type: PropTypes.oneOf(['facebook', 'twitter', 'linkedin', 'copy', 'mail']).isRequired, + className: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object, + PropTypes.array, + ]), +}; + +export default ShareButton; diff --git a/src/components/interface/Share/__tests__/Share.test.js b/src/components/interface/Share/__tests__/Share.test.js new file mode 100644 index 00000000..f4dc8f20 --- /dev/null +++ b/src/components/interface/Share/__tests__/Share.test.js @@ -0,0 +1,54 @@ +import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; + +import Enzyme, { shallow } from 'enzyme'; +import renderer from 'react-test-renderer'; +import React from 'react'; +import { Share, ShareButton } from '..'; + +Enzyme.configure({ adapter: new Adapter() }); + +jest.mock('uuid', () => ({ + v4: jest.fn(), +})); + +describe('', () => { + let wrapper; + + beforeEach(() => { + wrapper = (props = {}) => shallow( + , + ); + }); + + it('should render Share properly', () => { + const component = renderer + .create( + + {}} + type="facebook" + label="Partager sur facebook" + href="https://www.facebook.com/sharer.php" + /> + , + ) + .toJSON(); + expect(component).toMatchSnapshot(); + }); + + test('onClick Share facebook', () => { + const mockClick = jest.fn(); + const props = { + onClick: mockClick, + }; + + const component = wrapper({ ...props }); + component.find('.fr-btn--facebook').simulate('click', { preventDefault: () => {} }); + expect(mockClick).toHaveBeenCalled(); + }); +}); diff --git a/src/components/interface/Share/__tests__/__snapshots__/Share.test.js.snap b/src/components/interface/Share/__tests__/__snapshots__/Share.test.js.snap new file mode 100644 index 00000000..69568ad2 --- /dev/null +++ b/src/components/interface/Share/__tests__/__snapshots__/Share.test.js.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` should render Share properly 1`] = ` +
    +

    + Partager la page +

    + +
    +`; + +exports[` should render SideMenu properly 1`] = ` +
    +

    + Partager la page +

    + +
    +`; diff --git a/src/components/interface/Share/index.d.ts b/src/components/interface/Share/index.d.ts new file mode 100644 index 00000000..78117057 --- /dev/null +++ b/src/components/interface/Share/index.d.ts @@ -0,0 +1,4 @@ +import type Share from './Share'; +import type ShareButton from './ShareButton'; + +export type { Share, ShareButton }; diff --git a/src/components/interface/Share/index.js b/src/components/interface/Share/index.js new file mode 100644 index 00000000..c6a76396 --- /dev/null +++ b/src/components/interface/Share/index.js @@ -0,0 +1,4 @@ +import Share from './Share'; +import ShareButton from './ShareButton'; + +export { Share, ShareButton }; diff --git a/src/index.js b/src/index.js index 631e4513..5450beda 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ import Alert from './components/interface/Alert/index'; import { Badge, BadgeGroup } from './components/interface/Badge/index'; import { Breadcrumb, BreadcrumbItem } from './components/interface/Breadcrumb/index'; import { Button, ButtonGroup } from './components/interface/Button/index'; +import { Share, ShareButton } from './components/interface/Share/index'; import { Download, DownloadGroup } from './components/interface/Download/index'; import { Callout, CalloutTitle, CalloutText } from './components/interface/Callout/index'; import { @@ -121,6 +122,8 @@ const library = () => ({ Pagination, Radio, RadioGroup, + Share, + ShareButton, SearchBar, Select, SearchableSelect, diff --git a/src/style/reset-dsfr.css b/src/style/reset-dsfr.css index 2bc40c96..8f135697 100644 --- a/src/style/reset-dsfr.css +++ b/src/style/reset-dsfr.css @@ -34,6 +34,8 @@ span.error { button.fr-accordion__btn[aria-expanded=true]:before, button.fr-accordion__btn:before, .fr-link--close:before, +a[class^="fr-btn"]:before, +button[class^="fr-btn"]:before, [class^="fr-alert"]:before { font-family: "remixicon"; background-color: inherit; @@ -112,3 +114,33 @@ button.fr-accordion__btn[aria-expanded=true]:before { .fr-nav__btn:after { content: '\ea4e'; } + +a.fr-btn--facebook:before { + content: '\ecbb'; + font-size: 1.4rem; + line-height: 1.5rem; +} + +a.fr-btn--twitter:before { + content: '\f23b'; + font-size: 1.4rem; + line-height: 1.5rem; +} + +a.fr-btn--linkedin:before { + content: '\eeb4'; + font-size: 1.4rem; + line-height: 1.5rem; +} + +a.fr-btn--mail:before { + content: '\eef6'; + font-size: 1.4rem; + line-height: 1.5rem; +} + +button.fr-btn--copy:before { + content: '\ecd5'; + font-size: 1.4rem; + line-height: 1.5rem; +}