Add Switch Component

This commit is contained in:
copecone committed 2026-03-10 15:07:00 +09:00
1 parent 1faac851d0
commit c9461bd910
9 files changed
+163 -174

No files matched your search

+1
View File
@@ -0,0 +1 @@
<div class="switch-knob"></div>
+65
View File
@@ -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;
}
+41
View File
@@ -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())
}
}