ToolbarGroup
관련 툴바 동작이 하나의 재질 표면을 공유하는 그룹
목차
관련된 버튼을 하나의 둥근 표면에 묶습니다. Popup을 가로 방향으로 합성하며,
popupStyle.surfaceStyle로 그룹에만 Liquid Glass를 지정할 수 있습니다.
기본 사용법 (Basic Usage)#
Flutter와 Web의 생성자 이름과 스타일 슬롯이 같습니다.
ToolbarGroup(
ariaLabel: '편집 기록',
popupStyle: const CorePopupStyle(surfaceStyle: .liquidGlass),
children: [
Button(variant: .ghost, onPressed: undo, child: const Text('실행 취소')),
Button(variant: .ghost, onPressed: redo, child: const Text('다시 실행')),
],
)
Live Preview#
코드 보기
class ToolbarGroupDefaultExample extends StatefulComponent {
const ToolbarGroupDefaultExample({super.key});
@override
State<ToolbarGroupDefaultExample> createState() => _ToolbarGroupExampleState();
}
class _ToolbarGroupExampleState extends State<ToolbarGroupDefaultExample> {
int _zoom = 100;
void _handleZoomOut() => setState(() => _zoom = (_zoom - 10).clamp(50, 200));
void _handleZoomIn() => setState(() => _zoom = (_zoom + 10).clamp(50, 200));
@override
Component build(BuildContext context) {
return div(
[
Text('Zoom: $_zoom%'),
ToolbarGroup(
ariaLabel: 'Zoom controls',
popupStyle: const CorePopupStyle(surfaceStyle: .liquidGlass),
children: [
Button(variant: .ghost, onPressed: _zoom > 50 ? _handleZoomOut : null, child: const Text('Zoom out')),
Button(variant: .ghost, onPressed: _zoom < 200 ? _handleZoomIn : null, child: const Text('Zoom in')),
],
),
],
classes: 'flex flex-col items-center',
);
}
}
class ToolbarGroupDefaultExample extends StatefulWidget {
const ToolbarGroupDefaultExample({super.key});
@override
State<ToolbarGroupDefaultExample> createState() => _ToolbarGroupExampleState();
}
class _ToolbarGroupExampleState extends State<ToolbarGroupDefaultExample> {
int _zoom = 100;
void _handleZoomOut() => setState(() => _zoom = (_zoom - 10).clamp(50, 200));
void _handleZoomIn() => setState(() => _zoom = (_zoom + 10).clamp(50, 200));
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Zoom: $_zoom%'),
ToolbarGroup(
ariaLabel: 'Zoom controls',
popupStyle: const CorePopupStyle(surfaceStyle: .liquidGlass),
children: [
Button(variant: .ghost, onPressed: _zoom > 50 ? _handleZoomOut : null, child: const Text('Zoom out')),
Button(variant: .ghost, onPressed: _zoom < 200 ? _handleZoomIn : null, child: const Text('Zoom in')),
],
),
],
);
}
}
사용 시기 (When to Use)#
확대·축소, 실행 취소·다시 실행처럼 함께 사용하는 동작을 묶을 때 사용합니다. 화면 이동은 NavigationBar, 계층적인 명령 목록은 Menubar나 DropdownMenu를 사용합니다.
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
ariaLabel | String | 필수 | 비어 있지 않은, 번역된 그룹 이름 |
children |
Flutter List<Widget>, Web List<Component> |
필수 | 서로 관련된 컨트롤 |
popupStyle |
CorePopupStyle? |
null |
공유 패널의 재질·여백·모서리 등 |
스타일 시스템 (Style System)#
CoreToolbarGroupContract.defaultPopupStyle은 캡슐 모서리, 4px 안쪽 여백,
자식 간격 0을 기본으로 제공합니다. popupStyle에 지정한 값으로 덮어쓴 뒤
합성된 Popup의 테마와 재질 해석 경로를 따릅니다. 재질 축의 null은 상속이고,
defaultStyle은 명시적 불투명 재질입니다. 팔레트와 글꼴은 그대로 유지됩니다.
투명도 줄이기·고대비 설정이 로컬 유리 재질보다 우선합니다. 그룹에 유리를 지정해도 자식 버튼의 variant는 바뀌지 않으므로 공유 표면에는 ghost 버튼을 사용합니다.
동작 스펙 (Behavior)#
버튼의 콜백, 활성 상태, 포커스는 각 자식이 소유합니다. 그룹 자체는 명령을 실행하거나 선택 상태를 만들지 않습니다. 숨길 동작은 children에서 제외하며, 목록이 비어 있으면 패널과 접근성 그룹을 모두 그리지 않습니다.
사용 가이드라인 (Usage Guidelines)#
관련 기능마다 별도 그룹을 만들고 그룹 사이에 여백을 둡니다. 그룹 내부의 버튼 표현은 텍스트 또는 아이콘으로 일관되게 유지합니다. 아이콘만 사용하는 버튼에는 각각 접근 가능한 이름을 제공해야 합니다.
자식이 들어갈 폭은 호출자가 확보합니다. 그룹은 자동 줄바꿈이나 overflow 메뉴를 만들지 않습니다. AppBar 안에 별도 유리 그룹을 넣으면 AppBar의 채움을 투명하게 지정해 배경 필터가 겹치지 않도록 구성할 수 있습니다.
접근성 (Accessibility)#
역할#
Flutter는 CoUISemantics의 group 역할과 ariaLabel을 사용하고, Web은
role="group"과 aria-label을 제공합니다. 각 버튼은 자신의 역할과 활성 상태를
노출합니다. 빈 그룹은 접근성 트리에도 나타나지 않습니다.
키보드#
Tab으로 자식 컨트롤을 탐색하며 Enter/Space 활성화는 버튼이 담당합니다. 그룹 전용 방향키 탐색은 없습니다.
스크린 리더#
그룹의 이름은 호출자가 번역해 제공한 ariaLabel에서 옵니다. 각 버튼은 텍스트나
별도로 지정한 접근 가능한 이름을 사용합니다. 그룹 자체에 live region은 없습니다.
포커스 관리#
진입·이탈 순서는 자식 버튼의 일반 Tab 순서를 따릅니다. 포커스 트랩이나 자동 포커스 복귀를 만들지 않습니다. 포커스 링은 자식 버튼이 그립니다.
알려진 제약#
이 그룹은 ARIA toolbar의 roving 포커스 패턴을 구현하지 않습니다. 자식 버튼마다 Tab stop을 가지며, 많은 명령은 DropdownMenu로 나누어 구성합니다. 그룹의 이름은 아이콘 버튼 각각의 이름을 대신하지 않습니다.
크로스 플랫폼 차이점 (Platform Differences)#
Flutter는 Widget, Web은 Component 목록을 받습니다. API와 빈 그룹 처리, 캡슐 기하 및 재질 우선순위는 같습니다. 유리 렌더링은 Flutter의 Impeller 지원 여부와 Web 브라우저의 backdrop-filter 지원에 따라 달라집니다.
관련 컴포넌트#
- Button: 그룹 안에서 실행하는 동작
- Menubar: 계층적인 메뉴
- DropdownMenu: 추가 명령 목록