Select
controlled, uncontrolled, FormField API로 타입이 있는 Flutter 값 하나를 선택해요.
Material 키보드 탐색과 검색 동작을 유지하면서 controlled, uncontrolled, FormField API로 타입이 있는 값 하나를 선택해요.
핵심 속성
| 속성 | 설명 |
|---|---|
| 열린 상태 | 포인터 hover, open, selected 상태는 배경색으로만 강조해요. 포커스 테두리는 키보드에서 시작된 focus에만 표시해요. |
| 구성 | leading 콘텐츠를 넘기면 타입이 있는 값을 바꾸지 않고 트리거의 용도를 나타낼 수 있어요. 선택지에 보조 설명이 필요하면 TRSelectItem의 description을 추가하세요. 선택된 트리거에는 label만 남고 기본 검색은 두 문자열을 모두 찾아요. 테스트나 상태 복원에서 레이어와 시트의 선택지를 일관되게 식별해야 한다면 각 item에 key를 지정하세요. |
| 적응형 구조 | 제품의 레이아웃 정책에 따라 TRSelectPresentation.layer 또는 TRSelectPresentation.sheet를 선택하세요. 기준 요소에 붙는 레이어는 전체 목록으로 계산한 고유 크기를 유지하고, 시트는 전체 목록 높이를 유지하면서 화면 너비를 계속 따라가요. 명시한 고정 크기가 있으면 그 값이 우선해요. 검색 필드는 하나뿐인 선택지 스크롤 영역 밖에 있고, 그 위에서 휠이나 트랙패드, 드래그를 사용해도 목록이나 시트가 움직이지 않아요. |
| 레이어 크기 | TRLayerSize는 기준 요소에 붙는 레이어 전체에 적용돼요. 너비는 콘텐츠에 맞추거나 고정값을 사용하고, 기준 요소와 같게 하거나 그보다 작지 않게 정할 수 있어요. 높이는 콘텐츠에 맞추거나 고정값을 사용할 수 있어요. 선택한 범위를 적용한 뒤 안전 영역을 뺀 뷰포트가 최종 크기를 제한해요. |
설치
패키지를 추가한 뒤 공개 라이브러리를 가져오세요.
flutter pub add tinyrack_uiimport 'package:tinyrack_ui/tinyrack_ui.dart';플레이그라운드
사용법
import 'package:material_ui/material_ui.dart';
import 'package:tinyrack_ui/tinyrack_ui.dart';
TRSelect<String>.controlled(
value: channel,
items: const [
TRSelectItem(value: 'stable', label: 'Stable'),
TRSelectItem(value: 'beta', label: 'Beta'),
],
onValueChange: setChannel,
)예시
Controlled 값 고유 링크
부모가 값을 소유하면 named controlled constructor를 사용하세요. leading 콘텐츠는 트리거의 용도를 나타내고 item key는 레이어와 시트에서 같은 선택지를 식별해요. null 값은 선택 해제를 명확히 나타내요.
폼 검증 고유 링크
TRSelectFormField는 Material 키보드 동작을 유지하면서 검증, 저장, 초기화, 자동 검증, 상태 복원에 참여해요.
검색 가능한 선택지 고유 링크
목록을 읽는 것보다 입력하는 편이 빠를 만큼 선택지가 많다면 searchable을 설정하세요. 선택지 위에 필터 필드가 열리면서 포커스를 받고, 아래 방향키로 첫 번째 활성 일치 항목으로 이동하며, 일치 항목이 하나만 남으면 Enter로 확정해요. 레이블이 아닌 값으로 맞추려면 filter를 넘기세요.
제품이 정하는 표시 방식 고유 링크
Select가 반응형 조건을 추측하게 하지 말고 제품의 너비 구간에서 표시 방식을 정하세요. `width`와 `height`는 고정 검색 헤더를 포함한 팝업 전체를 나타내고 각각 따로 기본값을 가지므로, 한쪽만 지정해도 나머지 한쪽은 그대로 유지돼요. 선택한 표시 방식은 크기가 바뀌어도 Select를 닫을 때까지 유지돼요.
API
표시 방식과 제어
| Prop | 타입 / 기본값 | 용도 |
|---|---|---|
presentation | TRSelectPresentation · const TRSelectPresentation.layer() | 다음에 열 때 사용할 표시 방식을 호출하는 쪽에서 정해요. 열릴 때의 값은 닫힐 때까지 유지돼요. |
TRSelectPresentation.layer | width, height, placement = bottomStart, useRootOverlay = true | 공유 패널을 충돌을 피하는 레이어로 열어요. width와 height는 각각 따로 기본값을 가지므로 한쪽을 지정해도 나머지는 그대로예요. 기본 너비는 기준 요소와 TRMeasurements.measureMd보다 작지 않고 콘텐츠에 따라 TRMeasurements.overlayWidthSm까지 늘어나며, 콘텐츠 높이는 TRMeasurements.measureXl까지 허용해요. |
TRSelectPresentation.sheet | maxExtent = 1, snapPoints = const [], showDragHandle = true | 같은 패널을 모달 바텀 시트로 열어요. 콘텐츠 제스처는 선택지 스크롤 영역이 소유하고 보이는 핸들만 시트를 움직여요. |
controller | TRSelectController? · null | 선택한 표시 방식과 관계없이 isOpen을 읽고 open, close, toggle을 호출해요. |
TRSelectFormField | FormField<T> | 타입이 있는 검증, 저장, 초기화 동작을 유지하면서 presentation과 controller를 전달해요. |
padding | TRFieldPadding · TRFieldPadding.standard | 트리거가 크기 단계에 정의된 좌우 여백을 스스로 넣을지 정해요. 행이나 툴바가 이미 여백을 주는 자리에서는 TRFieldPadding.none을 써서 값과 화살표가 옆에 놓인 컨트롤과 같은 선에서 끝나게 해요. 높이는 그대로라 누를 수 있는 영역은 달라지지 않아요. |
공통 레이어 크기
| Prop | 타입 / 기본값 | 용도 |
|---|---|---|
TRLayerSize | width = TRLayerWidth.content(), height = TRLayerHeight.content() | 테두리와 여백을 포함한 레이어 전체의 너비·높이 정책을 조합해요. |
TRLayerWidth.content | {double? min, double? max} | 선택적인 최소·최대 범위 안에서 콘텐츠가 너비를 정하게 해요. |
TRLayerWidth.fixed | double value | 안전 영역을 뺀 뷰포트로 제한하기 전에 정확한 너비를 요청해요. |
TRLayerWidth.matchAnchor | {double? min, double? max} | 기준 요소 너비를 사용하되 선택한 최소·최대 범위로 제한해요. |
TRLayerWidth.atLeastAnchor | {double? min, double? max} | 콘텐츠가 기준 요소 너비 이상에서 늘어나게 해요. 기준 요소가 max보다 넓으면 안전 영역을 뺀 뷰포트가 더 작지 않은 한 기준 요소 너비가 우선해요. |
TRLayerHeight.content | {double? min, double? max} | 선택적인 최소·최대 범위 안에서 콘텐츠가 높이를 정하게 해요. |
TRLayerHeight.fixed | double value | 안전 영역을 뺀 뷰포트로 제한하기 전에 정확한 높이를 요청해요. |