8
core/src/components.d.ts
vendored
@ -2983,6 +2983,10 @@ export namespace Components {
|
||||
* If `true`, the user cannot interact with the toggle.
|
||||
*/
|
||||
"disabled": boolean;
|
||||
/**
|
||||
* Enables the on/off accessibility switch labels within the toggle.
|
||||
*/
|
||||
"enableOnOffLabels": boolean | undefined;
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
@ -6935,6 +6939,10 @@ declare namespace LocalJSX {
|
||||
* If `true`, the user cannot interact with the toggle.
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* Enables the on/off accessibility switch labels within the toggle.
|
||||
*/
|
||||
"enableOnOffLabels"?: boolean | undefined;
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
|
284
core/src/components/toggle/test/enable-on-off-labels/index.html
Normal file
@ -0,0 +1,284 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Toggle - enableOnOffLabels</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<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>
|
||||
|
||||
<style>
|
||||
/*
|
||||
* Dark Colors
|
||||
* ------------------
|
||||
*/
|
||||
|
||||
body.dark {
|
||||
--ion-color-primary: #428cff;
|
||||
--ion-color-primary-rgb: 66, 140, 255;
|
||||
--ion-color-primary-contrast: #ffffff;
|
||||
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-primary-shade: #3a7be0;
|
||||
--ion-color-primary-tint: #5598ff;
|
||||
|
||||
--ion-color-secondary: #50c8ff;
|
||||
--ion-color-secondary-rgb: 80, 200, 255;
|
||||
--ion-color-secondary-contrast: #ffffff;
|
||||
--ion-color-secondary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-secondary-shade: #46b0e0;
|
||||
--ion-color-secondary-tint: #62ceff;
|
||||
|
||||
--ion-color-tertiary: #6a64ff;
|
||||
--ion-color-tertiary-rgb: 106, 100, 255;
|
||||
--ion-color-tertiary-contrast: #ffffff;
|
||||
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-tertiary-shade: #5d58e0;
|
||||
--ion-color-tertiary-tint: #7974ff;
|
||||
|
||||
--ion-color-success: #2fdf75;
|
||||
--ion-color-success-rgb: 47, 223, 117;
|
||||
--ion-color-success-contrast: #000000;
|
||||
--ion-color-success-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-success-shade: #29c467;
|
||||
--ion-color-success-tint: #44e283;
|
||||
|
||||
--ion-color-warning: #ffd534;
|
||||
--ion-color-warning-rgb: 255, 213, 52;
|
||||
--ion-color-warning-contrast: #000000;
|
||||
--ion-color-warning-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-warning-shade: #e0bb2e;
|
||||
--ion-color-warning-tint: #ffd948;
|
||||
|
||||
--ion-color-danger: #ff4961;
|
||||
--ion-color-danger-rgb: 255, 73, 97;
|
||||
--ion-color-danger-contrast: #ffffff;
|
||||
--ion-color-danger-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-danger-shade: #e04055;
|
||||
--ion-color-danger-tint: #ff5b71;
|
||||
|
||||
--ion-color-dark: #f4f5f8;
|
||||
--ion-color-dark-rgb: 244, 245, 248;
|
||||
--ion-color-dark-contrast: #000000;
|
||||
--ion-color-dark-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-dark-shade: #d7d8da;
|
||||
--ion-color-dark-tint: #f5f6f9;
|
||||
|
||||
--ion-color-medium: #989aa2;
|
||||
--ion-color-medium-rgb: 152, 154, 162;
|
||||
--ion-color-medium-contrast: #000000;
|
||||
--ion-color-medium-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-medium-shade: #86888f;
|
||||
--ion-color-medium-tint: #a2a4ab;
|
||||
|
||||
--ion-color-light: #222428;
|
||||
--ion-color-light-rgb: 34, 36, 40;
|
||||
--ion-color-light-contrast: #ffffff;
|
||||
--ion-color-light-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-light-shade: #1e2023;
|
||||
--ion-color-light-tint: #383a3e;
|
||||
}
|
||||
|
||||
/*
|
||||
* iOS Dark Theme
|
||||
* -------------------
|
||||
*/
|
||||
|
||||
.ios body.dark {
|
||||
--ion-background-color: #000000;
|
||||
--ion-background-color-rgb: 0, 0, 0;
|
||||
|
||||
--ion-text-color: #ffffff;
|
||||
--ion-text-color-rgb: 255, 255, 255;
|
||||
|
||||
--ion-color-step-50: #0d0d0d;
|
||||
--ion-color-step-100: #1a1a1a;
|
||||
--ion-color-step-150: #262626;
|
||||
--ion-color-step-200: #333333;
|
||||
--ion-color-step-250: #404040;
|
||||
--ion-color-step-300: #4d4d4d;
|
||||
--ion-color-step-350: #595959;
|
||||
--ion-color-step-400: #666666;
|
||||
--ion-color-step-450: #737373;
|
||||
--ion-color-step-500: #808080;
|
||||
--ion-color-step-550: #8c8c8c;
|
||||
--ion-color-step-600: #999999;
|
||||
--ion-color-step-650: #a6a6a6;
|
||||
--ion-color-step-700: #b3b3b3;
|
||||
--ion-color-step-750: #bfbfbf;
|
||||
--ion-color-step-800: #cccccc;
|
||||
--ion-color-step-850: #d9d9d9;
|
||||
--ion-color-step-900: #e6e6e6;
|
||||
--ion-color-step-950: #f2f2f2;
|
||||
|
||||
--ion-toolbar-background: #0d0d0d;
|
||||
|
||||
--ion-item-background: #1c1c1c;
|
||||
--ion-item-background-activated: #313131;
|
||||
}
|
||||
|
||||
/*
|
||||
* Material Design Dark Theme
|
||||
* ------------------------------
|
||||
*/
|
||||
|
||||
.md body.dark {
|
||||
--ion-background-color: #121212;
|
||||
--ion-background-color-rgb: 18, 18, 18;
|
||||
|
||||
--ion-text-color: #ffffff;
|
||||
--ion-text-color-rgb: 255, 255, 255;
|
||||
|
||||
--ion-border-color: #222222;
|
||||
|
||||
--ion-color-step-50: #1e1e1e;
|
||||
--ion-color-step-100: #2a2a2a;
|
||||
--ion-color-step-150: #363636;
|
||||
--ion-color-step-200: #414141;
|
||||
--ion-color-step-250: #4d4d4d;
|
||||
--ion-color-step-300: #595959;
|
||||
--ion-color-step-350: #656565;
|
||||
--ion-color-step-400: #717171;
|
||||
--ion-color-step-450: #7d7d7d;
|
||||
--ion-color-step-500: #898989;
|
||||
--ion-color-step-550: #949494;
|
||||
--ion-color-step-600: #a0a0a0;
|
||||
--ion-color-step-650: #acacac;
|
||||
--ion-color-step-700: #b8b8b8;
|
||||
--ion-color-step-750: #c4c4c4;
|
||||
--ion-color-step-800: #d0d0d0;
|
||||
--ion-color-step-850: #dbdbdb;
|
||||
--ion-color-step-900: #e7e7e7;
|
||||
--ion-color-step-950: #f3f3f3;
|
||||
|
||||
--ion-item-background: #1a1b1e;
|
||||
}
|
||||
|
||||
/* Optional CSS, this is added for the flashing that happens when toggling between themes */
|
||||
ion-item {
|
||||
--transition: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Toggle - enableOnOffLabels</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button id="popover-trigger">Options</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-popover class="options-popover" trigger="popover-trigger">
|
||||
<ion-list lines="none">
|
||||
<ion-item id="dark-mode">
|
||||
<ion-label>Dark Mode</ion-label>
|
||||
<ion-checkbox slot="end"></ion-checkbox>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</ion-popover>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Unchecked</ion-label>
|
||||
<ion-toggle slot="end" enable-on-off-labels="true"></ion-toggle>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Checked</ion-label>
|
||||
<ion-toggle slot="end" enable-on-off-labels="true" 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-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Secondary Checked</ion-label>
|
||||
<ion-toggle slot="end" color="secondary" enable-on-off-labels="true" 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-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Success Checked</ion-label>
|
||||
<ion-toggle slot="end" color="success" enable-on-off-labels="true" 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-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Danger Checked</ion-label>
|
||||
<ion-toggle slot="end" color="danger" enable-on-off-labels="true" 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-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Tertiary Checked</ion-label>
|
||||
<ion-toggle slot="end" color="tertiary" enable-on-off-labels="true" 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-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Light Checked</ion-label>
|
||||
<ion-toggle slot="end" color="light" enable-on-off-labels="true" 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-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Medium Checked</ion-label>
|
||||
<ion-toggle slot="end" color="medium" enable-on-off-labels="true" 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-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Dark Checked</ion-label>
|
||||
<ion-toggle slot="end" color="dark" enable-on-off-labels="true" checked></ion-toggle>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
const darkModeCheckbox = document.querySelector('ion-checkbox');
|
||||
darkModeCheckbox.addEventListener('ionChange', (ev) => {
|
||||
if (ev.detail.checked) {
|
||||
document.body.classList.add('dark');
|
||||
} else {
|
||||
document.body.classList.remove('dark');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,40 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { test } from '@utils/test/playwright';
|
||||
|
||||
test.describe('toggle: enableOnOffLabels', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(`/src/components/toggle/test/enable-on-off-labels`);
|
||||
});
|
||||
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.setIonViewport();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(`toggle-on-off-labels-diff-${page.getSnapshotSettings()}.png`);
|
||||
});
|
||||
|
||||
test.describe('dark mode', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
const ionPopoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent');
|
||||
const ionPopoverDidDismiss = await page.spyOnEvent('ionPopoverDidDismiss');
|
||||
|
||||
await page.click('#popover-trigger');
|
||||
await ionPopoverDidPresent.next();
|
||||
|
||||
await page.click('#dark-mode');
|
||||
|
||||
await page.evaluate(() => {
|
||||
const popover = document.querySelector('ion-popover');
|
||||
return popover?.dismiss();
|
||||
});
|
||||
await ionPopoverDidDismiss.next();
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await page.setIonViewport();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(
|
||||
`toggle-on-off-labels-dark-mode-diff-${page.getSnapshotSettings()}.png`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
After Width: | Height: | Size: 260 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 252 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 201 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 173 KiB |
After Width: | Height: | Size: 200 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 172 KiB |
After Width: | Height: | Size: 257 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 213 KiB |
After Width: | Height: | Size: 248 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 198 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 198 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 175 KiB |
@ -30,6 +30,9 @@
|
||||
background: current-color(base);
|
||||
}
|
||||
|
||||
:host(.toggle-activated) .toggle-switch-icon {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// iOS Toggle Background Track: Unchecked
|
||||
// ----------------------------------------------------------
|
||||
@ -42,7 +45,6 @@
|
||||
transition: background-color $toggle-ios-transition-duration;
|
||||
}
|
||||
|
||||
|
||||
// iOS Toggle Inner Knob: Unchecked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
@ -50,6 +52,70 @@
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
// iOS Toggle On/Off Labels
|
||||
// ----------------------------------------------------------
|
||||
|
||||
.toggle-switch-icon {
|
||||
position: absolute;
|
||||
|
||||
top: 50%;
|
||||
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
|
||||
transform: translateY(-50%);
|
||||
|
||||
transition: opacity $toggle-ios-transition-duration, color $toggle-ios-transition-duration;
|
||||
}
|
||||
|
||||
.toggle-switch-icon {
|
||||
@include ltr() {
|
||||
/* stylelint-disable-next-line property-disallowed-list */
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
@include rtl() {
|
||||
/* stylelint-disable property-disallowed-list */
|
||||
right: initial;
|
||||
left: 6px;
|
||||
/* stylelint-enable property-disallowed-list */
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
|
||||
color: var(--ion-color-dark);
|
||||
}
|
||||
|
||||
:host(.toggle-checked) .toggle-switch-icon.toggle-switch-icon-checked {
|
||||
// The color contrast of iOS default on/off labels fails to meet WCAG 2.0.
|
||||
// We use Ionic's color contrast variables to meet the WCAG 2.0 standard (AAA).
|
||||
color: var(--ion-color-contrast, $toggle-ios-on-off-label-checked-color);
|
||||
}
|
||||
|
||||
:host(.toggle-checked) .toggle-switch-icon:not(.toggle-switch-icon-checked) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.toggle-switch-icon-checked {
|
||||
@include ltr() {
|
||||
/* stylelint-disable property-disallowed-list */
|
||||
right: initial;
|
||||
left: 4px;
|
||||
/* stylelint-enable property-disallowed-list */
|
||||
}
|
||||
|
||||
@include rtl() {
|
||||
/* stylelint-disable-next-line property-disallowed-list */
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
|
||||
transform: translateY(-50%) rotate(90deg);
|
||||
}
|
||||
|
||||
// iOS Toggle Background Oval: Activated or Checked
|
||||
// ----------------------------------------------------------
|
||||
@ -59,7 +125,6 @@
|
||||
transform: scale3d(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
// iOS Toggle Background Oval: Activated and Checked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
@ -67,7 +132,6 @@
|
||||
transform: scale3d(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
// iOS Toggle Inner Knob: Activated and Unchecked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
@ -75,7 +139,6 @@
|
||||
width: calc(var(--handle-width) + 6px);
|
||||
}
|
||||
|
||||
|
||||
// iOS Toggle Inner Knob: Activated and Checked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
@ -93,25 +156,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// iOS Toggle: Disabled
|
||||
// ----------------------------------------------------------
|
||||
|
||||
// .item-ios.item-toggle-disabled ion-label
|
||||
|
||||
:host(.toggle-disabled) {
|
||||
opacity: $toggle-ios-disabled-opacity;
|
||||
}
|
||||
|
||||
|
||||
// iOS Toggle Within An Item
|
||||
// ----------------------------------------------------------
|
||||
|
||||
:host(.in-item[slot]) {
|
||||
@include margin($toggle-ios-media-margin);
|
||||
@include padding($toggle-ios-item-end-padding-top, $toggle-ios-item-end-padding-end, $toggle-ios-item-end-padding-bottom, $toggle-ios-item-end-padding-start);
|
||||
@include padding(
|
||||
$toggle-ios-item-end-padding-top,
|
||||
$toggle-ios-item-end-padding-end,
|
||||
$toggle-ios-item-end-padding-bottom,
|
||||
$toggle-ios-item-end-padding-start
|
||||
);
|
||||
}
|
||||
|
||||
:host(.in-item[slot="start"]) {
|
||||
@include padding($toggle-ios-item-start-padding-top, $toggle-ios-item-start-padding-end, $toggle-ios-item-start-padding-bottom, $toggle-ios-item-start-padding-start);
|
||||
@include padding(
|
||||
$toggle-ios-item-start-padding-top,
|
||||
$toggle-ios-item-start-padding-end,
|
||||
$toggle-ios-item-start-padding-bottom,
|
||||
$toggle-ios-item-start-padding-start
|
||||
);
|
||||
}
|
||||
|
@ -75,3 +75,6 @@ $toggle-ios-item-end-padding-bottom: 5px !default;
|
||||
|
||||
/// @prop - Padding start of the toggle positioned on the end in an item
|
||||
$toggle-ios-item-end-padding-start: $item-ios-padding-start !default;
|
||||
|
||||
/// @prop - The text color of the on/off labels when the toggle is checked
|
||||
$toggle-ios-on-off-label-checked-color: #fff !default;
|
@ -34,6 +34,10 @@
|
||||
background: current-color(base);
|
||||
}
|
||||
|
||||
:host(.toggle-checked) .toggle-inner {
|
||||
color: var(--ion-color-contrast, $toggle-md-on-off-label-checked-color);
|
||||
}
|
||||
|
||||
// Material Design Toggle Background Track: Unchecked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
@ -41,14 +45,26 @@
|
||||
transition: background-color $toggle-md-transition-duration;
|
||||
}
|
||||
|
||||
|
||||
// Material Design Toggle Inner Knob: Unchecked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
.toggle-inner {
|
||||
will-change: background-color, transform;
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
color: $toggle-md-on-off-label-color;
|
||||
}
|
||||
|
||||
.toggle-inner .toggle-switch-icon {
|
||||
@include padding(1px);
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// Material Design Toggle: Disabled
|
||||
// ----------------------------------------------------------
|
||||
@ -68,17 +84,31 @@
|
||||
// opacity: $toggle-md-disabled-opacity;
|
||||
// }
|
||||
|
||||
|
||||
// Material Design Toggle Within An Item
|
||||
// ----------------------------------------------------------
|
||||
|
||||
:host(.in-item[slot]) {
|
||||
@include margin($toggle-md-media-margin-top, $toggle-md-media-margin-end, $toggle-md-media-margin-bottom, $toggle-md-media-margin-start);
|
||||
@include padding($toggle-md-item-end-padding-top, $toggle-md-item-end-padding-end, $toggle-md-item-end-padding-bottom, $toggle-md-item-end-padding-start);
|
||||
@include margin(
|
||||
$toggle-md-media-margin-top,
|
||||
$toggle-md-media-margin-end,
|
||||
$toggle-md-media-margin-bottom,
|
||||
$toggle-md-media-margin-start
|
||||
);
|
||||
@include padding(
|
||||
$toggle-md-item-end-padding-top,
|
||||
$toggle-md-item-end-padding-end,
|
||||
$toggle-md-item-end-padding-bottom,
|
||||
$toggle-md-item-end-padding-start
|
||||
);
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:host(.in-item[slot="start"]) {
|
||||
@include padding($toggle-md-item-start-padding-top, $toggle-md-item-start-padding-end, $toggle-md-item-start-padding-bottom, $toggle-md-item-start-padding-start);
|
||||
@include padding(
|
||||
$toggle-md-item-start-padding-top,
|
||||
$toggle-md-item-start-padding-end,
|
||||
$toggle-md-item-start-padding-bottom,
|
||||
$toggle-md-item-start-padding-start
|
||||
);
|
||||
}
|
||||
|
@ -99,3 +99,9 @@ $toggle-md-item-end-padding-bottom: 12px !default;
|
||||
|
||||
/// @prop - Padding start of the toggle positioned on the end in an item
|
||||
$toggle-md-item-end-padding-start: $item-md-padding-start !default;
|
||||
|
||||
/// @prop - The text color of the on/off labels
|
||||
$toggle-md-on-off-label-color: #000 !default;
|
||||
|
||||
/// @prop - The text color of the on/off labels when the toggle is checked
|
||||
$toggle-md-on-off-label-checked-color: #fff !default;
|
||||
|
@ -83,6 +83,7 @@ input {
|
||||
@include border-radius(var(--border-radius));
|
||||
|
||||
display: block;
|
||||
|
||||
position: relative;
|
||||
|
||||
width: 100%;
|
||||
@ -95,7 +96,6 @@ input {
|
||||
overflow: inherit;
|
||||
}
|
||||
|
||||
|
||||
// Toggle Background Track: Checked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
@ -103,7 +103,6 @@ input {
|
||||
background: var(--background-checked);
|
||||
}
|
||||
|
||||
|
||||
// Toggle Inner Knob: Unchecked
|
||||
// --------------------------------------------------
|
||||
|
||||
@ -127,7 +126,6 @@ input {
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
|
||||
// Toggle Inner Knob: Checked
|
||||
// ----------------------------------------------------------
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { Component, Element, Event, Host, Prop, State, Watch, h } from '@stencil/core';
|
||||
import { checkmarkOutline, removeOutline, ellipseOutline } from 'ionicons/icons';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import type { Color, Gesture, GestureDetail, StyleEventDetail, ToggleChangeEventDetail } from '../../interface';
|
||||
import type { Color, Gesture, GestureDetail, Mode, StyleEventDetail, ToggleChangeEventDetail } from '../../interface';
|
||||
import { getAriaLabel, renderHiddenInput } from '../../utils/helpers';
|
||||
import { hapticSelection } from '../../utils/native/haptic';
|
||||
import { isRTL } from '../../utils/rtl';
|
||||
@ -63,6 +64,11 @@ export class Toggle implements ComponentInterface {
|
||||
*/
|
||||
@Prop() value?: string | null = 'on';
|
||||
|
||||
/**
|
||||
* Enables the on/off accessibility switch labels within the toggle.
|
||||
*/
|
||||
@Prop() enableOnOffLabels: boolean | undefined = undefined;
|
||||
|
||||
/**
|
||||
* Emitted when the value property has changed.
|
||||
*/
|
||||
@ -178,8 +184,29 @@ export class Toggle implements ComponentInterface {
|
||||
this.ionBlur.emit();
|
||||
};
|
||||
|
||||
private getSwitchLabelIcon = (mode: Mode, checked: boolean) => {
|
||||
if (mode === 'md') {
|
||||
return checked ? checkmarkOutline : removeOutline;
|
||||
}
|
||||
return checked ? removeOutline : ellipseOutline;
|
||||
};
|
||||
|
||||
private renderOnOffSwitchLabels(mode: Mode, checked: boolean) {
|
||||
const icon = this.getSwitchLabelIcon(mode, checked);
|
||||
|
||||
return (
|
||||
<ion-icon
|
||||
class={{
|
||||
'toggle-switch-icon': true,
|
||||
'toggle-switch-icon-checked': checked,
|
||||
}}
|
||||
icon={icon}
|
||||
></ion-icon>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { activated, color, checked, disabled, el, inputId, name } = this;
|
||||
const { activated, color, checked, disabled, el, inputId, name, enableOnOffLabels } = this;
|
||||
const mode = getIonMode(this);
|
||||
const { label, labelId, labelText } = getAriaLabel(el, inputId);
|
||||
const value = this.getValue();
|
||||
@ -203,8 +230,15 @@ export class Toggle implements ComponentInterface {
|
||||
})}
|
||||
>
|
||||
<div class="toggle-icon" part="track">
|
||||
{/* The iOS on/off labels are rendered outside of .toggle-icon-wrapper,
|
||||
since the wrapper is translated when the handle is interacted with and
|
||||
this would move the on/off labels outside of the view box */}
|
||||
{enableOnOffLabels &&
|
||||
mode === 'ios' && [this.renderOnOffSwitchLabels(mode, true), this.renderOnOffSwitchLabels(mode, false)]}
|
||||
<div class="toggle-icon-wrapper">
|
||||
<div class="toggle-inner" part="handle" />
|
||||
<div class="toggle-inner" part="handle">
|
||||
{enableOnOffLabels && mode === 'md' && this.renderOnOffSwitchLabels(mode, checked)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label htmlFor={inputId}>{labelText}</label>
|
||||
|