From 598e3e6e5a18efa8d8127c7c4165629c8e44cc92 Mon Sep 17 00:00:00 2001 From: Vignesh_Manogar <61269786+Vignesh-Manogar-E3433@users.noreply.github.com> Date: Thu, 19 Mar 2020 19:25:37 +0530 Subject: [PATCH] feat(tabs): Implementation (#138) * feat(tabs): Initial commit * feat(tabs): Implemented {{nucleus-tabs}} Basic functionality working Refractoring some code * refactor(tabs): calling component attributes through get call * fix(tabs): Background variant border radius issue * refractor(tabs): current selected name change * fix(tabs): no focus on disabled button * fix(tabs): no focus on disabled button & safari text rendering issue * feat(tabs): 'beforeChange' handler implementation * feat(tabs): Adding customClasses prop to tabs * refractor(tabs): class names changed to follow existing conventions * refractor(tabs): Added missing empty lines at the end of files * fix(tabs): documentation issues * fix(tabs): safari font color on active element * refractor(tabs): Removed sending attributes in single props object * feat(tabs): select prop optional * feat(tabs): disabled as boolean or string * fix(tabs): focus styling not appearing on click * fix(tabs): removed vendor prefixes * fix(tabs): pressed and active hover state styling * refactor(tabs): Combined attribute bindings, class bindings. Single line if statements wrapped * refactor(tabs): changeFocusTab function Co-authored-by: Shibu Lijack --- packages/@nucleus/package.json | 1 + .../app/components/nucleus-tabs/demo-1.js | 17 + .../app/components/nucleus-tabs/demo-2.js | 29 ++ packages/@nucleus/tests/dummy/app/router.js | 1 + .../components/nucleus-tabs/demo-1.hbs | 20 ++ .../components/nucleus-tabs/demo-2.hbs | 22 ++ .../tests/dummy/app/templates/docs.hbs | 1 + .../templates/docs/components/nucleus-tabs.md | 166 ++++++++++ packages/tabs/CHANGELOG.md | 8 + packages/tabs/LICENSE.md | 9 + packages/tabs/README.md | 22 ++ .../tabs/addon/components/nucleus-tabs.js | 169 ++++++++++ .../components/nucleus-tabs/tab-list-item.js | 293 ++++++++++++++++++ .../components/nucleus-tabs/tab-panel.js | 98 ++++++ packages/tabs/addon/constants/nucleus-tabs.js | 10 + packages/tabs/addon/styles/addon.scss | 3 + .../styles/components/_nucleus-tabs.scss | 135 ++++++++ .../templates/components/nucleus-tabs.hbs | 20 ++ .../components/nucleus-tabs/tab-list-item.hbs | 1 + .../components/nucleus-tabs/tab-panel.hbs | 1 + packages/tabs/app/.gitkeep | 0 packages/tabs/app/components/nucleus-tabs.js | 1 + .../components/nucleus-tabs/tab-list-item.js | 1 + .../app/components/nucleus-tabs/tab-panel.js | 1 + packages/tabs/app/styles/app.scss | 3 + packages/tabs/config/deploy.js | 29 ++ packages/tabs/config/environment.js | 60 ++++ packages/tabs/ember-backstop/backstop.js | 37 +++ ...yle_tabs__assert0_0_document_0_webview.png | Bin 0 -> 11331 bytes ...yle_tabs__assert0_0_document_0_webview.png | Bin 0 -> 11339 bytes ...yle_tabs__assert0_0_document_0_webview.png | Bin 0 -> 11240 bytes ...led_tabs__assert0_0_document_0_webview.png | Bin 0 -> 12117 bytes ...disabled__assert0_0_document_0_webview.png | Bin 0 -> 26366 bytes ...variants__assert0_0_document_0_webview.png | Bin 0 -> 26409 bytes .../puppet/clickAndHoverHelper.js | 41 +++ .../engine_scripts/puppet/onReady.js | 11 + .../engine_scripts/puppet/overrideCSS.js | 13 + packages/tabs/ember-cli-build.js | 14 + packages/tabs/index.js | 34 ++ packages/tabs/package.json | 82 +++++ packages/tabs/testem.js | 30 ++ packages/tabs/tests/.eslintrc.js | 5 + packages/tabs/tests/dummy/app/app.js | 14 + .../tabs/tests/dummy/app/components/.gitkeep | 0 .../tabs/tests/dummy/app/controllers/.gitkeep | 0 .../tabs/tests/dummy/app/helpers/.gitkeep | 0 packages/tabs/tests/dummy/app/index.html | 25 ++ packages/tabs/tests/dummy/app/models/.gitkeep | 0 packages/tabs/tests/dummy/app/resolver.js | 3 + packages/tabs/tests/dummy/app/router.js | 12 + packages/tabs/tests/dummy/app/routes/.gitkeep | 0 packages/tabs/tests/dummy/app/styles/app.scss | 3 + .../tabs/tests/dummy/config/environment.js | 54 ++++ .../tests/dummy/config/optional-features.json | 3 + packages/tabs/tests/dummy/config/targets.js | 19 ++ packages/tabs/tests/dummy/public/robots.txt | 3 + packages/tabs/tests/helpers/.gitkeep | 0 packages/tabs/tests/index.html | 33 ++ packages/tabs/tests/integration/.gitkeep | 0 .../components/nucleus-tabs-test.js | 204 ++++++++++++ packages/tabs/tests/test-helper.js | 8 + packages/tabs/tests/unit/.gitkeep | 0 62 files changed, 1769 insertions(+) create mode 100644 packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-1.js create mode 100644 packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-2.js create mode 100644 packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-1.hbs create mode 100644 packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-2.hbs create mode 100644 packages/@nucleus/tests/dummy/app/templates/docs/components/nucleus-tabs.md create mode 100644 packages/tabs/CHANGELOG.md create mode 100644 packages/tabs/LICENSE.md create mode 100644 packages/tabs/README.md create mode 100644 packages/tabs/addon/components/nucleus-tabs.js create mode 100644 packages/tabs/addon/components/nucleus-tabs/tab-list-item.js create mode 100644 packages/tabs/addon/components/nucleus-tabs/tab-panel.js create mode 100644 packages/tabs/addon/constants/nucleus-tabs.js create mode 100644 packages/tabs/addon/styles/addon.scss create mode 100644 packages/tabs/addon/styles/components/_nucleus-tabs.scss create mode 100644 packages/tabs/addon/templates/components/nucleus-tabs.hbs create mode 100644 packages/tabs/addon/templates/components/nucleus-tabs/tab-list-item.hbs create mode 100644 packages/tabs/addon/templates/components/nucleus-tabs/tab-panel.hbs create mode 100644 packages/tabs/app/.gitkeep create mode 100644 packages/tabs/app/components/nucleus-tabs.js create mode 100644 packages/tabs/app/components/nucleus-tabs/tab-list-item.js create mode 100644 packages/tabs/app/components/nucleus-tabs/tab-panel.js create mode 100644 packages/tabs/app/styles/app.scss create mode 100644 packages/tabs/config/deploy.js create mode 100644 packages/tabs/config/environment.js create mode 100644 packages/tabs/ember-backstop/backstop.js create mode 100644 packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_background_style_tabs__assert0_0_document_0_webview.png create mode 100644 packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_border_style_tabs__assert0_0_document_0_webview.png create mode 100644 packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_default_style_tabs__assert0_0_document_0_webview.png create mode 100644 packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_disabled_tabs__assert0_0_document_0_webview.png create mode 100644 packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_the_different_variants_-_default_background_disabled__assert0_0_document_0_webview.png create mode 100644 packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_the_different_variants__assert0_0_document_0_webview.png create mode 100644 packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/clickAndHoverHelper.js create mode 100644 packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/onReady.js create mode 100644 packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/overrideCSS.js create mode 100644 packages/tabs/ember-cli-build.js create mode 100644 packages/tabs/index.js create mode 100644 packages/tabs/package.json create mode 100644 packages/tabs/testem.js create mode 100644 packages/tabs/tests/.eslintrc.js create mode 100644 packages/tabs/tests/dummy/app/app.js create mode 100644 packages/tabs/tests/dummy/app/components/.gitkeep create mode 100644 packages/tabs/tests/dummy/app/controllers/.gitkeep create mode 100644 packages/tabs/tests/dummy/app/helpers/.gitkeep create mode 100644 packages/tabs/tests/dummy/app/index.html create mode 100644 packages/tabs/tests/dummy/app/models/.gitkeep create mode 100644 packages/tabs/tests/dummy/app/resolver.js create mode 100644 packages/tabs/tests/dummy/app/router.js create mode 100644 packages/tabs/tests/dummy/app/routes/.gitkeep create mode 100644 packages/tabs/tests/dummy/app/styles/app.scss create mode 100644 packages/tabs/tests/dummy/config/environment.js create mode 100644 packages/tabs/tests/dummy/config/optional-features.json create mode 100644 packages/tabs/tests/dummy/config/targets.js create mode 100644 packages/tabs/tests/dummy/public/robots.txt create mode 100644 packages/tabs/tests/helpers/.gitkeep create mode 100644 packages/tabs/tests/index.html create mode 100644 packages/tabs/tests/integration/.gitkeep create mode 100644 packages/tabs/tests/integration/components/nucleus-tabs-test.js create mode 100644 packages/tabs/tests/test-helper.js create mode 100644 packages/tabs/tests/unit/.gitkeep diff --git a/packages/@nucleus/package.json b/packages/@nucleus/package.json index 335d8032..86c5bde9 100644 --- a/packages/@nucleus/package.json +++ b/packages/@nucleus/package.json @@ -27,6 +27,7 @@ "@freshworks/inline-banner": "^0.5.4", "@freshworks/modal": "^0.5.4", "@freshworks/toast-message": "^0.6.4", + "@freshworks/tabs": "^0.1.0", "ember-cli-autoprefixer": "^0.8.1", "ember-cli-babel": "^7.11.1", "ember-cli-htmlbars": "^4.0.0", diff --git a/packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-1.js b/packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-1.js new file mode 100644 index 00000000..54b22ed0 --- /dev/null +++ b/packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-1.js @@ -0,0 +1,17 @@ +// BEGIN-SNIPPET nucleus-tabs-2.js +import Component from '@ember/component'; +import { inject } from '@ember/service'; +import { get } from '@ember/object'; + +export default Component.extend({ + flashMessages: inject(), + actions: { + onChange(changedTo) { // changedTo, ChangedFrom, event params accepted + const flashMessages = get(this, 'flashMessages'); + flashMessages.info(`Custom action invoked. '${changedTo}' tab selected!`, { + timeout: 1500 + }); + } + } +}); +// END-SNIPPET diff --git a/packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-2.js b/packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-2.js new file mode 100644 index 00000000..ea26f50c --- /dev/null +++ b/packages/@nucleus/tests/dummy/app/components/nucleus-tabs/demo-2.js @@ -0,0 +1,29 @@ +// BEGIN-SNIPPET nucleus-tabs-3.js +import Component from '@ember/component'; +import { inject } from '@ember/service'; +import RSVP from 'rsvp'; +import { get } from '@ember/object'; + +export default Component.extend({ + flashMessages: inject(), + actions: { + beforeChange() { // changedTo, changedFrom, event params accepted + const flashMessages = get(this, 'flashMessages'); + flashMessages.info(`Performing asyncronous operation..`, { + timeout: 1500 + }); + return new RSVP.Promise(function(resolve) { + setTimeout(function () { + resolve(); + }, 2000); + }); + }, + onChange() { // changedTo, ChangedFrom, event params accepted + const flashMessages = get(this, 'flashMessages'); + flashMessages.info(`Tab changed.`, { + timeout: 1500 + }); + } + } +}); +// END-SNIPPET diff --git a/packages/@nucleus/tests/dummy/app/router.js b/packages/@nucleus/tests/dummy/app/router.js index 9de255c1..9823652c 100644 --- a/packages/@nucleus/tests/dummy/app/router.js +++ b/packages/@nucleus/tests/dummy/app/router.js @@ -20,6 +20,7 @@ Router.map(function() { this.route("nucleus-modal"); this.route("nucleus-toast-message"); this.route("nucleus-banner"); + this.route("nucleus-tabs"); }); this.route('not-found', { path: '/*path' }); diff --git a/packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-1.hbs b/packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-1.hbs new file mode 100644 index 00000000..14e98cdc --- /dev/null +++ b/packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-1.hbs @@ -0,0 +1,20 @@ +{{#docs-demo as |demo|}} + {{#demo.example name="nucleus-tabs-2.hbs" }} + {{#nucleus-tabs + description="site-navigation" + onChange=(action "onChange") as |tabs| }} + {{#tabs.panel name="I want apples" }} +
This is apples section
+ {{/tabs.panel}} + {{#tabs.panel name="I want oranges" }} +
This is oranges section
+ {{/tabs.panel}} + {{#tabs.panel name="I want grapes" }} +
This is grapes section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + {{/demo.example}} + + {{demo.snippet "nucleus-tabs-2.hbs"}} + {{demo.snippet "nucleus-tabs-2.js" label="component.js"}} +{{/docs-demo}} diff --git a/packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-2.hbs b/packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-2.hbs new file mode 100644 index 00000000..c6098491 --- /dev/null +++ b/packages/@nucleus/tests/dummy/app/templates/components/nucleus-tabs/demo-2.hbs @@ -0,0 +1,22 @@ +{{#docs-demo as |demo|}} + {{#demo.example name="nucleus-tabs-3.hbs" }} + {{#nucleus-tabs + description="site-navigation" + select="I want apples" + beforeChange=(action "beforeChange") + onChange=(action "onChange") as |tabs| }} + {{#tabs.panel name="I want apples" }} +
This is apples section
+ {{/tabs.panel}} + {{#tabs.panel name="I want oranges" }} +
This is oranges section
+ {{/tabs.panel}} + {{#tabs.panel name="I want grapes" }} +
This is grapes section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + {{/demo.example}} + + {{demo.snippet "nucleus-tabs-3.hbs"}} + {{demo.snippet "nucleus-tabs-3.js" label="component.js"}} +{{/docs-demo}} diff --git a/packages/@nucleus/tests/dummy/app/templates/docs.hbs b/packages/@nucleus/tests/dummy/app/templates/docs.hbs index e9e64633..ec66d07d 100644 --- a/packages/@nucleus/tests/dummy/app/templates/docs.hbs +++ b/packages/@nucleus/tests/dummy/app/templates/docs.hbs @@ -11,6 +11,7 @@ {{nav.item "Inline Banner" "docs.components.nucleus-inline-banner"}} {{nav.item "Modal" "docs.components.nucleus-modal"}} {{nav.item "Toast message" "docs.components.nucleus-toast-message"}} + {{nav.item "Tabs" "docs.components.nucleus-tabs"}} {{/viewer.nav}} {{#viewer.main}} diff --git a/packages/@nucleus/tests/dummy/app/templates/docs/components/nucleus-tabs.md b/packages/@nucleus/tests/dummy/app/templates/docs/components/nucleus-tabs.md new file mode 100644 index 00000000..a88bb093 --- /dev/null +++ b/packages/@nucleus/tests/dummy/app/templates/docs/components/nucleus-tabs.md @@ -0,0 +1,166 @@ +# Tabs + +```sh +yarn add @freshworks/tabs +``` + +Tabs are used to organise content under each section. Tabs are most helpful when there is a lot of content to show in a page. Tabs can help in showing content which are under the same level of hierarchy, under each section inside the same page. + +## Usage + +#### 1. Categorisation + +It's easy for the user to quickly distinguish which tab belongs to which content. + +{{#docs-demo as |demo|}} + {{#demo.example name="nucleus-tabs.hbs"}} + {{#nucleus-tabs + customClasses="sample-tab sample-tab-simple" + description="site-navigation" + select="I want apples" + variant="line" as |tabs| }} + {{#tabs.panel name="I want apples" }} +
This is apples section
+ {{/tabs.panel}} + {{#tabs.panel name="I want oranges" }} +
This is oranges section
+ {{/tabs.panel}} + {{#tabs.panel name="I want grapes" }} +
This is grapes section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + {{/demo.example}} + {{demo.snippet 'nucleus-tabs.hbs'}} +{{/docs-demo}} + +#### 2. Custom action 'on' changing tab + +{{nucleus-tabs/demo-1}} + +#### 3. Custom action 'before' changing tab + +{{nucleus-tabs/demo-2}} + +#### 4. Disabled tab + +{{#docs-demo as |demo|}} + {{#demo.example name="nucleus-tabs-4.hbs"}} + {{#nucleus-tabs + description="site-navigation" + variant="line" as |tabs| }} + {{#tabs.panel name="I want apples" }} +
This is apples section
+ {{/tabs.panel}} + {{#tabs.panel name="I want oranges" }} +
This is oranges section
+ {{/tabs.panel}} + {{#tabs.panel name="I want grapes" disabled=true }} +
This is grapes section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + {{/demo.example}} + {{demo.snippet 'nucleus-tabs-4.hbs'}} +{{/docs-demo}} + +## Styles + +#### 1. Default + +{{#docs-demo as |demo|}} + {{#demo.example name="nucleus-tabs-variant1.hbs"}} + {{#nucleus-tabs + description="site-navigation" + select="I want apples" + variant="line" as |tabs| }} + {{#tabs.panel name="I want apples" }} +
This is apples section
+ {{/tabs.panel}} + {{#tabs.panel name="I want oranges" }} +
This is oranges section
+ {{/tabs.panel}} + {{#tabs.panel name="I want grapes" }} +
This is grapes section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + {{/demo.example}} + {{demo.snippet 'nucleus-tabs-variant1.hbs'}} +{{/docs-demo}} + + + +#### 2. With Background +Pass 'variant' property as 'background'. + +{{#docs-demo as |demo|}} + {{#demo.example name="nucleus-tabs-variant2.hbs"}} + {{#nucleus-tabs + description="site-navigation" + select="I want apples" + variant="background" as |tabs| }} + {{#tabs.panel name="I want apples" }} +
This is apples section
+ {{/tabs.panel}} + {{#tabs.panel name="I want oranges" }} +
This is oranges section
+ {{/tabs.panel}} + {{#tabs.panel name="I want grapes" }} +
This is grapes section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + {{/demo.example}} + {{demo.snippet 'nucleus-tabs-variant2.hbs'}} +{{/docs-demo}} + + +## Guidelines + +✅ **Do's** + +1. Tabs should be placed in a single row over the content + +2. Include all interactive states for the tabs + + +🚫 **Dont's** + +1. Dont use tabs for sequential content. Users can navigate to any tab at any time and cannot be expected to do it sequentially. + +2. Dont use tabs for content in different levels of hierarchy. + +## Accessibility + +__role=tablist__ + +Indicates that the element serves as a container for a set of tabs. + +__aria-label=Entertainment__ + +Provides a label that describes the purpose of the set of tabs. + + +__role=tab__ + +Indicates the element serves as a tab control. + +__aria-select=true__ + +Indicates the tab control is activated and its associated panel is displayed. + +__aria-select=false__ + +Indicates the tab control is not active and its associated panel is NOT displayed. + +__aria-controls=IDREF__ + +Refers to the tabpanel element associated with the tab. + + +__role=tabpanel__ + +Indicates the element serves as a container for tab panel content. + +__aria-labelledby=IDREF__ + +Refers to the tab element that controls the panel. + +{{docs-note}} \ No newline at end of file diff --git a/packages/tabs/CHANGELOG.md b/packages/tabs/CHANGELOG.md new file mode 100644 index 00000000..71b67641 --- /dev/null +++ b/packages/tabs/CHANGELOG.md @@ -0,0 +1,8 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.0] - 2019-03-06 +### Added +- {{nucleus-tabs}} Initial imlpementation. \ No newline at end of file diff --git a/packages/tabs/LICENSE.md b/packages/tabs/LICENSE.md new file mode 100644 index 00000000..f8d1edb3 --- /dev/null +++ b/packages/tabs/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2019 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/tabs/README.md b/packages/tabs/README.md new file mode 100644 index 00000000..19854beb --- /dev/null +++ b/packages/tabs/README.md @@ -0,0 +1,22 @@ +@freshworks/tabs +============================================================================== + +``` +yarn add @freshworks/tabs +``` + +Tabs are used to organise content under each section. + +Scenario +------------------------------------------------------------------------------ +Tabs are most helpful when there is a lot of content to show in a page. Tabs can help in showing content which are under the same level of hierarchy, under each section inside the same page. + +Guidelines +------------------------------------------------------------------------------ +**Do's** +1. Tabs should be placed in a single row over the content +2. Include all interactive states for the tabs + + +**Dont's** +1. Dont use tabs for sequential content. Users can navigate to any tab at any time and cannot be expected to do it sequentially. diff --git a/packages/tabs/addon/components/nucleus-tabs.js b/packages/tabs/addon/components/nucleus-tabs.js new file mode 100644 index 00000000..3e439137 --- /dev/null +++ b/packages/tabs/addon/components/nucleus-tabs.js @@ -0,0 +1,169 @@ +import Component from '@ember/component'; +import { classNames, classNameBindings, layout as templateLayout } from '@ember-decorators/component'; +import layout from '../templates/components/nucleus-tabs'; +import { set, get, getProperties, computed, action } from '@ember/object'; +import defaultProp from '@freshworks/core/utils/default-decorator'; +import { A } from '@ember/array'; +import { oneWay }from '@ember/object/computed'; + +/** + __Usage:__ + + [Refer component page](/docs/components/nucleus-tabs) + + @class Nucleus Tabs + @namespace Components + @extends Ember.Component + @public +*/ +@templateLayout(layout) +@classNames('nucleus-tabs') +@classNameBindings('variantClass', 'customClasses') +class NucleusTabs extends Component { + /** + * description + * + * @field description + * @description to add aria label + * @type string|null + * @default null + * @readonly + * @public + */ + @defaultProp + description = null; + + /** + * customClasses + * + * @field customClasses + * @description to add custom class to the tabs component + * @type string + * @readonly + * @public + */ + @defaultProp + customClasses = ''; + + /** + * select + * + * @field select + * @description default open tab + * @type string|null + * @default null + * @readonly + * @public + */ + @defaultProp + select = null; + + /** + * variant + * + * @field variant + * @description tab styles, line/background + * @type string + * @default 'line' + * @readonly + * @public + */ + @defaultProp + variant = 'line'; + + /** + * tabPanels + * + * @field tabPanels + * @description Collection of all tab panels + * @type array + * @public + */ + tabPanels = A([]); + + /** + * tabListItems + * + * @field tabListItems + * @description Collection of all tab list items + * @type array + * @public + */ + tabListItems = A([]); + + /** + * selected + * + * @field selected + * @description takes intial value from select + * @type string|null + * @public + */ + @oneWay('select') + selected; + + /** + * variantClass + * + * @field variantClass + * @type string + * @public + */ + @computed('variant', function() { + return 'nucleus-tabs--' + get(this, 'variant'); + }) + variantClass; + + /** + * registerPanel + * + * @method registerPanel + * @param {Object} tab + * @public + * + */ + @action + registerPanel(tab) { + if(!get(this, 'selected') && (tab.disabled === 'false')) { + set(this, 'selected', tab.name); // set selected if not initially set + } + get(this, 'tabPanels').pushObject(tab); + } + + /** + * registerTabListItem + * + * @method registerTabListItem + * @param {Object} tab + * @public + * + */ + @action + registerTabListItem(tabList) { + get(this, 'tabListItems').pushObject(tabList); + } + + /** + * activateTab + * + * @method activateTab + * @description Handler that will be called when a tab is clicked + * @param {string} name + * @param {any} event + * @public + * + */ + @action + async activateTab(changedTo, event) { + const { beforeChange, onChange, currentTab } = getProperties(this, 'beforeChange', 'onChange', 'currentTab'); + if(beforeChange) { + await beforeChange.call(this, changedTo, currentTab, event); + } + set(this, 'selected', changedTo); + if(onChange) { + await onChange.call(this, changedTo, currentTab, event); + } + } +} + +export default NucleusTabs; diff --git a/packages/tabs/addon/components/nucleus-tabs/tab-list-item.js b/packages/tabs/addon/components/nucleus-tabs/tab-list-item.js new file mode 100644 index 00000000..21966c89 --- /dev/null +++ b/packages/tabs/addon/components/nucleus-tabs/tab-list-item.js @@ -0,0 +1,293 @@ +import Component from '@ember/component'; +import { classNames, attributeBindings, classNameBindings, tagName, layout as templateLayout } from '@ember-decorators/component'; +import layout from '../../templates/components/nucleus-tabs/tab-list-item'; +import { get, set, computed } from '@ember/object'; +import defaultProp from '@freshworks/core/utils/default-decorator'; +import { TABS_KEY_CODE } from '../../constants/nucleus-tabs' + +/** + __Usage:__ + + [Refer component page](/docs/components/nucleus-tabs) + + @class Nucleus Tab List Item + @namespace Components + @extends Ember.Component + @private +*/ +@tagName('div') +@templateLayout(layout) +@classNames('nucleus-tabs__list__item') +@classNameBindings('isActive:is-active', 'isDisabled:is-disabled', 'isPressed:is-pressed') +@attributeBindings('isDisabled:disabled', 'tabindex', 'title', 'role', 'aria-controls', 'aria-selected') +class TabListItem extends Component { + + /** + * disabled + * + * @field disabled + * @type string + * @default null + * @readonly + * @public + */ + @defaultProp + disabled = null; + + /** + * controls + * + * @field controls + * @description idref to what panel this tab item controls + * @type string|null + * @readonly + * @public + */ + @defaultProp + controls; + + /** + * selected + * + * @field selected + * @description currently selected tab + * @readonly + * @public + */ + @defaultProp + selected; + + /** + * tabOrder + * + * @field tabOrder + * @description order in which tabs are displayed. Only first tabs will not have tabIndex value + * @type number + * @readonly + * @public + */ + @defaultProp + tabOrder; + + /** + * role + * + * @field role + * @type string + * @default 'tab' + * @public + */ + role = 'tab'; + + /** + * isPressed + * + * @field isPressed + * @description to solve focus on click styling + * @type boolean + * @default false + * @public + */ + isPressed = false; + + /** + * tabindex + * + * @field tabindex + * @type string|null + * @public + */ + @computed('tabOrder', function() { + let tabIndex = null; + if(!get(this, 'isDisabled')) { + tabIndex = (get(this, 'tabOrder') === 0)? '0' : '-1'; + } + return tabIndex; + }) + tabindex; + + /** + * isActive + * + * @field isActive + * @type boolean + * @public + */ + @computed('selected', function() { + return (get(this, 'selected') === get(this, 'name')); + }) + isActive; + + /** + * isDisabled + * + * @field isDisabled + * @type boolean + * @public + */ + @computed('disabled', function() { + return (get(this, 'disabled').toString() === 'true')? true : false; + }) + isDisabled; + + /** + * title + * + * @field title + * @type string + * @public + */ + @computed('name', function() { + return get(this, 'name'); + }) + title; + + /** + * aria-controls + * + * @field aria-controls + * @type string + * @public + */ + @computed('controls', function() { + return get(this, 'controls'); + }) + 'aria-controls'; + + /** + * aria-selected + * + * @field aria-selected + * @type boolean + * @public + */ + @computed('selected', function() { + return (get(this, 'selected') === get(this, 'name')).toString(); + }) + 'aria-selected'; + + /** + * didInsertElement + * + * @method didInsertElement + * @description lifecycle event + * @public + * + */ + didInsertElement() { + get(this, 'registerTabListItem').call(this, { + id: get(this, 'elementId'), + name: get(this, 'name') + }); + } + + /** + * mouseDown + * + * @method mouseDown + * @description event handler : We are negating the style applied on click-focus + * @public + * + */ + mouseDown() { + if(get(this, 'isDisabled') === false) { + set(this, 'isPressed', true); + } + } + + /** + * focusOut + * + * @method focusOut + * @description event handler : Removing style that was applied during press to negate focus + * @public + * + */ + focusOut() { + if(get(this, 'isPressed') === true) { + set(this, 'isPressed', false); + } + } + + /** + * click + * + * @method click + * @description event handler + * @public + * + */ + click(event) { + if(get(this, 'isDisabled') === false) { + get(this, 'handleActivateTab').call(this, get(this, 'name'), event); + } + } + + /** + * keyDown + * + * @method keyDown + * @description event handler + * @public + * + */ + keyDown(event) { + event.stopPropagation(); + const targetElement = event.target; + const firstElement = targetElement.parentElement.firstElementChild; + const lastElement = targetElement.parentElement.lastElementChild; + + const keyCode = TABS_KEY_CODE; + switch (event.keyCode) { + case keyCode.ENTER: + case keyCode.SPACE: + event.preventDefault(); + targetElement.click(); + break; + case keyCode.END: + lastElement.focus(); + break; + case keyCode.HOME: + firstElement.focus(); + break; + case keyCode.LEFT: + get(this, '_changeTabFocus').call(this, 'previous', targetElement); + break; + case keyCode.RIGHT: + get(this, '_changeTabFocus').call(this, 'next', targetElement); + break; + default: + break; + } + } + + /** + * _changeTabFocus + * + * @method _changeTabFocus + * @description Change focus based on direction + * @param {string} direction takes either 'next' or 'previous' + * @param {Object} element + * @param {Object} [elementInFocus] + * @private + * + */ + _changeTabFocus(direction, element, elementInFocus) { + let adjacentElement; + if(direction === 'previous') { + adjacentElement = (element.previousElementSibling)? element.previousElementSibling : element.parentElement.lastElementChild; + } else { + adjacentElement = (element.nextElementSibling)? element.nextElementSibling : element.parentElement.firstElementChild; + } + + if(elementInFocus && (elementInFocus.id === adjacentElement.id)) { + return; + } else if(adjacentElement.getAttribute('tabindex') === null) { + get(this, '_changeTabFocus').call(this, direction, adjacentElement, element); + } else { + adjacentElement.focus(); + } + } +} + +export default TabListItem; diff --git a/packages/tabs/addon/components/nucleus-tabs/tab-panel.js b/packages/tabs/addon/components/nucleus-tabs/tab-panel.js new file mode 100644 index 00000000..9303c6c5 --- /dev/null +++ b/packages/tabs/addon/components/nucleus-tabs/tab-panel.js @@ -0,0 +1,98 @@ +import Component from '@ember/component'; +import { classNames, attributeBindings, classNameBindings, tagName, layout as templateLayout } from '@ember-decorators/component'; +import layout from '../../templates/components/nucleus-tabs/tab-panel'; +import { get, computed } from '@ember/object'; +import defaultProp from '@freshworks/core/utils/default-decorator'; + +/** + __Usage:__ + + [Refer component page](/docs/components/nucleus-tabs) + + @class Nucleus Tab Panel + @namespace Components + @extends Ember.Component + @public +*/ +@tagName('div') +@templateLayout(layout) +@classNames('nucleus-tabs__panel') +@classNameBindings('isActive:is-active') +@attributeBindings('tabindex', 'role', 'aria-labelledby') +class TabPanel extends Component { + + /** + * disabled + * + * @field disabled + * @type string + * @default 'false' + * @readonly + * @public + */ + @defaultProp + disabled = 'false'; + + /** + * tabindex + * + * @field tabindex + * @default '0' + * @type string + * @public + */ + tabindex = '0'; + + /** + * role + * + * @field role + * @type string + * @public + */ + role = 'tabpanel' + + /** + * isActive + * + * @field isActive + * @type boolean + * @public + */ + @computed('selected', function() { + return (get(this, 'selected') === get(this, 'name')); + }) + isActive; + + /** + * aria-labelledby + * + * @field aria-labelledby + * @type string + * @public + */ + @computed('tabListItems.[]', function() { + const tabListItems = get(this, 'tabListItems'); + const tabList = tabListItems.findBy('name', get(this, 'name')); + return (tabList)? tabList.id : ''; + }) + 'aria-labelledby'; + + /** + * didInsertElement + * + * @method didInsertElement + * @description lifecycle event + * @public + * + */ + didInsertElement() { + get(this, 'registerPanel').call(this, { + id: get(this, 'elementId'), + name: get(this, 'name'), + disabled: get(this, 'disabled') + }); + } +} + +export default TabPanel; diff --git a/packages/tabs/addon/constants/nucleus-tabs.js b/packages/tabs/addon/constants/nucleus-tabs.js new file mode 100644 index 00000000..8f8692a1 --- /dev/null +++ b/packages/tabs/addon/constants/nucleus-tabs.js @@ -0,0 +1,10 @@ +const TABS_KEY_CODE = { + ENTER: 13, + SPACE: 32, + END: 35, + HOME: 36, + LEFT: 37, + RIGHT: 39 +}; + +export { TABS_KEY_CODE }; diff --git a/packages/tabs/addon/styles/addon.scss b/packages/tabs/addon/styles/addon.scss new file mode 100644 index 00000000..1cc72022 --- /dev/null +++ b/packages/tabs/addon/styles/addon.scss @@ -0,0 +1,3 @@ +@import "nucleus/variables"; +@import "nucleus/animations"; +@import "./components/nucleus-tabs"; diff --git a/packages/tabs/addon/styles/components/_nucleus-tabs.scss b/packages/tabs/addon/styles/components/_nucleus-tabs.scss new file mode 100644 index 00000000..4387ad74 --- /dev/null +++ b/packages/tabs/addon/styles/components/_nucleus-tabs.scss @@ -0,0 +1,135 @@ +.nucleus-tabs { + + $self: &; + + display: flex; + flex-direction: column; + + &__list { + width: 100%; + overflow: scroll hidden; + + &__container { + display: flex; + flex-wrap: nowrap; + width: 100%; + padding: 0 12px; + border-bottom: 1px solid $color-smoke-50; + } + + &__item { + flex-shrink: 0; + position: relative; + text-align: center; + line-height: 20px; + padding: 10px 8px; + margin: 0 4px; + font-size: 14px; + color: $color-smoke-700; + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + + &::before { + display: block; + content: attr(title); + font-weight: 500; + height: 0; + overflow: hidden; + visibility: hidden; + } + + &::after { + content: ''; + position: absolute; + left: 0; + bottom: -1px; + width: 100%; + box-sizing: border-box; + } + + &:hover { + outline: none; + border: 0; + box-shadow: none; + cursor: pointer; + + &::after { + border-bottom: 2px solid $color-smoke-100; + } + } + + &:focus { + outline: none; + border: 0; + box-shadow: none; + + &::after { + height: calc(100% + 1px); + border: 2px solid $color-azure-800; + border-radius: 4px; + } + } + + &.is-pressed { + &::after { + border: 0; + border-radius: 0; + border-bottom: 0; + } + + &:hover::after { + border-bottom: 2px solid $color-smoke-100; + } + + &.is-active::after { + border-bottom: 2px solid $color-azure-800; + } + } + + &.is-active { + color: $color-azure-800; + font-weight: 500; + + &::after { + border-bottom: 2px solid $color-azure-800; + } + } + + &.is-disabled { + color: $color-smoke-300; + + &:hover { + cursor: default; + + &::after { + display: none; + } + } + } + } + } + + &__panel { + width: 100%; + display: none; + padding: 8px 20px; + + &.is-active { + display: block; + } + } + + &--background { + #{ $self }__list { + background: $color-smoke-25; + border: 1px solid $color-smoke-50; + border-radius: 4px; + } + } +} diff --git a/packages/tabs/addon/templates/components/nucleus-tabs.hbs b/packages/tabs/addon/templates/components/nucleus-tabs.hbs new file mode 100644 index 00000000..e0ba1844 --- /dev/null +++ b/packages/tabs/addon/templates/components/nucleus-tabs.hbs @@ -0,0 +1,20 @@ +
+
+ {{#each tabPanels key="id" as |tab index|}} + {{#nucleus-tabs/tab-list-item + registerTabListItem=(action registerTabListItem) + name=tab.name + disabled=tab.disabled + controls=tab.id + tabOrder=index + selected=selected + handleActivateTab=(action activateTab)}} + {{tab.name}} + {{/nucleus-tabs/tab-list-item}} + {{/each}} +
+
+ +{{yield (hash + panel=(component "nucleus-tabs/tab-panel" registerPanel=(action "registerPanel") selected=selected tabListItems=tabListItems) +)}} diff --git a/packages/tabs/addon/templates/components/nucleus-tabs/tab-list-item.hbs b/packages/tabs/addon/templates/components/nucleus-tabs/tab-list-item.hbs new file mode 100644 index 00000000..889d9eea --- /dev/null +++ b/packages/tabs/addon/templates/components/nucleus-tabs/tab-list-item.hbs @@ -0,0 +1 @@ +{{yield}} diff --git a/packages/tabs/addon/templates/components/nucleus-tabs/tab-panel.hbs b/packages/tabs/addon/templates/components/nucleus-tabs/tab-panel.hbs new file mode 100644 index 00000000..889d9eea --- /dev/null +++ b/packages/tabs/addon/templates/components/nucleus-tabs/tab-panel.hbs @@ -0,0 +1 @@ +{{yield}} diff --git a/packages/tabs/app/.gitkeep b/packages/tabs/app/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/app/components/nucleus-tabs.js b/packages/tabs/app/components/nucleus-tabs.js new file mode 100644 index 00000000..f51454bb --- /dev/null +++ b/packages/tabs/app/components/nucleus-tabs.js @@ -0,0 +1 @@ +export { default } from '@freshworks/tabs/components/nucleus-tabs'; diff --git a/packages/tabs/app/components/nucleus-tabs/tab-list-item.js b/packages/tabs/app/components/nucleus-tabs/tab-list-item.js new file mode 100644 index 00000000..87c6a9c1 --- /dev/null +++ b/packages/tabs/app/components/nucleus-tabs/tab-list-item.js @@ -0,0 +1 @@ +export { default } from '@freshworks/tabs/components/nucleus-tabs/tab-list-item'; diff --git a/packages/tabs/app/components/nucleus-tabs/tab-panel.js b/packages/tabs/app/components/nucleus-tabs/tab-panel.js new file mode 100644 index 00000000..8279bd3a --- /dev/null +++ b/packages/tabs/app/components/nucleus-tabs/tab-panel.js @@ -0,0 +1 @@ +export { default } from '@freshworks/tabs/components/nucleus-tabs/tab-panel'; diff --git a/packages/tabs/app/styles/app.scss b/packages/tabs/app/styles/app.scss new file mode 100644 index 00000000..f281a636 --- /dev/null +++ b/packages/tabs/app/styles/app.scss @@ -0,0 +1,3 @@ +// Dummy file + +// Ember cli 3.4 expects styles/app.scss file to be found inside app folder. diff --git a/packages/tabs/config/deploy.js b/packages/tabs/config/deploy.js new file mode 100644 index 00000000..b5581aed --- /dev/null +++ b/packages/tabs/config/deploy.js @@ -0,0 +1,29 @@ +/* eslint-env node */ +'use strict'; + +module.exports = function(deployTarget) { + let ENV = { + build: {} + // include other plugin configuration that applies to all deploy targets here + }; + + if (deployTarget === 'development') { + ENV.build.environment = 'development'; + // configure other plugins for development deploy target here + } + + if (deployTarget === 'staging') { + ENV.build.environment = 'production'; + // configure other plugins for staging deploy target here + } + + if (deployTarget === 'production') { + ENV.build.environment = 'production'; + // configure other plugins for production deploy target here + } + + // Note: if you need to build some configuration asynchronously, you can return + // a promise that resolves with the ENV object instead of returning the + // ENV object synchronously. + return ENV; +}; diff --git a/packages/tabs/config/environment.js b/packages/tabs/config/environment.js new file mode 100644 index 00000000..defadf30 --- /dev/null +++ b/packages/tabs/config/environment.js @@ -0,0 +1,60 @@ +'use strict'; + +/* eslint-env node */ +module.exports = function(environment) { + let ENV = { + modulePrefix: 'nucleus', + environment, + rootURL: '/', + locationType: 'auto', + EmberENV: { + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true + }, + EXTEND_PROTOTYPES: { + // Prevent Ember Data from overriding Date.parse. + Date: false + } + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + } + }; + + ENV['ember-a11y-testing'] = { + componentOptions: { + turnAuditOff: true, // Change to true to disable the audit in development + visualNoiseLevel: 2, + axeViolationClassNames: ['alert-box', 'alert-box--a11y'] + } + } + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + // ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + // ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + // Testem prefers this... + ENV.locationType = 'none'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; + ENV.APP.autoboot = false; + } + + if (environment === 'production') { + // here you can enable a production-specific feature + } + + return ENV; +}; diff --git a/packages/tabs/ember-backstop/backstop.js b/packages/tabs/ember-backstop/backstop.js new file mode 100644 index 00000000..09bad864 --- /dev/null +++ b/packages/tabs/ember-backstop/backstop.js @@ -0,0 +1,37 @@ +/* eslint-env node */ +module.exports = { + id: `ember-backstop test`, + viewports: [ + { + label: 'webview', + width: 1440, + height: 900, + }, + ], + onBeforeScript: `puppet/onBefore.js`, + onReadyScript: `puppet/onReady.js`, + scenarios: [ + { + label: '{testName}', + cookiePath: 'backstop_data/engine_scripts/cookies.json', + url: '{origin}/backstop/dview/{testId}/{scenarioId}', + delay: 500, + }, + ], + paths: { + bitmaps_reference: 'backstop_data/bitmaps_reference', + bitmaps_test: 'backstop_data/bitmaps_test', + engine_scripts: 'backstop_data/engine_scripts', + html_report: 'backstop_data/html_report', + ci_report: 'backstop_data/ci_report', + }, + report: [], + engine: 'puppet', + engineOptions: { + args: ['--no-sandbox'], + }, + asyncCaptureLimit: 10, + asyncCompareLimit: 50, + debug: false, + debugWindow: false, +}; diff --git a/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_background_style_tabs__assert0_0_document_0_webview.png b/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_background_style_tabs__assert0_0_document_0_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..578e1a07d2d577156e0116da201ca640b4a1100e GIT binary patch literal 11331 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 literal 0 HcmV?d00001 diff --git a/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_border_style_tabs__assert0_0_document_0_webview.png b/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_border_style_tabs__assert0_0_document_0_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..eeb77a3a63b4d6adedd30dfe928e3a25f5c79e38 GIT binary patch literal 11339 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 AC;$Ke literal 0 HcmV?d00001 diff --git a/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_default_style_tabs__assert0_0_document_0_webview.png b/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_default_style_tabs__assert0_0_document_0_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..aff3e31d8abc05f3d26bad5e3a97c0ce5f530b53 GIT binary patch literal 11240 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 Si=RS;L0ojYQ1kWmpZ*0uC}0Hu literal 0 HcmV?d00001 diff --git a/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_disabled_tabs__assert0_0_document_0_webview.png b/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_disabled_tabs__assert0_0_document_0_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..5a7f6d94f43b87f19b053835fdff413a33e00a84 GIT binary patch literal 12117 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 AfB*mh literal 0 HcmV?d00001 diff --git a/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_the_different_variants_-_default_background_disabled__assert0_0_document_0_webview.png b/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_the_different_variants_-_default_background_disabled__assert0_0_document_0_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..4285e2d4141fc7f5a992f8bb6d620338bce75780 GIT binary patch literal 26366 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 literal 0 HcmV?d00001 diff --git a/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_the_different_variants__assert0_0_document_0_webview.png b/packages/tabs/ember-backstop/backstop_data/bitmaps_reference/ember-backstoptest_Integration__Component__nucleus-tabs__visual_regression_for_the_different_variants__assert0_0_document_0_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..e74c112145fb8bec22edfd5c0b26e6ee36f98f6e GIT binary patch literal 26409 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 Nip!pTclzp`{|i7~ { + const hoverSelector = scenario.hoverSelectors || scenario.hoverSelector; + const clickSelector = scenario.clickSelectors || scenario.clickSelector; + const keyPressSelector = scenario.keyPressSelectors || scenario.keyPressSelector; + const scrollToSelector = scenario.scrollToSelector; + const postInteractionWait = scenario.postInteractionWait; // selector [str] | ms [int] + + if (keyPressSelector) { + for (const keyPressSelectorItem of [].concat(keyPressSelector)) { + await page.waitFor(keyPressSelectorItem.selector); + await page.type(keyPressSelectorItem.selector, keyPressSelectorItem.keyPress); + } + } + + if (hoverSelector) { + for (const hoverSelectorIndex of [].concat(hoverSelector)) { + await page.waitFor(hoverSelectorIndex); + await page.hover(hoverSelectorIndex); + } + } + + if (clickSelector) { + for (const clickSelectorIndex of [].concat(clickSelector)) { + await page.waitFor(clickSelectorIndex); + await page.click(clickSelectorIndex); + } + } + + if (postInteractionWait) { + await page.waitFor(postInteractionWait); + } + + if (scrollToSelector) { + await page.waitFor(scrollToSelector); + await page.evaluate(scrollToSelector => { + document.querySelector(scrollToSelector).scrollIntoView(); + }, scrollToSelector); + } +}; diff --git a/packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/onReady.js b/packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/onReady.js new file mode 100644 index 00000000..94c95fe8 --- /dev/null +++ b/packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/onReady.js @@ -0,0 +1,11 @@ +/* eslint-env browser, node */ + +const debug = require('debug')('BackstopJS'); + +module.exports = async (page, scenario) => { + debug('SCENARIO > ' + scenario.label); + await require('./overrideCSS')(page, scenario); + await require('./clickAndHoverHelper')(page, scenario); + + // add more ready handlers here... +}; diff --git a/packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/overrideCSS.js b/packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/overrideCSS.js new file mode 100644 index 00000000..29cd0e20 --- /dev/null +++ b/packages/tabs/ember-backstop/backstop_data/engine_scripts/puppet/overrideCSS.js @@ -0,0 +1,13 @@ +/* eslint-env browser, node */ + +module.exports = function(page) { + // inject arbitrary css to override styles + page.evaluate(() => { + const BACKSTOP_TEST_CSS_OVERRIDE = `#ember-testing {width: 100% !important; height: 100% !important; -webkit-transform: scale(1) !important; transform: scale(1) !important;}`; + let style = document.createElement('style'); + style.type = 'text/css'; + let styleNode = document.createTextNode(BACKSTOP_TEST_CSS_OVERRIDE); + style.appendChild(styleNode); + document.head.appendChild(style); + }); +}; diff --git a/packages/tabs/ember-cli-build.js b/packages/tabs/ember-cli-build.js new file mode 100644 index 00000000..b908d9d4 --- /dev/null +++ b/packages/tabs/ember-cli-build.js @@ -0,0 +1,14 @@ +'use strict'; + +// eslint-disable-next-line node/no-unpublished-require +const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); + +module.exports = function(defaults) { + let app = new EmberAddon(defaults, + { + hinting: false + } + ); + + return app.toTree(); +}; diff --git a/packages/tabs/index.js b/packages/tabs/index.js new file mode 100644 index 00000000..5b337fac --- /dev/null +++ b/packages/tabs/index.js @@ -0,0 +1,34 @@ +/* eslint-env node */ +'use strict'; +// eslint-disable-next-line node/no-unpublished-require +const mergeTrees = require('broccoli-merge-trees'); +// eslint-disable-next-line node/no-unpublished-require +const Funnel = require('broccoli-funnel'); +const path = require('path'); + +module.exports = { + name: '@freshworks/tabs', + + isDevelopingAddon() { + return true; + }, + + included(app, parentAddon) { + let target = (parentAddon || app); + target.options = target.options || {}; + target.options.babel = target.options.babel || { includePolyfill: true }; + return this._super.included.apply(this, arguments); + }, + + treeForAddonStyles(tree) { + let coreStyleTree = new Funnel(this.getCoreStylesPath(), { + destDir: 'nucleus' + }); + return mergeTrees([coreStyleTree, tree]); + }, + + getCoreStylesPath() { + let pkgPath = path.dirname(require.resolve(`@freshworks/core/package.json`)); + return path.join(pkgPath, 'app/styles'); + } +}; diff --git a/packages/tabs/package.json b/packages/tabs/package.json new file mode 100644 index 00000000..456afef5 --- /dev/null +++ b/packages/tabs/package.json @@ -0,0 +1,82 @@ +{ + "name": "@freshworks/tabs", + "version": "0.1.0", + "description": "tabs component in Nucleus", + "keywords": [ + "ember-addon" + ], + "repository": "https://github.com/freshdesk/nucleus", + "license": "MIT", + "author": "", + "directories": { + "doc": "doc", + "test": "tests" + }, + "scripts": { + "build": "ember build", + "start": "ember serve -p 4003", + "deploy": "ember deploy production", + "test": "ember backstop-remote & COVERAGE=TRUE ember test --test-port=1509", + "posttest": "ember backstop-stop", + "test:dev": "COVERAGE=TRUE ember test --server -launch=false" + }, + "dependencies": { + "@freshworks/core": "^0.1.9", + "@freshworks/icon": "^0.5.0", + "ember-cli-babel": "^7.11.1", + "ember-cli-htmlbars": "^4.0.0", + "ember-cli-sass": "^10.0.0", + "ember-css-transitions": "^0.1.16", + "ember-decorators": "^6.1.1", + "ember-decorators-polyfill": "shibulijack-fd/ember-decorators-polyfill#master", + "ember-truth-helpers": "^2.1.0" + }, + "devDependencies": { + "@ember/optional-features": "^1.0.0", + "broccoli-asset-rev": "^3.0.0", + "broccoli-funnel": "^2.0.2", + "broccoli-merge-trees": "^3.0.2", + "ember-a11y-testing": "^1.0.0", + "ember-backstop": "^1.3.4", + "ember-cli": "~3.13.1", + "ember-cli-autoprefixer": "^0.8.1", + "ember-cli-code-coverage": "^1.0.0-beta.8", + "ember-cli-dependency-checker": "^3.1.0", + "ember-cli-deploy": "^1.0.2", + "ember-cli-deploy-build": "^1.1.1", + "ember-cli-deploy-git": "^1.3.3", + "ember-cli-deploy-git-ci": "^1.0.1", + "ember-cli-flash": "^1.7.2", + "ember-cli-inject-live-reload": "^2.0.1", + "ember-cli-sri": "^2.1.1", + "ember-cli-uglify": "^3.0.0", + "ember-disable-prototype-extensions": "^1.1.3", + "ember-export-application-global": "^2.0.0", + "ember-load-initializers": "^2.1.0", + "ember-maybe-import-regenerator": "^0.1.6", + "ember-qunit": "^4.5.1", + "ember-resolver": "^5.3.0", + "ember-sinon": "^4.0.0", + "ember-sinon-qunit": "^3.4.0", + "ember-source": "~3.13.0", + "ember-test-selectors": "^2.1.0", + "loader.js": "^4.7.0", + "qunit-dom": "^0.9.0", + "sass": "^1.23.0" + }, + "engines": { + "node": "8.* || >= 10.*" + }, + "ember-addon": { + "configPath": "tests/dummy/config", + "before": [ + "ember-cli-htmlbars", + "ember-svg-jar" + ] + }, + "publishConfig": { + "access": "public" + }, + "homepage": "https://freshdesk.github.io/nucleus", + "gitHead": "272f136386ba4d45348c6498f55a1dabe873d1fc" +} diff --git a/packages/tabs/testem.js b/packages/tabs/testem.js new file mode 100644 index 00000000..e23f1188 --- /dev/null +++ b/packages/tabs/testem.js @@ -0,0 +1,30 @@ +module.exports = { + test_page: 'tests/index.html?hidepassed', + disable_watching: true, + launch_in_ci: [ + 'Chrome' + ], + launch_in_dev: [ + 'Chrome' + ], + browser_args: { + Chrome: { + ci: [ + // --no-sandbox is needed when running Chrome inside a container + process.env.CI ? '--no-sandbox' : null, + '--headless', + '--disable-dev-shm-usage', + '--disable-software-rasterizer', + '--mute-audio', + '--remote-debugging-port=0', + '--window-size=1440,900' + ].filter(Boolean) + } + }, + proxies: { + '/backstop': { + target: 'http://localhost:1509', + secure: false + } + } +} diff --git a/packages/tabs/tests/.eslintrc.js b/packages/tabs/tests/.eslintrc.js new file mode 100644 index 00000000..fbf25552 --- /dev/null +++ b/packages/tabs/tests/.eslintrc.js @@ -0,0 +1,5 @@ +module.exports = { + env: { + embertest: true + } +}; diff --git a/packages/tabs/tests/dummy/app/app.js b/packages/tabs/tests/dummy/app/app.js new file mode 100644 index 00000000..b3b2bd67 --- /dev/null +++ b/packages/tabs/tests/dummy/app/app.js @@ -0,0 +1,14 @@ +import Application from '@ember/application'; +import Resolver from './resolver'; +import loadInitializers from 'ember-load-initializers'; +import config from './config/environment'; + +const App = Application.extend({ + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, + Resolver +}); + +loadInitializers(App, config.modulePrefix); + +export default App; diff --git a/packages/tabs/tests/dummy/app/components/.gitkeep b/packages/tabs/tests/dummy/app/components/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/tests/dummy/app/controllers/.gitkeep b/packages/tabs/tests/dummy/app/controllers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/tests/dummy/app/helpers/.gitkeep b/packages/tabs/tests/dummy/app/helpers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/tests/dummy/app/index.html b/packages/tabs/tests/dummy/app/index.html new file mode 100644 index 00000000..1f84141c --- /dev/null +++ b/packages/tabs/tests/dummy/app/index.html @@ -0,0 +1,25 @@ + + + + + + Nucleus - The Freshworks Design System + + + + {{content-for "head"}} + + + + + {{content-for "head-footer"}} + + + {{content-for "body"}} + + + + + {{content-for "body-footer"}} + + diff --git a/packages/tabs/tests/dummy/app/models/.gitkeep b/packages/tabs/tests/dummy/app/models/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/tests/dummy/app/resolver.js b/packages/tabs/tests/dummy/app/resolver.js new file mode 100644 index 00000000..2fb563d6 --- /dev/null +++ b/packages/tabs/tests/dummy/app/resolver.js @@ -0,0 +1,3 @@ +import Resolver from 'ember-resolver'; + +export default Resolver; diff --git a/packages/tabs/tests/dummy/app/router.js b/packages/tabs/tests/dummy/app/router.js new file mode 100644 index 00000000..1202e6cf --- /dev/null +++ b/packages/tabs/tests/dummy/app/router.js @@ -0,0 +1,12 @@ +import EmberRouter from '@ember/routing/router'; +import config from './config/environment'; + +const Router = EmberRouter.extend({ + location: config.locationType, + rootURL: config.rootURL +}); + +Router.map(function() { +}); + +export default Router; \ No newline at end of file diff --git a/packages/tabs/tests/dummy/app/routes/.gitkeep b/packages/tabs/tests/dummy/app/routes/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/tests/dummy/app/styles/app.scss b/packages/tabs/tests/dummy/app/styles/app.scss new file mode 100644 index 00000000..f281a636 --- /dev/null +++ b/packages/tabs/tests/dummy/app/styles/app.scss @@ -0,0 +1,3 @@ +// Dummy file + +// Ember cli 3.4 expects styles/app.scss file to be found inside app folder. diff --git a/packages/tabs/tests/dummy/config/environment.js b/packages/tabs/tests/dummy/config/environment.js new file mode 100644 index 00000000..3dda71a8 --- /dev/null +++ b/packages/tabs/tests/dummy/config/environment.js @@ -0,0 +1,54 @@ +'use strict'; + +/* eslint-env node */ +module.exports = function(environment) { + let ENV = { + modulePrefix: 'dummy', + environment, + rootURL: '/', + locationType: 'auto', + EmberENV: { + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true + }, + EXTEND_PROTOTYPES: { + // Prevent Ember Data from overriding Date.parse. + Date: false + } + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + } + }; + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + // ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + // ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + // Testem prefers this... + ENV.locationType = 'none'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; + ENV.APP.autoboot = false; + } + + if (environment === 'production') { + // Allow ember-cli-addon-docs to update the rootURL in compiled assets + ENV.rootURL = 'ADDON_DOCS_ROOT_URL'; + // here you can enable a production-specific feature + } + + return ENV; +}; diff --git a/packages/tabs/tests/dummy/config/optional-features.json b/packages/tabs/tests/dummy/config/optional-features.json new file mode 100644 index 00000000..b1902623 --- /dev/null +++ b/packages/tabs/tests/dummy/config/optional-features.json @@ -0,0 +1,3 @@ +{ + "jquery-integration": false +} diff --git a/packages/tabs/tests/dummy/config/targets.js b/packages/tabs/tests/dummy/config/targets.js new file mode 100644 index 00000000..ebacf95b --- /dev/null +++ b/packages/tabs/tests/dummy/config/targets.js @@ -0,0 +1,19 @@ +'use strict'; + +/* eslint-env node */ +const browsers = [ + 'last 1 Chrome versions', + 'last 1 Firefox versions', + 'last 1 Safari versions' +]; + +const isCI = !!process.env.CI; +const isProduction = process.env.EMBER_ENV === 'production'; + +if (isCI || isProduction) { + browsers.push('ie 11'); +} + +module.exports = { + browsers +}; diff --git a/packages/tabs/tests/dummy/public/robots.txt b/packages/tabs/tests/dummy/public/robots.txt new file mode 100644 index 00000000..f5916452 --- /dev/null +++ b/packages/tabs/tests/dummy/public/robots.txt @@ -0,0 +1,3 @@ +# http://www.robotstxt.org +User-agent: * +Disallow: diff --git a/packages/tabs/tests/helpers/.gitkeep b/packages/tabs/tests/helpers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/tests/index.html b/packages/tabs/tests/index.html new file mode 100644 index 00000000..5209b852 --- /dev/null +++ b/packages/tabs/tests/index.html @@ -0,0 +1,33 @@ + + + + + + Dummy Tests + + + + {{content-for "head"}} + {{content-for "test-head"}} + + + + + + {{content-for "head-footer"}} + {{content-for "test-head-footer"}} + + + {{content-for "body"}} + {{content-for "test-body"}} + + + + + + + + {{content-for "body-footer"}} + {{content-for "test-body-footer"}} + + diff --git a/packages/tabs/tests/integration/.gitkeep b/packages/tabs/tests/integration/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/tabs/tests/integration/components/nucleus-tabs-test.js b/packages/tabs/tests/integration/components/nucleus-tabs-test.js new file mode 100644 index 00000000..69918558 --- /dev/null +++ b/packages/tabs/tests/integration/components/nucleus-tabs-test.js @@ -0,0 +1,204 @@ +import { module } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import test from 'ember-sinon-qunit/test-support/test'; +import a11yAudit from 'ember-a11y-testing/test-support/audit'; +import { render, click } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import backstop from 'ember-backstop/test-support/backstop'; + +let sampleTabsTemplate = hbs` + {{#nucleus-tabs description="site-navigation" select="home" variant="background" as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{#tabs.panel name="about" }} +
This is about us section
+ {{/tabs.panel}} + {{#tabs.panel name="contact" }} +
This is the contact section
+ {{/tabs.panel}} + {{/nucleus-tabs}} +`; + +module('Integration | Component | nucleus-tabs', function(hooks) { + setupRenderingTest(hooks); + + hooks.beforeEach(function() { + this.actions = {}; + this.send = (actionName, ...args) => this.actions[actionName].apply(this, args); + }); + + test('it should yield tab-list items and tab-panels', async function(assert) { + await render(sampleTabsTemplate); + assert.dom('.nucleus-tabs').exists({ count: 1 }, 'Tabs component exists.'); + assert.dom('.nucleus-tabs .nucleus-tabs__list').exists({ count: 1 }, 'Tabs component has a Tab list'); + assert.dom('.nucleus-tabs .nucleus-tabs__list__item').exists({ count: 3 }, 'Tabs component has 3 Tab list items'); + assert.dom('.nucleus-tabs .nucleus-tabs__panel').exists({ count: 3 }, 'Tabs component has right number of Tab panels'); + }); + + test('it should have only selected panel as active', async function(assert) { + await render(sampleTabsTemplate); + assert.dom('.nucleus-tabs .nucleus-tabs__panel.is-active').exists({ count: 1 }, 'Only one active panel at a time'); + assert.dom('.nucleus-tabs .nucleus-tabs__panel.is-active').hasText('This is the home section'); + }); + + test('it should have only selected tab list item as active', async function(assert) { + await render(sampleTabsTemplate); + assert.dom('.nucleus-tabs .nucleus-tabs__list__item.is-active').exists({ count: 1 }, 'Only one active panel at a time'); + assert.dom('.nucleus-tabs .nucleus-tabs__list__item.is-active').hasText('home'); + }); + + test('it should attach appropriate background class for the background variant', async function(assert) { + await render(sampleTabsTemplate); + assert.dom('.nucleus-tabs.nucleus-tabs--background').exists({ count: 1 }, 'Has one appropriate class when passing variant as prop'); + }); + + test('it should attach appropriate line class for the line variant', async function(assert) { + await render(hbs` + {{#nucleus-tabs description="site-navigation" select="home" as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + `); + assert.dom('.nucleus-tabs.nucleus-tabs--line').exists({ count: 1 }, 'Has line class when no variant passed as prop'); + }); + + test('it should attach disable class to disabled tab list item', async function(assert) { + await render(hbs` + {{#nucleus-tabs description="site-navigation" select="home" as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{#tabs.panel name="about" disabled="true" }} +
This is the home section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + `); + assert.dom('.nucleus-tabs .nucleus-tabs__list__item.is-disabled').exists({ count: 1 }, 'Has disabled class when disabled prop is passed'); + }); + + test('it should not enable tab when tab list item is disabled', async function(assert) { + await render(hbs` + {{#nucleus-tabs description="site-navigation" select="home" as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{#tabs.panel name="about" disabled="true" }} +
This is the home section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + `); + await click('.nucleus-tabs .nucleus-tabs__list__item:not(.is-active)'); + assert.dom('.nucleus-tabs .nucleus-tabs__list__item.is-active').hasText('home'); + }); + + test('it should yeilds onChange action', async function(assert) { + let onChangeAction = this.spy(); + this.actions.onChange = onChangeAction; + await render(hbs` + {{#nucleus-tabs description="site-navigation" select="home" onChange=(action "onChange") as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{#tabs.panel name="about" }} +
This is the about section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + `); + + await click('.nucleus-tabs .nucleus-tabs__list__item:not(.is-active)'); + assert.ok(onChangeAction.calledOnce, 'onChange action has been called.'); + }); + + test('it should yeilds beforeChange action', async function(assert) { + let beforeChangeAction = this.spy(); + this.actions.beforeChange = beforeChangeAction; + await render(hbs` + {{#nucleus-tabs description="site-navigation" select="home" beforeChange=(action "beforeChange") as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{#tabs.panel name="about" }} +
This is the about section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + `); + + await click('.nucleus-tabs .nucleus-tabs__list__item:not(.is-active)'); + assert.ok(beforeChangeAction.calledOnce, 'beforeChange action has been called.'); + }); + + test('it should call beforeChange action ahead of onChange action', async function(assert) { + let beforeChangeAction = this.spy(function() { + assert.step('beforeChange'); + }); + this.actions.beforeChange = beforeChangeAction; + let onChangeAction = this.spy(function() { + assert.step('onChange'); + }); + this.actions.onChange = onChangeAction; + await render(hbs` + {{#nucleus-tabs description="site-navigation" select="home" beforeChange=(action "beforeChange") onChange=(action "onChange") as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{#tabs.panel name="about" }} +
This is the about section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + `); + + await click('.nucleus-tabs .nucleus-tabs__list__item:not(.is-active)'); + assert.ok(beforeChangeAction.calledOnce, 'beforeChange action has been called.'); + assert.ok(onChangeAction.calledOnce, 'beforeChange action has been called.'); + assert.verifySteps(['beforeChange', 'onChange']); + }); + + test('it has accessibility attributes', async function(assert) { + await render(sampleTabsTemplate); + assert.dom('.nucleus-tabs .nucleus-tabs__list').hasAttribute('role', 'tablist'); + assert.dom('.nucleus-tabs .nucleus-tabs__list').hasAttribute('aria-label', 'site-navigation'); + assert.dom('.nucleus-tabs .nucleus-tabs__list .nucleus-tabs__list__item').hasAttribute('role', 'tab'); + assert.dom('.nucleus-tabs .nucleus-tabs__list .nucleus-tabs__list__item.is-active').hasAttribute('aria-selected', 'true'); + assert.dom('.nucleus-tabs .nucleus-tabs__list .nucleus-tabs__list__item:not(.is-active)').hasAttribute('aria-selected', 'false'); + assert.dom('.nucleus-tabs .nucleus-tabs__list .nucleus-tabs__list__item').hasAttribute('aria-controls'); + assert.dom('.nucleus-tabs .nucleus-tabs__panel').hasAttribute('role', 'tabpanel'); + assert.dom('.nucleus-tabs .nucleus-tabs__panel').hasAttribute('aria-labelledby'); + }); + + test('it passes a11y tests', async function(assert) { + await render(sampleTabsTemplate); + + return a11yAudit(this.element).then(() => { + assert.ok(true, 'no a11y errors found!'); + }); + }); + + test('visual regression for the different variants - default, background, disabled', async function(assert) { + await render(hbs` +
Default:
+ {{#nucleus-tabs description="site-navigation" select="home" as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{/nucleus-tabs}} +
With background:
+ {{#nucleus-tabs description="site-navigation" variant="background" select="home" as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{/nucleus-tabs}} +
With disabled:
+ {{#nucleus-tabs description="site-navigation" variant="background" select="home" as |tabs|}} + {{#tabs.panel name="home" }} +
This is the home section
+ {{/tabs.panel}} + {{#tabs.panel name="about" disabled="true" }} +
This is the home section
+ {{/tabs.panel}} + {{/nucleus-tabs}} + `); + await backstop(assert, {scenario:{misMatchThreshold: 0.001}}); + }); +}); diff --git a/packages/tabs/tests/test-helper.js b/packages/tabs/tests/test-helper.js new file mode 100644 index 00000000..0382a848 --- /dev/null +++ b/packages/tabs/tests/test-helper.js @@ -0,0 +1,8 @@ +import Application from '../app'; +import config from '../config/environment'; +import { setApplication } from '@ember/test-helpers'; +import { start } from 'ember-qunit'; + +setApplication(Application.create(config.APP)); + +start(); diff --git a/packages/tabs/tests/unit/.gitkeep b/packages/tabs/tests/unit/.gitkeep new file mode 100644 index 00000000..e69de29b