feat: integrate latest HMDesign design system updates

This commit is contained in:
DESKTOP-KPCP6AL\ㅅㅎ committed 2026-10-11 11:09:03 +09:00
1 parent 99faec189e
commit 1c4e0bb9a1
209 files changed
+8845 -552

No files matched your search

@@ -189,6 +189,7 @@ function DataTablePagination<TData extends RowData>({
className?: string
}) {
const { pageIndex, pageSize } = table.state.pagination
const pageSizeLabelId = React.useId()
const pageCount = Math.max(table.getPageCount(), 1)
const page = pageIndex + 1
const selected = table.getFilteredSelectedRowModel().rows.length
@@ -203,9 +204,9 @@ function DataTablePagination<TData extends RowData>({
{selected > 0 ? `${selected}개 선택됨 · 전체 ${total}개` : `전체 ${total}개`}
</p>
<div data-slot="data-table-page-size">
<span id="data-table-page-size-label">페이지당</span>
<span id={pageSizeLabelId}>페이지당</span>
<Select value={String(pageSize)} onValueChange={(value) => table.setPageSize(Number(value))}>
<SelectTrigger size="medium" aria-labelledby="data-table-page-size-label">
<SelectTrigger size="medium" aria-labelledby={pageSizeLabelId}>
<SelectValue />
</SelectTrigger>
<SelectContent>
@@ -14,8 +14,12 @@ import { Input, type InputSize } from "../../components/ui/input"
// <Select>…</Select> <Combobox … /> <DatePicker … />
// <FilterBarActions><Button onClick={reset}>초기화</Button></FilterBarActions>
// </FilterBar>
function FilterBar({ className, ...props }: React.ComponentProps<"div">) {
return <div data-slot="filter-bar" className={cn("flex flex-wrap items-center", className)} {...props} />
type FilterBarProps = React.ComponentProps<"div"> & {
/** Opt-in publisher list composition. Omitted preserves the general layout. */
layout?: "default" | "list-basic" | "list-extended"
}
function FilterBar({ className, layout = "default", ...props }: FilterBarProps) {
return <div data-slot="filter-bar" data-layout={layout === "default" ? undefined : layout} className={cn("flex flex-wrap items-center", className)} {...props} />
}
type FilterBarSearchProps = Omit<React.ComponentProps<"input">, "size" | "value" | "defaultValue" | "onChange" | "type"> & {
@@ -32,22 +36,30 @@ function FilterBarSearch({
size = "medium",
placeholder = "검색",
"aria-label": ariaLabel,
readOnly,
disabled,
ref,
...props
}: FilterBarSearchProps) {
const inputRef = React.useRef<HTMLInputElement>(null)
React.useImperativeHandle(ref, () => inputRef.current!, [])
return (
<div data-slot="filter-bar-search" className={cn("relative", className)}>
<SearchIcon aria-hidden="true" data-slot="filter-bar-search-icon" className="pointer-events-none absolute" />
<Input
ref={inputRef}
type="search"
size={size}
value={value}
placeholder={placeholder}
aria-label={ariaLabel ?? placeholder}
readOnly={readOnly}
disabled={disabled}
onChange={(event) => onValueChange(event.target.value)}
{...props}
/>
{value ? (
<button type="button" data-slot="filter-bar-search-clear" aria-label="검색어 지우기" className="absolute" onClick={() => onValueChange("")}>
{value && !readOnly && !disabled ? (
<button type="button" data-slot="filter-bar-search-clear" aria-label="검색어 지우기" className="absolute" onClick={() => { inputRef.current?.focus(); onValueChange("") }}>
<XIcon aria-hidden="true" />
</button>
) : null}
@@ -61,4 +73,4 @@ function FilterBarActions({ className, ...props }: React.ComponentProps<"div">)
}
export { FilterBar, FilterBarActions, FilterBarSearch }
export type { FilterBarSearchProps }
export type { FilterBarProps, FilterBarSearchProps }
+3 -3
View File
@@ -115,14 +115,14 @@ type GNBUserProps = Omit<React.ComponentProps<"button">, "children"> & {
// Trigger button of the user menu: name / role text on the desktop bar; the Avatar (children) shows on the mobile bar only, where the
// text is hidden (ui-viz's profile is text-only, so the desktop bar has no image). Because of that the
// accessible name defaults to "<name> 사용자 메뉴". Use it as `<DropdownMenuTrigger asChild>`; the data-slot comes after the
// accessible name includes the visible name and description, followed by "사용자 메뉴". Use it as `<DropdownMenuTrigger asChild>`; the data-slot comes after the
// spread so the trigger's own slot does not replace it (same rule as Button).
function GNBUser({ className, name, description, children, "aria-label": ariaLabel, ...props }: GNBUserProps) {
return (
<button type="button" aria-label={ariaLabel ?? `${name} 사용자 메뉴`} className={cn("flex items-center", className)} {...props} data-slot="gnb-user">
<button type="button" aria-label={ariaLabel ?? `${name}${description ? ` ${description}` : ""} 사용자 메뉴`} className={cn("flex items-center", className)} {...props} data-slot="gnb-user">
{children}
<span data-slot="gnb-user-text">
<span data-slot="gnb-user-name">{name}</span>
<span data-slot="gnb-user-name">{name}{description ? " " : null}</span>
{description ? <span data-slot="gnb-user-description">{description}</span> : null}
</span>
</button>
+2 -2
View File
@@ -99,10 +99,10 @@ type LNBProfileProps = Omit<React.ComponentProps<"button">, "children"> & {
// it composes directly with `DropdownMenuTrigger asChild`; Radix owns Enter / Space, arrow navigation, Escape and focus return.
function LNBProfile({ className, name, description, children, "aria-label": ariaLabel, ...props }: LNBProfileProps) {
return (
<button type="button" aria-label={ariaLabel ?? `${name} 사용자 메뉴`} className={cn(className)} {...props} data-slot="lnb-profile">
<button type="button" aria-label={ariaLabel ?? `${name}${description ? ` ${description}` : ""} 사용자 메뉴`} className={cn(className)} {...props} data-slot="lnb-profile">
{children}
<div data-slot="lnb-profile-text">
<strong>{name}</strong>
<strong>{name}{description ? " " : null}</strong>
{description ? <p>{description}</p> : null}
</div>
</button>