Skip to content

Commit

Permalink
feat(elements|ino-switch): support icons (#724)
Browse files Browse the repository at this point in the history
Co-authored-by: janivo <[email protected]>
Co-authored-by: Jan-Niklas Voß <[email protected]>
  • Loading branch information
3 people authored Oct 20, 2022
1 parent 36d62af commit 8027499
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 79 deletions.
220 changes: 159 additions & 61 deletions packages/elements/src/components/ino-switch/ino-switch.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
@use '@material/switch';
@use '@material/switch/styles';
@use 'base/new-theme' as theme;


@use 'base/theme' as old-theme;

@mixin set-track-border-color {
.mdc-switch__track {
Expand All @@ -13,90 +12,189 @@
}
}


// general styles
ino-switch {
display: flex;
align-items: center;
gap: 10px;

&:not(.ino-switch-disabled) .mdc-switch {
cursor: pointer;
}

&.ino-switch-disabled .mdc-switch {
cursor: default;
pointer-events: none;
}

.mdc-switch__ripple {
display: none;
}
}


// default switch styles
ino-switch.ino-switch__default {

height: 22px;

@include switch.theme(
(
selected-handle-color: white,
selected-hover-handle-color: white,
selected-focus-handle-color: white,
selected-pressed-handle-color: white,
disabled-selected-handle-color: theme.$n-6,
selected-track-color: theme.$primary,
selected-hover-track-color: theme.$primary,
selected-focus-track-color: theme.$primary,
selected-pressed-track-color: theme.$primary,
unselected-focus-track-color: theme.$n-5,
unselected-hover-track-color: theme.$n-5,
disabled-selected-track-color: transparent,
)
(
selected-handle-color: white,
selected-hover-handle-color: white,
selected-focus-handle-color: white,
selected-pressed-handle-color: white,
selected-track-color: theme.$primary,
selected-hover-track-color: theme.$primary,
selected-focus-track-color: theme.$primary,
selected-pressed-track-color: theme.$primary,
unselected-focus-track-color: theme.$n-5,
unselected-hover-track-color: theme.$n-5,
track-height: 20px,
track-width: 36px,
track-shape: 18px,
handle-height: 16px,
handle-width: 16px,
handle-shape: 14px,
selected-icon-size: 10px,
unselected-icon-size: 10px,
handle-surface-color: white,
unselected-handle-color: white,
unselected-track-color: theme.$n-6,
unselected-hover-handle-color: white,
unselected-focus-handle-color: white,
unselected-pressed-handle-color: white,
disabled-selected-handle-color: theme.$n-6,
disabled-selected-track-color: transparent,
disabled-unselected-track-color: transparent,
disabled-unselected-handle-color: theme.$n-6,
disabled-track-opacity: 1,
disabled-handle-opacity: 1,
)
);

.mdc-switch--selected:focus,
.mdc-switch--unselected:focus {
@include set-track-border-color;
}

.mdc-switch {
&--selected {
.mdc-switch__handle {
margin-left: -2px;
}
&--selected .mdc-switch__handle {
margin-left: -2px;
}
&--unselected {
.mdc-switch__handle {
margin-left: 2px;
}

&--unselected .mdc-switch__handle {
margin-left: 2px;
}
}

// custom disabled state styling
.mdc-switch:disabled {
.mdc-switch__track {
opacity: 1;
&:disabled .mdc-switch__track {
border: 2px solid theme.$n-6;
margin: -1.5px;
}
.mdc-switch__handle::after {
opacity: 1;
}
}
}

ino-switch {
$disabled-color: #F3F3F5;

// icon toggle switch styles
ino-switch.ino-switch__icon-toggle .mdc-switch {
display: flex;
gap: 10px;
align-items: center;
height: 30px;
cursor: pointer;
justify-content: center;
height: 36px;
width: 104px;

&.ino-switch-disabled {
cursor: default;
pointer-events: none;
.switch-icon {
display: flex;
justify-content: center;
align-items: center;
height: 28px;
width: 48px;
color: theme.$n-3;
fill: theme.$n-3;

ino-icon {
--icon-width: 20px;
--icon-height: 20px;
--icon-color: #{theme.$n-3};
}

&--selected ino-icon {
--icon-color: #{old-theme.color(primary, dark)};
color: old-theme.color(primary, dark);
fill: old-theme.color(primary, dark);
}

&--unselected::after {
content: '';
position: absolute;
top: 0;
left: 0;
background-color: transparent;
transition: background-color 300ms linear;
width: 100%;
height: 100%;
border-radius: 32px;
z-index: -1;
}
}

&:hover .switch-icon--unselected::after {
background-color: theme.$n-7;
}

// set basic styles, DOES NOT SUPPORT CSS-VARS
@include switch.theme(
(
track-height: 20px,
track-width: 36px,
track-shape: 18px,
handle-height: 16px,
handle-width: 16px,
handle-shape: 14px,
selected-icon-size: 10px,
unselected-icon-size: 10px,
handle-surface-color: white,
unselected-handle-color: white,
unselected-track-color: theme.$n-6,
disabled-unselected-handle-color: theme.$n-6,
disabled-unselected-track-color: transparent,
unselected-hover-handle-color: white,
unselected-focus-handle-color: white,
unselected-pressed-handle-color: white,
)
(
selected-handle-color: white,
selected-hover-handle-color: white,
selected-focus-handle-color: white,
selected-pressed-handle-color: white,
selected-track-color: theme.$n-7,
selected-hover-track-color: theme.$n-6,
selected-focus-track-color: theme.$n-6,
selected-pressed-track-color: theme.$n-6,
track-height: 36px,
track-width: 104px,
track-shape: 18px,
handle-height: 28px,
handle-width: 48px,
handle-shape: 14px,
selected-icon-size: 20px,
unselected-icon-size: 20px,
handle-surface-color: white,
unselected-handle-color: white,
unselected-track-color: theme.$n-7,
unselected-focus-track-color: theme.$n-6,
unselected-hover-track-color: theme.$n-6,
disabled-selected-track-color: transparent,
disabled-selected-handle-color: white,
disabled-unselected-handle-color: white,
disabled-unselected-track-color: $disabled-color,
disabled-track-opacity: 1,
unselected-hover-handle-color: white,
unselected-focus-handle-color: white,
unselected-pressed-handle-color: white,
)
);

// hide ripple effect
.mdc-switch__ripple {
display: none;
&.mdc-switch {
.mdc-switch__track {
position: absolute;
}

&--selected .mdc-switch__handle {
margin-left: -4px;
}

&--unselected .mdc-switch__handle {
margin-left: 4px;
}
}
}

ino-switch.ino-switch-disabled.ino-switch__icon-toggle .switch-icon--selected ino-icon {
--icon-color: #{theme.$n-4};
color: theme.$n-4;
fill: theme.$n-4;
}
83 changes: 69 additions & 14 deletions packages/elements/src/components/ino-switch/ino-switch.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import {MDCSwitch} from '@material/switch';
import {Component, ComponentInterface, Element, Event, EventEmitter, h, Host, Prop, Watch,} from '@stencil/core';
import { MDCSwitch } from '@material/switch';
import {
Component,
ComponentInterface,
Element,
Event,
EventEmitter,
h,
Host,
Prop,
Watch,
} from '@stencil/core';
import classNames from 'classnames';

import {generateUniqueId} from '../../util/component-utils';
import {renderHiddenInput} from '../../util/helpers';
import { generateUniqueId, hasSlotContent } from '../../util/component-utils';
import { renderHiddenInput } from '../../util/helpers';

/**
* @slot default - Label of the switch
Expand Down Expand Up @@ -45,9 +55,17 @@ export class Switch implements ComponentInterface {
*/
@Prop() name?: string;


componentDidLoad() {
this.mdcSwitch = new MDCSwitch(this.mdcSwitchEl);

const hasLeadingSlot = hasSlotContent(this.el, 'leading');
const hasTrailingSlot = hasSlotContent(this.el, 'trailing');

if (hasLeadingSlot != hasTrailingSlot) {
console.error(
'[ino-switch] Two icons (leading & trailing) are required in order to use the icon switch.'
);
}
}

disconnectedCallback() {
Expand All @@ -62,50 +80,87 @@ export class Switch implements ComponentInterface {
private handleChange = (e: MouseEvent) => {
e.stopPropagation();

if(this.disabled) return;
if (this.disabled) return;

this.checkedChange.emit(!this.checked);
};

render() {
const {el, name, disabled} = this;
const { el, name, disabled } = this;

const hiddenInput = renderHiddenInput(el, name, '', disabled);
hiddenInput.checked = this.checked;

const hasLeadingSlot = hasSlotContent(this.el, 'leading');
const hasTrailingSlot = hasSlotContent(this.el, 'trailing');

const hostClasses = classNames(
'ino-switch',
hasLeadingSlot || hasTrailingSlot
? 'ino-switch__icon-toggle'
: 'ino-switch__default',
{
'ino-switch-disabled': this.disabled
'ino-switch-disabled': this.disabled,
'ino-switch-icon-disabled': this.disabled,
}
);

const switchClasses = classNames(
'mdc-switch',
this.checked ? 'mdc-switch--selected' : 'mdc-switch--unselected',
{
'mdc-switch': true,
'ino-switch__icon-toggle': hasLeadingSlot && hasTrailingSlot,
}
);

const iconClasses = classNames('mdc-switch__icons', 'switch-icon');

const leadingIconClasses = classNames(
iconClasses,
!this.checked ? 'switch-icon--selected' : 'switch-icon--unselected'
);

const trailingIconClasses = classNames(
iconClasses,
this.checked ? 'switch-icon--selected' : 'switch-icon--unselected'
);

return (
<Host class={hostClasses} checked={this.checked} disabled={this.disabled} onClick={this.handleChange}>
<Host
class={hostClasses}
checked={this.checked}
disabled={this.disabled}
onClick={this.handleChange}
>
<button
id={this.switchId}
ref={el => this.mdcSwitchEl = el}
ref={(el) => (this.mdcSwitchEl = el)}
class={switchClasses}
disabled={this.disabled}
type="button"
role="switch"
aria-checked={this.checked}

>
<div class="mdc-switch__track"/>
{hasLeadingSlot && (
<span class={leadingIconClasses}>
<slot name={'leading'} />
</span>
)}
<div class="mdc-switch__track" />
<div class="mdc-switch__handle-track">
<div class="mdc-switch__handle">
<div class="mdc-switch__ripple"/>
<div class="mdc-switch__ripple" />
</div>
</div>
{hasTrailingSlot && (
<span class={trailingIconClasses}>
<slot name={'trailing'} />
</span>
)}
</button>
<label htmlFor={this.switchId} onClick={(e) => e.stopPropagation()}>
<slot/>
<slot />
</label>
</Host>
);
Expand Down
Loading

0 comments on commit 8027499

Please sign in to comment.