Skip to content

Commit bc0bdc4

Browse files
authored
feat(toggle): on/off icons for toggle (#25459)
Resolves #20524
1 parent 7cdc388 commit bc0bdc4

File tree

33 files changed

+493
-21
lines changed

33 files changed

+493
-21
lines changed

core/src/components.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,10 @@ export namespace Components {
29832983
* If `true`, the user cannot interact with the toggle.
29842984
*/
29852985
"disabled": boolean;
2986+
/**
2987+
* Enables the on/off accessibility switch labels within the toggle.
2988+
*/
2989+
"enableOnOffLabels": boolean | undefined;
29862990
/**
29872991
* The mode determines which platform styles to use.
29882992
*/
@@ -6935,6 +6939,10 @@ declare namespace LocalJSX {
69356939
* If `true`, the user cannot interact with the toggle.
69366940
*/
69376941
"disabled"?: boolean;
6942+
/**
6943+
* Enables the on/off accessibility switch labels within the toggle.
6944+
*/
6945+
"enableOnOffLabels"?: boolean | undefined;
69386946
/**
69396947
* The mode determines which platform styles to use.
69406948
*/
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
<!DOCTYPE html>
2+
<html lang="en" dir="ltr">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Toggle - enableOnOffLabels</title>
6+
<meta
7+
name="viewport"
8+
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
9+
/>
10+
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
11+
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
12+
<script src="../../../../../scripts/testing/scripts.js"></script>
13+
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
14+
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
15+
16+
<style>
17+
/*
18+
* Dark Colors
19+
* ------------------
20+
*/
21+
22+
body.dark {
23+
--ion-color-primary: #428cff;
24+
--ion-color-primary-rgb: 66, 140, 255;
25+
--ion-color-primary-contrast: #ffffff;
26+
--ion-color-primary-contrast-rgb: 255, 255, 255;
27+
--ion-color-primary-shade: #3a7be0;
28+
--ion-color-primary-tint: #5598ff;
29+
30+
--ion-color-secondary: #50c8ff;
31+
--ion-color-secondary-rgb: 80, 200, 255;
32+
--ion-color-secondary-contrast: #ffffff;
33+
--ion-color-secondary-contrast-rgb: 255, 255, 255;
34+
--ion-color-secondary-shade: #46b0e0;
35+
--ion-color-secondary-tint: #62ceff;
36+
37+
--ion-color-tertiary: #6a64ff;
38+
--ion-color-tertiary-rgb: 106, 100, 255;
39+
--ion-color-tertiary-contrast: #ffffff;
40+
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
41+
--ion-color-tertiary-shade: #5d58e0;
42+
--ion-color-tertiary-tint: #7974ff;
43+
44+
--ion-color-success: #2fdf75;
45+
--ion-color-success-rgb: 47, 223, 117;
46+
--ion-color-success-contrast: #000000;
47+
--ion-color-success-contrast-rgb: 0, 0, 0;
48+
--ion-color-success-shade: #29c467;
49+
--ion-color-success-tint: #44e283;
50+
51+
--ion-color-warning: #ffd534;
52+
--ion-color-warning-rgb: 255, 213, 52;
53+
--ion-color-warning-contrast: #000000;
54+
--ion-color-warning-contrast-rgb: 0, 0, 0;
55+
--ion-color-warning-shade: #e0bb2e;
56+
--ion-color-warning-tint: #ffd948;
57+
58+
--ion-color-danger: #ff4961;
59+
--ion-color-danger-rgb: 255, 73, 97;
60+
--ion-color-danger-contrast: #ffffff;
61+
--ion-color-danger-contrast-rgb: 255, 255, 255;
62+
--ion-color-danger-shade: #e04055;
63+
--ion-color-danger-tint: #ff5b71;
64+
65+
--ion-color-dark: #f4f5f8;
66+
--ion-color-dark-rgb: 244, 245, 248;
67+
--ion-color-dark-contrast: #000000;
68+
--ion-color-dark-contrast-rgb: 0, 0, 0;
69+
--ion-color-dark-shade: #d7d8da;
70+
--ion-color-dark-tint: #f5f6f9;
71+
72+
--ion-color-medium: #989aa2;
73+
--ion-color-medium-rgb: 152, 154, 162;
74+
--ion-color-medium-contrast: #000000;
75+
--ion-color-medium-contrast-rgb: 0, 0, 0;
76+
--ion-color-medium-shade: #86888f;
77+
--ion-color-medium-tint: #a2a4ab;
78+
79+
--ion-color-light: #222428;
80+
--ion-color-light-rgb: 34, 36, 40;
81+
--ion-color-light-contrast: #ffffff;
82+
--ion-color-light-contrast-rgb: 255, 255, 255;
83+
--ion-color-light-shade: #1e2023;
84+
--ion-color-light-tint: #383a3e;
85+
}
86+
87+
/*
88+
* iOS Dark Theme
89+
* -------------------
90+
*/
91+
92+
.ios body.dark {
93+
--ion-background-color: #000000;
94+
--ion-background-color-rgb: 0, 0, 0;
95+
96+
--ion-text-color: #ffffff;
97+
--ion-text-color-rgb: 255, 255, 255;
98+
99+
--ion-color-step-50: #0d0d0d;
100+
--ion-color-step-100: #1a1a1a;
101+
--ion-color-step-150: #262626;
102+
--ion-color-step-200: #333333;
103+
--ion-color-step-250: #404040;
104+
--ion-color-step-300: #4d4d4d;
105+
--ion-color-step-350: #595959;
106+
--ion-color-step-400: #666666;
107+
--ion-color-step-450: #737373;
108+
--ion-color-step-500: #808080;
109+
--ion-color-step-550: #8c8c8c;
110+
--ion-color-step-600: #999999;
111+
--ion-color-step-650: #a6a6a6;
112+
--ion-color-step-700: #b3b3b3;
113+
--ion-color-step-750: #bfbfbf;
114+
--ion-color-step-800: #cccccc;
115+
--ion-color-step-850: #d9d9d9;
116+
--ion-color-step-900: #e6e6e6;
117+
--ion-color-step-950: #f2f2f2;
118+
119+
--ion-toolbar-background: #0d0d0d;
120+
121+
--ion-item-background: #1c1c1c;
122+
--ion-item-background-activated: #313131;
123+
}
124+
125+
/*
126+
* Material Design Dark Theme
127+
* ------------------------------
128+
*/
129+
130+
.md body.dark {
131+
--ion-background-color: #121212;
132+
--ion-background-color-rgb: 18, 18, 18;
133+
134+
--ion-text-color: #ffffff;
135+
--ion-text-color-rgb: 255, 255, 255;
136+
137+
--ion-border-color: #222222;
138+
139+
--ion-color-step-50: #1e1e1e;
140+
--ion-color-step-100: #2a2a2a;
141+
--ion-color-step-150: #363636;
142+
--ion-color-step-200: #414141;
143+
--ion-color-step-250: #4d4d4d;
144+
--ion-color-step-300: #595959;
145+
--ion-color-step-350: #656565;
146+
--ion-color-step-400: #717171;
147+
--ion-color-step-450: #7d7d7d;
148+
--ion-color-step-500: #898989;
149+
--ion-color-step-550: #949494;
150+
--ion-color-step-600: #a0a0a0;
151+
--ion-color-step-650: #acacac;
152+
--ion-color-step-700: #b8b8b8;
153+
--ion-color-step-750: #c4c4c4;
154+
--ion-color-step-800: #d0d0d0;
155+
--ion-color-step-850: #dbdbdb;
156+
--ion-color-step-900: #e7e7e7;
157+
--ion-color-step-950: #f3f3f3;
158+
159+
--ion-item-background: #1a1b1e;
160+
}
161+
162+
/* Optional CSS, this is added for the flashing that happens when toggling between themes */
163+
ion-item {
164+
--transition: none;
165+
}
166+
</style>
167+
</head>
168+
169+
<body>
170+
<ion-app>
171+
<ion-header>
172+
<ion-toolbar>
173+
<ion-title>Toggle - enableOnOffLabels</ion-title>
174+
<ion-buttons slot="end">
175+
<ion-button id="popover-trigger">Options</ion-button>
176+
</ion-buttons>
177+
<ion-popover class="options-popover" trigger="popover-trigger">
178+
<ion-list lines="none">
179+
<ion-item id="dark-mode">
180+
<ion-label>Dark Mode</ion-label>
181+
<ion-checkbox slot="end"></ion-checkbox>
182+
</ion-item>
183+
</ion-list>
184+
</ion-popover>
185+
</ion-toolbar>
186+
</ion-header>
187+
188+
<ion-content>
189+
<ion-list>
190+
<ion-item>
191+
<ion-label>Unchecked</ion-label>
192+
<ion-toggle slot="end" enable-on-off-labels="true"></ion-toggle>
193+
</ion-item>
194+
195+
<ion-item>
196+
<ion-label>Checked</ion-label>
197+
<ion-toggle slot="end" enable-on-off-labels="true" checked></ion-toggle>
198+
</ion-item>
199+
200+
<ion-item>
201+
<ion-label>Secondary Unchecked</ion-label>
202+
<ion-toggle slot="end" color="secondary" enable-on-off-labels="true"></ion-toggle>
203+
</ion-item>
204+
205+
<ion-item>
206+
<ion-label>Secondary Checked</ion-label>
207+
<ion-toggle slot="end" color="secondary" enable-on-off-labels="true" checked></ion-toggle>
208+
</ion-item>
209+
210+
<ion-item>
211+
<ion-label>Success Unchecked</ion-label>
212+
<ion-toggle slot="end" color="success" enable-on-off-labels="true"></ion-toggle>
213+
</ion-item>
214+
215+
<ion-item>
216+
<ion-label>Success Checked</ion-label>
217+
<ion-toggle slot="end" color="success" enable-on-off-labels="true" checked></ion-toggle>
218+
</ion-item>
219+
220+
<ion-item>
221+
<ion-label>Danger Unchecked</ion-label>
222+
<ion-toggle slot="end" color="danger" enable-on-off-labels="true"></ion-toggle>
223+
</ion-item>
224+
225+
<ion-item>
226+
<ion-label>Danger Checked</ion-label>
227+
<ion-toggle slot="end" color="danger" enable-on-off-labels="true" checked></ion-toggle>
228+
</ion-item>
229+
230+
<ion-item>
231+
<ion-label>Tertiary Unchecked</ion-label>
232+
<ion-toggle slot="end" color="tertiary" enable-on-off-labels="true"></ion-toggle>
233+
</ion-item>
234+
235+
<ion-item>
236+
<ion-label>Tertiary Checked</ion-label>
237+
<ion-toggle slot="end" color="tertiary" enable-on-off-labels="true" checked></ion-toggle>
238+
</ion-item>
239+
240+
<ion-item>
241+
<ion-label>Light Unchecked</ion-label>
242+
<ion-toggle slot="end" color="light" enable-on-off-labels="true"></ion-toggle>
243+
</ion-item>
244+
245+
<ion-item>
246+
<ion-label>Light Checked</ion-label>
247+
<ion-toggle slot="end" color="light" enable-on-off-labels="true" checked></ion-toggle>
248+
</ion-item>
249+
250+
<ion-item>
251+
<ion-label>Medium Unchecked</ion-label>
252+
<ion-toggle slot="end" color="medium" enable-on-off-labels="true"></ion-toggle>
253+
</ion-item>
254+
255+
<ion-item>
256+
<ion-label>Medium Checked</ion-label>
257+
<ion-toggle slot="end" color="medium" enable-on-off-labels="true" checked></ion-toggle>
258+
</ion-item>
259+
260+
<ion-item>
261+
<ion-label>Dark Unchecked</ion-label>
262+
<ion-toggle slot="end" color="dark" enable-on-off-labels="true"></ion-toggle>
263+
</ion-item>
264+
265+
<ion-item>
266+
<ion-label>Dark Checked</ion-label>
267+
<ion-toggle slot="end" color="dark" enable-on-off-labels="true" checked></ion-toggle>
268+
</ion-item>
269+
</ion-list>
270+
</ion-content>
271+
</ion-app>
272+
273+
<script>
274+
const darkModeCheckbox = document.querySelector('ion-checkbox');
275+
darkModeCheckbox.addEventListener('ionChange', (ev) => {
276+
if (ev.detail.checked) {
277+
document.body.classList.add('dark');
278+
} else {
279+
document.body.classList.remove('dark');
280+
}
281+
});
282+
</script>
283+
</body>
284+
</html>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { expect } from '@playwright/test';
2+
import { test } from '@utils/test/playwright';
3+
4+
test.describe('toggle: enableOnOffLabels', () => {
5+
test.beforeEach(async ({ page }) => {
6+
await page.goto(`/src/components/toggle/test/enable-on-off-labels`);
7+
});
8+
9+
test('should not have visual regressions', async ({ page }) => {
10+
await page.setIonViewport();
11+
12+
expect(await page.screenshot()).toMatchSnapshot(`toggle-on-off-labels-diff-${page.getSnapshotSettings()}.png`);
13+
});
14+
15+
test.describe('dark mode', () => {
16+
test('should not have visual regressions', async ({ page }) => {
17+
const ionPopoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent');
18+
const ionPopoverDidDismiss = await page.spyOnEvent('ionPopoverDidDismiss');
19+
20+
await page.click('#popover-trigger');
21+
await ionPopoverDidPresent.next();
22+
23+
await page.click('#dark-mode');
24+
25+
await page.evaluate(() => {
26+
const popover = document.querySelector('ion-popover');
27+
return popover?.dismiss();
28+
});
29+
await ionPopoverDidDismiss.next();
30+
31+
await page.waitForChanges();
32+
33+
await page.setIonViewport();
34+
35+
expect(await page.screenshot()).toMatchSnapshot(
36+
`toggle-on-off-labels-dark-mode-diff-${page.getSnapshotSettings()}.png`
37+
);
38+
});
39+
});
40+
});

0 commit comments

Comments
 (0)