[as] feat: 행정지원 패널 전체접기/펼침 기능
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
export { NoData } from "./no-data";
|
||||
export { PageLayout } from "./page-layout";
|
||||
export { SectionCollapsible } from "./section-collapsible";
|
||||
export {
|
||||
SectionCollapsibleGroup,
|
||||
SectionCollapsibleToggle,
|
||||
} from "./section-collapsible-group";
|
||||
export type { TextShimmerProps } from "./text-shimmer";
|
||||
export { TEXT_SHIMMER_CLASS, TextShimmer } from "./text-shimmer";
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, type ReactNode, useCallback, useContext, useMemo, useState } from "react";
|
||||
|
||||
import { ChevronsDownUp, ChevronsUpDown } from "lucide-react";
|
||||
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface SectionCollapsibleGroupValue {
|
||||
batchOpen: boolean;
|
||||
batchVersion: number;
|
||||
expandAll: () => void;
|
||||
collapseAll: () => void;
|
||||
}
|
||||
|
||||
const SectionCollapsibleGroupContext = createContext<SectionCollapsibleGroupValue | null>(null);
|
||||
|
||||
function useSectionCollapsibleGroup() {
|
||||
return useContext(SectionCollapsibleGroupContext);
|
||||
}
|
||||
|
||||
interface SectionCollapsibleGroupProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
function SectionCollapsibleGroup({ children }: SectionCollapsibleGroupProps) {
|
||||
const [batch, setBatch] = useState({ open: true, version: 0 });
|
||||
|
||||
const expandAll = useCallback(() => {
|
||||
setBatch((prev) => ({ open: true, version: prev.version + 1 }));
|
||||
}, []);
|
||||
|
||||
const collapseAll = useCallback(() => {
|
||||
setBatch((prev) => ({ open: false, version: prev.version + 1 }));
|
||||
}, []);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
batchOpen: batch.open,
|
||||
batchVersion: batch.version,
|
||||
expandAll,
|
||||
collapseAll,
|
||||
}),
|
||||
[batch.open, batch.version, expandAll, collapseAll],
|
||||
);
|
||||
|
||||
return (
|
||||
<SectionCollapsibleGroupContext.Provider value={value}>
|
||||
{children}
|
||||
</SectionCollapsibleGroupContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function SectionCollapsibleToggle() {
|
||||
const group = useSectionCollapsibleGroup();
|
||||
|
||||
if (!group) return null;
|
||||
|
||||
const { batchOpen, expandAll, collapseAll } = group;
|
||||
|
||||
return (
|
||||
<div className="sticky top-[6rem] z-30 flex justify-start gap-2 bg-container px-4 py-2">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="white"
|
||||
className="gap-1 px-4 tracking-tight"
|
||||
aria-expanded={batchOpen}
|
||||
onClick={collapseAll}
|
||||
>
|
||||
<ChevronsDownUp className="shrink-0" />
|
||||
전체접기
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="white"
|
||||
className="gap-1 px-4 tracking-tight"
|
||||
aria-expanded={batchOpen}
|
||||
onClick={expandAll}
|
||||
>
|
||||
<ChevronsUpDown className="shrink-0" />
|
||||
전체펼침
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { SectionCollapsibleGroup, SectionCollapsibleToggle, useSectionCollapsibleGroup };
|
||||
@@ -1,11 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { type ReactNode, useState } from "react";
|
||||
|
||||
import { ChevronDown } from "lucide-react";
|
||||
|
||||
import { cn, Collapsible, CollapsibleContent, CollapsibleTrigger } from "@common/components";
|
||||
|
||||
import { useSectionCollapsibleGroup } from "./section-collapsible-group";
|
||||
|
||||
interface SectionCollapsibleProps {
|
||||
title: ReactNode;
|
||||
defaultOpen?: boolean;
|
||||
@@ -13,8 +15,19 @@ interface SectionCollapsibleProps {
|
||||
}
|
||||
|
||||
function SectionCollapsible({ title, defaultOpen = true, children }: SectionCollapsibleProps) {
|
||||
const group = useSectionCollapsibleGroup();
|
||||
const [open, setOpen] = useState(group?.batchOpen ?? defaultOpen);
|
||||
const [seenVersion, setSeenVersion] = useState(group?.batchVersion ?? 0);
|
||||
|
||||
if (group && group.batchVersion !== seenVersion) {
|
||||
setSeenVersion(group.batchVersion);
|
||||
setOpen(group.batchOpen);
|
||||
}
|
||||
|
||||
const collapsibleProps = group ? { open, onOpenChange: setOpen } : { defaultOpen };
|
||||
|
||||
return (
|
||||
<Collapsible defaultOpen={defaultOpen} className="mx-4 rounded-sm border bg-background">
|
||||
<Collapsible {...collapsibleProps} className="mx-4 rounded-sm border bg-background">
|
||||
<CollapsibleTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user