Add Switch Component
This commit is contained in:
1 parent
1faac851d0
commit
c9461bd910
9 files changed
+163
-174
No files matched your search
@@ -0,0 +1 @@
|
||||
<div class="switch-knob"></div>
|
||||
@@ -0,0 +1,65 @@
|
||||
@use "sass:math";
|
||||
@use "sass:list";
|
||||
@use "styles/library" as library;
|
||||
|
||||
$slider_on_bg: #FF6E37;
|
||||
$slider_off_bg: #999999;
|
||||
|
||||
$switch_dimension: (57px, 30px);
|
||||
$switch_slider_dimension: (24px, 24px);
|
||||
$switch_padding: (3px, 3px);
|
||||
$switch_border_radius: 15px;
|
||||
|
||||
$switch_animation_timing: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
$switch_animation_duration: 0.3s;
|
||||
|
||||
:host {
|
||||
display: inline-block;
|
||||
width: list.nth($switch_dimension, 1); height: list.nth($switch_dimension, 2);
|
||||
border-radius: $switch_border_radius;
|
||||
background-color: $slider_off_bg;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2) inset;
|
||||
outline: none;
|
||||
|
||||
--switch-duration: #{$switch_animation_duration};
|
||||
transition: background-color var(--switch-duration) $switch_animation_timing;
|
||||
|
||||
&.reduce-motion {
|
||||
--switch-duration: 0s;
|
||||
}
|
||||
|
||||
&:hover, &:focus-within {
|
||||
.switch-knob {
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2) inset, 0 0 0 2px white, 0 0 0 4px $slider_on_bg;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $slider_on_bg;
|
||||
|
||||
.switch-knob {
|
||||
|
||||
transform: translate(
|
||||
list.nth($switch_dimension, 1) - list.nth($switch_slider_dimension, 1) - list.nth($switch_padding, 1) * 2,
|
||||
list.nth($switch_dimension, 2) - list.nth($switch_slider_dimension, 2) - list.nth($switch_padding, 2) * 2
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.switch-knob {
|
||||
position: absolute;
|
||||
width: list.nth($switch_slider_dimension, 1); height: list.nth($switch_slider_dimension, 2);
|
||||
left: list.nth($switch_padding, 1); top: list.nth($switch_padding, 2);
|
||||
background-color: white;
|
||||
border-radius: 50%;
|
||||
user-select: none;
|
||||
transition: transform var(--switch-duration) $switch_animation_timing;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Component, input, model, output } from '@angular/core'
|
||||
|
||||
@Component({
|
||||
selector: 'switch',
|
||||
imports: [],
|
||||
templateUrl: './switch.html',
|
||||
styleUrl: './switch.scss',
|
||||
host: {
|
||||
'role': 'switch',
|
||||
'tabindex': '0',
|
||||
'[attr.aria-checked]': 'isActive()',
|
||||
'[class.active]': 'isActive()',
|
||||
'[class.reduce-motion]': 'reduceMotion()',
|
||||
'(click)': 'onClick()',
|
||||
'(keydown.enter)': 'onClick()',
|
||||
'(keydown.space)': 'onSpaceDown($event)'
|
||||
}
|
||||
})
|
||||
export class Switch {
|
||||
isActive = model<boolean>(false);
|
||||
reduceMotion = input<boolean>(
|
||||
typeof window !== 'undefined'
|
||||
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
: false
|
||||
);
|
||||
toggle = output<boolean>()
|
||||
|
||||
onClick(): void {
|
||||
this.isActive.update(value => !value)
|
||||
this.onToggle()
|
||||
}
|
||||
|
||||
onSpaceDown(event: Event): void {
|
||||
event.preventDefault(); // 스페이스바 스크롤 방지
|
||||
this.onClick();
|
||||
}
|
||||
|
||||
onToggle(): void {
|
||||
this.toggle.emit(this.isActive())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user