CommandPalette
애플리케이션이 할 수 있는 모든 것을 필드 하나 뒤에 둡니다. 메뉴 바가 담을 수 있는 것보다 액션이 많아진 키보드 중심 제품이 취하는 모양입니다. 어디에 두었는지 기억하는 대신, 원하는 것을 입력합니다.
import { CommandPalette } from 'neba';
<CommandPalette
items={[
{ value: 'deploy', label: 'Deploy production', group: 'Actions', onSelect: deploy },
{ value: 'logs', label: 'Go to logs', group: 'Navigate' }
]}
/>;Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| items * | readonly CommandItem[] | — | 팔레트가 할 수 있는 모든 것 |
| open | boolean | — | 팔레트가 열려 있는지. onOpenChange와 함께 쓰면 controlled 컴포넌트가 됩니다 |
| defaultOpen | boolean | false | 열린 채로 시작할지 (uncontrolled) |
| onOpenChange | (open: boolean) => void | — | 열리고 닫힐 때마다 호출됩니다 |
| onSelect | (item: CommandItem) => void | — | 명령이 실행될 때, 그 명령 자신의 onSelect 뒤에 호출됩니다. 어느 쪽이든 팔레트는 닫힙니다 |
| shortcut | string | false | 'Mod+K' | 팔레트를 여는 키. window에 바인딩됩니다. Mod는 Mac에서 Command, 그 밖에서는 Control입니다. false는 아무것도 바인딩하지 않습니다 |
| width | number | string | — | 시트가 넓어질 수 있는 한계. 숫자는 px입니다 |
| maxHeight | number | string | 320 | 목록이 스크롤되기 전까지의 높이 |
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 타입 스케일과 필드의 높이, 시트의 너비 상한 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | 표시된 행과 시트의 가장자리가 띠는 색 역할 |
| density공통 | 'default' | 'compact' | 'default' | 행의 세로 여백만 바꿉니다 |
| locale | string | — | BCP 47 태그. placeholder와 빈 줄, dialog의 이름을 이 언어로 씁니다 |
| placeholder | string | — | 필드의 placeholder |
| emptyMessage | ReactNode | — | 아무것도 맞지 않았을 때 행이 있었을 자리의 문구 |
| label | string | — | dialog의 접근성 이름. 보이는 제목이 없습니다 |
| className | string | — | 시트에 붙는 class |
| classNames | NebaSlots<'backdrop' | 'viewport' | 'input' | 'list' | 'group' | 'item' | 'empty'> | — | 루트 뒤에 있는 각 파트의 class. 루트 자체는 className이 맡으므로 root 키는 없습니다 |
CommandItem
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| value * | string | — | 명령을 식별하는 값 |
| label * | string | — | 행에 쓰이는 말이자 검색어가 대조되는 대상 |
| description | ReactNode | — | 라벨 아래 한 줄, 어디로 가는지, 무엇을 바꾸는지 |
| icon | ReactNode | — | 라벨 앞의 글리프 |
| shortcut | string | — | 같은 일을 하는 키. Shortcut과 같은 표기이며, 팔레트가 바인딩하지는 않습니다 |
| group | string | — | 이 명령이 속한 제목. group이 바뀔 때마다 제목이 그려지므로 같은 그룹은 붙여서 나열해야 합니다 |
| keywords | readonly string[] | — | 검색에는 쓰이지만 그려지지 않는 단어들 |
| disabled | boolean | false | 목록에는 있지만 실행되지 않습니다 |
| onSelect | () => void | — | 실행했을 때 하는 일 |
Menu는 한자리에 있는 짧은 목록이라 찾기 전에 이미 모든 행이 보입니다. Combobox는 값을 돌려줍니다. 이 컴포넌트는 실행되는 동작을 돌려줍니다.
예시
items · group
명령은 주어진 순서대로 그려지고, group이 바뀔 때마다 제목이 그려집니다. 그래서 한 그룹의 명령은 붙여서 나열해야 합니다. icon과 shortcut이 행의 양 끝을 채우고, description은 라벨 아래 한 줄이 됩니다.
keywords
검색에는 쓰이지만 화면에는 절대 그려지지 않는 단어들입니다. 같은 명령을 다른 제품이 부르는 이름, 약어, 독자가 검색했을 법한 말. undo라고 쳐서 Roll back이 나오는 것이 팔레트를 두 번 열게 만드는 이유입니다.
shortcut
팔레트를 여는 키이며 window에 바인딩됩니다. Mod는 Mac에서 Command, 그 밖에서는 Control입니다. Shortcut이 그리는 것과 같은 표기를, 쓰는 대신 읽습니다. false는 아무것도 바인딩하지 않습니다. 키보드를 직접 관리하는 애플리케이션을 위한 것입니다.
onSelect
각 명령이 자기 onSelect를 가질 수 있고, 팔레트의 onSelect는 그 뒤에 항목과 함께 호출됩니다. 어느 쪽이든 팔레트는 닫히며, 입력한 검색어는 닫히는 길에 버려집니다.
size
size는 타입 스케일과 필드의 높이, 시트가 넓어질 수 있는 한계를 정합니다. width와 maxHeight는 뒤의 두 가지를 각각 덮어씁니다.
className · classNames
className은 시트(검색 필드와 행이 놓이는 판)에 붙습니다. 그 바깥과 안쪽은 모두 classNames로 갑니다.
<CommandPalette
items={commands}
className="max-w-2xl"
classNames={{ backdrop: 'backdrop-blur-none', item: 'rounded-none' }}
/>slot은 backdrop, viewport, input, list, group, item, empty입니다. backdrop과 viewport는 시트 바깥에 그려지므로 시트를 기준으로 쓴 것으로는 찾을 수 없고, group은 행 사이의 heading 하나이지 그 아래 행들이 아닙니다. 넘긴 class가 컴포넌트 자신의 class와 어떻게 겨루는지는 prop 규약을 보세요.
접근성
- 시트는
label이 이름이 되는 modal dialog입니다. 보이는 제목이 따로 없습니다. 열릴 때 focus가 필드로 들어가고, 닫힐 때 독자가 있던 자리로 되돌아갑니다. - 필드는
listbox위의combobox이며, 표시된 행은aria-activedescendant로 전달됩니다. 포인터와 방향키가 같은 표시를 움직이므로 Enter가 표시된 것 외의 행을 실행하는 일이 없습니다. - Escape로 닫힙니다.
- 팔레트가 어떤 명령에 이르는 유일한 통로가 되어서는 안 됩니다. 안에 있는 모든 것은 다른 경로로도 닿을 수 있어야 합니다. 팔레트의 존재를 모르는 독자에게 다른 기회는 없습니다.