본문으로 건너뛰기

PlToggle

눌린 채로 남는 버튼, 그리고 하나의 상태를 나누는 그 묶음입니다. 꺼진 상태는 중립입니다. 쉬고 있는 토글은 아직 취해지지 않은 액션이 아니라, 지금 거짓인 상태이기 때문입니다.

React
tsx
import { PlToggle, PlToggleGroup } from 'plass-ui';

<PlToggle pressed={bold} onPressedChange={setBold}>
  Bold
</PlToggle>;

<PlToggleGroup multiple value={marks} onValueChange={setMarks}>
  <PlToggle value="bold">Bold</PlToggle>
  <PlToggle value="italic">Italic</PlToggle>
</PlToggleGroup>;
dart
import 'package:plass_ui/plass_ui.dart';

PlToggle(
  pressed: bold,
  onPressedChanged: (bool next) => setState(() => bold = next),
  child: const Text('Bold'),
);

PlToggleGroup(
  multiple: true,
  value: marks,
  onValueChanged: (List<String> next) => setState(() => marks = next),
  children: const <Widget>[
    PlToggle(value: 'bold', child: Text('Bold')),
    PlToggle(value: 'italic', child: Text('Italic')),
  ],
);

Props

Prop타입기본값설명
variant공통'solid' | 'glass' | 'ghost''glass'**꺼져 있을 때** 키가 무엇으로 만들어졌는지. 켜지면 어느 재질이든 색 계열이 나섭니다
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'높이와 타입 스케일
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통'default' | 'compact''default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통0 | 1 | 2 | 30그림자 깊이. 0이 기본이고 PlButton보다 한 단계 아래입니다 — 토글은 액션이 아니라 상태이고, 상태는 페이지 위에 떠서 기다리지 않습니다
pressedboolean켜져 있는지. onPressedChange와 함께 controlled로 씁니다
defaultPressedbooleanfalse켜진 채로 시작할지
onPressedChange(pressed: boolean) => void켜지거나 꺼질 때
valuestringPlToggleGroup 안에서 이 토글을 식별합니다
startIconReactNode라벨 앞에 놓이는 내용. em으로 크기가 정해져 라벨을 따릅니다
endIconReactNode라벨 뒤에 놓이는 내용
fullWidthbooleanfalse컨테이너 너비까지 늘어납니다
disabledbooleanfalse눌 수 없게 하고 tab 순서에서 뺍니다
childrenReactNode라벨. 없으면 받은 아이콘 둘레로 정사각형이 됩니다 — 그래도 aria-label은 필요합니다
Prop타입기본값설명
variant공통PlassVariant?PlassVariant.glass**꺼져 있을 때** 키가 무엇으로 만들어졌는지. 켜지면 어느 재질이든 색 계열이 나섭니다
size공통PlassSize?PlassSize.md높이와 타입 스케일
color공통PlassColor?PlassColor.primary의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통PlassDensity?PlassDensity.standard여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통int?0그림자 깊이. 0이 기본이고 PlButton보다 한 단계 아래입니다 — 토글은 액션이 아니라 상태이고, 상태는 페이지 위에 떠서 기다리지 않습니다
pressedbool?켜져 있는지. onPressedChange와 함께 controlled로 씁니다
defaultPressedboolfalse켜진 채로 시작할지
onPressedChangedValueChanged<bool>?켜지거나 꺼질 때
valueString?PlToggleGroup 안에서 이 토글을 식별합니다
startIconWidget?라벨 앞에 놓이는 내용. em으로 크기가 정해져 라벨을 따릅니다
endIconWidget?라벨 뒤에 놓이는 내용
fullWidthboolfalse컨테이너 너비까지 늘어납니다
disabledbool?false눌 수 없게 하고 tab 순서에서 뺍니다
semanticLabelString?스크린 리더가 부르는 이름. 라벨 없이 아이콘만 있는 토글에는 사실상 필수입니다
focusNodeFocusNode?바깥에서 focus를 옮겨야 하는 호출자를 위한 focus node
autofocusboolfalse처음 지어질 때 focus를 가져갈지
childWidget?라벨. 없으면 받은 아이콘 둘레로 정사각형이 됩니다 — 그래도 aria-label은 필요합니다

네이티브 <button> 속성은 모두 그대로 전달됩니다. color는 여기서 Plass의 prop이라, value는 제출되는 값이 아니라 그룹 안에서 토글을 식별하는 것이라 제외됩니다.

PlToggleGroup

Prop타입기본값설명
variant공통'solid' | 'glass' | 'ghost''glass'세트의 모든 토글에 전달됩니다
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'높이와 타입 스케일
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통'default' | 'compact''default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통0 | 1 | 2 | 30그림자 깊이. 세트의 모든 토글에 전달됩니다
valuereadonly string[]어느 토글이 켜져 있는지, value로. 하나든 여럿이든 배열입니다 — multiple을 켜도 타입이 바뀌지 않는 모양입니다
defaultValuereadonly string[]어느 것이 켜진 채로 시작할지
onValueChange(value: string[]) => void세트의 값이 바뀔 때
multiplebooleanfalse한 번에 둘 이상 켜질 수 있는지. 꺼져 있으면 하나를 켤 때 이전 것이 꺼집니다
orientation공통'horizontal' | 'vertical''horizontal'토글이 늘어서는 방향
disabledboolean세트의 모든 토글을 한 번에 끕니다
loopFocusbooleantrue화살표 키가 양 끝에서 돌아가는지
fullWidthbooleanfalse컨테이너까지 늘어나고 너비를 토글들에 고르게 나눕니다
childrenReactNode세트를 이루는 PlToggle들
Prop타입기본값설명
children * List<Widget>세트를 이루는 토글들. 세트에 속하려면 각자 value가 있어야 합니다
valueList<String>?어느 토글이 켜져 있는지, value로. 하나든 여럿이든 배열입니다 — multiple을 켜도 타입이 바뀌지 않는 모양입니다
defaultValueList<String><String>[]어느 것이 켜진 채로 시작할지
onValueChangedValueChanged<List<String>>?세트의 값이 바뀔 때
multipleboolfalse한 번에 둘 이상 켜질 수 있는지. 꺼져 있으면 하나를 켤 때 이전 것이 꺼집니다
orientation공통PlassOrientationPlassOrientation.horizontal토글이 늘어서는 방향
variant공통PlassVariant?'glass'세트의 모든 토글에 전달됩니다
size공통PlassSize?'md'높이와 타입 스케일
color공통PlassColor?'primary'의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통PlassDensity?'default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통int?0그림자 깊이. 세트의 모든 토글에 전달됩니다
disabledbool?세트의 모든 토글을 한 번에 끕니다
fullWidthboolfalse컨테이너까지 늘어나고 너비를 토글들에 고르게 나눕니다

공용 축(variant size color density elevation)이 라이브러리 전체에서 무엇을 뜻하는지는 prop 규약에 있습니다.

Toggle, switch, checkbox 중 고르기

  • 토글은 옆에 있는 것의 상태를 바꿉니다. 선택한 글자의 볼드, 캔버스의 그리드, 목록의 필터. 컨트롤이고, 폼에는 들어가지 않습니다.
  • PlSwitch는 설정을 바꾸고, 그 변화 자체가 핵심입니다.
  • PlCheckbox는 컨트롤이 아니라 폼 안의 답입니다.
  • 하나를 고르는 이라면 PlSegmentedButton이나 PlRadioGroup입니다. multiple 없는 PlToggleGroup은 그것처럼 보이지만 아닙니다. 담고 있는 것은 답이 아니라 상태입니다.

Examples

variant

꺼져 있을 때 키가 무엇으로 만들어졌는지입니다. 켜지면 어느 재질이든 색 계열이 나서고, 그때 내놓는 두 답은 PlSegmentedButton의 선택된 세그먼트가 내놓는 것과 같습니다. solid는 그러데이션과 on-fill 잉크를, glassghost는 시트를 밝히고 라벨을 accent로 둡니다.

꺼져 있을 때 잉크는 셋 다 --plass-muted-fg이고, 어느 것에도 색이 들어가지 않습니다. 꺼진 토글은 맑은 유리 한 조각이고, 색 계열은 누름과 함께 도착하지 그전에는 오지 않습니다.

이는 포인터 아래에서도 그대로입니다. 잃어버리기 쉬운 쪽이 이쪽입니다. 호버도 여전히 꺼진 상태이므로 중립적인 유리 사다리를 오릅니다. solidglass가 이미 쓰고 있던 같은 두 칸이고, 색 계열 자신의 wash는 결코 아닙니다. 그것은 on이 칠해지는 색이기 때문입니다. 상태가 둘인 컨트롤은 거짓인 상태를 참인 상태의 색으로 그려 놓고 차이를 잉크에만 맡길 수 없습니다.

React

elevation

켜진 토글은 들어 올려진 토글이 아닙니다. elevation은 두 상태에서 같고 색만 바뀝니다. "켜짐"은 키가 페이지에서 얼마나 떠 있는지가 아니라 토글 옆에 있는 것에 대한 사실이기 때문입니다.

기본값은 0이고 PlButton보다 한 단계 아래인데, 같은 이유입니다.

size

컨트롤 사다리 그대로입니다. md 토글은 40px이고 옆의 필드·버튼과 줄이 맞습니다. density는 여백만 옮깁니다.

React

PlToggleGroup

두 가지가 일어나는데 그중 하나만 시각적입니다. 이웃을 마주하는 모서리가 각지는 것. 그것이 겉모습입니다. 나머지 절반은 세트가 값을 쥔다는 것입니다. 토글들이 하나의 배열로 보고하고, variant, size, color, density, elevation, disabled는 토글마다가 아니라 그룹에서 한 번 정해집니다.

값은 두 경우 모두 배열입니다. multiple을 켜도 타입이 바뀌지 않는 유일한 모양입니다.

React

아이콘만, 라벨 없이

children을 빼면 토글은 받은 아이콘 둘레로 정사각형이 됩니다. 툴바 토글이 바로 그것입니다. 그래도 aria-label은 필요합니다. 라벨이 통째로 그림인 컨트롤에는 접근 가능한 이름이 아예 없습니다.

React

React 빌드와 다른 점

ReactFlutter이유
Base UI의 aria-pressedSemantics(toggled:)프레임워크 자신의 이름으로 된 같은 주장입니다: 무언가를 하는 버튼이 아니라 상태가 붙은 버튼.
그룹 전체가 tab stop 하나, 안에서는 화살표 키토글마다 focus stop 하나Base UI의 roving tab index에 대응하는 것이 widgets.dart에는 없고, 잘못 구현한 roving focus는 플랫폼 자신의 순회보다 나쁩니다. 값이 정말로 필요한 자리에서는 PlSegmentedButton이 진짜를 지니고 있습니다.
자유롭게 조합하는 children그룹의 children: List<Widget>어느 구성원이 양 끝인지 알아야 올바른 모서리를 각지게 할 수 있고, 그룹이 셀 수 있는 것이 리스트입니다.
loopFocus돌릴 roving focus가 없습니다.
onPressedChangeonPressedChangedFlutter의 이름입니다.
aria-labelsemanticLabelFlutter의 이름입니다.
className, style, 네이티브 속성전달할 class 목록도 style 속성도 없습니다.

Accessibility

  • Base UI가 aria-pressed를 지닌 진짜 <button>을 그립니다. "이건 무언가를 한다"가 아니라 "이건 상태다"라고 말하는 것이 그것입니다.
  • PlToggleGroup은 tab stop 하나이고 화살표 키가 구성원 사이를 움직입니다. 토글 여덟 개짜리 툴바가 여덟 번이 아니라 두 번의 키 누름 깊이가 되는 이유입니다. loopFocus가 양 끝에서 화살표가 돌아가는지 정합니다.
  • 아이콘만 있는 토글에는 aria-label이 필요합니다. 다른 무엇도 그것에 이름을 주지 못합니다.
  • disabled는 토글을 tab 순서에서 뺍니다. 그룹의 disabled는 모든 구성원에 한 번에 그렇게 합니다.
  • 포인터 빛은 disabled인 동안 꺼집니다. 아무도 누를 수 없는 표면이 포인터에 답하지 않도록.
  • 토글은 Semantics(button: true, toggled: …)이고, 반대쪽의 aria-pressed와 같은 주장입니다.
  • 라벨 없이 아이콘만 있는 토글에는 semanticLabel이 필요합니다. 다른 무엇도 그것에 이름을 주지 못합니다.
  • disabled는 토글을 focus 순서에서 빼고 포인터에 아예 답하지 않게 합니다. 빛도 함께 꺼집니다.
  • 그룹 안의 토글은 각자 하나의 focus stop입니다. roving focus는 여기에 없고, React 빌드에 있고 여기에 없는 유일한 것이 그것입니다.

Released under the MIT License