@loword/loword-design-system 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,7 @@ const Next = ({ children, className, ...props }) => (_jsx(LDDataCalendarBase.Nex
17
17
  /** 요일과 날짜 셀을 7열로 렌더링하는 그리드입니다. */
18
18
  const Grid = ({ weekdayClassName, ...props }) => (_jsx(LDDataCalendarBase.Grid, { weekdayClassName: cn('py-[10px] display14 text-mono500 mobile:py-1 mobile:display12', weekdayClassName), ...props }));
19
19
  /** 날짜와 해당 날짜의 데이터를 표시하는 셀입니다. */
20
- const Cell = ({ className, dateClassName, ...props }) => (_jsx(LDDataCalendarBase.Cell, { className: cn('flex min-h-[100px] flex-col gap-[15px] py-[10px] data-outside:*:text-mono400 mobile:min-h-13 mobile:gap-1 mobile:py-1', 'ld-transition data-selectable:cursor-pointer data-selectable:rounded-[5px] data-selectable:hover:bg-mono100', 'data-[selected=true]:bg-tintBlue data-[selected=true]:hover:bg-tintBlue', className), dateClassName: cn('self-start display16 leading-none font-normal data-outside:font-normal data-outside:text-mono400 data-weekend:text-danger600 data-outside:data-weekend:text-danger400 mobile:display12', dateClassName), ...props }));
20
+ const Cell = ({ className, dateClassName, ...props }) => (_jsx(LDDataCalendarBase.Cell, { className: cn('flex min-h-25 flex-col gap-[15px] py-[10px] data-outside:opacity-50 mobile:min-h-13 mobile:gap-1 mobile:py-1', 'ld-transition data-selectable:cursor-pointer data-selectable:rounded-[5px] data-selectable:hover:bg-mono100', 'data-[selected=true]:bg-tintBlue data-[selected=true]:hover:bg-tintBlue', className), dateClassName: cn('self-start display16 leading-none font-normal data-weekend:text-danger600 mobile:display12', dateClassName), ...props }));
21
21
  /** 선택한 날짜의 상세 내용을 표시하는 모바일 영역입니다. */
22
22
  const Detail = ({ className, ...props }) => (_jsx(LDDataCalendarBase.Detail, { className: cn('mt-md hidden rounded-[10px] bg-mono50 p-md mobile:block', className), ...props }));
23
23
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"LDLNB.d.ts","sourceRoot":"","sources":["../../../src/components/LDLNB/LDLNB.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIpD,OAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAIpE,MAAM,WAAW,UAAU;IACzB,kBAAkB;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iCAAiC;IACjC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD;;;;GAIG;AACH,QAAA,MAAM,KAAK,GAAI,yKAgBZ,UAAU,4CAqGZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"LDLNB.d.ts","sourceRoot":"","sources":["../../../src/components/LDLNB/LDLNB.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIpD,OAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAGpE,MAAM,WAAW,UAAU;IACzB,kBAAkB;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iCAAiC;IACjC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD;;;;GAIG;AACH,QAAA,MAAM,KAAK,GAAI,yKAgBZ,UAAU,4CAoGZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
@@ -6,7 +6,6 @@ import { useEffect, useState } from 'react';
6
6
  import LDDrawer from '../../components/LDDrawer/LDDrawer.js';
7
7
  import LNBBase from '../../components/LDLNB/LNBBase.js';
8
8
  import cn from '../../utils/cn.js';
9
- import { isActivePath } from '../../utils/utils.js';
10
9
  // mobile: variant(max-width: calc(--size_md - 1px) = 767px)와 동일 기준
11
10
  const MOBILE_QUERY = '(max-width: 767px)';
12
11
  // tablet: variant(--size_md 768px ~ calc(--size_lg - 1px) 991px)와 동일 기준
@@ -39,7 +38,7 @@ const LDLNB = ({ items, pathname, as = Link, onNavigate, name, email, profileIma
39
38
  };
40
39
  }, []);
41
40
  const resolvedSize = size ?? (isTablet ? TABLET_SIZE : PC_SIZE);
42
- const nav = (isMobile) => (_jsx(LNBBase.Provider, { isMobile: isMobile, items: items, pathname: pathname, defaultCollapsed: isMobile ? false : defaultCollapsed, size: resolvedSize, minWidth: minWidth, children: _jsxs(LNBBase.Root, { className: className, trigger: _jsx(LNBBase.Trigger, {}), children: [_jsx(LNBBase.Header, { name: name, email: email, profileImage: profileImage, handleLogout: handleLogout }), isMobile && children, _jsx(LNBBase.Content, { children: items.map((group) => (_jsx(LNBBase.Group, { label: group.label, noSlider: group.noSlider, children: _jsx(LNBBase.Menu, { label: group.label, noSlider: group.noSlider, tabCount: group.tabs?.length ?? 0, children: group.tabs?.map((tab) => (_jsx(LNBBase.MenuItem, { as: as, href: tab.path, icon: tab.icon, isActive: isActivePath(pathname, tab.path), onClick: () => {
41
+ const nav = (isMobile) => (_jsx(LNBBase.Provider, { isMobile: isMobile, items: items, pathname: pathname, defaultCollapsed: isMobile ? false : defaultCollapsed, size: resolvedSize, minWidth: minWidth, children: _jsxs(LNBBase.Root, { className: className, trigger: _jsx(LNBBase.Trigger, {}), children: [_jsx(LNBBase.Header, { name: name, email: email, profileImage: profileImage, handleLogout: handleLogout }), isMobile && children, _jsx(LNBBase.Content, { children: items.map((group) => (_jsx(LNBBase.Group, { label: group.label, noSlider: group.noSlider, children: _jsx(LNBBase.Menu, { label: group.label, noSlider: group.noSlider, tabCount: group.tabs?.length ?? 0, children: group.tabs?.map((tab) => (_jsx(LNBBase.MenuItem, { as: as, href: tab.path, icon: tab.icon, onClick: () => {
43
42
  onNavigate?.(tab.path);
44
43
  setOpen(false);
45
44
  }, children: tab.label }, tab.path))) }) }, group.label))) }), _jsx(LNBBase.ResizeWidthBar, { className: "absolute inset-y-0 right-0" })] }) }));
@@ -58,7 +58,6 @@ interface MenuProps {
58
58
  interface MenuItemProps {
59
59
  as?: ElementType;
60
60
  href: string;
61
- isActive?: boolean;
62
61
  children: ReactNode;
63
62
  icon?: ReactNode;
64
63
  className?: string;
@@ -75,7 +74,7 @@ declare const LNBBase: {
75
74
  Content: ({ children, className }: ContentProps) => import("react/jsx-runtime").JSX.Element;
76
75
  Group: ({ children, label, noSlider }: GroupProps) => import("react/jsx-runtime").JSX.Element;
77
76
  Menu: ({ children, label, noSlider, tabCount }: MenuProps) => import("react/jsx-runtime").JSX.Element;
78
- MenuItem: ({ as: Comp, href, isActive, children, icon, className, ...rest }: MenuItemProps) => import("react/jsx-runtime").JSX.Element;
77
+ MenuItem: ({ as: Comp, href, children, icon, className, ...rest }: MenuItemProps) => import("react/jsx-runtime").JSX.Element;
79
78
  ResizeWidthBar: ({ className }: IResizeWidthBar) => import("react/jsx-runtime").JSX.Element | null;
80
79
  };
81
80
  export default LNBBase;
@@ -1 +1 @@
1
- {"version":3,"file":"LNBBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDLNB/LNBBase.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,WAAW,EAEX,SAAS,EAEV,MAAM,OAAO,CAAC;AAoBf,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiDD,UAAU,aAAa;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA6FD,UAAU,SAAS;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAgCD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2BD,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAqCD,UAAU,YAAY;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD,UAAU,UAAU;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAuCD,UAAU,SAAS;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA6BD,UAAU,aAAa;IACrB,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgCD,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmDD,QAAA,MAAM,OAAO;2FApYV,aAAa;6CAgGgC,SAAS;6BAkCzB,YAAY;0DAgCiB,WAAW;uCAwC9B,YAAY;2CAsBR,UAAU;oDA4CG,SAAS;iFA6CjE,aAAa;oCA0BuB,eAAe;CA2DrD,CAAC;AAEF,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"LNBBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDLNB/LNBBase.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,WAAW,EAEX,SAAS,EAEV,MAAM,OAAO,CAAC;AAoBf,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAmDD,UAAU,aAAa;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0GD,UAAU,SAAS;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAgCD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2BD,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAqCD,UAAU,YAAY;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD,UAAU,UAAU;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAuCD,UAAU,SAAS;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA6BD,UAAU,aAAa;IACrB,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgCD,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmDD,QAAA,MAAM,OAAO;2FAhZV,aAAa;6CA6GgC,SAAS;6BAkCzB,YAAY;0DAgCiB,WAAW;uCAwC9B,YAAY;2CAsBR,UAAU;oDA4CG,SAAS;uEA2CjE,aAAa;oCA2BuB,eAAe;CA2DrD,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -5,7 +5,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState, }
5
5
  import LDAvatar from '../../components/LDAvatar/LDAvatar.js';
6
6
  import RenderIcon from '../../components/RenderIcon/RenderIcon.js';
7
7
  import cn from '../../utils/cn.js';
8
- import { isActivePath } from '../../utils/utils.js';
8
+ import { findActivePath } from '../../utils/utils.js';
9
9
  const DEFAULT_MIN_WIDTH = 144;
10
10
  const DEFAULT_SIZE = 300;
11
11
  const LNBContext = createContext(null);
@@ -36,6 +36,9 @@ const Provider = ({ children, isMobile, items = [], pathname = '', size = DEFAUL
36
36
  setOpenGroups((prev) => prev.includes(label) ? prev.filter((g) => g !== label) : [...prev, label]);
37
37
  }, []);
38
38
  const isGroupOpen = useCallback((label) => openGroups.includes(label), [openGroups]);
39
+ // 항목마다 따로 판정하면 `/admin` 과 `/admin/group` 이 동시에 켜진다.
40
+ // 후보 전체에서 가장 구체적인 경로 하나만 골라 MenuItem·그룹 펼침이 함께 쓴다.
41
+ const activePath = useMemo(() => findActivePath(pathname, items.flatMap((item) => item.tabs?.map((tab) => tab.path) ?? [])), [items, pathname]);
39
42
  // size(펼침 기본 너비)는 뷰포트 구간에 따라 바뀐다. width는 useState 초기값이라
40
43
  // 그대로 두면 마운트 시점 값에 고정되므로, size가 바뀌면 새 기본값으로 맞춘다.
41
44
  useEffect(() => {
@@ -48,7 +51,7 @@ const Provider = ({ children, isMobile, items = [], pathname = '', size = DEFAUL
48
51
  setOpenGroups([]);
49
52
  return;
50
53
  }
51
- const matchedLabel = items.find((item) => item.tabs?.some((tab) => isActivePath(pathname, tab.path)))?.label;
54
+ const matchedLabel = items.find((item) => item.tabs?.some((tab) => tab.path === activePath))?.label;
52
55
  if (matchedLabel && !openGroups.includes(matchedLabel)) {
53
56
  setOpenGroups((prev) => [...prev, matchedLabel]);
54
57
  }
@@ -57,6 +60,7 @@ const Provider = ({ children, isMobile, items = [], pathname = '', size = DEFAUL
57
60
  }, [pathname]);
58
61
  const contextValue = useMemo(() => ({
59
62
  isMobile,
63
+ activePath,
60
64
  collapsed,
61
65
  toggleCollapsed,
62
66
  openGroups,
@@ -67,6 +71,7 @@ const Provider = ({ children, isMobile, items = [], pathname = '', size = DEFAUL
67
71
  size,
68
72
  }), [
69
73
  isMobile,
74
+ activePath,
70
75
  collapsed,
71
76
  toggleCollapsed,
72
77
  openGroups,
@@ -115,8 +120,9 @@ const Menu = ({ children, label, noSlider, tabCount = 0 }) => {
115
120
  : 'auto',
116
121
  }, children: children }));
117
122
  };
118
- const MenuItem = ({ as: Comp = 'a', href, isActive, children, icon, className, ...rest }) => {
119
- const { collapsed } = useLNBContext();
123
+ const MenuItem = ({ as: Comp = 'a', href, children, icon, className, ...rest }) => {
124
+ const { collapsed, activePath } = useLNBContext();
125
+ const isActive = href === activePath;
120
126
  return (_jsxs(Comp, { href: href, className: cn('flex w-full items-center gap-sm p-sm display16 bold mobile:display14 mobile:medium', 'cursor-pointer rounded-[5px] text-neutral500 ld-transition hover:bg-neutral100 hover:text-neutral900', 'overflow-hidden whitespace-nowrap', collapsed && 'justify-center', isActive &&
121
127
  'bg-tintBlue text-blue400 hover:bg-tintBlue hover:text-blue400', className), ...rest, children: [_jsx(RenderIcon, { className: "icon-md", children: icon }), !collapsed && children] }));
122
128
  };
@@ -4,6 +4,10 @@ export interface TableColumnMeta {
4
4
  headerAlign?: 'left' | 'center' | 'right';
5
5
  /** 체크박스/액션 컬럼처럼 헤더에 시각적 텍스트가 없을 때 스크린리더에만 노출할 이름 */
6
6
  headerScreenReaderLabel?: string;
7
+ /** 이 컬럼 헤더 셀(`<th>`)에 추가할 클래스 — `classNames.headCell` 뒤에 병합된다 */
8
+ headerClassName?: string;
9
+ /** 이 컬럼 바디 셀(`<td>`)에 추가할 클래스 — `classNames.cell` 뒤에 병합된다 */
10
+ cellClassName?: string;
7
11
  }
8
12
  export type TOpenRowState = Record<string | number, boolean>;
9
13
  export interface HeadlessTableProps<TData, TColumn> {
@@ -1 +1 @@
1
- {"version":3,"file":"HeadlessTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/HeadlessTable.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HeadlessTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/HeadlessTable.tsx"],"names":[],"mappings":"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"}
@@ -124,6 +124,16 @@ const HeadlessTable = ({ columns, data, rowCount, paginationState, onPageChange,
124
124
  id: c.id,
125
125
  width: headerCells[i]?.getBoundingClientRect().width ?? 0,
126
126
  min: c.columnDef.minSize ?? 0,
127
+ /**
128
+ * NOTE: size 미지정 = 남는 공간 흡수 컬럼.
129
+ * 이 컬럼에 px를 기록하면 columnWidths의 undefined가 사라져
130
+ * tableStyle이 [CASE 2] 고정폭으로 뒤집히고, 그 뒤로는 viewport를
131
+ * 넓혀도 테이블이 드래그 시점 폭에 갇힌다.
132
+ * 그래서 배분 계산에는 참여시키되 columnSizing에는 쓰지 않는다.
133
+ * 남는 공간은 table-fixed가 이 컬럼에 주고, 그 값은 아래에서
134
+ * 계산한 width와 같다(총합이 컨테이너 폭으로 보존되므로).
135
+ */
136
+ absorbs: c.columnDef.size === undefined,
127
137
  }));
128
138
  const index = cols.findIndex((c) => c.id === columnId);
129
139
  const target = cols[index];
@@ -148,7 +158,8 @@ const HeadlessTable = ({ columns, data, rowCount, paginationState, onPageChange,
148
158
  ideal -= delta * (shareOf(c) / shareTotal);
149
159
  }
150
160
  const width = Math.round(ideal) - assigned;
151
- next[c.id] = width;
161
+ if (!c.absorbs)
162
+ next[c.id] = width;
152
163
  assigned += width;
153
164
  });
154
165
  table.setColumnSizing((old) => ({ ...old, ...next }));
@@ -1 +1 @@
1
- {"version":3,"file":"LDCollapsibleTanstackTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/LDCollapsibleTanstackTable.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD,OAAsB,EACpB,KAAK,kBAAkB,EACxB,MAAM,oCAAoC,CAAC;AAK5C,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,+BAA+B,CAAC,KAAK,EAAE,OAAO,CAAE,SAAQ,IAAI,CAC3E,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,EAClC,UAAU,CACX;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,kBAAkB,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,SAAS,CAAC;IAC9C,UAAU,CAAC,EAAE,WAAW,CAAC;CAC1B;AAED,QAAA,MAAM,0BAA0B,GAAI,KAAK,EAAE,OAAO,EAAE,4OAiBjD,+BAA+B,CAAC,KAAK,EAAE,OAAO,CAAC,4CAoMjD,CAAC;AAEF,eAAe,0BAA0B,CAAC"}
1
+ {"version":3,"file":"LDCollapsibleTanstackTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/LDCollapsibleTanstackTable.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD,OAAsB,EACpB,KAAK,kBAAkB,EACxB,MAAM,oCAAoC,CAAC;AAK5C,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,+BAA+B,CAAC,KAAK,EAAE,OAAO,CAAE,SAAQ,IAAI,CAC3E,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,EAClC,UAAU,CACX;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,kBAAkB,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,SAAS,CAAC;IAC9C,UAAU,CAAC,EAAE,WAAW,CAAC;CAC1B;AAED,QAAA,MAAM,0BAA0B,GAAI,KAAK,EAAE,OAAO,EAAE,4OAiBjD,+BAA+B,CAAC,KAAK,EAAE,OAAO,CAAC,4CA2MjD,CAAC;AAEF,eAAe,0BAA0B,CAAC"}
@@ -13,7 +13,7 @@ const LDCollapsibleTanstackTable = ({ columns, data, rowCount, paginationState,
13
13
  root: cn('table-fixed', classNames?.root),
14
14
  }, children: [_jsx(LDTable.Header, { className: classNames?.thead, children: headerGroups.map((hg) => (_jsx(LDTable.HeaderRow, { className: cn('group w-full', classNames?.headRow), children: hg.headers.map((header) => {
15
15
  const h = getHeader(header);
16
- return (_jsxs(LDTable.HeaderCell, { className: cn('relative overflow-hidden', h.canSort && 'cursor-pointer', classNames?.headCell), style: { width: h.size }, onClick: h.toggleSortingHandler, children: [_jsxs("span", { className: cn('flex items-center gap-0.5 align-middle', h.meta?.headerAlign === 'right'
16
+ return (_jsxs(LDTable.HeaderCell, { className: cn('relative overflow-hidden', h.canSort && 'cursor-pointer', classNames?.headCell, h.meta?.headerClassName), style: { width: h.size }, onClick: h.toggleSortingHandler, children: [_jsxs("span", { className: cn('flex items-center gap-0.5 align-middle', h.meta?.headerAlign === 'right'
17
17
  ? 'justify-end'
18
18
  : h.meta?.headerAlign === 'left'
19
19
  ? 'justify-start'
@@ -25,7 +25,7 @@ const LDCollapsibleTanstackTable = ({ columns, data, rowCount, paginationState,
25
25
  row.toggleSelected();
26
26
  }, children: row.getVisibleCells().map((cell, idx) => {
27
27
  const c = getCell(cell);
28
- return (_jsxs(LDTable.Cell, { className: classNames?.cell, children: [_jsx("div", { className: cn('flex w-full items-center', c.meta?.headerAlign === 'left'
28
+ return (_jsxs(LDTable.Cell, { className: cn(classNames?.cell, c.meta?.cellClassName), children: [_jsx("div", { className: cn('flex w-full items-center', c.meta?.headerAlign === 'left'
29
29
  ? 'justify-start'
30
30
  : c.meta?.headerAlign === 'right'
31
31
  ? 'justify-end'
@@ -1 +1 @@
1
- {"version":3,"file":"LDTanstackTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/LDTanstackTable.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAsB,EACpB,KAAK,kBAAkB,EACxB,MAAM,oCAAoC,CAAC;AAW5C,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAE,SAAQ,IAAI,CAChE,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,EAClC,UAAU,CACX;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;CACjD;AAED,QAAA,MAAM,eAAe,GAAI,KAAK,EAAE,OAAO,EAAE,0OAiBtC,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,4CAgMtC,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"LDTanstackTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/LDTanstackTable.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAsB,EACpB,KAAK,kBAAkB,EACxB,MAAM,oCAAoC,CAAC;AAW5C,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAE,SAAQ,IAAI,CAChE,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,EAClC,UAAU,CACX;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;CACjD;AAED,QAAA,MAAM,eAAe,GAAI,KAAK,EAAE,OAAO,EAAE,0OAiBtC,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,4CAoMtC,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -27,7 +27,7 @@ const LDTanstackTable = ({ columns, data, rowCount, paginationState, onPageChang
27
27
  const RowComp = enableRowDragging ? SortableRow : PlainRow;
28
28
  const bodyRows = rows.map((row) => (_jsx(RowComp, { rowId: row.id, selected: row.getIsSelected(), className: classNames?.row, onClick: () => row.toggleSelected(), children: row.getVisibleCells().map((cell) => {
29
29
  const c = getCell(cell);
30
- return (_jsx(LDTable.Cell, { className: classNames?.cell, children: _jsx("div", { className: cn('flex w-full items-center', c.meta?.headerAlign === 'left'
30
+ return (_jsx(LDTable.Cell, { className: cn(classNames?.cell, c.meta?.cellClassName), children: _jsx("div", { className: cn('flex w-full items-center', c.meta?.headerAlign === 'left'
31
31
  ? 'justify-start'
32
32
  : c.meta?.headerAlign === 'right'
33
33
  ? 'justify-end'
@@ -38,7 +38,7 @@ const LDTanstackTable = ({ columns, data, rowCount, paginationState, onPageChang
38
38
  root: cn('table-fixed', classNames?.root),
39
39
  }, children: [_jsx(LDTable.Header, { className: classNames?.thead, children: headerGroups.map((hg) => (_jsx(LDTable.HeaderRow, { className: cn('group w-full', classNames?.headRow), children: hg.headers.map((header) => {
40
40
  const h = getHeader(header);
41
- return (_jsxs(LDTable.HeaderCell, { className: cn('relative overflow-hidden', h.canSort && 'cursor-pointer', classNames?.headCell), style: { width: h.size }, onClick: h.toggleSortingHandler, children: [h.meta?.headerScreenReaderLabel && (_jsx("span", { className: "sr-only", children: h.meta.headerScreenReaderLabel })), _jsxs("span", { className: cn('flex items-center gap-0.5 align-middle', h.meta?.headerAlign === 'right'
41
+ return (_jsxs(LDTable.HeaderCell, { className: cn('relative overflow-hidden', h.canSort && 'cursor-pointer', classNames?.headCell, h.meta?.headerClassName), style: { width: h.size }, onClick: h.toggleSortingHandler, children: [h.meta?.headerScreenReaderLabel && (_jsx("span", { className: "sr-only", children: h.meta.headerScreenReaderLabel })), _jsxs("span", { className: cn('flex items-center gap-0.5 align-middle', h.meta?.headerAlign === 'right'
42
42
  ? 'justify-end'
43
43
  : h.meta?.headerAlign === 'left'
44
44
  ? 'justify-start'
@@ -19,8 +19,8 @@ export interface TableRowProps {
19
19
  export declare const PlainRow: ({ selected, className, onClick, children, }: TableRowProps) => import("react/jsx-runtime").JSX.Element;
20
20
  /** 드래그가 켜져 있을 때의 행 */
21
21
  export declare const SortableRow: ({ rowId, selected, className, onClick, children, }: TableRowProps) => import("react/jsx-runtime").JSX.Element;
22
- export declare const LDRowDragHandle: ({ rowId, className, }: {
23
- rowId: string;
22
+ export declare const LDRowDragHandle: ({ className, }: {
24
23
  className?: string;
25
- }) => import("react/jsx-runtime").JSX.Element;
24
+ rowId?: string;
25
+ }) => import("react/jsx-runtime").JSX.Element | null;
26
26
  //# sourceMappingURL=TableRowDnd.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TableRowDnd.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/TableRowDnd.tsx"],"names":[],"mappings":"AAEA,OAAO,EAOL,KAAK,gBAAgB,EAGtB,MAAM,eAAe,CAAC;AAUvB,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,eAAO,MAAM,cAAc,GAAI,6BAG5B;IACD,YAAY,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC7E,QAAQ,EAAE,SAAS,CAAC;CACrB,4CAwBA,CAAC;AAIF,eAAO,MAAM,mBAAmB,GAAI,uBAGjC;IACD,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,QAAQ,EAAE,SAAS,CAAC;CACrB,4CAIA,CAAC;AAIF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,GAAI,6CAKtB,aAAa,4CAIf,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,WAAW,GAAI,oDAMzB,aAAa,4CAmBf,CAAC;AAIF,eAAO,MAAM,eAAe,GAAI,uBAG7B;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,4CAoBA,CAAC"}
1
+ {"version":3,"file":"TableRowDnd.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/TableRowDnd.tsx"],"names":[],"mappings":"AAGA,OAAO,EAOL,KAAK,gBAAgB,EAGtB,MAAM,eAAe,CAAC;AAWvB,OAAO,EAAiB,KAAK,SAAS,EAAuB,MAAM,OAAO,CAAC;AAM3E,eAAO,MAAM,cAAc,GAAI,6BAG5B;IACD,YAAY,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC7E,QAAQ,EAAE,SAAS,CAAC;CACrB,4CAwBA,CAAC;AAIF,eAAO,MAAM,mBAAmB,GAAI,uBAGjC;IACD,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,QAAQ,EAAE,SAAS,CAAC;CACrB,4CAIA,CAAC;AAIF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,GAAI,6CAKtB,aAAa,4CAIf,CAAC;AAaF,sBAAsB;AACtB,eAAO,MAAM,WAAW,GAAI,oDAMzB,aAAa,4CAgCf,CAAC;AAIF,eAAO,MAAM,eAAe,GAAI,gBAE7B;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,mDAyBA,CAAC"}
@@ -5,6 +5,7 @@ import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
5
5
  import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable';
6
6
  import { CSS } from '@dnd-kit/utilities';
7
7
  import { GripVertical } from 'lucide-react';
8
+ import { createContext, useContext, useMemo } from 'react';
8
9
  import LDTable from '../../components/LDTable/LDTable.js';
9
10
  import cn from '../../utils/cn.js';
10
11
  // ── DndContext ──
@@ -23,18 +24,21 @@ export const RowDndProvider = ({ onRowDragEnd, children, }) => {
23
24
  export const RowSortableProvider = ({ rowIds, children, }) => (_jsx(SortableContext, { items: rowIds, strategy: verticalListSortingStrategy, children: children }));
24
25
  /** 드래그가 꺼져 있을 때의 행. `SortableRow`와 prop 모양을 맞춰 교체 가능하게 둔다 */
25
26
  export const PlainRow = ({ selected, className, onClick, children, }) => (_jsx(LDTable.Row, { selected: selected, className: className, onClick: onClick, children: children }));
27
+ const RowDragHandleContext = createContext(null);
26
28
  /** 드래그가 켜져 있을 때의 행 */
27
29
  export const SortableRow = ({ rowId, selected, className, onClick, children, }) => {
28
- const { setNodeRef, transform, transition, isDragging } = useSortable({
29
- id: rowId,
30
- });
31
- return (_jsx(LDTable.Row, { ref: setNodeRef, selected: selected, className: cn(isDragging && 'relative z-10 opacity-80', className), onClick: onClick, style: {
32
- transform: CSS.Transform.toString(transform),
33
- transition: isDragging ? 'none' : transition,
34
- }, children: children }));
30
+ const { setNodeRef, setActivatorNodeRef, attributes, listeners, transform, transition, isDragging, } = useSortable({ id: rowId });
31
+ const handleContext = useMemo(() => ({ setActivatorNodeRef, attributes, listeners, isDragging }), [setActivatorNodeRef, attributes, listeners, isDragging]);
32
+ return (_jsx(RowDragHandleContext, { value: handleContext, children: _jsx(LDTable.Row, { ref: setNodeRef, selected: selected, className: cn(isDragging && 'relative z-10 opacity-80', className), onClick: onClick, style: {
33
+ transform: CSS.Transform.toString(transform),
34
+ transition: isDragging ? 'none' : transition,
35
+ }, children: children }) }));
35
36
  };
36
37
  // ── Handle ──
37
- export const LDRowDragHandle = ({ rowId, className, }) => {
38
- const { attributes, listeners, isDragging } = useSortable({ id: rowId });
39
- return (_jsx("button", { type: "button", "aria-label": "\uC21C\uC11C \uBCC0\uACBD", onClick: (e) => e.stopPropagation(), className: cn('flex size-6 touch-none items-center justify-center', 'text-neutral400 ld-transition hover:text-neutral700', isDragging ? 'cursor-grabbing' : 'cursor-grab', className), ...attributes, ...listeners, children: _jsx(GripVertical, { size: 16 }) }));
38
+ export const LDRowDragHandle = ({ className, }) => {
39
+ const context = useContext(RowDragHandleContext);
40
+ if (!context)
41
+ return null;
42
+ const { setActivatorNodeRef, attributes, listeners, isDragging } = context;
43
+ return (_jsx("button", { ref: setActivatorNodeRef, type: "button", "aria-label": "\uC21C\uC11C \uBCC0\uACBD", onClick: (e) => e.stopPropagation(), className: cn('flex size-6 touch-none items-center justify-center', 'text-neutral400 ld-transition hover:text-neutral700', isDragging ? 'cursor-grabbing' : 'cursor-grab', className), ...attributes, ...listeners, children: _jsx(GripVertical, { size: 16 }) }));
40
44
  };
package/dist/index.css CHANGED
@@ -65,9 +65,11 @@
65
65
  --color-neutral700: #535a64;
66
66
  --color-neutral800: #3a3f46;
67
67
  --color-neutral900: #191f28;
68
+ --color-blue100: #b8c9ff;
68
69
  --color-blue200: #8fabff;
69
70
  --color-blue400: #2158fd;
70
71
  --color-blue500: #003fff;
72
+ --color-blue700: #002699;
71
73
  --color-red200: #ff9494;
72
74
  --color-red500: #ff4747;
73
75
  --color-orange400: #ff7a33;
@@ -78,6 +80,7 @@
78
80
  --color-green600: #00de47;
79
81
  --color-green700: #00cc41;
80
82
  --color-pink500: #ff33d3;
83
+ --color-pink600: #e61eb8;
81
84
  --color-purple500: #7b40c7;
82
85
  --color-danger50: #fef7f7;
83
86
  --color-danger100: #fdefef;
@@ -462,6 +465,9 @@
462
465
  .top-1\/2 {
463
466
  top: calc(1 / 2 * 100%);
464
467
  }
468
+ .top-1\/4 {
469
+ top: calc(1 / 4 * 100%);
470
+ }
465
471
  .top-2 {
466
472
  top: calc(var(--spacing) * 2);
467
473
  }
@@ -519,6 +525,9 @@
519
525
  .left-1\/2 {
520
526
  left: calc(1 / 2 * 100%);
521
527
  }
528
+ .left-1\/4 {
529
+ left: calc(1 / 4 * 100%);
530
+ }
522
531
  .left-5 {
523
532
  left: calc(var(--spacing) * 5);
524
533
  }
@@ -1296,6 +1305,9 @@
1296
1305
  .table {
1297
1306
  display: table;
1298
1307
  }
1308
+ .aspect-4\/3 {
1309
+ aspect-ratio: 4/3;
1310
+ }
1299
1311
  .aspect-square {
1300
1312
  aspect-ratio: 1 / 1;
1301
1313
  }
@@ -1506,6 +1518,9 @@
1506
1518
  .h-48 {
1507
1519
  height: calc(var(--spacing) * 48);
1508
1520
  }
1521
+ .h-50 {
1522
+ height: calc(var(--spacing) * 50);
1523
+ }
1509
1524
  .h-60 {
1510
1525
  height: calc(var(--spacing) * 60);
1511
1526
  }
@@ -1563,6 +1578,9 @@
1563
1578
  .h-\[80vh\] {
1564
1579
  height: 80vh;
1565
1580
  }
1581
+ .h-\[220px\] {
1582
+ height: 220px;
1583
+ }
1566
1584
  .h-\[calc\(100vh-64px\)\] {
1567
1585
  height: calc(100vh - 64px);
1568
1586
  }
@@ -1578,6 +1596,9 @@
1578
1596
  .h-px {
1579
1597
  height: 1px;
1580
1598
  }
1599
+ .h-screen {
1600
+ height: 100vh;
1601
+ }
1581
1602
  .max-h-57\.5 {
1582
1603
  max-height: calc(var(--spacing) * 57.5);
1583
1604
  }
@@ -1626,6 +1647,9 @@
1626
1647
  .min-h-10 {
1627
1648
  min-height: calc(var(--spacing) * 10);
1628
1649
  }
1650
+ .min-h-25 {
1651
+ min-height: calc(var(--spacing) * 25);
1652
+ }
1629
1653
  .min-h-100 {
1630
1654
  min-height: calc(var(--spacing) * 100);
1631
1655
  }
@@ -1732,6 +1756,9 @@
1732
1756
  .w-80 {
1733
1757
  width: calc(var(--spacing) * 80);
1734
1758
  }
1759
+ .w-96 {
1760
+ width: calc(var(--spacing) * 96);
1761
+ }
1735
1762
  .w-99 {
1736
1763
  width: calc(var(--spacing) * 99);
1737
1764
  }
@@ -1741,9 +1768,18 @@
1741
1768
  .w-120 {
1742
1769
  width: calc(var(--spacing) * 120);
1743
1770
  }
1771
+ .w-125 {
1772
+ width: calc(var(--spacing) * 125);
1773
+ }
1774
+ .w-140 {
1775
+ width: calc(var(--spacing) * 140);
1776
+ }
1744
1777
  .w-150 {
1745
1778
  width: calc(var(--spacing) * 150);
1746
1779
  }
1780
+ .w-160 {
1781
+ width: calc(var(--spacing) * 160);
1782
+ }
1747
1783
  .w-\[60px\] {
1748
1784
  width: 60px;
1749
1785
  }
@@ -1852,6 +1888,9 @@
1852
1888
  animation: bell-ring 600ms ease-in-out;
1853
1889
  transform-origin: top center;
1854
1890
  }
1891
+ .origin-center {
1892
+ transform-origin: center;
1893
+ }
1855
1894
  .-translate-1\/2 {
1856
1895
  --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
1857
1896
  --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
@@ -1948,6 +1987,9 @@
1948
1987
  .resize {
1949
1988
  resize: both;
1950
1989
  }
1990
+ .grid-cols-1 {
1991
+ grid-template-columns: repeat(1, minmax(0, 1fr));
1992
+ }
1951
1993
  .grid-cols-2 {
1952
1994
  grid-template-columns: repeat(2, minmax(0, 1fr));
1953
1995
  }
@@ -2351,6 +2393,9 @@
2351
2393
  .bg-\(--calendar-range-band\) {
2352
2394
  background-color: var(--calendar-range-band);
2353
2395
  }
2396
+ .bg-\[\#1a6dcc\] {
2397
+ background-color: #1a6dcc;
2398
+ }
2354
2399
  .bg-accept600 {
2355
2400
  background-color: var(--color-accept600);
2356
2401
  }
@@ -2378,6 +2423,9 @@
2378
2423
  .bg-blue-500 {
2379
2424
  background-color: var(--color-blue-500);
2380
2425
  }
2426
+ .bg-blue100 {
2427
+ background-color: var(--color-blue100);
2428
+ }
2381
2429
  .bg-current {
2382
2430
  background-color: currentcolor;
2383
2431
  }
@@ -2492,12 +2540,43 @@
2492
2540
  .bg-yellow-400 {
2493
2541
  background-color: var(--color-yellow-400);
2494
2542
  }
2543
+ .bg-linear-to-br {
2544
+ --tw-gradient-position: to bottom right;
2545
+ @supports (background-image: linear-gradient(in lab, red, red)) {
2546
+ --tw-gradient-position: to bottom right in oklab;
2547
+ }
2548
+ background-image: linear-gradient(var(--tw-gradient-stops));
2549
+ }
2495
2550
  .bg-\[linear-gradient\(to_left\,transparent_50\%\,var\(--calendar-range-band\)_50\%\)\] {
2496
2551
  background-image: linear-gradient(to left,transparent 50%,var(--calendar-range-band) 50%);
2497
2552
  }
2498
2553
  .bg-\[linear-gradient\(to_right\,transparent_50\%\,var\(--calendar-range-band\)_50\%\)\] {
2499
2554
  background-image: linear-gradient(to right,transparent 50%,var(--calendar-range-band) 50%);
2500
2555
  }
2556
+ .from-lb500 {
2557
+ --tw-gradient-from: var(--color-lb500);
2558
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
2559
+ }
2560
+ .from-orange500 {
2561
+ --tw-gradient-from: var(--color-orange500);
2562
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
2563
+ }
2564
+ .from-purple500 {
2565
+ --tw-gradient-from: var(--color-purple500);
2566
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
2567
+ }
2568
+ .to-blue700 {
2569
+ --tw-gradient-to: var(--color-blue700);
2570
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
2571
+ }
2572
+ .to-lb700 {
2573
+ --tw-gradient-to: var(--color-lb700);
2574
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
2575
+ }
2576
+ .to-pink600 {
2577
+ --tw-gradient-to: var(--color-pink600);
2578
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
2579
+ }
2501
2580
  .bg-clip-content {
2502
2581
  background-clip: content-box;
2503
2582
  }
@@ -2600,6 +2679,9 @@
2600
2679
  .px-8 {
2601
2680
  padding-inline: calc(var(--spacing) * 8);
2602
2681
  }
2682
+ .px-10 {
2683
+ padding-inline: calc(var(--spacing) * 10);
2684
+ }
2603
2685
  .px-\[10px\] {
2604
2686
  padding-inline: 10px;
2605
2687
  }
@@ -2675,6 +2757,9 @@
2675
2757
  .pt-6 {
2676
2758
  padding-top: calc(var(--spacing) * 6);
2677
2759
  }
2760
+ .pt-7 {
2761
+ padding-top: calc(var(--spacing) * 7);
2762
+ }
2678
2763
  .pt-10 {
2679
2764
  padding-top: calc(var(--spacing) * 10);
2680
2765
  }
@@ -2709,6 +2794,9 @@
2709
2794
  .pb-4 {
2710
2795
  padding-bottom: calc(var(--spacing) * 4);
2711
2796
  }
2797
+ .pb-6 {
2798
+ padding-bottom: calc(var(--spacing) * 6);
2799
+ }
2712
2800
  .pb-10 {
2713
2801
  padding-bottom: calc(var(--spacing) * 10);
2714
2802
  }
@@ -2844,6 +2932,15 @@
2844
2932
  .text-\[13px\] {
2845
2933
  font-size: 13px;
2846
2934
  }
2935
+ .text-\[15px\] {
2936
+ font-size: 15px;
2937
+ }
2938
+ .text-display14 {
2939
+ font-size: var(--text-display14);
2940
+ }
2941
+ .text-display20 {
2942
+ font-size: var(--text-display20);
2943
+ }
2847
2944
  .text-display24 {
2848
2945
  font-size: var(--text-display24);
2849
2946
  }
@@ -2926,6 +3023,9 @@
2926
3023
  .text-\(--calendar-accent\) {
2927
3024
  color: var(--calendar-accent);
2928
3025
  }
3026
+ .text-\[\#1a6dcc\] {
3027
+ color: #1a6dcc;
3028
+ }
2929
3029
  .text-black {
2930
3030
  color: var(--color-black);
2931
3031
  }
@@ -2938,6 +3038,9 @@
2938
3038
  .text-blue400 {
2939
3039
  color: var(--color-blue400);
2940
3040
  }
3041
+ .text-blue500 {
3042
+ color: var(--color-blue500);
3043
+ }
2941
3044
  .text-danger400 {
2942
3045
  color: var(--color-danger400);
2943
3046
  }
@@ -3078,6 +3181,9 @@
3078
3181
  .opacity-80 {
3079
3182
  opacity: 80%;
3080
3183
  }
3184
+ .opacity-90 {
3185
+ opacity: 90%;
3186
+ }
3081
3187
  .opacity-100 {
3082
3188
  opacity: 100%;
3083
3189
  }
@@ -3234,6 +3340,11 @@
3234
3340
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
3235
3341
  transition-duration: var(--tw-duration, var(--default-transition-duration));
3236
3342
  }
3343
+ .transition-shadow {
3344
+ transition-property: box-shadow;
3345
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
3346
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
3347
+ }
3237
3348
  .transition-transform {
3238
3349
  transition-property: transform, translate, scale, rotate;
3239
3350
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
@@ -3753,6 +3864,14 @@
3753
3864
  }
3754
3865
  }
3755
3866
  }
3867
+ .hover\:shadow-md {
3868
+ &:hover {
3869
+ @media (hover: hover) {
3870
+ --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
3871
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
3872
+ }
3873
+ }
3874
+ }
3756
3875
  .hover\:outline-neutral200 {
3757
3876
  &:hover {
3758
3877
  @media (hover: hover) {
@@ -3980,15 +4099,9 @@
3980
4099
  opacity: 40%;
3981
4100
  }
3982
4101
  }
3983
- .data-outside\:font-normal {
3984
- &[data-outside] {
3985
- --tw-font-weight: var(--font-weight-normal);
3986
- font-weight: var(--font-weight-normal);
3987
- }
3988
- }
3989
- .data-outside\:text-mono400 {
4102
+ .data-outside\:opacity-50 {
3990
4103
  &[data-outside] {
3991
- color: var(--color-mono400);
4104
+ opacity: 50%;
3992
4105
  }
3993
4106
  }
3994
4107
  .data-outside\:\*\:text-mono400 {
@@ -4022,13 +4135,6 @@
4022
4135
  color: var(--color-danger600);
4023
4136
  }
4024
4137
  }
4025
- .data-outside\:data-weekend\:text-danger400 {
4026
- &[data-outside] {
4027
- &[data-weekend] {
4028
- color: var(--color-danger400);
4029
- }
4030
- }
4031
- }
4032
4138
  .data-\[active\=true\]\:bg-lb500 {
4033
4139
  &[data-active="true"] {
4034
4140
  background-color: var(--color-lb500);
@@ -4475,11 +4581,21 @@
4475
4581
  color: var(--color-neutral900);
4476
4582
  }
4477
4583
  }
4584
+ .md\:grid-cols-2 {
4585
+ @media (width >= 48rem) {
4586
+ grid-template-columns: repeat(2, minmax(0, 1fr));
4587
+ }
4588
+ }
4478
4589
  .md\:flex-row {
4479
4590
  @media (width >= 48rem) {
4480
4591
  flex-direction: row;
4481
4592
  }
4482
4593
  }
4594
+ .lg\:grid-cols-3 {
4595
+ @media (width >= 64rem) {
4596
+ grid-template-columns: repeat(3, minmax(0, 1fr));
4597
+ }
4598
+ }
4483
4599
  .mobile\:invisible {
4484
4600
  @media (max-width: calc(768px - 1px)) {
4485
4601
  visibility: hidden;
@@ -5790,6 +5906,48 @@
5790
5906
  inherits: false;
5791
5907
  initial-value: solid;
5792
5908
  }
5909
+ @property --tw-gradient-position {
5910
+ syntax: "*";
5911
+ inherits: false;
5912
+ }
5913
+ @property --tw-gradient-from {
5914
+ syntax: "<color>";
5915
+ inherits: false;
5916
+ initial-value: #0000;
5917
+ }
5918
+ @property --tw-gradient-via {
5919
+ syntax: "<color>";
5920
+ inherits: false;
5921
+ initial-value: #0000;
5922
+ }
5923
+ @property --tw-gradient-to {
5924
+ syntax: "<color>";
5925
+ inherits: false;
5926
+ initial-value: #0000;
5927
+ }
5928
+ @property --tw-gradient-stops {
5929
+ syntax: "*";
5930
+ inherits: false;
5931
+ }
5932
+ @property --tw-gradient-via-stops {
5933
+ syntax: "*";
5934
+ inherits: false;
5935
+ }
5936
+ @property --tw-gradient-from-position {
5937
+ syntax: "<length-percentage>";
5938
+ inherits: false;
5939
+ initial-value: 0%;
5940
+ }
5941
+ @property --tw-gradient-via-position {
5942
+ syntax: "<length-percentage>";
5943
+ inherits: false;
5944
+ initial-value: 50%;
5945
+ }
5946
+ @property --tw-gradient-to-position {
5947
+ syntax: "<length-percentage>";
5948
+ inherits: false;
5949
+ initial-value: 100%;
5950
+ }
5793
5951
  @property --tw-leading {
5794
5952
  syntax: "*";
5795
5953
  inherits: false;
@@ -5976,6 +6134,15 @@
5976
6134
  --tw-skew-y: initial;
5977
6135
  --tw-divide-x-reverse: 0;
5978
6136
  --tw-border-style: solid;
6137
+ --tw-gradient-position: initial;
6138
+ --tw-gradient-from: #0000;
6139
+ --tw-gradient-via: #0000;
6140
+ --tw-gradient-to: #0000;
6141
+ --tw-gradient-stops: initial;
6142
+ --tw-gradient-via-stops: initial;
6143
+ --tw-gradient-from-position: 0%;
6144
+ --tw-gradient-via-position: 50%;
6145
+ --tw-gradient-to-position: 100%;
5979
6146
  --tw-leading: initial;
5980
6147
  --tw-font-weight: initial;
5981
6148
  --tw-tracking: initial;
@@ -1,10 +1,36 @@
1
1
  /**
2
- * 현재 경로가 해당 링크의 경로와 **정확히** 일치하는지 판별합니다.
2
+ * 현재 경로가 해당 링크의 경로에 속하는지 판별합니다.
3
3
  *
4
- * 접두사(prefix) 비교는 쓰지 않습니다. `startsWith`로 판별하면 `/admin`이
5
- * `/admin/group`·`/admin-group`까지 활성으로 잡아 여러 메뉴가 동시에 켜집니다.
4
+ * `href` 정확히 같거나 `href` **하위 경로**면 활성으로 봅니다.
5
+ * `/products/items` 같은 상세 페이지에서도 상위 메뉴 `/products` 가 켜져 있어야
6
+ * 하기 때문입니다.
7
+ *
8
+ * 단순 `startsWith` 는 쓰지 않습니다. 세그먼트 경계(`/`)를 요구해서
9
+ * `/foo-bar` 가 `/foo` 에 걸리는 오탐을 막습니다. 루트(`/`)는 모든 경로의
10
+ * 접두사이므로 정확히 일치할 때만 활성입니다.
11
+ *
12
+ * 쿼리스트링과 해시는 비교하지 않습니다. `/search?q=A` 와 `/search?q=B` 는 같은
13
+ * 페이지이므로 검색어가 바뀌어도 메뉴가 꺼지면 안 됩니다. 반대로 `href` 를
14
+ * `/orders?status=done` 처럼 쿼리로 구분하는 메뉴는 서로 구별되지 않습니다.
15
+ *
16
+ * 주의: 항목 단위 판정이라 `/admin` 과 `/admin/group` 이 둘 다 메뉴에 있으면
17
+ * `/admin/group` 에서 두 항목이 함께 활성이 됩니다. 하나만 켜려면 호출부에서
18
+ * 가장 긴 매칭을 골라야 합니다.
6
19
  */
7
20
  export declare const isActivePath: (pathname: string, href: string) => boolean;
21
+ /**
22
+ * 후보 경로 목록 중 현재 경로에 **가장 구체적으로** 맞는 하나를 고릅니다.
23
+ * 맞는 것이 없으면 `null` 입니다.
24
+ *
25
+ * `isActivePath` 는 항목 단위 판정이라 `/admin` 과 `/admin/group` 이 둘 다 후보면
26
+ * `/admin/group` 에서 두 항목이 함께 활성이 됩니다. 메뉴에서 하나만 켜려면
27
+ * 후보 전체를 보고 가장 긴 경로를 골라야 합니다.
28
+ *
29
+ * 정규화한 경로 길이로 비교하므로 `/foo` 와 `/foo/` 처럼 같은 경로를 가리키는
30
+ * 표기 차이는 우열을 만들지 않고, 동률이면 먼저 나온 후보를 씁니다.
31
+ * 반환값은 정규화 이전의 원본 문자열이라 호출부에서 `===` 로 항목을 찾을 수 있습니다.
32
+ */
33
+ export declare const findActivePath: (pathname: string, candidates: readonly string[]) => string | null;
8
34
  /** 숫자를 정수로 내림 후 천 단위 콤마를 붙인 문자열로 변환합니다 (LDChart 툴팁 표시용). */
9
35
  export declare const formatNumberWithComma: (num?: number) => string;
10
36
  /** 숫자를 K/M 단위로 축약해 표시합니다 (LDChart y축 눈금 표시용). */
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,MAAM,MAAM,KAAG,OAC3C,CAAC;AAEpB,4DAA4D;AAC5D,eAAO,MAAM,qBAAqB,GAAI,MAAK,MAAU,WAMpD,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,WAQpD,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAgDA;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,MAAM,MAAM,KAAG,OAO7D,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GACzB,UAAU,MAAM,EAChB,YAAY,SAAS,MAAM,EAAE,KAC5B,MAAM,GAAG,IAeX,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,qBAAqB,GAAI,MAAK,MAAU,WAMpD,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,WAQpD,CAAC"}
@@ -1,10 +1,99 @@
1
1
  /**
2
- * 현재 경로가 해당 링크의 경로와 **정확히** 일치하는지 판별합니다.
2
+ * URL 파싱용 더미 origin. `new URL()`에 base 를 주면 상대 경로·`..` 해석과
3
+ * 쿼리스트링·해시 분리를 표준 파서가 대신 처리한다.
4
+ */
5
+ const PARSE_BASE = 'http://ld.local';
6
+ /**
7
+ * 퍼센트 인코딩을 되돌립니다. `decodeURIComponent` 가 아니라 `decodeURI` 를 쓰는
8
+ * 이유는 `%2F` 같은 예약 문자까지 풀면 경로 구분자가 늘어나 세그먼트 경계가
9
+ * 어긋나기 때문입니다. 잘못된 인코딩이면 원문 그대로 비교합니다.
10
+ */
11
+ const safeDecode = (value) => {
12
+ try {
13
+ return decodeURI(value);
14
+ }
15
+ catch {
16
+ return value;
17
+ }
18
+ };
19
+ /**
20
+ * 비교 가능한 형태로 경로를 정규화합니다.
21
+ *
22
+ * - origin·쿼리스트링·해시 제거 (`https://a.com/foo?x=1#y` → `/foo`)
23
+ * - 상대 경로와 `.`·`..` 해석 (`foo/../bar` → `/bar`)
24
+ * - 중복 슬래시 축약 (`/foo//bar` → `/foo/bar`)
25
+ * - 끝 슬래시 제거 (루트 `/` 는 유지)
26
+ * - 퍼센트 인코딩 해제 (`/%EC%83%81%ED%92%88` → `/상품`)
27
+ *
28
+ * 대소문자는 구분합니다. 경로는 대소문자를 구분하는 것이 표준이고, 서로 다른
29
+ * 라우트를 같은 것으로 묶으면 오히려 오탐이 됩니다.
30
+ */
31
+ const toComparablePath = (value) => {
32
+ let pathname;
33
+ try {
34
+ ({ pathname } = new URL(value, PARSE_BASE));
35
+ }
36
+ catch {
37
+ // URL 로 해석되지 않는 문자열(예: 'http://')은 정규화 없이 원문을 쓴다.
38
+ return value;
39
+ }
40
+ const collapsed = safeDecode(pathname).replace(/\/{2,}/g, '/');
41
+ return collapsed.length > 1 && collapsed.endsWith('/')
42
+ ? collapsed.slice(0, -1)
43
+ : collapsed;
44
+ };
45
+ /**
46
+ * 현재 경로가 해당 링크의 경로에 속하는지 판별합니다.
47
+ *
48
+ * `href` 와 정확히 같거나 `href` 의 **하위 경로**면 활성으로 봅니다.
49
+ * `/products/items` 같은 상세 페이지에서도 상위 메뉴 `/products` 가 켜져 있어야
50
+ * 하기 때문입니다.
51
+ *
52
+ * 단순 `startsWith` 는 쓰지 않습니다. 세그먼트 경계(`/`)를 요구해서
53
+ * `/foo-bar` 가 `/foo` 에 걸리는 오탐을 막습니다. 루트(`/`)는 모든 경로의
54
+ * 접두사이므로 정확히 일치할 때만 활성입니다.
55
+ *
56
+ * 쿼리스트링과 해시는 비교하지 않습니다. `/search?q=A` 와 `/search?q=B` 는 같은
57
+ * 페이지이므로 검색어가 바뀌어도 메뉴가 꺼지면 안 됩니다. 반대로 `href` 를
58
+ * `/orders?status=done` 처럼 쿼리로 구분하는 메뉴는 서로 구별되지 않습니다.
59
+ *
60
+ * 주의: 항목 단위 판정이라 `/admin` 과 `/admin/group` 이 둘 다 메뉴에 있으면
61
+ * `/admin/group` 에서 두 항목이 함께 활성이 됩니다. 하나만 켜려면 호출부에서
62
+ * 가장 긴 매칭을 골라야 합니다.
63
+ */
64
+ export const isActivePath = (pathname, href) => {
65
+ const current = toComparablePath(pathname);
66
+ const target = toComparablePath(href);
67
+ if (target === '/')
68
+ return current === '/';
69
+ return current === target || current.startsWith(`${target}/`);
70
+ };
71
+ /**
72
+ * 후보 경로 목록 중 현재 경로에 **가장 구체적으로** 맞는 하나를 고릅니다.
73
+ * 맞는 것이 없으면 `null` 입니다.
3
74
  *
4
- * 접두사(prefix) 비교는 쓰지 않습니다. `startsWith`로 판별하면 `/admin`이
5
- * `/admin/group`·`/admin-group`까지 활성으로 잡아 여러 메뉴가 동시에 켜집니다.
75
+ * `isActivePath` 항목 단위 판정이라 `/admin` `/admin/group` 이 둘 다 후보면
76
+ * `/admin/group` 에서 항목이 함께 활성이 됩니다. 메뉴에서 하나만 켜려면
77
+ * 후보 전체를 보고 가장 긴 경로를 골라야 합니다.
78
+ *
79
+ * 정규화한 경로 길이로 비교하므로 `/foo` 와 `/foo/` 처럼 같은 경로를 가리키는
80
+ * 표기 차이는 우열을 만들지 않고, 동률이면 먼저 나온 후보를 씁니다.
81
+ * 반환값은 정규화 이전의 원본 문자열이라 호출부에서 `===` 로 항목을 찾을 수 있습니다.
6
82
  */
7
- export const isActivePath = (pathname, href) => pathname === href;
83
+ export const findActivePath = (pathname, candidates) => {
84
+ let matched = null;
85
+ let matchedLength = -1;
86
+ for (const candidate of candidates) {
87
+ if (!isActivePath(pathname, candidate))
88
+ continue;
89
+ const length = toComparablePath(candidate).length;
90
+ if (length > matchedLength) {
91
+ matched = candidate;
92
+ matchedLength = length;
93
+ }
94
+ }
95
+ return matched;
96
+ };
8
97
  /** 숫자를 정수로 내림 후 천 단위 콤마를 붙인 문자열로 변환합니다 (LDChart 툴팁 표시용). */
9
98
  export const formatNumberWithComma = (num = 0) => {
10
99
  if (isNaN(num)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loword/loword-design-system",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "로워드 디자인 시스템 컴포넌트 패키지(Tailwind v4)",
5
5
  "keywords": [
6
6
  "react",
@@ -48,10 +48,6 @@
48
48
  },
49
49
  "license": "MIT",
50
50
  "peerDependencies": {
51
- "@dnd-kit/core": "^6.3.1",
52
- "@dnd-kit/modifiers": "^9.0.0",
53
- "@dnd-kit/sortable": "^10.0.0",
54
- "@dnd-kit/utilities": "^3.2.2",
55
51
  "@radix-ui/react-accordion": "^1.2.16",
56
52
  "@radix-ui/react-dialog": "^1.1.15",
57
53
  "@radix-ui/react-popover": "^1.1.15",
@@ -92,18 +88,6 @@
92
88
  "next": {
93
89
  "optional": true
94
90
  },
95
- "@dnd-kit/core": {
96
- "optional": true
97
- },
98
- "@dnd-kit/modifiers": {
99
- "optional": true
100
- },
101
- "@dnd-kit/sortable": {
102
- "optional": true
103
- },
104
- "@dnd-kit/utilities": {
105
- "optional": true
106
- },
107
91
  "@radix-ui/react-accordion": {
108
92
  "optional": true
109
93
  },
@@ -202,10 +186,6 @@
202
186
  }
203
187
  },
204
188
  "devDependencies": {
205
- "@dnd-kit/core": "^6.3.1",
206
- "@dnd-kit/modifiers": "^9.0.0",
207
- "@dnd-kit/sortable": "^10.0.0",
208
- "@dnd-kit/utilities": "^3.2.2",
209
189
  "@eslint/js": "^9.31.0",
210
190
  "@hookform/resolvers": "^5.4.0",
211
191
  "@radix-ui/react-accordion": "^1.2.16",
@@ -277,6 +257,10 @@
277
257
  "zod": "^4.4.3"
278
258
  },
279
259
  "dependencies": {
260
+ "@dnd-kit/core": "^6.3.1",
261
+ "@dnd-kit/modifiers": "^9.0.0",
262
+ "@dnd-kit/sortable": "^10.0.0",
263
+ "@dnd-kit/utilities": "^3.2.2",
280
264
  "clsx": "^2.1.1",
281
265
  "lucide-react": "^0.536.0",
282
266
  "react-hook-form": "^7.62.0",