Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,7 @@ ion-toast,part,wrapper
ion-toggle,shadow
ion-toggle,prop,alignment,"center" | "start" | undefined,undefined,false,false
ion-toggle,prop,checked,boolean,false,false,false
ion-toggle,prop,checkedIcon,null | string | undefined,undefined,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,config.get('toggleOnOffLabels'),false,false
Expand All @@ -2078,6 +2079,7 @@ ion-toggle,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',fal
ion-toggle,prop,mode,"ios" | "md",undefined,false,false
ion-toggle,prop,name,string,this.inputId,false,false
ion-toggle,prop,required,boolean,false,false,false
ion-toggle,prop,uncheckedIcon,null | string | undefined,undefined,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
Expand Down
18 changes: 18 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3700,6 +3700,10 @@ export namespace Components {
* @default false
*/
"checked": boolean;
/**
* The built-in named SVG icon name or the exact `src` of an SVG file to use when the toggle is checked.
*/
"checkedIcon"?: string | null;
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
Expand Down Expand Up @@ -3745,6 +3749,10 @@ export namespace Components {
* @default false
*/
"required": boolean;
/**
* The built-in named SVG icon name or the exact `src` of an SVG file to use when the toggle is unchecked.
*/
"uncheckedIcon"?: string | null;
/**
* The value of the toggle does not mean if it's checked or not, use the `checked` property for that. The value of a toggle is analogous to the value of a `<input type="checkbox">`, it's only used when the toggle participates in a native `<form>`.
* @default 'on'
Expand Down Expand Up @@ -9094,6 +9102,10 @@ declare namespace LocalJSX {
* @default false
*/
"checked"?: boolean;
/**
* The built-in named SVG icon name or the exact `src` of an SVG file to use when the toggle is checked.
*/
"checkedIcon"?: string | null;
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
Expand Down Expand Up @@ -9151,6 +9163,10 @@ declare namespace LocalJSX {
* @default false
*/
"required"?: boolean;
/**
* The built-in named SVG icon name or the exact `src` of an SVG file to use when the toggle is unchecked.
*/
"uncheckedIcon"?: string | null;
/**
* The value of the toggle does not mean if it's checked or not, use the `checked` property for that. The value of a toggle is analogous to the value of a `<input type="checkbox">`, it's only used when the toggle participates in a native `<form>`.
* @default 'on'
Expand Down Expand Up @@ -9907,6 +9923,8 @@ declare namespace LocalJSX {
"helperText": string;
"value": string | null;
"enableOnOffLabels": boolean | undefined;
"checkedIcon": string | null;
"uncheckedIcon": string | null;
"labelPlacement": 'start' | 'end' | 'fixed' | 'stacked';
"justify": 'start' | 'end' | 'space-between';
"alignment": 'start' | 'center';
Expand Down
6 changes: 5 additions & 1 deletion core/src/components/toggle/test/states/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,18 @@
<div class="grid">
<div class="grid-item">
<h2>Unchecked</h2>
<ion-toggle>Enable Notifications</ion-toggle>
<ion-toggle >Enable Notifications</ion-toggle>
</div>

<div class="grid-item">
<h2>Checked</h2>
<ion-toggle checked="true">Enable Notifications</ion-toggle>
</div>

<ion-toggle enable-on-off-labels="true" checked-icon="heart" unchecked-icon="close" checked="true">Icons Toggle</ion-toggle>



<div class="grid-item">
<h2>Disabled, Unchecked</h2>
<ion-toggle disabled="true">Enable Notifications</ion-toggle>
Expand Down
53 changes: 53 additions & 0 deletions core/src/components/toggle/test/toggle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { newSpecPage } from '@stencil/core/testing';
import { checkmarkOutline, ellipseOutline, removeOutline } from 'ionicons/icons';

import { config } from '../../../global/config';
import { Toggle } from '../toggle';
Expand Down Expand Up @@ -41,6 +42,58 @@ describe('toggle', () => {
});
});

describe('checkedIcon and uncheckedIcon', () => {
it('should set custom checked icon on the instance, overriding config', async () => {
const t = await newToggle();
t.checkedIcon = 'custom-checked-icon-instance';
config.reset({
toggleCheckedIcon: 'custom-checked-icon-config',
});

expect((t as any).getSwitchLabelIcon('md', true)).toBe('custom-checked-icon-instance');
});

it('should set custom unchecked icon on the instance, overriding config', async () => {
const t = await newToggle();
t.uncheckedIcon = 'custom-unchecked-icon-instance';
config.reset({
toggleUncheckedIcon: 'custom-unchecked-icon-config',
});

expect((t as any).getSwitchLabelIcon('md', false)).toBe('custom-unchecked-icon-instance');
});

it('should set custom checked icon in the config', async () => {
const t = await newToggle();
config.reset({
toggleCheckedIcon: 'custom-checked-icon-config',
});

expect((t as any).getSwitchLabelIcon('md', true)).toBe('custom-checked-icon-config');
});

it('should set custom unchecked icon in the config', async () => {
const t = await newToggle();
config.reset({
toggleUncheckedIcon: 'custom-unchecked-icon-config',
});

expect((t as any).getSwitchLabelIcon('md', false)).toBe('custom-unchecked-icon-config');
});

it('should use default icons in md mode', async () => {
const t = await newToggle();
expect((t as any).getSwitchLabelIcon('md', true)).toBe(checkmarkOutline);
expect((t as any).getSwitchLabelIcon('md', false)).toBe(removeOutline);
});

it('should use default icons in ios mode', async () => {
const t = await newToggle();
expect((t as any).getSwitchLabelIcon('ios', true)).toBe(removeOutline);
expect((t as any).getSwitchLabelIcon('ios', false)).toBe(ellipseOutline);
});
});

describe('shadow parts', () => {
it('should have shadow parts', async () => {
const page = await newSpecPage({
Expand Down
14 changes: 10 additions & 4 deletions core/src/components/toggle/toggle.md.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
--handle-max-height: #{$toggle-md-handle-max-height};
--handle-spacing: 0;
--handle-transition: #{$toggle-md-transition};
--on-off-label-icon-size: 13px;


}

// Toggle Native Wrapper
Expand Down Expand Up @@ -61,10 +64,13 @@
}

.toggle-inner .toggle-switch-icon {
@include padding(1px);

width: 100%;
height: 100%;
width: var(--on-off-label-icon-size);
height: var(--on-off-label-icon-size);
min-width: var(--on-off-label-icon-size);
min-height: var(--on-off-label-icon-size);
display: block;
opacity: 0.86;
transition: transform $toggle-md-transition-duration, opacity $toggle-md-transition-duration, color $toggle-md-transition-duration;
}

// Material Design Toggle: Disabled
Expand Down
19 changes: 17 additions & 2 deletions core/src/components/toggle/toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ export class Toggle implements ComponentInterface {
*/
@Prop() enableOnOffLabels: boolean | undefined = config.get('toggleOnOffLabels');

/**
* The built-in named SVG icon name or the exact `src` of an SVG file
* to use when the toggle is checked.
*/
@Prop() checkedIcon?: string | null;

/**
* The built-in named SVG icon name or the exact `src` of an SVG file
* to use when the toggle is unchecked.
*/
@Prop() uncheckedIcon?: string | null;

/**
* 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.
Expand Down Expand Up @@ -348,10 +360,13 @@ export class Toggle implements ComponentInterface {
};

private getSwitchLabelIcon = (mode: Mode, checked: boolean) => {
const checkedIcon = this.checkedIcon ?? config.get('toggleCheckedIcon');
const uncheckedIcon = this.uncheckedIcon ?? config.get('toggleUncheckedIcon');

if (mode === 'md') {
return checked ? checkmarkOutline : removeOutline;
return checked ? checkedIcon ?? checkmarkOutline : uncheckedIcon ?? removeOutline;
}
return checked ? removeOutline : ellipseOutline;
return checked ? checkedIcon ?? removeOutline : uncheckedIcon ?? ellipseOutline;
};

private renderOnOffSwitchLabels(mode: Mode, checked: boolean) {
Expand Down
10 changes: 10 additions & 0 deletions core/src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ export interface IonicConfig {
*/
toggleOnOffLabels?: boolean;

/**
* Overrides the default checked icon in all `<ion-toggle>` components.
*/
toggleCheckedIcon?: string;

/**
* Overrides the default unchecked icon in all `<ion-toggle>` components.
*/
toggleUncheckedIcon?: string;

/**
* Overrides the default spinner for all `ion-loading` overlays, ie. the ones
* created with `ion-loading-controller`.
Expand Down
4 changes: 2 additions & 2 deletions packages/angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2567,14 +2567,14 @@ Shorthand for ionToastDidDismiss.


@ProxyCmp({
inputs: ['alignment', 'checked', 'color', 'disabled', 'enableOnOffLabels', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'required', 'value']
inputs: ['alignment', 'checked', 'checkedIcon', 'color', 'disabled', 'enableOnOffLabels', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'required', 'uncheckedIcon', 'value']
})
@Component({
selector: 'ion-toggle',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['alignment', 'checked', 'color', 'disabled', 'enableOnOffLabels', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'required', 'value'],
inputs: ['alignment', 'checked', 'checkedIcon', 'color', 'disabled', 'enableOnOffLabels', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'required', 'uncheckedIcon', 'value'],
})
export class IonToggle {
protected el: HTMLIonToggleElement;
Expand Down
2 changes: 2 additions & 0 deletions packages/vue/src/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,8 @@ export const IonToggle: StencilVueComponent<JSX.IonToggle, JSX.IonToggle["checke
'helperText',
'value',
'enableOnOffLabels',
'checkedIcon',
'uncheckedIcon',
'labelPlacement',
'justify',
'alignment',
Expand Down