diff --git a/core/package.json b/core/package.json index 3afefe7cdb..d1dc6a2490 100644 --- a/core/package.json +++ b/core/package.json @@ -30,7 +30,7 @@ "loader/" ], "dependencies": { - "ionicons": "4.5.5" + "ionicons": "4.5.6" }, "devDependencies": { "@stencil/core": "0.17.3-0", diff --git a/core/src/components/action-sheet/action-sheet.tsx b/core/src/components/action-sheet/action-sheet.tsx index 0353ba39d7..bb90ea59c4 100644 --- a/core/src/components/action-sheet/action-sheet.tsx +++ b/core/src/components/action-sheet/action-sheet.tsx @@ -196,6 +196,8 @@ export class ActionSheet implements ComponentInterface, OverlayInterface { zIndex: 20000 + this.overlayIndex, }, class: { + [`${this.mode}`]: true, + ...getClassMap(this.cssClass), 'action-sheet-translucent': this.translucent } diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx index 75a54ea8ce..d3d0937f02 100644 --- a/core/src/components/alert/alert.tsx +++ b/core/src/components/alert/alert.tsx @@ -392,6 +392,7 @@ export class Alert implements ComponentInterface, OverlayInterface { }, class: { ...getClassMap(this.cssClass), + [`${this.mode}`]: true, 'alert-translucent': this.translucent } }; diff --git a/core/src/components/anchor/anchor.tsx b/core/src/components/anchor/anchor.tsx index 8bc8f149e6..83a4833114 100644 --- a/core/src/components/anchor/anchor.tsx +++ b/core/src/components/anchor/anchor.tsx @@ -1,6 +1,6 @@ import { Component, ComponentInterface, Listen, Prop } from '@stencil/core'; -import { Color, RouterDirection } from '../../interface'; +import { Color, Mode, RouterDirection } from '../../interface'; import { createColorClasses, openURL } from '../../utils/theme'; @Component({ @@ -9,6 +9,7 @@ import { createColorClasses, openURL } from '../../utils/theme'; shadow: true }) export class Anchor implements ComponentInterface { + mode!: Mode; @Prop({ context: 'window' }) win!: Window; @@ -40,6 +41,7 @@ export class Anchor implements ComponentInterface { return { class: { ...createColorClasses(this.color), + [`${this.mode}`]: true, 'ion-activatable': true } }; diff --git a/core/src/components/app/app.tsx b/core/src/components/app/app.tsx index 22f18660fa..e9f45ea54c 100644 --- a/core/src/components/app/app.tsx +++ b/core/src/components/app/app.tsx @@ -1,6 +1,6 @@ import { Component, ComponentInterface, Element, Prop, QueueApi } from '@stencil/core'; -import { Config } from '../../interface'; +import { Config, Mode } from '../../interface'; import { rIC } from '../../utils/helpers'; import { isPlatform } from '../../utils/platform'; @@ -9,6 +9,7 @@ import { isPlatform } from '../../utils/platform'; styleUrl: 'app.scss' }) export class App implements ComponentInterface { + mode!: Mode; @Element() el!: HTMLElement; @@ -34,6 +35,7 @@ export class App implements ComponentInterface { hostData() { return { class: { + [`${this.mode}`]: true, 'ion-page': true, 'force-statusbar-padding': this.config.getBoolean('_forceStatusbarPadding') } diff --git a/core/src/components/avatar/avatar.tsx b/core/src/components/avatar/avatar.tsx index eef8f5913b..11afa2ee77 100644 --- a/core/src/components/avatar/avatar.tsx +++ b/core/src/components/avatar/avatar.tsx @@ -1,5 +1,7 @@ import { Component, ComponentInterface } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-avatar', styleUrls: { @@ -9,6 +11,15 @@ import { Component, ComponentInterface } from '@stencil/core'; shadow: true }) export class Avatar implements ComponentInterface { + mode!: Mode; + + hostData() { + return { + class: { + [`${this.mode}`]: true, + } + }; + } render() { return ; diff --git a/core/src/components/back-button/back-button.tsx b/core/src/components/back-button/back-button.tsx index 5f55176344..811e46055c 100644 --- a/core/src/components/back-button/back-button.tsx +++ b/core/src/components/back-button/back-button.tsx @@ -62,6 +62,7 @@ export class BackButton implements ComponentInterface { return { class: { ...createColorClasses(this.color), + [`${this.mode}`]: true, 'button': true, // ion-buttons target .button 'ion-activatable': true, diff --git a/core/src/components/backdrop/backdrop.tsx b/core/src/components/backdrop/backdrop.tsx index bb2426155a..0e58abb40c 100644 --- a/core/src/components/backdrop/backdrop.tsx +++ b/core/src/components/backdrop/backdrop.tsx @@ -1,5 +1,6 @@ import { Component, ComponentInterface, Event, EventEmitter, Listen, Prop } from '@stencil/core'; +import { Mode } from '../../interface'; import { GESTURE_CONTROLLER } from '../../utils/gesture'; import { now } from '../../utils/helpers'; @@ -12,6 +13,7 @@ import { now } from '../../utils/helpers'; shadow: true }) export class Backdrop implements ComponentInterface { + mode!: Mode; private lastClick = -10000; private blocker = GESTURE_CONTROLLER.createBlocker({ @@ -78,6 +80,7 @@ export class Backdrop implements ComponentInterface { return { tabindex: '-1', class: { + [`${this.mode}`]: true, 'backdrop-hide': !this.visible, 'backdrop-no-tappable': !this.tappable, } diff --git a/core/src/components/badge/badge.tsx b/core/src/components/badge/badge.tsx index 4e3fc8d5d4..8bcaa2d7e8 100644 --- a/core/src/components/badge/badge.tsx +++ b/core/src/components/badge/badge.tsx @@ -26,7 +26,10 @@ export class Badge implements ComponentInterface { hostData() { return { - class: createColorClasses(this.color) + class: { + ...createColorClasses(this.color), + [`${this.mode}`]: true + } }; } diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx index b4eed33c31..5618293b9f 100644 --- a/core/src/components/button/button.tsx +++ b/core/src/components/button/button.tsx @@ -148,6 +148,7 @@ export class Button implements ComponentInterface { 'aria-disabled': disabled ? 'true' : null, class: { ...createColorClasses(color), + [`${this.mode}`]: true, [buttonType]: true, [`${buttonType}-${expand}`]: expand !== undefined, [`${buttonType}-${size}`]: size !== undefined, diff --git a/core/src/components/buttons/buttons.tsx b/core/src/components/buttons/buttons.tsx index a8f737a121..8f44eb8180 100644 --- a/core/src/components/buttons/buttons.tsx +++ b/core/src/components/buttons/buttons.tsx @@ -1,5 +1,7 @@ import { Component, ComponentInterface } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-buttons', styleUrls: { @@ -8,4 +10,14 @@ import { Component, ComponentInterface } from '@stencil/core'; }, scoped: true, }) -export class Buttons implements ComponentInterface {} +export class Buttons implements ComponentInterface { + mode!: Mode; + + hostData() { + return { + class: { + [`${this.mode}`]: true + } + }; + } +} diff --git a/core/src/components/card-content/card-content.tsx b/core/src/components/card-content/card-content.tsx index fff0a86337..fdc3aa10c6 100644 --- a/core/src/components/card-content/card-content.tsx +++ b/core/src/components/card-content/card-content.tsx @@ -1,7 +1,6 @@ import { Component, ComponentInterface, Prop } from '@stencil/core'; import { Mode } from '../../interface'; -import { createThemedClasses } from '../../utils/theme'; @Component({ tag: 'ion-card-content', @@ -19,7 +18,12 @@ export class CardContent implements ComponentInterface { hostData() { return { - class: createThemedClasses(this.mode, 'card-content') + class: { + [`${this.mode}`]: true, + + // Used internally for styling + [`card-content-${this.mode}`]: true + } }; } } diff --git a/core/src/components/card-header/card-header.tsx b/core/src/components/card-header/card-header.tsx index 93b2965c5c..e210736558 100644 --- a/core/src/components/card-header/card-header.tsx +++ b/core/src/components/card-header/card-header.tsx @@ -34,6 +34,7 @@ export class CardHeader implements ComponentInterface { class: { ...createColorClasses(this.color), 'card-header-translucent': this.translucent, + [`${this.mode}`]: true } }; } diff --git a/core/src/components/card-subtitle/card-subtitle.tsx b/core/src/components/card-subtitle/card-subtitle.tsx index 37b29d71af..7f1b6df0d3 100644 --- a/core/src/components/card-subtitle/card-subtitle.tsx +++ b/core/src/components/card-subtitle/card-subtitle.tsx @@ -26,7 +26,10 @@ export class CardSubtitle implements ComponentInterface { hostData() { return { - class: createColorClasses(this.color), + class: { + ...createColorClasses(this.color), + [`${this.mode}`]: true + }, 'role': 'heading', 'aria-level': '3' }; diff --git a/core/src/components/card-title/card-title.tsx b/core/src/components/card-title/card-title.tsx index 1fea16eaa0..231e0dd04f 100644 --- a/core/src/components/card-title/card-title.tsx +++ b/core/src/components/card-title/card-title.tsx @@ -26,7 +26,10 @@ export class CardTitle implements ComponentInterface { hostData() { return { - class: createColorClasses(this.color), + class: { + ...createColorClasses(this.color), + [`${this.mode}`]: true + }, 'role': 'heading', 'aria-level': '2' }; diff --git a/core/src/components/card/card.tsx b/core/src/components/card/card.tsx index 759e17eb44..a140e5e54e 100644 --- a/core/src/components/card/card.tsx +++ b/core/src/components/card/card.tsx @@ -27,7 +27,10 @@ export class Card implements ComponentInterface { hostData() { return { - class: createColorClasses(this.color) + class: { + ...createColorClasses(this.color), + [`${this.mode}`]: true + } }; } } diff --git a/core/src/components/checkbox/checkbox.tsx b/core/src/components/checkbox/checkbox.tsx index a5c146fb51..4340f6f757 100644 --- a/core/src/components/checkbox/checkbox.tsx +++ b/core/src/components/checkbox/checkbox.tsx @@ -137,6 +137,7 @@ export class Checkbox implements ComponentInterface { 'aria-labelledby': labelId, class: { ...createColorClasses(color), + [`${this.mode}`]: true, 'in-item': hostContext('ion-item', el), 'checkbox-checked': checked, 'checkbox-disabled': disabled, diff --git a/core/src/components/chip/chip.tsx b/core/src/components/chip/chip.tsx index c174302595..69dea9e4fc 100644 --- a/core/src/components/chip/chip.tsx +++ b/core/src/components/chip/chip.tsx @@ -33,6 +33,7 @@ export class Chip implements ComponentInterface { return { class: { ...createColorClasses(this.color), + [`${this.mode}`]: true, 'chip-outline': this.outline, 'ion-activatable': true, } diff --git a/core/src/components/col/col.tsx b/core/src/components/col/col.tsx index d3bd78cea7..6f0daacf28 100644 --- a/core/src/components/col/col.tsx +++ b/core/src/components/col/col.tsx @@ -1,5 +1,6 @@ import { Component, ComponentInterface, Element, Listen, Prop } from '@stencil/core'; +import { Mode } from '../../interface'; import { matchBreakpoint } from '../../utils/media'; const win = window as any; @@ -12,6 +13,8 @@ const BREAKPOINTS = ['', 'xs', 'sm', 'md', 'lg', 'xl']; shadow: true }) export class Col implements ComponentInterface { + mode!: Mode; + @Prop({ context: 'window' }) win!: Window; @Element() el!: HTMLStencilElement; @@ -247,6 +250,9 @@ export class Col implements ComponentInterface { hostData() { const isRTL = this.win.document.dir === 'rtl'; return { + class: { + [`${this.mode}`]: true + }, style: { ...this.calculateOffset(isRTL), ...this.calculatePull(isRTL), diff --git a/core/src/components/content/content.tsx b/core/src/components/content/content.tsx index 2e0b17001a..513c88943b 100644 --- a/core/src/components/content/content.tsx +++ b/core/src/components/content/content.tsx @@ -293,6 +293,7 @@ export class Content implements ComponentInterface { return { class: { ...createColorClasses(this.color), + [`${this.mode}`]: true, 'content-sizing': hostContext('ion-popover', this.el), 'overscroll': !!this.forceOverscroll, }, diff --git a/core/src/components/datetime/datetime-util.spec.ts b/core/src/components/datetime/datetime-util.spec.ts index f0b343f6d0..effe879e99 100644 --- a/core/src/components/datetime/datetime-util.spec.ts +++ b/core/src/components/datetime/datetime-util.spec.ts @@ -2,7 +2,7 @@ import { convertDataToISO, parseDate } from './datetime-util'; describe('datetime-util', () => { describe('convertDataToISO', () => { - it('prints an emptry string for an empty datetime', () => { + it('prints an empty string for an empty datetime', () => { expect(convertDataToISO({})).toEqual(''); }); diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index 8c37a6adb2..c5af45ab9a 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -615,6 +615,7 @@ export class Datetime implements ComponentInterface { 'aria-haspopup': 'true', 'aria-labelledby': labelId, class: { + [`${this.mode}`]: true, 'datetime-disabled': disabled, 'datetime-readonly': readonly, 'datetime-placeholder': addPlaceholderClass, diff --git a/core/src/components/fab-button/fab-button.tsx b/core/src/components/fab-button/fab-button.tsx index aa88f239ee..fc099e179a 100755 --- a/core/src/components/fab-button/fab-button.tsx +++ b/core/src/components/fab-button/fab-button.tsx @@ -95,6 +95,7 @@ export class FabButton implements ComponentInterface { 'aria-disabled': disabled ? 'true' : null, class: { ...createColorClasses(color), + [`${this.mode}`]: true, 'fab-button-in-list': inList, 'fab-button-translucent-in-list': inList && translucent, 'fab-button-close-active': activated, diff --git a/core/src/components/fab-list/fab-list.tsx b/core/src/components/fab-list/fab-list.tsx index 961c310723..2ce5e14a48 100644 --- a/core/src/components/fab-list/fab-list.tsx +++ b/core/src/components/fab-list/fab-list.tsx @@ -1,11 +1,15 @@ import { Component, ComponentInterface, Element, Prop, Watch } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-fab-list', styleUrl: 'fab-list.scss', shadow: true }) export class FabList implements ComponentInterface { + mode!: Mode; + @Element() el!: HTMLIonFabElement; /** @@ -32,6 +36,7 @@ export class FabList implements ComponentInterface { hostData() { return { class: { + [`${this.mode}`]: true, 'fab-list-active': this.activated, [`fab-list-side-${this.side}`]: true } diff --git a/core/src/components/fab/fab.tsx b/core/src/components/fab/fab.tsx index 1cd86807fd..7ec8e97218 100644 --- a/core/src/components/fab/fab.tsx +++ b/core/src/components/fab/fab.tsx @@ -1,11 +1,14 @@ import { Component, ComponentInterface, Element, Listen, Method, Prop, Watch } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-fab', styleUrl: 'fab.scss', shadow: true }) export class Fab implements ComponentInterface { + mode!: Mode; @Element() el!: HTMLElement; @@ -75,6 +78,7 @@ export class Fab implements ComponentInterface { hostData() { return { class: { + [`${this.mode}`]: true, [`fab-horizontal-${this.horizontal}`]: this.horizontal !== undefined, [`fab-vertical-${this.vertical}`]: this.vertical !== undefined, 'fab-edge': this.edge diff --git a/core/src/components/footer/footer.tsx b/core/src/components/footer/footer.tsx index 0a05abbb64..f2320c9996 100644 --- a/core/src/components/footer/footer.tsx +++ b/core/src/components/footer/footer.tsx @@ -1,7 +1,6 @@ import { Component, ComponentInterface, Prop } from '@stencil/core'; import { Mode } from '../../interface'; -import { createThemedClasses } from '../../utils/theme'; @Component({ tag: 'ion-footer', @@ -25,13 +24,15 @@ export class Footer implements ComponentInterface { @Prop() translucent = false; hostData() { - const themedClasses = createThemedClasses(this.mode, 'footer'); - const translucentClasses = this.translucent ? createThemedClasses(this.mode, 'footer-translucent') : null; - return { class: { - ...themedClasses, - ...translucentClasses + [`${this.mode}`]: true, + + // Used internally for styling + [`footer-${this.mode}`]: true, + + [`footer-translucent`]: this.translucent, + [`footer-translucent-${this.mode}`]: this.translucent, } }; } diff --git a/core/src/components/footer/test/translucent/e2e.ts b/core/src/components/footer/test/translucent/e2e.ts new file mode 100644 index 0000000000..5ee2922356 --- /dev/null +++ b/core/src/components/footer/test/translucent/e2e.ts @@ -0,0 +1,14 @@ +import { newE2EPage } from '@stencil/core/testing'; + +import { checkComponentModeClasses } from '../../../../utils/test/utils'; + +test('footer: translucent', async () => { + const page = await newE2EPage({ + url: '/src/components/footer/test/translucent?ionic:_testing=true' + }); + + await checkComponentModeClasses(await page.find('ion-footer'), 'footer-translucent'); + + const compare = await page.compareScreenshot(); + expect(compare).toMatchScreenshot(); +}); diff --git a/core/src/components/grid/grid.tsx b/core/src/components/grid/grid.tsx index 30ee66ac44..83833748b8 100644 --- a/core/src/components/grid/grid.tsx +++ b/core/src/components/grid/grid.tsx @@ -1,11 +1,14 @@ import { Component, ComponentInterface, Prop } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-grid', styleUrl: 'grid.scss', shadow: true }) export class Grid implements ComponentInterface { + mode!: Mode; /** * If `true`, the grid will have a fixed width based on the screen size. @@ -15,6 +18,7 @@ export class Grid implements ComponentInterface { hostData() { return { class: { + [`${this.mode}`]: true, 'grid-fixed': this.fixed } }; diff --git a/core/src/components/header/header.tsx b/core/src/components/header/header.tsx index dc0de9f6fa..1cd2c7bd86 100644 --- a/core/src/components/header/header.tsx +++ b/core/src/components/header/header.tsx @@ -1,7 +1,6 @@ import { Component, ComponentInterface, Prop } from '@stencil/core'; import { Mode } from '../../interface'; -import { createThemedClasses } from '../../utils/theme'; @Component({ tag: 'ion-header', @@ -25,13 +24,15 @@ export class Header implements ComponentInterface { @Prop() translucent = false; hostData() { - const themedClasses = createThemedClasses(this.mode, 'header'); - const translucentClasses = this.translucent ? createThemedClasses(this.mode, 'header-translucent') : null; - return { class: { - ...themedClasses, - ...translucentClasses + [`${this.mode}`]: true, + + // Used internally for styling + [`header-${this.mode}`]: true, + + [`header-translucent`]: this.translucent, + [`header-translucent-${this.mode}`]: this.translucent, } }; } diff --git a/core/src/components/header/test/translucent/e2e.ts b/core/src/components/header/test/translucent/e2e.ts new file mode 100644 index 0000000000..dcc2964855 --- /dev/null +++ b/core/src/components/header/test/translucent/e2e.ts @@ -0,0 +1,14 @@ +import { newE2EPage } from '@stencil/core/testing'; + +import { checkComponentModeClasses } from '../../../../utils/test/utils'; + +test('header: translucent', async () => { + const page = await newE2EPage({ + url: '/src/components/header/test/translucent?ionic:_testing=true' + }); + + await checkComponentModeClasses(await page.find('ion-header'), 'header-translucent'); + + const compare = await page.compareScreenshot(); + expect(compare).toMatchScreenshot(); +}); diff --git a/core/src/components/img/img.tsx b/core/src/components/img/img.tsx index 9d43afc445..06c52cace3 100644 --- a/core/src/components/img/img.tsx +++ b/core/src/components/img/img.tsx @@ -1,11 +1,14 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Prop, State, Watch } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-img', styleUrl: 'img.scss', shadow: true }) export class Img implements ComponentInterface { + mode!: Mode; private io?: IntersectionObserver; @@ -81,6 +84,14 @@ export class Img implements ComponentInterface { } } + hostData() { + return { + class: { + [`${this.mode}`]: true, + } + }; + } + render() { return ( , diff --git a/core/src/components/modal/test/test.utils.ts b/core/src/components/modal/test/test.utils.ts index 4a5a3f0816..4c5e772a89 100644 --- a/core/src/components/modal/test/test.utils.ts +++ b/core/src/components/modal/test/test.utils.ts @@ -19,18 +19,18 @@ export async function testModal( await page.click(selector); await page.waitForSelector(selector); - let popover = await page.find('ion-modal'); - await popover.waitForVisible(); + let modal = await page.find('ion-modal'); + await modal.waitForVisible(); screenshotCompares.push(await page.compareScreenshot()); - await popover.callMethod('dismiss'); - await popover.waitForNotVisible(); + await modal.callMethod('dismiss'); + await modal.waitForNotVisible(); screenshotCompares.push(await page.compareScreenshot('dismiss')); - popover = await page.find('ion-modal'); - expect(popover).toBeNull(); + modal = await page.find('ion-modal'); + expect(modal).toBeNull(); for (const screenshotCompare of screenshotCompares) { expect(screenshotCompare).toMatchScreenshot(); diff --git a/core/src/components/note/note.tsx b/core/src/components/note/note.tsx index 7fa26be73b..c2f7a8be42 100644 --- a/core/src/components/note/note.tsx +++ b/core/src/components/note/note.tsx @@ -26,7 +26,10 @@ export class Note implements ComponentInterface { hostData() { return { - class: createColorClasses(this.color) + class: { + ...createColorClasses(this.color), + [`${this.mode}`]: true, + } }; } diff --git a/core/src/components/picker-column/picker-column.tsx b/core/src/components/picker-column/picker-column.tsx index 7600d3d611..293174b0e0 100644 --- a/core/src/components/picker-column/picker-column.tsx +++ b/core/src/components/picker-column/picker-column.tsx @@ -349,6 +349,7 @@ export class PickerColumnCmp implements ComponentInterface { hostData() { return { class: { + [`${this.mode}`]: true, 'picker-col': true, 'picker-opts-left': this.col.align === 'left', 'picker-opts-right': this.col.align === 'right' diff --git a/core/src/components/picker/picker.tsx b/core/src/components/picker/picker.tsx index 68279289fe..510a82013f 100644 --- a/core/src/components/picker/picker.tsx +++ b/core/src/components/picker/picker.tsx @@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Me import { Animation, AnimationBuilder, Config, CssClassMap, Mode, OverlayEventDetail, OverlayInterface, PickerButton, PickerColumn } from '../../interface'; import { dismiss, eventMethod, present } from '../../utils/overlays'; -import { createThemedClasses, getClassMap } from '../../utils/theme'; +import { getClassMap } from '../../utils/theme'; import { iosEnterAnimation } from './animations/ios.enter'; import { iosLeaveAnimation } from './animations/ios.leave'; @@ -204,7 +204,11 @@ export class Picker implements ComponentInterface, OverlayInterface { return { 'aria-modal': 'true', class: { - ...createThemedClasses(this.mode, 'picker'), + [`${this.mode}`]: true, + + // Used internally for styling + [`picker-${this.mode}`]: true, + ...getClassMap(this.cssClass) }, style: { diff --git a/core/src/components/popover/popover.tsx b/core/src/components/popover/popover.tsx index 7f0af453ae..e9e354a905 100644 --- a/core/src/components/popover/popover.tsx +++ b/core/src/components/popover/popover.tsx @@ -205,6 +205,7 @@ export class Popover implements ComponentInterface, OverlayInterface { }, class: { ...getClassMap(this.cssClass), + [`${this.mode}`]: true, 'popover-translucent': this.translucent } }; diff --git a/core/src/components/progress-bar/progress-bar.tsx b/core/src/components/progress-bar/progress-bar.tsx index badd6d1fea..2c40643965 100644 --- a/core/src/components/progress-bar/progress-bar.tsx +++ b/core/src/components/progress-bar/progress-bar.tsx @@ -62,6 +62,7 @@ export class ProgressBar implements ComponentInterface { 'aria-valuemax': 1, class: { ...createColorClasses(color), + [`${this.mode}`]: true, [`progress-bar-${type}`]: true, 'progress-paused': paused, 'progress-bar-reversed': document.dir === 'rtl' ? !reversed : reversed diff --git a/core/src/components/radio-group/radio-group.tsx b/core/src/components/radio-group/radio-group.tsx index 191528f480..004c4d43ac 100644 --- a/core/src/components/radio-group/radio-group.tsx +++ b/core/src/components/radio-group/radio-group.tsx @@ -1,11 +1,12 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Prop, Watch } from '@stencil/core'; -import { RadioGroupChangeEventDetail } from '../../interface'; +import { Mode, RadioGroupChangeEventDetail } from '../../interface'; @Component({ tag: 'ion-radio-group' }) export class RadioGroup implements ComponentInterface { + mode!: Mode; private inputId = `ion-rg-${radioGroupIds++}`; private labelId = `${this.inputId}-lbl`; @@ -122,7 +123,10 @@ export class RadioGroup implements ComponentInterface { hostData() { return { 'role': 'radiogroup', - 'aria-labelledby': this.labelId + 'aria-labelledby': this.labelId, + class: { + [`${this.mode}`]: true, + } }; } } diff --git a/core/src/components/radio/radio.tsx b/core/src/components/radio/radio.tsx index 7096415770..84c644f476 100644 --- a/core/src/components/radio/radio.tsx +++ b/core/src/components/radio/radio.tsx @@ -163,6 +163,7 @@ export class Radio implements ComponentInterface { 'aria-labelledby': labelId, class: { ...createColorClasses(color), + [`${this.mode}`]: true, 'in-item': hostContext('ion-item', el), 'interactive': true, 'radio-checked': checked, diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index ce97a1e8a0..bd9a60ad7c 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -379,6 +379,7 @@ export class Range implements ComponentInterface { return { class: { ...createColorClasses(this.color), + [`${this.mode}`]: true, 'in-item': hostContext('ion-item', this.el), 'range-disabled': this.disabled, 'range-pressed': this.pressedKnob !== undefined, diff --git a/core/src/components/refresher-content/refresher-content.tsx b/core/src/components/refresher-content/refresher-content.tsx index 4940ad58f4..2cbbd3ff17 100644 --- a/core/src/components/refresher-content/refresher-content.tsx +++ b/core/src/components/refresher-content/refresher-content.tsx @@ -43,6 +43,14 @@ export class RefresherContent implements ComponentInterface { } } + hostData() { + return { + class: { + [`${this.mode}`]: true, + } + }; + } + render() { return [
diff --git a/core/src/components/refresher/refresher.tsx b/core/src/components/refresher/refresher.tsx index da81476d6d..3341fdfb2e 100644 --- a/core/src/components/refresher/refresher.tsx +++ b/core/src/components/refresher/refresher.tsx @@ -1,7 +1,6 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Method, Prop, QueueApi, State, Watch } from '@stencil/core'; import { Gesture, GestureDetail, Mode, RefresherEventDetail } from '../../interface'; -import { createThemedClasses } from '../../utils/theme'; @Component({ tag: 'ion-refresher', @@ -350,7 +349,10 @@ export class Refresher implements ComponentInterface { return { slot: 'fixed', class: { - ...createThemedClasses(this.mode, 'refresher'), + [`${this.mode}`]: true, + + // Used internally for styling + [`refresher-${this.mode}`]: true, 'refresher-active': this.state !== RefresherState.Inactive, 'refresher-pulling': this.state === RefresherState.Pulling, diff --git a/core/src/components/reorder-group/reorder-group.tsx b/core/src/components/reorder-group/reorder-group.tsx index 10fdc0f809..905781fa8f 100644 --- a/core/src/components/reorder-group/reorder-group.tsx +++ b/core/src/components/reorder-group/reorder-group.tsx @@ -1,6 +1,6 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Method, Prop, QueueApi, State, Watch } from '@stencil/core'; -import { Gesture, GestureDetail, ItemReorderEventDetail } from '../../interface'; +import { Gesture, GestureDetail, ItemReorderEventDetail, Mode } from '../../interface'; import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from '../../utils/haptic'; const enum ReorderGroupState { @@ -14,6 +14,7 @@ const enum ReorderGroupState { styleUrl: 'reorder-group.scss' }) export class ReorderGroup implements ComponentInterface { + mode!: Mode; private selectedItemEl?: HTMLElement; private selectedItemHeight!: number; @@ -293,6 +294,7 @@ export class ReorderGroup implements ComponentInterface { hostData() { return { class: { + [`${this.mode}`]: true, 'reorder-enabled': !this.disabled, 'reorder-list-active': this.state !== ReorderGroupState.Idle, } diff --git a/core/src/components/reorder/reorder.tsx b/core/src/components/reorder/reorder.tsx index 2b4d3fd104..4391b4754c 100644 --- a/core/src/components/reorder/reorder.tsx +++ b/core/src/components/reorder/reorder.tsx @@ -20,6 +20,14 @@ export class Reorder implements ComponentInterface { ev.stopImmediatePropagation(); } + hostData() { + return { + class: { + [`${this.mode}`]: true, + } + }; + } + render() { return ( diff --git a/core/src/components/ripple-effect/ripple-effect.tsx b/core/src/components/ripple-effect/ripple-effect.tsx index 0102167268..066967c45b 100644 --- a/core/src/components/ripple-effect/ripple-effect.tsx +++ b/core/src/components/ripple-effect/ripple-effect.tsx @@ -1,11 +1,14 @@ import { Component, ComponentInterface, Element, Method, Prop, QueueApi } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-ripple-effect', styleUrl: 'ripple-effect.scss', shadow: true }) export class RippleEffect implements ComponentInterface { + mode!: Mode; @Element() el!: HTMLElement; @@ -79,6 +82,7 @@ export class RippleEffect implements ComponentInterface { return { role: 'presentation', class: { + [`${this.mode}`]: true, 'unbounded': this.unbounded } }; diff --git a/core/src/components/row/row.tsx b/core/src/components/row/row.tsx index 7b830a0d5d..c947353e6f 100644 --- a/core/src/components/row/row.tsx +++ b/core/src/components/row/row.tsx @@ -1,11 +1,22 @@ import { Component, ComponentInterface } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-row', styleUrl: 'row.scss', shadow: true }) export class Row implements ComponentInterface { + mode!: Mode; + + hostData() { + return { + class: { + [`${this.mode}`]: true, + } + }; + } render() { return ; } diff --git a/core/src/components/searchbar/searchbar.tsx b/core/src/components/searchbar/searchbar.tsx index f8407f6f0e..1645a2b2aa 100644 --- a/core/src/components/searchbar/searchbar.tsx +++ b/core/src/components/searchbar/searchbar.tsx @@ -352,6 +352,7 @@ export class Searchbar implements ComponentInterface { return { class: { ...createColorClasses(this.color), + [`${this.mode}`]: true, 'searchbar-animated': animated, 'searchbar-no-animate': animated && this.noAnimate, 'searchbar-has-value': (this.getValue() !== ''), diff --git a/core/src/components/segment-button/segment-button.tsx b/core/src/components/segment-button/segment-button.tsx index 271423fb22..b2fd6ea5a4 100644 --- a/core/src/components/segment-button/segment-button.tsx +++ b/core/src/components/segment-button/segment-button.tsx @@ -71,6 +71,7 @@ export class SegmentButton implements ComponentInterface { return { 'aria-disabled': disabled ? 'true' : null, class: { + [`${this.mode}`]: true, 'segment-button-has-label': hasLabel, 'segment-button-has-icon': hasIcon, 'segment-button-has-label-only': hasLabel && !hasIcon, diff --git a/core/src/components/segment/segment.tsx b/core/src/components/segment/segment.tsx index 4eb1284d38..aa29084562 100644 --- a/core/src/components/segment/segment.tsx +++ b/core/src/components/segment/segment.tsx @@ -99,6 +99,7 @@ export class Segment implements ComponentInterface { return { class: { ...createColorClasses(this.color), + [`${this.mode}`]: true, 'segment-disabled': this.disabled, 'segment-scrollable': this.scrollable } diff --git a/core/src/components/select-option/select-option.tsx b/core/src/components/select-option/select-option.tsx index fbd15271b9..c855416642 100644 --- a/core/src/components/select-option/select-option.tsx +++ b/core/src/components/select-option/select-option.tsx @@ -1,11 +1,14 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Prop } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-select-option', shadow: true, styleUrl: 'select-option.scss' }) export class SelectOption implements ComponentInterface { + mode!: Mode; private inputId = `ion-selopt-${selectOptionIds++}`; @@ -55,7 +58,10 @@ export class SelectOption implements ComponentInterface { hostData() { return { 'role': 'option', - 'id': this.inputId + 'id': this.inputId, + class: { + [`${this.mode}`]: true, + } }; } } diff --git a/core/src/components/select-popover/select-popover.tsx b/core/src/components/select-popover/select-popover.tsx index f167fe425c..d6e933d5e2 100644 --- a/core/src/components/select-popover/select-popover.tsx +++ b/core/src/components/select-popover/select-popover.tsx @@ -34,6 +34,14 @@ export class SelectPopover implements ComponentInterface { } } + hostData() { + return { + class: { + [`${this.mode}`]: true, + } + }; + } + render() { return ( diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx index ce1b3d59f3..4f42c5adfe 100644 --- a/core/src/components/select/select.tsx +++ b/core/src/components/select/select.tsx @@ -455,6 +455,7 @@ export class Select implements ComponentInterface { 'aria-haspopup': 'dialog', 'aria-labelledby': labelId, class: { + [`${this.mode}`]: true, 'in-item': hostContext('ion-item', this.el), 'select-disabled': this.disabled, } diff --git a/core/src/components/skeleton-text/skeleton-text.tsx b/core/src/components/skeleton-text/skeleton-text.tsx index 9dde1e234b..56872b14f3 100644 --- a/core/src/components/skeleton-text/skeleton-text.tsx +++ b/core/src/components/skeleton-text/skeleton-text.tsx @@ -1,6 +1,6 @@ import { Component, ComponentInterface, Element, Prop } from '@stencil/core'; -import { Config } from '../../interface'; +import { Config, Mode } from '../../interface'; import { hostContext } from '../../utils/theme'; @Component({ @@ -9,6 +9,7 @@ import { hostContext } from '../../utils/theme'; shadow: true }) export class SkeletonText implements ComponentInterface { + mode!: Mode; @Element() el!: HTMLElement; @@ -49,6 +50,7 @@ export class SkeletonText implements ComponentInterface { return { class: { + [`${this.mode}`]: true, 'skeleton-text-animated': animated, 'in-media': inMedia }, diff --git a/core/src/components/slide/slide.tsx b/core/src/components/slide/slide.tsx index 0033f3c51c..b165a42c89 100644 --- a/core/src/components/slide/slide.tsx +++ b/core/src/components/slide/slide.tsx @@ -1,11 +1,14 @@ import { Component, ComponentInterface, Event } from '@stencil/core'; import { EventEmitter } from 'ionicons/dist/types/stencil.core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-slide', styleUrl: 'slide.scss' }) export class Slide implements ComponentInterface { + mode!: Mode; /** @internal */ @Event() ionSlideChanged!: EventEmitter; @@ -21,6 +24,7 @@ export class Slide implements ComponentInterface { hostData() { return { class: { + [`${this.mode}`]: true, 'swiper-slide': true, 'swiper-zoom-container': true } diff --git a/core/src/components/slides/slides.scss b/core/src/components/slides/slides.scss index 13db253731..bd36fe27fd 100644 --- a/core/src/components/slides/slides.scss +++ b/core/src/components/slides/slides.scss @@ -4,7 +4,7 @@ // Slides // -------------------------------------------------- -.slides { +ion-slides { /** * @prop --bullet-background: Background of the pagination bullets * @prop --bullet-background-active: Background of the active pagination bullet diff --git a/core/src/components/slides/slides.tsx b/core/src/components/slides/slides.tsx index 7b481dcc5c..097539c780 100644 --- a/core/src/components/slides/slides.tsx +++ b/core/src/components/slides/slides.tsx @@ -2,7 +2,6 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Me import { Mode } from '../../interface'; import { rIC } from '../../utils/helpers.js'; -import { createThemedClasses } from '../../utils/theme.js'; import { SwiperInterface, SwiperOptions } from './swiper/swiper-interface'; @@ -450,7 +449,11 @@ export class Slides implements ComponentInterface { hostData() { return { class: { - ...createThemedClasses(this.mode, 'slides'), + [`${this.mode}`]: true, + + // Used internally for styling + [`slides-${this.mode}`]: true, + 'swiper-container': true } }; diff --git a/core/src/components/spinner/spinner.tsx b/core/src/components/spinner/spinner.tsx index 02c6f50a10..a5d065672d 100644 --- a/core/src/components/spinner/spinner.tsx +++ b/core/src/components/spinner/spinner.tsx @@ -50,7 +50,7 @@ export class Spinner implements ComponentInterface { return { class: { ...createColorClasses(this.color), - + [`${this.mode}`]: true, [`spinner-${this.getName()}`]: true, 'spinner-paused': !!this.paused || this.config.getBoolean('_testing') } diff --git a/core/src/components/split-pane/split-pane.scss b/core/src/components/split-pane/split-pane.scss index df991481ea..5ae038afcd 100644 --- a/core/src/components/split-pane/split-pane.scss +++ b/core/src/components/split-pane/split-pane.scss @@ -3,7 +3,7 @@ // Split Pane // -------------------------------------------------- -.split-pane { +ion-split-pane { /** * @prop --border: Border between panes */ diff --git a/core/src/components/split-pane/split-pane.tsx b/core/src/components/split-pane/split-pane.tsx index 37624af1b3..841f41daff 100644 --- a/core/src/components/split-pane/split-pane.tsx +++ b/core/src/components/split-pane/split-pane.tsx @@ -1,7 +1,6 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Prop, State, Watch } from '@stencil/core'; import { Mode } from '../../interface'; -import { createThemedClasses } from '../../utils/theme'; const SPLIT_PANE_MAIN = 'split-pane-main'; const SPLIT_PANE_SIDE = 'split-pane-side'; @@ -165,7 +164,11 @@ export class SplitPane implements ComponentInterface { hostData() { return { class: { - ...createThemedClasses(this.mode, 'split-pane'), + [`${this.mode}`]: true, + + // Used internally for styling + [`split-pane-${this.mode}`]: true, + 'split-pane-visible': this.visible } }; diff --git a/core/src/components/tab-bar/tab-bar.tsx b/core/src/components/tab-bar/tab-bar.tsx index f89ef68294..5f6480eb25 100644 --- a/core/src/components/tab-bar/tab-bar.tsx +++ b/core/src/components/tab-bar/tab-bar.tsx @@ -74,6 +74,7 @@ export class TabBar implements ComponentInterface { 'aria-hidden': keyboardVisible ? 'true' : null, class: { ...createColorClasses(color), + [`${this.mode}`]: true, 'tab-bar-translucent': translucent, 'tab-bar-hidden': keyboardVisible, } diff --git a/core/src/components/tab-button/tab-button.tsx b/core/src/components/tab-button/tab-button.tsx index f1e5143900..cb86c0e1bc 100644 --- a/core/src/components/tab-button/tab-button.tsx +++ b/core/src/components/tab-button/tab-button.tsx @@ -96,6 +96,7 @@ export class TabButton implements ComponentInterface { 'aria-selected': selected ? 'true' : null, 'id': tab !== undefined ? `tab-button-${tab}` : null, class: { + [`${this.mode}`]: true, 'tab-selected': selected, 'tab-disabled': disabled, 'tab-has-label': hasLabel, diff --git a/core/src/components/tabs/test/standalone/e2e.ts b/core/src/components/tabs/test/standalone/e2e.ts new file mode 100644 index 0000000000..69a7bb857e --- /dev/null +++ b/core/src/components/tabs/test/standalone/e2e.ts @@ -0,0 +1,26 @@ +import { newE2EPage } from '@stencil/core/testing'; + +test('tabs: standalone', async () => { + const page = await newE2EPage({ + url: '/src/components/tabs/test/standalone?ionic:_testing=true' + }); + + const compares = []; + + // Initial page load + compares.push(await page.compareScreenshot()); + + let tabButton = await page.find('#tab-button-tab-one'); + await tabButton.click(); + + compares.push(await page.compareScreenshot(`tab one`)); + + tabButton = await page.find('#tab-button-tab-two'); + await tabButton.click(); + + compares.push(await page.compareScreenshot(`tab two`)); + + for (const compare of compares) { + expect(compare).toMatchScreenshot(); + } +}); diff --git a/core/src/components/tabs/test/vanilla/index.html b/core/src/components/tabs/test/standalone/index.html similarity index 56% rename from core/src/components/tabs/test/vanilla/index.html rename to core/src/components/tabs/test/standalone/index.html index 76fe94d145..d38c4b065b 100644 --- a/core/src/components/tabs/test/vanilla/index.html +++ b/core/src/components/tabs/test/standalone/index.html @@ -3,7 +3,7 @@ - Tab - Vanilla + Tabs - Standalone @@ -14,14 +14,24 @@ - + -
Div One
+
+

Tab One

+
-
Div Two
+
+

Tab Two

+
+
+ + +
+

Tab Three

+
@@ -34,23 +44,41 @@ Tab Two + + + Tab Three + +
+ + diff --git a/core/src/components/tabs/test/vanilla/e2e.js b/core/src/components/tabs/test/vanilla/e2e.js deleted file mode 100644 index 5a6131a049..0000000000 --- a/core/src/components/tabs/test/vanilla/e2e.js +++ /dev/null @@ -1,34 +0,0 @@ -// 'use strict'; - -// const { register, Page, platforms } = require('../../../../../scripts/e2e'); -// const { getElement, waitAndGetElementById, waitForTransition } = require('../../../../../scripts/e2e/utils'); - -// class E2ETestPage extends Page { -// constructor(driver, platform) { -// super(driver, `http://localhost:3333/src/components/tabs/test/vanilla?ionic:mode=${platform}`); -// } -// } - -// platforms.forEach(platform => { -// describe('tabs/vanilla', () => { -// register('should init', driver => { -// const page = new E2ETestPage(driver, platform); -// return page.navigate(); -// }); - -// register('should check each tab', async (driver, testContext) => { -// testContext.timeout(60000); -// const page = new E2ETestPage(driver, platform); - -// await waitForTransition(300); - -// const tabTwoButton = await waitAndGetElementById(driver, 'tab-t-0-1'); -// tabTwoButton.click(); -// await waitForTransition(600); - -// const tabThreeButton = await waitAndGetElementById(driver, 'tab-t-0-2'); -// tabThreeButton.click(); -// await waitForTransition(600); -// }); -// }); -// }); diff --git a/core/src/components/text/text.tsx b/core/src/components/text/text.tsx index 6b41464ab8..455c3c2f61 100644 --- a/core/src/components/text/text.tsx +++ b/core/src/components/text/text.tsx @@ -24,7 +24,10 @@ export class Text implements ComponentInterface { hostData() { return { - class: createColorClasses(this.color) + class: { + ...createColorClasses(this.color), + [`${this.mode}`]: true, + } }; } diff --git a/core/src/components/textarea/textarea.tsx b/core/src/components/textarea/textarea.tsx index 97bcf96812..13dd1fe41a 100644 --- a/core/src/components/textarea/textarea.tsx +++ b/core/src/components/textarea/textarea.tsx @@ -266,7 +266,10 @@ export class Textarea implements ComponentInterface { hostData() { return { 'aria-disabled': this.disabled ? 'true' : null, - class: createColorClasses(this.color) + class: { + ...createColorClasses(this.color), + [`${this.mode}`]: true, + } }; } diff --git a/core/src/components/thumbnail/thumbnail.tsx b/core/src/components/thumbnail/thumbnail.tsx index 8b1198d555..0ca03bbb01 100644 --- a/core/src/components/thumbnail/thumbnail.tsx +++ b/core/src/components/thumbnail/thumbnail.tsx @@ -1,11 +1,22 @@ import { Component, ComponentInterface } from '@stencil/core'; +import { Mode } from '../../interface'; + @Component({ tag: 'ion-thumbnail', styleUrl: 'thumbnail.scss', shadow: true }) export class Thumbnail implements ComponentInterface { + mode!: Mode; + + hostData() { + return { + class: { + [`${this.mode}`]: true, + } + }; + } render() { return ; } diff --git a/core/src/components/title/title.scss b/core/src/components/title/title.scss index 08b463e62d..16f6c949cc 100644 --- a/core/src/components/title/title.scss +++ b/core/src/components/title/title.scss @@ -62,4 +62,4 @@ overflow: hidden; pointer-events: auto; -} +} \ No newline at end of file diff --git a/core/src/components/title/title.tsx b/core/src/components/title/title.tsx index ceff504083..9962970214 100644 --- a/core/src/components/title/title.tsx +++ b/core/src/components/title/title.tsx @@ -28,10 +28,13 @@ export class ToolbarTitle implements ComponentInterface { hostData() { const mode = this.getMode(); + return { class: { + [`${mode}`]: true, + [`title-${mode}`]: true, + ...createColorClasses(this.color), - [`title-${mode}`]: true } }; } diff --git a/core/src/components/toast/toast.tsx b/core/src/components/toast/toast.tsx index 1d3a6ad682..3a160d4f6f 100644 --- a/core/src/components/toast/toast.tsx +++ b/core/src/components/toast/toast.tsx @@ -226,6 +226,8 @@ export class Toast implements ComponentInterface, OverlayInterface { zIndex: 60000 + this.overlayIndex, }, class: { + [`${this.mode}`]: true, + ...createColorClasses(this.color), ...getClassMap(this.cssClass), 'toast-translucent': this.translucent diff --git a/core/src/components/toggle/toggle.tsx b/core/src/components/toggle/toggle.tsx index dd5989e440..9fa7f38b14 100644 --- a/core/src/components/toggle/toggle.tsx +++ b/core/src/components/toggle/toggle.tsx @@ -195,6 +195,7 @@ export class Toggle implements ComponentInterface { class: { ...createColorClasses(color), + [`${this.mode}`]: true, 'in-item': hostContext('ion-item', el), 'toggle-activated': activated, 'toggle-checked': checked, diff --git a/core/src/components/toolbar/toolbar.tsx b/core/src/components/toolbar/toolbar.tsx index b1e5e0fa6c..ade3ad61e4 100644 --- a/core/src/components/toolbar/toolbar.tsx +++ b/core/src/components/toolbar/toolbar.tsx @@ -72,8 +72,10 @@ export class Toolbar implements ComponentInterface { return { class: { + [`${this.mode}`]: true, + ...childStyles, - ...createColorClasses(this.color) + ...createColorClasses(this.color), } }; } diff --git a/core/src/utils/test/modes/e2e.ts b/core/src/utils/test/modes/e2e.ts new file mode 100644 index 0000000000..0ff2fb66d8 --- /dev/null +++ b/core/src/utils/test/modes/e2e.ts @@ -0,0 +1,74 @@ +import { newE2EPage } from '@stencil/core/testing'; + +import { checkComponentModeClasses, checkModeClasses } from '../utils'; + +// This test is to loop through all components that should have +// specific classes added and test them +test('component: modes', async () => { + const page = await newE2EPage({ + url: '/src/utils/test/modes?ionic:_testing=true' + }); + + // First test: .button class + // ---------------------------------------------------------------- + // components that need to have the `button` class + // for use in styling by other components (`ion-buttons`) + // e.g. + let tags = ['ion-button', 'ion-back-button', 'ion-menu-button']; + + for (const tag of tags) { + const el = await page.find(tag); + expect(el).toHaveClass('button'); + } + + // Second test: .item class + // ---------------------------------------------------------------- + // components that need to have the `item` class + // for use in styling by other components + // e.g. + tags = ['ion-item', 'ion-item-divider', 'ion-item-group']; + + for (const tag of tags) { + const el = await page.find(tag); + expect(el).toHaveClass('item'); + } + + // Third test: .{component}-{mode} class + // ---------------------------------------------------------------- + // components that need to have their tag name + // + mode as a class for internal styling + // e.g. + tags = ['ion-card-content', 'ion-footer', 'ion-header', 'ion-infinite-scroll-content', 'ion-item-group', 'ion-item-options', 'ion-list', 'ion-picker', 'ion-refresher', 'ion-slides', 'ion-split-pane']; + + for (const tag of tags) { + const el = await page.find(tag); + await checkComponentModeClasses(el); + } + + // Fourth test: .{mode} class + // ---------------------------------------------------------------- + // components that need to have the mode class + // added for external / user styling + // e.g. + tags = ['ion-action-sheet', 'ion-alert', 'ion-anchor', 'ion-app', 'ion-avatar', 'ion-back-button', 'ion-backdrop', 'ion-badge', 'ion-button', 'ion-buttons', 'ion-card-content', 'ion-card-header', 'ion-card-subtitle', 'ion-card-title', 'ion-card', 'ion-checkbox', 'ion-chip', 'ion-col', 'ion-content', 'ion-datetime', 'ion-fab', 'ion-fab-button', 'ion-fab-list', 'ion-footer', 'ion-grid', 'ion-header', 'ion-icon', 'ion-img', 'ion-infinite-scroll', 'ion-infinite-scroll-content', 'ion-input', 'ion-item', 'ion-item-divider', 'ion-item-group', 'ion-item-option', 'ion-item-options', 'ion-item-sliding', 'ion-label', 'ion-list', 'ion-list-header', 'ion-loading', 'ion-modal', 'ion-menu', 'ion-menu-button', 'ion-menu-toggle', 'ion-note', 'ion-picker', 'ion-picker-column', 'ion-popover', 'ion-progress-bar', 'ion-radio', 'ion-radio-group', 'ion-range', 'ion-refresher', 'ion-refresher-content', 'ion-reorder', 'ion-reorder-group', 'ion-ripple-effect', 'ion-row', 'ion-searchbar', 'ion-segment', 'ion-segment-button', 'ion-select', 'ion-select-option', 'ion-select-popover', 'ion-skeleton-text', 'ion-slide', 'ion-slides', 'ion-spinner', 'ion-split-pane', 'ion-tab-bar', 'ion-tab-button', 'ion-text', 'ion-textarea', 'ion-thumbnail', 'ion-title', 'ion-toast', 'ion-toggle', 'ion-toolbar']; + + for (const tag of tags) { + await page.waitForSelector(tag); + const el = await page.find(tag); + await checkModeClasses(el); + } + + // Fifth test: changing mode + // ---------------------------------------------------------------- + // change the mode on a button and then check the classes + // make sure it has the new mode and not the old mode + // e.g. + const button = await page.find('ion-button'); + const mode = await button.getProperty('mode'); + + button.setAttribute('mode', 'blah'); + await page.waitForChanges(); + + expect(button).not.toHaveClass(`${mode}`); + expect(button).toHaveClass(`blah`); +}); diff --git a/core/src/utils/test/modes/index.html b/core/src/utils/test/modes/index.html new file mode 100644 index 0000000000..b9262540e3 --- /dev/null +++ b/core/src/utils/test/modes/index.html @@ -0,0 +1,176 @@ + + + + + + Components - Modes + + + + + + + + + + + + + + +
+ + + Components: Modes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + diff --git a/core/src/utils/test/utils.ts b/core/src/utils/test/utils.ts index af51a59cfd..77508b3ba7 100644 --- a/core/src/utils/test/utils.ts +++ b/core/src/utils/test/utils.ts @@ -1,4 +1,4 @@ -import { E2EPage } from '@stencil/core/testing'; +import { E2EElement, E2EPage } from '@stencil/core/testing'; import { ElementHandle } from 'puppeteer'; export function generateE2EUrl(component: string, type: string, rtl = false): string { @@ -112,3 +112,39 @@ export async function queryDeep(page: E2EPage, ...selectors: string[]): Promise< if (parentElement) { resolve(parentElement); } }); } + +/** + * Given an element and optional selector, use the selector if + * it exists or get the node name of that element if not. Combine + * with the current mode to verify the correct classes exist. + * + * @param el: E2EElement - The element to verify classes on + * @param selector: string - A selector to use instead of the element tag name + * + * Examples: + * await checkComponentModeClasses(await page.find('ion-card-content')) + * => expect(el).toHaveClass(`card-content-{mode}`); + * + * await checkComponentModeClasses(await page.find('ion-card-content'), 'some-class') + * => expect(el).toHaveClass(`some-class-{mode}`); + */ +export async function checkComponentModeClasses(el: E2EElement, selector?: string) { + // If passed a selector to use, use that, else grab the nodeName + // of the element and remove the ion prefix to get the class selector + const component = selector !== undefined ? selector : el.nodeName.toLowerCase().replace('ion-', ''); + + const mode = await el.getProperty('mode'); + + expect(el).toHaveClass(`${component}-${mode}`); +} + +/** + * Given an element, get the mode and verify it exists as a class + * + * @param el: E2EElement - the element to verify the mode class on + */ +export async function checkModeClasses(el: E2EElement) { + const mode = await el.getProperty('mode'); + + expect(el).toHaveClass(`${mode}`); +} diff --git a/core/src/utils/theme.ts b/core/src/utils/theme.ts index 1a2b10ceb8..b732243c33 100644 --- a/core/src/utils/theme.ts +++ b/core/src/utils/theme.ts @@ -1,4 +1,4 @@ -import { Color, CssClassMap, Mode, RouterDirection } from '../interface'; +import { Color, CssClassMap, RouterDirection } from '../interface'; export function hostContext(selector: string, el: HTMLElement): boolean { return el.closest(selector) !== null; @@ -14,13 +14,6 @@ export function createColorClasses(color: Color | undefined | null): CssClassMap } : undefined; } -export function createThemedClasses(mode: Mode | undefined, name: string): CssClassMap { - return { - [name]: true, - [`${name}-${mode}`]: mode !== undefined - }; -} - export function getClassList(classes: string | (string | null | undefined)[] | undefined): string[] { if (classes !== undefined) { const array = Array.isArray(classes) ? classes : classes.split(' ');