본문으로 건너뛰기

PlList

행이 쌓인 묶음입니다. 목록이 시트이고 행은 그 위에 놓인 것이므로, sizedensity는 묶음의 속성이고 행은 그것을 물려받습니다.

React
tsx
import { PlList, PlListItem } from 'plass-ui';

<PlList>
  <PlListItem description="Three unread" onClick={open}>
    Inbox
  </PlListItem>
  <PlListItem description="One saved">Drafts</PlListItem>
</PlList>;
dart
import 'package:plass_ui/plass_ui.dart';

PlList(
  children: <Widget>[
    PlListItem(description: const Text('Three unread'), onPressed: open, child: const Text('Inbox')),
    const PlListItem(description: Text('One saved'), child: Text('Drafts')),
  ],
);

Props

Prop타입기본값설명
variant공통'solid' | 'glass' | 'ghost''glass'시트의 재질. 컨테이너가 그렇듯 시트에는 색이 들어가지 않습니다. card 안이라면 ghost — card가 이미 시트인데 그 안의 두 번째 테두리는 사각형이 하나 더 늘어난 것뿐입니다
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은 그림자 없음
dividersbooleanfalse행을 여백 대신 헤어라인으로 나눕니다. 들리는 것보다 많이 바뀝니다 — 선이 시트의 양 끝까지 닿아야 하므로 시트는 안쪽 여백을, 행은 둥근 모서리를 내놓습니다
renderuseRender.RenderPropul이 아닌 다른 요소로 렌더링합니다 — 순서가 핵심인 목록이라면 render={<ol />}
childrenReactNodePlListItem들
Prop타입기본값설명
children * List<Widget>행들
variant공통PlassVariantPlassVariant.glass시트의 재질. 컨테이너가 그렇듯 시트에는 색이 들어가지 않습니다. card 안이라면 ghost — card가 이미 시트인데 그 안의 두 번째 테두리는 사각형이 하나 더 늘어난 것뿐입니다
size공통PlassSizePlassSize.md행의 타입 스케일과 여백. 행마다가 아니라 묶음 전체의 속성입니다
color공통PlassColorPlassColor.primary의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통PlassDensityPlassDensity.standard여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통int0그림자 깊이. 0은 그림자 없음
dividersboolfalse행을 여백 대신 헤어라인으로 나눕니다. 들리는 것보다 많이 바뀝니다 — 선이 시트의 양 끝까지 닿아야 하므로 시트는 안쪽 여백을, 행은 둥근 모서리를 내놓습니다

네이티브 <ul> 속성은 그대로 전달됩니다. color는 여기서 Plass의 prop이라 전달 대상에서 제외됩니다.

PlListItem

Prop타입기본값설명
onClick(event: MouseEvent) => void넘기는 것이 행을 진짜 button으로 만듭니다. li가 아니라 그 button에 놓입니다
hrefstring행을 링크로 그립니다
startIconReactNode라벨 앞의 것 — 아이콘, avatar, 상태 점
endIconReactNode라벨 뒤, 누를 수 있는 영역 안쪽의 것
descriptionReactNode라벨 아래 한 줄. 타입 스케일 한 칸 아래에 흐린 색
actionReactNode행 끝에 고정되는 컨트롤 — switch, 메뉴 버튼. 일부러 누를 수 있는 영역 **바깥**입니다. 이동도 하고 토글도 담는 행에는 누를 것이 둘이고, button 안의 button은 브라우저가 파싱하며 다시 쓰는 마크업입니다
selectedbooleanfalse선택된 행 — 열린 페이지, 현재 필터. 링크에는 aria-current="page", button에는 "true"가 붙습니다
disabled공통booleanfalse사용할 수 없음. 빛이 꺼지고 누를 수 없게 됩니다
childrenReactNode라벨
Prop타입기본값설명
childWidget?라벨
onPressedVoidCallback?넘기는 것이 행을 진짜 button으로 만듭니다. li가 아니라 그 button에 놓입니다
startIconWidget?라벨 앞의 것 — 아이콘, avatar, 상태 점
endIconWidget?라벨 뒤, 누를 수 있는 영역 안쪽의 것
descriptionWidget?라벨 아래 한 줄. 타입 스케일 한 칸 아래에 흐린 색
actionWidget?행 끝에 고정되는 컨트롤 — switch, 메뉴 버튼. 일부러 누를 수 있는 영역 **바깥**입니다. 이동도 하고 토글도 담는 행에는 누를 것이 둘이고, button 안의 button은 브라우저가 파싱하며 다시 쓰는 마크업입니다
selectedboolfalse선택된 행 — 열린 페이지, 현재 필터. 링크에는 aria-current="page", button에는 "true"가 붙습니다
disabled공통boolfalse사용할 수 없음. 빛이 꺼지고 누를 수 없게 됩니다

네이티브 <li> 속성은 안쪽의 button이나 link가 아니라 <li>에 그대로 전달됩니다. size, density, dividers는 감싸는 PlList에서 상속됩니다. 그중 하나를 두고 이웃과 의견이 다른 행은 구멍 난 목록입니다.

size, density, color, dividers는 감싸는 PlList에서 InheritedWidget을 통해 상속됩니다. 그중 하나를 두고 이웃과 의견이 다른 행은 구멍 난 목록입니다. PlList 밖의 PlListItem이 기본값을 고르는 대신 단언으로 막는 이유이기도 합니다. 행은 무언가 행입니다.

라이브러리 전체에서 공유 축(variant size color density elevation)이 뜻하는 바는 prop 규칙에 있습니다.

Examples

행 하나

껍데기는 언제나 <li>입니다. 바뀌는 것은 그 안에 든 것입니다. 그냥 내용이 놓이거나, onClick이나 href가 주어지면 그 내용을 감싸는 진짜 <button> 또는 <a>가 놓입니다.

action은 일부러 그 누를 수 있는 영역 바깥에 놓입니다. 이동도 하고 토글도 담는 행에는 누를 것이 둘이고, <button> 안의 <button>은 브라우저가 파싱하며 다시 쓰는 마크업입니다.

onPressed가 있는 행은 버튼으로 알려지는 focus stop이고, 없는 행은 role도 focus stop도 더하지 않습니다.

action은 일부러 그 누를 수 있는 영역 바깥에 놓입니다. 이동도 하고 토글도 담는 행에는 누를 것이 둘이고, 중첩된 제스처 인식기는 탭 하나를 두 번 받습니다.

React

dividers

dividers를 켜면 선이 시트의 양 끝까지 닿아야 하므로, 목록은 안쪽 여백을 내놓고 행은 둥근 모서리를 내놓습니다. 행이 떠 있는 타일이면서 동시에 그어진 줄일 수는 없습니다.

React

variant

PlCard가 그렇듯 시트에는 색이 들어가지 않습니다. 목록은 남의 내용을 담고, 그 내용은 자기 색을 가지고 도착합니다.

card 안이라면 ghost입니다. card가 이미 시트인데, 그 안의 두 번째 테두리 사각형은 사각형이 하나 더 늘어난 것뿐입니다.

React

size

React

Accessibility

  • 아래에 Base UI 프리미티브가 없는 것은 의도입니다. 목록은 복합 위젯이 아닙니다. roving focus도, 선택 모델도, 자기만의 키보드 규약도 없습니다. menu나 listbox 프리미티브를 끌어오면 그냥 링크 목록에 메뉴의 의미를 붙이게 됩니다.
  • role="list"를 명시적으로 씁니다. Tailwind의 리셋이 모든 <ul>에서 불릿을 없애고, Safari는 그와 함께 목록 의미까지 없애기 때문입니다.
  • 선택된 링크는 aria-current="page"를, 선택된 button은 aria-current="true"를 답니다. 앞의 것은 "지금 보고 있는 페이지", 뒤의 것은 "이것들 중 고른 하나"입니다. aria-pressed는 세 번째 것, 즉 토글이고, 선택된 행은 토글이 아닙니다.
  • onClickhref도 없는 행은 role도 tab stop도 더하지 않습니다. click 핸들러만 달린 죽은 <div>는 키보드에 보이지 않습니다.
  • action에 든 컨트롤에는 자기 이름을 주세요. 행과는 별개의 tab stop이고, 거기 있는 이유가 그것입니다.
  • 목록은 복합 위젯이 아닙니다(roving focus도, 선택 모델도, 자기만의 키보드 규약도 없습니다). 그래서 행을 묶는 것 말고는 role을 더하지 않고, 각 행이 스스로 이름을 갖습니다.
  • 선택된 행은 선택되었다고 보고합니다. 토글이 아니고, 토글인 척하지도 않습니다.
  • onPressed가 없는 행은 role도 focus stop도 더하지 않습니다.
  • action에 든 위젯에는 자기 이름을 주세요. 행과는 별개의 focus stop이고, 거기 있는 이유가 그것입니다.
  • 목록에 선이 그어져 있으면 행의 focus ring은 안쪽으로 돌아섭니다. 잘리는 시트 가장자리에서 잘려 나가지 않게 하기 위해서입니다.

React 빌드와 다른 점

ReactFlutter이유
onClick / hrefonPressedFlutter에는 링크 요소가 없습니다. 이동하는 행은 onPressed에서 라우터를 부릅니다.
<ul> / <li>role="list"묶인 semantics 노드리셋할 불릿도, 리셋이 앗아 갈 목록 의미도 없습니다.
aria-current="page""true"selectedFlutter의 semantics 트리에는 선택 플래그 하나가 있을 뿐, 페이지와 선택지의 구분이 없습니다.
React 컨텍스트InheritedWidget같은 생각을 Flutter의 말로, 같은 이유로 한 것입니다. 자식을 복제하는 방식은 호출자가 행을 한 번 감싸는 순간 닿지 않게 됩니다.
renderFlutter에는 요소를 바꿔 끼우는 수단이 없습니다.
행의 childrenchildFlutter의 이름입니다.

Released under the MIT License