Skip to content

Commit

Permalink
feat(toggle): component can be used outside of ion-item (#26357)
Browse files Browse the repository at this point in the history
resolves #25570, resolves #23213

BREAKING CHANGE:

The `--background` and `--background-checked` variables have been renamed to `--track-background` and `--track-background-checked`, respectively.
  • Loading branch information
liamdebeasi committed Nov 29, 2022
1 parent 0ca6fee commit c74901c
Show file tree
Hide file tree
Showing 293 changed files with 1,716 additions and 218 deletions.
2 changes: 2 additions & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ Developers using these components will need to migrate to using Swiper.js direct

- `ionChange` is no longer emitted when the `checked` property of `ion-toggle` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking the toggle to set it on or off.

- The `--background` and `--background-checked` variables have been renamed to `--track-background` and `--track-background-checked`, respectively.

<h4 id="version-7x-virtual-scroll">Virtual Scroll</h4>

`ion-virtual-scroll` has been removed from Ionic.
Expand Down
4 changes: 2 additions & 2 deletions angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2247,13 +2247,13 @@ when programmatically changing the value of the `checked` property.

@ProxyCmp({
defineCustomElementFn: undefined,
inputs: ['checked', 'color', 'disabled', 'enableOnOffLabels', 'mode', 'name', 'value']
inputs: ['checked', 'color', 'disabled', 'enableOnOffLabels', 'justify', 'labelPlacement', 'mode', 'name', 'value']
})
@Component({
selector: 'ion-toggle',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
inputs: ['checked', 'color', 'disabled', 'enableOnOffLabels', 'mode', 'name', 'value']
inputs: ['checked', 'color', 'disabled', 'enableOnOffLabels', 'justify', 'labelPlacement', 'mode', 'name', 'value']
})
export class IonToggle {
protected el: HTMLElement;
Expand Down
6 changes: 4 additions & 2 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1428,14 +1428,14 @@ ion-toggle,prop,checked,boolean,false,false,false
ion-toggle,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-toggle,prop,disabled,boolean,false,false,false
ion-toggle,prop,enableOnOffLabels,boolean | undefined,undefined,false,false
ion-toggle,prop,justify,"end" | "space-between" | "start",'space-between',false,false
ion-toggle,prop,labelPlacement,"end" | "fixed" | "start",'start',false,false
ion-toggle,prop,mode,"ios" | "md",undefined,false,false
ion-toggle,prop,name,string,this.inputId,false,false
ion-toggle,prop,value,null | string | undefined,'on',false,false
ion-toggle,event,ionBlur,void,true
ion-toggle,event,ionChange,ToggleChangeEventDetail<any>,true
ion-toggle,event,ionFocus,void,true
ion-toggle,css-prop,--background
ion-toggle,css-prop,--background-checked
ion-toggle,css-prop,--border-radius
ion-toggle,css-prop,--handle-background
ion-toggle,css-prop,--handle-background-checked
Expand All @@ -1446,6 +1446,8 @@ ion-toggle,css-prop,--handle-max-height
ion-toggle,css-prop,--handle-spacing
ion-toggle,css-prop,--handle-transition
ion-toggle,css-prop,--handle-width
ion-toggle,css-prop,--track-background
ion-toggle,css-prop,--track-background-checked
ion-toggle,part,handle
ion-toggle,part,track

Expand Down
16 changes: 16 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2994,6 +2994,14 @@ export namespace Components {
* Enables the on/off accessibility switch labels within the toggle.
*/
"enableOnOffLabels": boolean | undefined;
/**
* How to pack the label and toggle within a line. `'start'`: The label and toggle will appear on the left in LTR and on the right in RTL. `'end'`: The label and toggle will appear on the right in LTR and on the left in RTL. `'space-between'`: The label and toggle will appear on opposite ends of the line with space between the two elements.
*/
"justify": 'start' | 'end' | 'space-between';
/**
* Where to place the label relative to the input. `'start'`: The label will appear to the left of the toggle in LTR and to the right in RTL. `'end'`: The label will appear to the right of the toggle in LTR and to the left in RTL. `'fixed'`: The label has the same behavior as `'start'` except it also has a fixed width. Long text will be truncated with ellipses ("...").
*/
"labelPlacement": 'start' | 'end' | 'fixed';
/**
* The mode determines which platform styles to use.
*/
Expand Down Expand Up @@ -6990,6 +6998,14 @@ declare namespace LocalJSX {
* Enables the on/off accessibility switch labels within the toggle.
*/
"enableOnOffLabels"?: boolean | undefined;
/**
* How to pack the label and toggle within a line. `'start'`: The label and toggle will appear on the left in LTR and on the right in RTL. `'end'`: The label and toggle will appear on the right in LTR and on the left in RTL. `'space-between'`: The label and toggle will appear on opposite ends of the line with space between the two elements.
*/
"justify"?: 'start' | 'end' | 'space-between';
/**
* Where to place the label relative to the input. `'start'`: The label will appear to the left of the toggle in LTR and to the right in RTL. `'end'`: The label will appear to the right of the toggle in LTR and to the left in RTL. `'fixed'`: The label has the same behavior as `'start'` except it also has a fixed width. Long text will be truncated with ellipses ("...").
*/
"labelPlacement"?: 'start' | 'end' | 'fixed';
/**
* The mode determines which platform styles to use.
*/
Expand Down
22 changes: 22 additions & 0 deletions core/src/components/toggle/test/a11y/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Toggle - a11y</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>

<body>
<main>
<h1>Toggle - a11y</h1>

<ion-toggle>my label</ion-toggle><br />
<ion-toggle aria-label="my aria label"></ion-toggle><br />
</main>
</body>
</html>
17 changes: 17 additions & 0 deletions core/src/components/toggle/test/a11y/toggle.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';

test.describe('toggle: a11y', () => {
test.beforeEach(async ({ skip }) => {
skip.rtl();
skip.mode('md');
});

test('should not have accessibility violations', async ({ page }) => {
await page.goto(`/src/components/toggle/test/a11y`);

const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
});
120 changes: 7 additions & 113 deletions core/src/components/toggle/test/basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,124 +20,18 @@
<ion-toolbar>
<ion-title>Toggle - Basic</ion-title>
<ion-buttons slot="primary">
<ion-toggle aria-label="Toggle"></ion-toggle>
<ion-toggle aria-label="Enable Notifications"></ion-toggle>
</ion-buttons>
</ion-toolbar>
</ion-header>

<ion-content id="content">
<ion-list>
<ion-item>
<ion-label>Orange</ion-label>
<ion-toggle id="orange" slot="start" name="orange"></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Apple</ion-label>
<ion-toggle slot="start" name="apple" checked></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Banana</ion-label>
<ion-toggle slot="start" name="banana" checked class="toggle-part"></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Cherry, disabled</ion-label>
<ion-toggle slot="start" color="danger" name="cherry" disabled></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Grape, checked, disabled</ion-label>
<ion-toggle slot="start" id="grapeChecked" value="grape" name="grape" checked disabled></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Kiwi, (ionChange) Secondary color</ion-label>
<ion-toggle slot="start" color="secondary" (ionChange)="kiwiChange($event)"></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Strawberry, (ionChange) checked="true"</ion-label>
<ion-toggle slot="start" color="light" (ionChange)="strawberryChange($event)" checked="true"></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Checkbox right, checked, really long text that should ellipsis</ion-label>
<ion-toggle slot="end" color="danger" checked></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Checkbox right side</ion-label>
<ion-toggle slot="end" checked></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Button w/ right side default icon, really long text that should ellipsis</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>

<ion-item>
<ion-label>Custom</ion-label>
<ion-toggle slot="start" style="--border-radius: 0px; --handle-border-radius: 0px" checked></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Stop Immediate Event Propagation</ion-label>
<ion-toggle slot="start" checked id="eventPropagation"></ion-toggle>
</ion-item>
</ion-list>

<p aria-hidden="true" class="ion-text-center">
<ion-button onClick="toggleBoolean('grapeChecked', 'checked')" fill="outline" size="small"
>Grape Checked</ion-button
>
<ion-button onClick="toggleBoolean('grapeChecked', 'disabled')" fill="outline" size="small"
>Grape Disabled</ion-button
>
<ion-button onClick="printForm()" fill="outline" size="small">Print Form</ion-button>
</p>

<p>
<ion-toggle aria-label="Stand-alone toggle" id="standAloneChecked"></ion-toggle>
Stand-alone toggle:
<span id="standAloneCheckedSpan"></span>
</p>
<ion-content class="ion-padding">
<ion-toggle
>Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable Notifications
Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable
Notifications</ion-toggle
>
</ion-content>

<style>
.toggle-part.toggle-checked::part(handle) {
background: red;
}

.toggle-part.toggle-checked::part(track) {
background: purple;
}

.toggle-part::part(handle) {
background: green;
}

.toggle-part::part(track) {
background: hotpink;
}
</style>

<script>
function printForm(ev) {}

function toggleBoolean(id, prop) {
var el = document.getElementById(id);

var isTrue = el[prop] ? false : true;
el[prop] = isTrue;
}

document.getElementById('eventPropagation').addEventListener('click', (evt) => {
evt.stopImmediatePropagation();
console.log('clicked');
});
</script>
</ion-app>
</body>
</html>
25 changes: 25 additions & 0 deletions core/src/components/toggle/test/color/toggle.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';

test.describe('toggle: color', () => {
test.beforeEach(({ skip }) => {
skip.rtl();
});
test('should apply color when checked', async ({ page }) => {
await page.setContent(`
<ion-toggle color="danger" checked="true">Label</ion-toggle>
`);

const toggle = page.locator('ion-toggle');
expect(await toggle.screenshot()).toMatchSnapshot(`toggle-color-checked-${page.getSnapshotSettings()}.png`);
});

test('should not apply color when unchecked', async ({ page }) => {
await page.setContent(`
<ion-toggle color="danger">Label</ion-toggle>
`);

const toggle = page.locator('ion-toggle');
expect(await toggle.screenshot()).toMatchSnapshot(`toggle-color-unchecked-${page.getSnapshotSettings()}.png`);
});
});
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 16 additions & 32 deletions core/src/components/toggle/test/enable-on-off-labels/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,83 +188,67 @@
<ion-content>
<ion-list>
<ion-item>
<ion-label>Unchecked</ion-label>
<ion-toggle slot="end" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" enable-on-off-labels="true">Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Checked</ion-label>
<ion-toggle slot="end" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" enable-on-off-labels="true" checked>Checked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Secondary Unchecked</ion-label>
<ion-toggle slot="end" color="secondary" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" color="secondary" enable-on-off-labels="true">Secondary Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Secondary Checked</ion-label>
<ion-toggle slot="end" color="secondary" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" color="secondary" enable-on-off-labels="true" checked>Secondary Checked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Success Unchecked</ion-label>
<ion-toggle slot="end" color="success" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" color="success" enable-on-off-labels="true">Success Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Success Checked</ion-label>
<ion-toggle slot="end" color="success" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" color="success" enable-on-off-labels="true" checked>Success Checked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Danger Unchecked</ion-label>
<ion-toggle slot="end" color="danger" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" color="danger" enable-on-off-labels="true">Danger Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Danger Checked</ion-label>
<ion-toggle slot="end" color="danger" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" color="danger" enable-on-off-labels="true" checked>Danger Checked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Tertiary Unchecked</ion-label>
<ion-toggle slot="end" color="tertiary" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" color="tertiary" enable-on-off-labels="true">Tertiary Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Tertiary Checked</ion-label>
<ion-toggle slot="end" color="tertiary" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" color="tertiary" enable-on-off-labels="true" checked>Tertiary Checked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Light Unchecked</ion-label>
<ion-toggle slot="end" color="light" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" color="light" enable-on-off-labels="true">Light Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Light Checked</ion-label>
<ion-toggle slot="end" color="light" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" color="light" enable-on-off-labels="true" checked>Light Checked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Medium Unchecked</ion-label>
<ion-toggle slot="end" color="medium" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" color="medium" enable-on-off-labels="true">Medium Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Medium Checked</ion-label>
<ion-toggle slot="end" color="medium" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" color="medium" enable-on-off-labels="true" checked>Medium Checked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Dark Unchecked</ion-label>
<ion-toggle slot="end" color="dark" enable-on-off-labels="true"></ion-toggle>
<ion-toggle slot="end" color="dark" enable-on-off-labels="true">Dark Unchecked</ion-toggle>
</ion-item>

<ion-item>
<ion-label>Dark Checked</ion-label>
<ion-toggle slot="end" color="dark" enable-on-off-labels="true" checked></ion-toggle>
<ion-toggle slot="end" color="dark" enable-on-off-labels="true" checked>Dark Checked</ion-toggle>
</ion-item>
</ion-list>
</ion-content>
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c74901c

Please sign in to comment.