feat: integrate latest HMDesign design system updates
This commit is contained in:
1 parent
99faec189e
commit
1c4e0bb9a1
209 files changed
+8845
-552
No files matched your search
+20
-13
@@ -1,5 +1,7 @@
|
||||
# Filter Bar (Pattern)
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 공통 FilterBar 기본 배치는 유지. 목록 소비자는 공개 `layout="list-basic" | "list-extended"` prop으로 가운데·왼쪽 정렬과 actions auto margin 제거를 선택한다. 기존 [src/list-screen.css](../../src/list-screen.css) 소비자는 호환성을 유지한다. PageHeader 밖의 흰 Card 하나에 조건→검색어→조회→초기화 순서, 간격 8px, 조회 Solid Green·초기화 Outline Gray를 적용한다. readOnly·disabled Search에는 Clear 버튼을 노출하지 않는다. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7, Pattern 절)를 따른다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -14,7 +16,7 @@
|
||||
|
||||
## 2. 목적 / 사용 범위
|
||||
|
||||
목록·업무 화면의 검색 조건 행. Data Table 없이도 쓸 수 있고, 값은 소비자가 소유한다. ui-viz의 Search Field(선택값 칩 + 후보)는 별개의 복합 컨트롤이라 이 Pattern에 넣지 않았다.
|
||||
목록·업무 화면의 검색 조건 행. Table·Card 목록·모바일 목록의 검색에서 우선 검토하며 Data Table 없이도 쓸 수 있고, 값은 소비자가 소유한다. 맞는 부분만 조합할 수 있다. 요구사항이 chips/복수 검색 등 공개 API·구조로 표현되지 않으면 구체적인 미사용 이유를 기록하고 HM Component로 조합한다. ui-viz의 Search Field(선택값 칩 + 후보)는 별개의 복합 컨트롤이라 이 Pattern에 넣지 않았다.
|
||||
|
||||
## 3. 구성 요소
|
||||
|
||||
@@ -23,16 +25,19 @@
|
||||
## 4. 구조
|
||||
|
||||
```tsx
|
||||
<FilterBar>
|
||||
<FilterBarSearch value={q} onValueChange={setQ} placeholder="이름·부서 검색" />
|
||||
<FilterBar layout="list-extended">
|
||||
<Select>…</Select> <Combobox … /> <DatePicker … />
|
||||
<FilterBarActions><Button variant="cancel" appearance="outline">초기화</Button></FilterBarActions>
|
||||
<FilterBarSearch value={q} onValueChange={setQ} placeholder="이름·부서 검색" />
|
||||
<FilterBarActions>
|
||||
<Button type="button" variant="primary" appearance="solid" onClick={apply}>조회</Button>
|
||||
<Button type="button" variant="cancel" appearance="outline" onClick={reset}>초기화</Button>
|
||||
</FilterBarActions>
|
||||
</FilterBar>
|
||||
```
|
||||
|
||||
## 5. Public API
|
||||
|
||||
- `FilterBar`, `FilterBarActions`: `div` props. wrapper에 role을 두지 않는다.
|
||||
- `FilterBar`: `div` props + 선택적 `layout: "default" | "list-basic" | "list-extended"`. 기본은 기존 배치 유지. `FilterBarProps` 공개 type 추가. `FilterBarActions`: `div` props. wrapper에 role을 두지 않는다.
|
||||
- `FilterBarSearch`: `value`, `onValueChange`(필수), `size`(Input size, 기본 `medium`), `placeholder`(기본 "검색"), 나머지 `input` props. `aria-label` 기본값은 placeholder. 값이 있으면 지우기 버튼(`aria-label="검색어 지우기"`).
|
||||
- Reset은 소비자가 Button과 callback으로 구성한다(Pattern에 `onReset` prop 없음).
|
||||
- Dashboard의 빠른 상태 전환(`all / active / hold / done / issue`)은 `FilterBar`가 소유하지 않는다. `FilterBar`는 검색·Select·Combobox·DatePicker 등의 조회 조건 layout으로 유지하고, 상태 필터는 Dashboard status contract를 소비하는 별도 조합으로 배치한다.
|
||||
@@ -41,9 +46,9 @@
|
||||
|
||||
Pattern은 상태가 없다. Data Table과 연결할 때는 검색 → `table.setGlobalFilter`, 열 선택 → `column.setFilterValue`로 소비자가 잇는다(`data-table.md` §6).
|
||||
|
||||
FilterBar에는 `onSearch / onSubmit / onReset` 공개 API나 조회 시점 강제가 없다. 검색어 지우기도 `onValueChange("")`만 호출한다. 즉시 적용할지 조회 버튼으로 적용할지, 초기화 후 바로 전체 목록을 복원할지는 소비자가 결정한다. [대표 Story](../../src/patterns/filter-bar.stories.tsx)의 조회 버튼에는 실행 callback이 없고 조건 수는 입력값으로 계산한다. [DataTable 연동 verification](../../src/patterns/data-table.stories.tsx)의 `WithFilterBarStory`는 입력 즉시 table 필터를 변경하며 조회 버튼은 없다. 이 둘을 조회 버튼 적용 계약으로 해석하지 않는다.
|
||||
FilterBar에는 `onSearch / onSubmit / onReset` 공개 API나 조회 시점 강제가 없다. 검색어 지우기도 `onValueChange("")`만 호출한다. 즉시 적용할지 조회 버튼으로 적용할지, 초기화 후 바로 전체 목록을 복원할지는 소비자가 결정한다. [대표 Story](../../src/patterns/filter-bar.stories.tsx)는 입력 조건 수와 조회 적용 조건 수를 구분하고 조회/초기화 callback을 실행한다. [DataTable 연동 verification](../../src/patterns/data-table.stories.tsx)의 `WithFilterBarStory`는 입력 즉시 table 필터를 변경하며 조회 버튼은 없다. 이 둘을 조회 버튼 적용 계약으로 해석하지 않는다.
|
||||
|
||||
DatePicker / Combobox는 대표 Story에서 `controlled={true}`로 사용한다. 부모가 각 `value`를 소유하고 초기화 시 `setDate(undefined)` / `setCategory(undefined)`로 비우므로, 선택값 초기화 목적의 `key` remount는 필요 없다. 검색·상태 등 나머지 조회 조건도 부모가 함께 초기화한다. FilterBar 공개 API와 초기화 / 조회 Outline 버튼 세트는 유지한다. 외부 값 초기화는 자식 `onValueChange`를 호출하지 않으며, 팝업 닫기·검색어·달력 월 초기화를 보장하지 않는다.
|
||||
DatePicker / Combobox는 대표 Story에서 `controlled={true}`로 사용한다. 부모가 각 `value`를 소유하고 초기화 시 `setDate(undefined)` / `setCategory(undefined)`로 비우므로, 선택값 초기화 목적의 `key` remount는 필요 없다. 검색·상태 등 나머지 조회 조건도 부모가 함께 초기화한다. FilterBar 공개 API는 유지하고 목록의 조회/초기화 버튼은 위 최신 소비 계약을 따른다. 외부 값 초기화는 자식 `onValueChange`를 호출하지 않으며, 팝업 닫기·검색어·달력 월 초기화를 보장하지 않는다.
|
||||
|
||||
### 6.1 조회 버튼으로 적용하는 소비 예제
|
||||
|
||||
@@ -52,7 +57,7 @@ DatePicker / Combobox는 대표 Story에서 `controlled={true}`로 사용한다.
|
||||
```tsx
|
||||
import { useMemo, useState } from "react"
|
||||
import {
|
||||
Button, DataTable, FilterBar, FilterBarActions, FilterBarSearch,
|
||||
Button, Card, CardContent, DataTable, FilterBar, FilterBarActions, FilterBarSearch,
|
||||
Select, SelectContent, SelectItem, SelectTrigger, SelectValue, useDataTable,
|
||||
type DataTableColumnDef,
|
||||
} from "@hm-design/ui"
|
||||
@@ -84,8 +89,8 @@ export function QueryList() {
|
||||
table.setPageIndex(0)
|
||||
}
|
||||
return <>
|
||||
<FilterBar>
|
||||
<FilterBarSearch value={draft.query} onValueChange={query => setDraft(s => ({ ...s, query }))} placeholder="이름 검색" />
|
||||
<Card><CardContent>
|
||||
<FilterBar layout="list-basic">
|
||||
<Select value={draft.status} onValueChange={status => setDraft(s => ({ ...s, status }))}>
|
||||
<SelectTrigger size="medium" aria-label="사용자 상태"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -94,13 +99,15 @@ export function QueryList() {
|
||||
<SelectItem value="inactive">비활성</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FilterBarSearch value={draft.query} onValueChange={query => setDraft(s => ({ ...s, query }))} placeholder="이름 검색" />
|
||||
<FilterBarActions>
|
||||
<Button type="button" variant="primary" appearance="solid" size="default" onClick={apply}>조회</Button>
|
||||
<Button type="button" variant="cancel" appearance="outline" size="default" onClick={reset}>초기화</Button>
|
||||
<Button type="button" variant="primary" appearance="outline" size="default" onClick={apply}>조회</Button>
|
||||
</FilterBarActions>
|
||||
</FilterBar>
|
||||
<p role="status">조회 결과 {data.length}건</p>
|
||||
<DataTable table={table} emptyMessage="조건에 맞는 사용자가 없습니다." />
|
||||
</CardContent></Card>
|
||||
</>
|
||||
}
|
||||
```
|
||||
@@ -119,11 +126,11 @@ Input, Select, Combobox, Date Picker, Button(그 외 Popover 등 자유). 각
|
||||
|
||||
`Patterns/Data/Filter Bar` → `Filter Bar`: 검색, 상태 Select, 분류 Combobox, 날짜 Date Picker, 초기화 / 조회, 적용된 조건 수.
|
||||
|
||||
대표 Story의 초기화 / 조회는 목록의 반복 조회·보조 작업 세트다. [Button 사용 위치와 버튼 세트 규칙](../components/button.md#5-사용-위치와-버튼-세트)에 따라 둘 다 `appearance="outline"`, `size="default"`를 사용하고 역할만 `cancel` / `primary`로 구분한다. FilterBar는 Button appearance를 강제하지 않으며 소비자가 같은 세트의 appearance와 size를 맞춘다. 대표 Story의 조회는 실행 callback이 없는 조합 예시이고, 적용된 조건 수는 입력 상태에 즉시 반영된다.
|
||||
현재 대표 Story는 조건→검색어→조회→초기화, 조회 `variant="primary" appearance="solid"`·초기화 `variant="cancel" appearance="outline"`를 사용한다. 이는 [최신 목록 검색 계약](../guidelines/publisher-additional-review-2026-10-10.md)에 따른 Button 세트 예외다. FilterBar 자체가 Button appearance나 조회 시점을 강제하지 않는다. 대표 Story의 입력 조건 수는 즉시 변하지만 조회 적용 조건 수는 조회 클릭에만 반영되며 초기화는 둘 다 비운다. 업무 화면은 §6.1처럼 요청된 동작을 구현하며 Story의 부가 기능을 필수로 복사하지 않는다.
|
||||
|
||||
## 10. Accessibility
|
||||
|
||||
검색은 `type="search"` + `aria-label`, 아이콘은 `aria-hidden`. 컨트롤마다 `aria-label`을 준다(Story 기준). Reset·Clear는 `button`. wrapper는 시맨틱 변경 없음. 브라우저 기본 검색 지우기 버튼은 숨기고 자체 버튼을 쓴다.
|
||||
검색은 `type="search"` + `aria-label`, 아이콘은 `aria-hidden`. 컨트롤마다 `aria-label`을 준다(Story 기준). Reset·Clear는 `button`. wrapper는 시맨틱 변경 없음. 지우기 버튼이 사라질 때 검색 입력에 focus를 돌려주며 소비자 ref 전달을 유지한다. 브라우저 기본 검색 지우기 버튼은 숨기고 자체 버튼을 쓴다.
|
||||
|
||||
## 11. Responsive
|
||||
|
||||
|
||||
Reference in new issue
Block a user