From dc176831535867315ecb367429624c68e444678c Mon Sep 17 00:00:00 2001 From: Kalin Chernev Date: Wed, 6 Mar 2019 17:08:30 +0200 Subject: [PATCH] feat: Add expandable component (#46) # PR description I've tried to make the composition of the button structure easy to follow inside the template, by following a path of which variable is defined and later use how. Although it's tempting to expose the `collapsed` property to the public, in order to allow for `knobs`, I haven't, following the story of the React component. All buttons have been updated to include `data-ecl-label` attribute, probably something not [migrated](https://github.com/ec-europa/europa-component-library/blob/v2-dev/src/systems/ec/implementations/react/packages/button/src/Button.jsx#L38) yet because of a lack of use case. Which happens in this pull request, as the vanilla JS implementation requires the presence of this attribute. The `@ecl/ec-utility-typography` dependency is added here, but not in the React, because React can render children in a more flexible way, here we need it because of `ecl-u-type-paragraph-m`. ## QA Checklist In order to ensure a safe and quick review, please check that your PR follow those guidelines: - [x] I have put the vanilla component as `devDependencies` - [x] I have put the specs package as `devDependencies` - [x] I have added the components directly used in the twig file (with `include` or `embed`) as `dependencies` - [x] My component is listed in `@ecl-twig/ec-components`'s `dependencies` - [x] My variables naming follow the guidelines (snake case for twig) - [x] I have provided tests - [x] I have provided documentation (for the "notes" tab) - [x] If my local `yarn.lock` contains changes, I have committed it - [x] I have given my PR the proper label (`pr: review needed` to indicate that I'm done and now waiting for a review ,`pr: wip` to indicate that I'm actively working on it ...) --- .../__snapshots__/composition.test.js.snap | 2 +- .../__snapshots__/accordion.test.js.snap | 3 + .../__snapshots__/button.test.js.snap | 7 ++ .../ec-component-button/button.html.twig | 2 +- .../ec-component-expandable/.npmignore | 4 + .../ec-component-expandable/README.md | 7 ++ .../__snapshots__/expandable.test.js.snap | 104 ++++++++++++++++++ .../ec-component-expandable/demo/data.js | 22 ++++ .../docs/expandable.md | 47 ++++++++ .../expandable.html.twig | 94 ++++++++++++++++ .../expandable.story.js | 49 +++++++++ .../expandable.test.js | 25 +++++ .../ec-component-expandable/package.json | 33 ++++++ .../__snapshots__/file.test.js.snap | 1 + .../__snapshots__/language-list.test.js.snap | 1 + .../__snapshots__/search-form.test.js.snap | 1 + .../__snapshots__/site-header.test.js.snap | 2 + src/ec/packages/ec-components/package.json | 5 +- yarn.lock | 19 ++++ 19 files changed, 424 insertions(+), 4 deletions(-) create mode 100644 src/ec/packages/ec-component-expandable/.npmignore create mode 100644 src/ec/packages/ec-component-expandable/README.md create mode 100644 src/ec/packages/ec-component-expandable/__snapshots__/expandable.test.js.snap create mode 100644 src/ec/packages/ec-component-expandable/demo/data.js create mode 100644 src/ec/packages/ec-component-expandable/docs/expandable.md create mode 100644 src/ec/packages/ec-component-expandable/expandable.html.twig create mode 100644 src/ec/packages/ec-component-expandable/expandable.story.js create mode 100644 src/ec/packages/ec-component-expandable/expandable.test.js create mode 100644 src/ec/packages/ec-component-expandable/package.json diff --git a/src/ec/examples/composition/__snapshots__/composition.test.js.snap b/src/ec/examples/composition/__snapshots__/composition.test.js.snap index 3ad610688..fa85c6d20 100644 --- a/src/ec/examples/composition/__snapshots__/composition.test.js.snap +++ b/src/ec/examples/composition/__snapshots__/composition.test.js.snap @@ -3,7 +3,7 @@ exports[`EC - Composition renders correctly 1`] = ` "
diff --git a/src/ec/packages/ec-component-accordion/__snapshots__/accordion.test.js.snap b/src/ec/packages/ec-component-accordion/__snapshots__/accordion.test.js.snap index 468511f71..856b1db3c 100644 --- a/src/ec/packages/ec-component-accordion/__snapshots__/accordion.test.js.snap +++ b/src/ec/packages/ec-component-accordion/__snapshots__/accordion.test.js.snap @@ -32,6 +32,7 @@ exports[`EC - Accordion renders correctly 1`] = ` Delivery of last pending proposals, a common Destiny of unity, the hour of European Democracy @@ -72,6 +73,7 @@ exports[`EC - Accordion renders correctly 1`] = ` Energy union and climate @@ -112,6 +114,7 @@ exports[`EC - Accordion renders correctly 1`] = ` Delivery of last pending proposals, a common Destiny of unity, the hour of European Democracy diff --git a/src/ec/packages/ec-component-button/__snapshots__/button.test.js.snap b/src/ec/packages/ec-component-button/__snapshots__/button.test.js.snap index 290c65b4d..1d568c9e3 100644 --- a/src/ec/packages/ec-component-button/__snapshots__/button.test.js.snap +++ b/src/ec/packages/ec-component-button/__snapshots__/button.test.js.snap @@ -10,6 +10,7 @@ exports[`EC - Button CTA button - icon after renders correctly 1`] = ` > CTA Button with icon @@ -45,6 +46,7 @@ exports[`EC - Button CTA button - icon before renders correctly 1`] = ` Call to action button @@ -62,6 +64,7 @@ exports[`EC - Button CTA renders correctly 1`] = ` > Call to action button @@ -88,6 +91,7 @@ exports[`EC - Button Ghost renders correctly 1`] = ` > Ghost button @@ -105,6 +109,7 @@ exports[`EC - Button Primary renders correctly 1`] = ` > Primary button @@ -122,6 +127,7 @@ exports[`EC - Button Search renders correctly 1`] = ` > Search button @@ -139,6 +145,7 @@ exports[`EC - Button Secondary renders correctly 1`] = ` > Secondary button diff --git a/src/ec/packages/ec-component-button/button.html.twig b/src/ec/packages/ec-component-button/button.html.twig index 2e09894a0..062267729 100644 --- a/src/ec/packages/ec-component-button/button.html.twig +++ b/src/ec/packages/ec-component-button/button.html.twig @@ -57,7 +57,7 @@ {%- if _icon.name is not empty and _icon_position == 'before' -%} {%- include '../ec-component-icon/icon.html.twig' with { icon: _icon, extra_classes: 'ecl-button__icon ecl-button__icon--before' } -%} {%- endif -%} - {% block label _label %} + {% block label _label %} {%- if _icon.name is not empty and _icon_position == 'after' -%} {%- include '../ec-component-icon/icon.html.twig' with { icon: _icon, extra_classes: 'ecl-button__icon ecl-button__icon--after' } -%} {%- endif -%} diff --git a/src/ec/packages/ec-component-expandable/.npmignore b/src/ec/packages/ec-component-expandable/.npmignore new file mode 100644 index 000000000..6a93e7ba1 --- /dev/null +++ b/src/ec/packages/ec-component-expandable/.npmignore @@ -0,0 +1,4 @@ +__snapshots__ +*.story.js +*.test.js +**/*.md diff --git a/src/ec/packages/ec-component-expandable/README.md b/src/ec/packages/ec-component-expandable/README.md new file mode 100644 index 000000000..782156cc1 --- /dev/null +++ b/src/ec/packages/ec-component-expandable/README.md @@ -0,0 +1,7 @@ +# ECL Twig - EC Expandable component + +npm package: `@ecl-twig/ec-component-expandable` + +```shell +npm install --save @ecl-twig/ec-component-expandable +``` diff --git a/src/ec/packages/ec-component-expandable/__snapshots__/expandable.test.js.snap b/src/ec/packages/ec-component-expandable/__snapshots__/expandable.test.js.snap new file mode 100644 index 000000000..2f43957ab --- /dev/null +++ b/src/ec/packages/ec-component-expandable/__snapshots__/expandable.test.js.snap @@ -0,0 +1,104 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EC - Expandable renders correctly 1`] = ` +
+ + +
+`; + +exports[`EC - Expandable renders correctly when expanded 1`] = ` +
+ +
+

+ The EU is building an energy union that ensures Europe’s energy supply is safe, viable and accessible to all. In doing so, it can boost the economy and attract investments that can create new jobs opportunities. +

+
+
+`; diff --git a/src/ec/packages/ec-component-expandable/demo/data.js b/src/ec/packages/ec-component-expandable/demo/data.js new file mode 100644 index 000000000..db1106f77 --- /dev/null +++ b/src/ec/packages/ec-component-expandable/demo/data.js @@ -0,0 +1,22 @@ +/* eslint-disable import/no-extraneous-dependencies, no-param-reassign */ +import specData from '@ecl/ec-specs-expandable/demo/data'; + +const adapter = initialData => { + // Copy reference specification demo data. + const adaptedData = JSON.parse(JSON.stringify(initialData)); + + adaptedData.label_expanded = adaptedData.labelExpanded; + adaptedData.label_collapsed = adaptedData.labelCollapsed; + + const [type, name] = adaptedData.button.icon.shape.split('--'); + + adaptedData.button.icon = { + type, + name, + ...adaptedData.button.icon, + }; + + return adaptedData; +}; + +export default adapter(specData); diff --git a/src/ec/packages/ec-component-expandable/docs/expandable.md b/src/ec/packages/ec-component-expandable/docs/expandable.md new file mode 100644 index 000000000..568de9e09 --- /dev/null +++ b/src/ec/packages/ec-component-expandable/docs/expandable.md @@ -0,0 +1,47 @@ +# ECL Twig - EC Expandable component + +npm package: `@ecl-twig/ec-component-expandable` + +```shell +npm install --save @ecl-twig/ec-component-expandable +``` + +### Parameters: + +- "id" (string) (default: '') +- "label_expanded" (string) (default: '') +- "label_collapsed" (string) (default: '') +- "label_collapsed" (string) (default: '') +- "expanded" (boolean) (default: false) Rendered in collapsed state by default. Expanded state by default is also possible. +- "button" (predefined structure) : Button component structure +- "extra_classes" (optional) (string) (default: '') Extra classes (space separated) +- "extra_attributes" (optional) (array) (default: []) Extra attributes + - "name" (string) Attribute name, eg. 'data-test' + - "value" (string) Attribute value, eg: 'data-test-1' + +### Blocks: + +- "content" + +### Example: + + +```twig +{% include 'path/to/expandable.html.twig' with { + id: 'expandable-example', + button: { + label: 'Collapsed button', + variant: 'secondary', + icon: { + type: 'ui', + name: 'corner-arrow', + transform: 'rotate-180', + size: 'fluid', + }, + }, + label_expanded: 'Expanded button', + label_collapsed: 'Collapsed button', + content: + 'The EU is building an energy union that ensures Europe’s energy supply is safe, viable and accessible to all. In doing so, it can boost the economy and attract investments that can create new jobs opportunities.', +} %} +``` diff --git a/src/ec/packages/ec-component-expandable/expandable.html.twig b/src/ec/packages/ec-component-expandable/expandable.html.twig new file mode 100644 index 000000000..d2e3d15a2 --- /dev/null +++ b/src/ec/packages/ec-component-expandable/expandable.html.twig @@ -0,0 +1,94 @@ +{% spaceless %} + +{# + Parameters: + - "id" (string) (default: '') + - "label_expanded" (string) (default: '') + - "label_collapsed" (string) (default: '') + - "label_collapsed" (string) (default: '') + - "expanded" (boolean) (default: false) + - "button" (predefined structure) : Button component structure + - "extra_classes" (string) (default: '') + - "extra_attributes" (array) (default: []): format: [ + { + "name" (string) (default: ''), + "value" (string) (default: '') + }, + ... + ] + + Blocks: + - "content" +#} + +{# Internal properties #} + +{% set _id = id|default('') %} +{% set _css_class = 'ecl-expandable' %} +{% set _extra_attributes = "data-ecl-expandable='true'" %} + +{% set _label_expanded = label_expanded|default('') %} +{% set _label_collapsed = label_collapsed|default('') %} +{% set _aria_controls = _id ~ '-content' %} +{% set _content = content|default('') %} + +{% set _expanded = expanded|default(false) %} +{% set _content_hidden_attribute = '' %} + +{# Internal logic - Process properties #} + +{% if extra_classes is defined and extra_classes is not empty %} + {% set _css_class = _css_class ~ ' ' ~ extra_classes %} +{% endif %} + +{% if extra_attributes is defined and extra_attributes is not empty and extra_attributes is iterable %} + {% for attr in extra_attributes %} + {% set _extra_attributes = _extra_attributes ~ ' ' ~ attr.name ~ '="' ~ attr.value ~ '"' %} + {% endfor %} +{% endif %} + +{# Print the result #} + +
+ {% set _button_attributes = [ + { name: 'aria-controls', value: _aria_controls }, + { name: 'data-ecl-expandable-toggle', value: 'true' }, + { name: 'data-ecl-label-expanded', value: _label_expanded }, + { name: 'data-ecl-label-collapsed', value: _label_collapsed }, + ] + %} + + {% if _expanded %} + {% set _button_attributes = _button_attributes|merge([ + { name: 'aria-expanded', value: _expanded }, + ]) + %} + + {% set _label = _label_expanded %} + {% set _content_hidden_attribute = '' %} + + {% else %} + {% set _label = _label_collapsed %} + {% set _content_hidden_attribute = 'hidden' %} + {% endif %} + + {% include '../ec-component-button/button.html.twig' with { + label: _label, + variant: 'secondary', + type: 'button', + icon_position: "after", + extra_classes: 'ecl-expandable__toggle', + extra_attributes: _button_attributes, + }|merge(button) %} +
+

+ {%- block content _content -%} +

+
+
+ +{% endspaceless %} diff --git a/src/ec/packages/ec-component-expandable/expandable.story.js b/src/ec/packages/ec-component-expandable/expandable.story.js new file mode 100644 index 000000000..f40a39f94 --- /dev/null +++ b/src/ec/packages/ec-component-expandable/expandable.story.js @@ -0,0 +1,49 @@ +import { storiesOf } from '@storybook/html'; +import { withKnobs, text } from '@storybook/addon-knobs'; +import { withNotes } from '@ecl-twig/storybook-addon-notes'; +import withCode from '@ecl-twig/storybook-addon-code'; + +import defaultSprite from '@ecl/ec-resources-icons/dist/sprites/icons.svg'; +import demoData from './demo/data'; + +import expandable from './expandable.html.twig'; +import notes from './docs/expandable.md'; + +storiesOf('Components/Expandable', module) + .addDecorator(withKnobs) + .addDecorator(withCode) + .addDecorator(withNotes) + .add( + 'default', + () => { + demoData.button.icon.path = defaultSprite; + demoData.label_expanded = text('Label Expanded', demoData.labelExpanded); + demoData.label_collapsed = text( + 'Label Collapsed', + demoData.labelCollapsed + ); + demoData.content = text('Content', demoData.content); + + const html = expandable(demoData); + + const demo = document.createDocumentFragment(); + + const htmlElement = document.createElement('div'); + htmlElement.innerHTML = html.trim(); + demo.append(htmlElement.firstChild); + + const scriptElement = document.createElement('script'); + scriptElement.innerHTML = ` + var expandableElement = document.querySelector('[data-ecl-expandable]'); + var expandable = new ECL.Expandable(expandableElement); + expandable.init(); + `; + demo.append(scriptElement); + + return demo; + }, + + { + notes: { markdown: notes }, + } + ); diff --git a/src/ec/packages/ec-component-expandable/expandable.test.js b/src/ec/packages/ec-component-expandable/expandable.test.js new file mode 100644 index 000000000..a64cd694a --- /dev/null +++ b/src/ec/packages/ec-component-expandable/expandable.test.js @@ -0,0 +1,25 @@ +import path from 'path'; +import { renderTwigFileAsNode } from '@ecl-twig/test-utils'; + +import demoData from './demo/data'; + +// Add SVG icon path. +demoData.button.icon.path = 'example'; + +describe('EC - Expandable', () => { + const template = path.resolve(__dirname, './expandable.html.twig'); + const render = params => renderTwigFileAsNode(template, params); + + test('renders correctly', () => { + expect.assertions(1); + + return expect(render(demoData)).resolves.toMatchSnapshot(); + }); + + test('renders correctly when expanded', () => { + expect.assertions(1); + + const expanded = Object.assign({}, demoData, { expanded: true }); + return expect(render(expanded)).resolves.toMatchSnapshot(); + }); +}); diff --git a/src/ec/packages/ec-component-expandable/package.json b/src/ec/packages/ec-component-expandable/package.json new file mode 100644 index 000000000..ef9e86fef --- /dev/null +++ b/src/ec/packages/ec-component-expandable/package.json @@ -0,0 +1,33 @@ +{ + "name": "@ecl-twig/ec-component-expandable", + "author": "European Commission", + "license": "EUPL-1.1", + "version": "0.0.1-alpha", + "description": "ECL Twig - EC Expandable", + "dependencies": { + "@ecl-twig/ec-component-button": "^0.0.1-alpha" + }, + "devDependencies": { + "@ecl/ec-component-expandable": "^2.1.1", + "@ecl/ec-resources-icons": "~2.1.0", + "@ecl/ec-specs-expandable": "^2.1.1", + "@ecl/ec-utility-typography": "^2.1.1" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ec-europa/ecl-twig.git" + }, + "bugs": { + "url": "https://github.com/ec-europa/ecl-twig/issues" + }, + "homepage": "https://github.com/ec-europa/ecl-twig", + "keywords": [ + "ecl", + "europa-component-library", + "design-system", + "twig" + ] +} diff --git a/src/ec/packages/ec-component-file/__snapshots__/file.test.js.snap b/src/ec/packages/ec-component-file/__snapshots__/file.test.js.snap index fa9fe5b8d..4574fa6f8 100644 --- a/src/ec/packages/ec-component-file/__snapshots__/file.test.js.snap +++ b/src/ec/packages/ec-component-file/__snapshots__/file.test.js.snap @@ -73,6 +73,7 @@ exports[`EC - File With translation renders correctly 1`] = ` > Other languages (3) diff --git a/src/ec/packages/ec-component-language-list/__snapshots__/language-list.test.js.snap b/src/ec/packages/ec-component-language-list/__snapshots__/language-list.test.js.snap index a9bae049c..ef9978f0e 100644 --- a/src/ec/packages/ec-component-language-list/__snapshots__/language-list.test.js.snap +++ b/src/ec/packages/ec-component-language-list/__snapshots__/language-list.test.js.snap @@ -22,6 +22,7 @@ exports[`EC - Language List Overlay renders correctly 1`] = ` > Close diff --git a/src/ec/packages/ec-component-search-form/__snapshots__/search-form.test.js.snap b/src/ec/packages/ec-component-search-form/__snapshots__/search-form.test.js.snap index 2b5cba992..a527d5deb 100644 --- a/src/ec/packages/ec-component-search-form/__snapshots__/search-form.test.js.snap +++ b/src/ec/packages/ec-component-search-form/__snapshots__/search-form.test.js.snap @@ -25,6 +25,7 @@ exports[`EC - Search Form Default renders correctly 1`] = ` > Search diff --git a/src/ec/packages/ec-component-site-header/__snapshots__/site-header.test.js.snap b/src/ec/packages/ec-component-site-header/__snapshots__/site-header.test.js.snap index 87a93213c..213226be3 100644 --- a/src/ec/packages/ec-component-site-header/__snapshots__/site-header.test.js.snap +++ b/src/ec/packages/ec-component-site-header/__snapshots__/site-header.test.js.snap @@ -75,6 +75,7 @@ exports[`EC - Site Header Default renders correctly 1`] = ` > Search @@ -169,6 +170,7 @@ exports[`EC - Site Header Translated renders correctly 1`] = ` > Recherche diff --git a/src/ec/packages/ec-components/package.json b/src/ec/packages/ec-components/package.json index 38f00526a..4a5655ba6 100644 --- a/src/ec/packages/ec-components/package.json +++ b/src/ec/packages/ec-components/package.json @@ -10,8 +10,10 @@ "dependencies": { "@ecl-twig/ec-component-accordion": "^0.0.1-alpha", "@ecl-twig/ec-component-blockquote": "^0.0.1-alpha", + "@ecl-twig/ec-component-breadcrumb": "^0.0.1-alpha", "@ecl-twig/ec-component-button": "^0.0.1-alpha", "@ecl-twig/ec-component-card": "^0.0.1-alpha", + "@ecl-twig/ec-component-expandable": "^0.0.1-alpha", "@ecl-twig/ec-component-file": "^0.0.1-alpha", "@ecl-twig/ec-component-footer": "^0.0.1-alpha", "@ecl-twig/ec-component-icon": "^0.0.1-alpha", @@ -23,8 +25,7 @@ "@ecl-twig/ec-component-social-media-follow": "^0.0.1-alpha", "@ecl-twig/ec-component-social-media-share": "^0.0.1-alpha", "@ecl-twig/ec-component-tag": "^0.0.1-alpha", - "@ecl-twig/ec-component-text-input": "^0.0.1-alpha", - "@ecl-twig/ec-component-breadcrumb": "^0.0.1-alpha" + "@ecl-twig/ec-component-text-input": "^0.0.1-alpha" }, "repository": { "type": "git", diff --git a/yarn.lock b/yarn.lock index 5a0c2d50b..9a2709bef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -812,6 +812,13 @@ "@ecl/ec-component-link" "^2.1.1" "@ecl/ec-component-tag" "^2.1.1" +"@ecl/ec-component-expandable@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@ecl/ec-component-expandable/-/ec-component-expandable-2.1.1.tgz#9440ac42e2829f49730ce62e8ee24e99b33c0499" + integrity sha512-vhJ9qbqJbVF8nEbTyaARhBLjNfgfT+pPLsnVL7YW/04MnYjUEGZQGgkV5Gc1aZ+TUaPHKqIpyIGwtImm76H7Kw== + dependencies: + "@ecl/ec-base" "^2.1.1" + "@ecl/ec-component-file@^2.1.1": version "2.1.1" resolved "https://registry.yarnpkg.com/@ecl/ec-component-file/-/ec-component-file-2.1.1.tgz#9d4117baf13f27982630b0be709ff79da1e42f3e" @@ -998,6 +1005,11 @@ resolved "https://registry.yarnpkg.com/@ecl/ec-specs-card/-/ec-specs-card-2.1.1.tgz#c53f60ffa6382d9023778e0ea544d80b52f35468" integrity sha512-NXRlmxq6rp6/moVBj0j6b4yeOtSlub0UFeFYjuk3wU2ojPHDOiV0lDm7U0A5rdSiw79oyFy9AGRwjYBDGWSz+Q== +"@ecl/ec-specs-expandable@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@ecl/ec-specs-expandable/-/ec-specs-expandable-2.1.1.tgz#1a3f28f06257d040cf1258713964f2f203988a06" + integrity sha512-Oq77pM2a/NgI/96CG1qqnGcHZgmtO/tQNQUeExU8LpvNweQFqpmQ4A3EJaBS+s2WYE8M/viNsMCVGYkooFiM0g== + "@ecl/ec-specs-file@^2.1.1": version "2.1.1" resolved "https://registry.yarnpkg.com/@ecl/ec-specs-file/-/ec-specs-file-2.1.1.tgz#0140c516d4b74908fcd53620a713c7e4c9e98135" @@ -1065,6 +1077,13 @@ dependencies: "@ecl/ec-base" "^2.1.1" +"@ecl/ec-utility-typography@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@ecl/ec-utility-typography/-/ec-utility-typography-2.1.1.tgz#8a2bf682f4d12c1342fb37bf076a5727f60596ba" + integrity sha512-mHskyoP1rFsGPQe1AveYEhytj9fwVWkrsMmmEgDg0onYgkXN8PuWHQ55ZM7RV5nmcxQOGEU2RdykQc4X55xpfQ== + dependencies: + "@ecl/ec-base" "^2.1.1" + "@emotion/cache@^0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-0.8.8.tgz#2c3bd1aa5fdb88f1cc2325176a3f3201739e726c"