@loword/loword-design-system 0.0.13 → 0.0.15

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDButton/ButtonBase.tsx"],"names":[],"mappings":"AA0BA,eAAO,MAAM,UAAU;UACP,KAAK,CAAC,WAAW;CAChC,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ButtonBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDButton/ButtonBase.tsx"],"names":[],"mappings":"AAsCA,eAAO,MAAM,UAAU;UACP,KAAK,CAAC,WAAW;CAChC,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1,8 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import cn from '../../utils/cn.js';
3
- const Root = ({ as, className, children, ref, ...props }) => {
4
- const Component = as ?? 'button';
5
- return (_jsx(Component, { ref: ref, className: cn('relative inline-flex flex-row items-center justify-center', className), ...props, children: children }));
3
+ const Root = ({ as, className, children, ref, href, disabled, ...props }) => {
4
+ // as가 href를 가질 때 (a, NextLink 등) disabled=true일 경우 href를 제거하고 span으로 렌더링
5
+ const isDisabledLink = href && disabled;
6
+ const Component = isDisabledLink ? 'span' : (as ?? 'button');
7
+ return (_jsx(Component, { ref: ref, className: cn('relative inline-flex flex-row items-center justify-center', className), "aria-disabled": disabled || undefined, ...(!isDisabledLink && { href, disabled }), ...props, children: children }));
6
8
  };
7
9
  export const ButtonBase = {
8
10
  Root: Root,
@@ -1 +1 @@
1
- {"version":3,"file":"LDButton.d.ts","sourceRoot":"","sources":["../../../src/components/LDButton/LDButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAQpE,KAAK,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAC5D,KAAK,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,QAAQ,CAAC;AACb,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AACzC,KAAK,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AA6E/C,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAOtD,CAAC;AAcF,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,WAAW,IAAI,yBAAyB,CAC1E,CAAC,EACD,YAAY,CACb,CAAC;AAEF,KAAK,eAAe,GAAG,CAAC,CAAC,SAAS,KAAK,CAAC,WAAW,GAAG,QAAQ,EAC5D,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KACpB,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;AAE/B,QAAA,MAAM,QAAQ,EAAE,eAoEf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"LDButton.d.ts","sourceRoot":"","sources":["../../../src/components/LDButton/LDButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAQpE,KAAK,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAC5D,KAAK,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,QAAQ,CAAC;AACb,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AACzC,KAAK,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AA+E/C,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAOtD,CAAC;AAcF,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,WAAW,IAAI,yBAAyB,CAC1E,CAAC,EACD,YAAY,CACb,CAAC;AAEF,KAAK,eAAe,GAAG,CAAC,CAAC,SAAS,KAAK,CAAC,WAAW,GAAG,QAAQ,EAC5D,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KACpB,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;AAE/B,QAAA,MAAM,QAAQ,EAAE,eAoEf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import cn from '../../utils/cn.js';
3
- import ButtonBase from './ButtonBase.js';
4
3
  import { renderIcon } from '../../utils/renderIcon.js';
4
+ import ButtonBase from './ButtonBase.js';
5
5
  import ButtonSpinner from './ButtonSpinner.js';
6
6
  // ── 스타일 매핑 (static) ──
7
7
  const variantBaseClasses = {
@@ -11,9 +11,9 @@ const variantBaseClasses = {
11
11
  danger: 'bg-danger500 text-white',
12
12
  },
13
13
  outline: {
14
- neutral: 'bg-white outline outline-neutral100 text-neutral900',
15
- point: 'bg-white outline outline-lb500 text-lb500',
16
- danger: 'bg-white outline outline-danger500 text-danger500',
14
+ neutral: 'bg-white outline -outline-offset-1 outline-neutral100 text-neutral900',
15
+ point: 'bg-white outline -outline-offset-1 outline-lb500 text-lb500',
16
+ danger: 'bg-white outline -outline-offset-1 outline-danger500 text-danger500',
17
17
  },
18
18
  ghost: {
19
19
  neutral: 'bg-transparent text-neutral900',
@@ -50,7 +50,7 @@ const variantHoverClasses = {
50
50
  };
51
51
  const variantDisabledClasses = {
52
52
  solid: 'bg-mono300 text-white',
53
- outline: 'text-mono300 outline outline-neutral100',
53
+ outline: 'text-mono300 outline -outline-offset-1 outline-neutral100',
54
54
  ghost: 'text-mono300',
55
55
  link: 'text-mono300 underline underline-offset-[4px]',
56
56
  };
@@ -118,12 +118,12 @@ const Slide = ({ slidesPerView = 'auto', index, total, className, style, childre
118
118
  const Prev = ({ className, children, ...props }) => {
119
119
  const { scrollPrev, canScrollPrev, orientation } = useCarouselContext();
120
120
  return (_jsx("button", { type: "button", onClick: scrollPrev, disabled: !canScrollPrev, "aria-label": props['aria-label'] ?? '이전', className: cn('ld-carousel__nav', orientation === 'vertical' && 'ld-carousel__nav--vertical', className), children: children ??
121
- (orientation === 'vertical' ? (_jsx(ChevronUp, { size: 32, strokeWidth: 1.4 })) : (_jsx(ChevronLeft, { size: 32, strokeWidth: 1.4 }))) }));
121
+ (orientation === 'vertical' ? (_jsx(ChevronUp, { size: 28, strokeWidth: 1.4 })) : (_jsx(ChevronLeft, { size: 28, strokeWidth: 1.4 }))) }));
122
122
  };
123
123
  const Next = ({ className, children, ...props }) => {
124
124
  const { scrollNext, canScrollNext, orientation } = useCarouselContext();
125
125
  return (_jsx("button", { type: "button", onClick: scrollNext, disabled: !canScrollNext, "aria-label": props['aria-label'] ?? '다음', className: cn('ld-carousel__nav', orientation === 'vertical' && 'ld-carousel__nav--vertical', className), children: children ??
126
- (orientation === 'vertical' ? (_jsx(ChevronDown, { size: 32, strokeWidth: 1.4 })) : (_jsx(ChevronRight, { size: 32, strokeWidth: 1.4 }))) }));
126
+ (orientation === 'vertical' ? (_jsx(ChevronDown, { size: 28, strokeWidth: 1.4 })) : (_jsx(ChevronRight, { size: 28, strokeWidth: 1.4 }))) }));
127
127
  };
128
128
  const TopArrows = ({ className, children, ...props }) => {
129
129
  const { scrollNext, scrollPrev, canScrollNext, canScrollPrev, orientation } = useCarouselContext();
@@ -28,6 +28,14 @@ export interface LDCarouselProps {
28
28
  showCounter?: boolean;
29
29
  /** 한 화면에 보일 슬라이드 수. 기본 1. `'auto'`면 각 슬라이드가 내용 폭대로 배치 */
30
30
  slidesPerView?: number | 'auto';
31
+ /** 여러 행으로 쌓는 그리드 설정. 미지정 시 단일 행 */
32
+ grid?: {
33
+ /** 세로로 쌓을 행 개수. 2 이상이면 슬라이드를 행 개수만큼 세로로 묶어 한 열씩 넘긴다.
34
+ * 열이 달라도 같은 행은 같은 선상에서 시작하며, 카드 높이 자체는 콘텐츠대로 유지된다 */
35
+ rows: number;
36
+ /** 채우는 순서. 'row'(가로 우선: 0,1,2 / 3,4,5) · 'col'(세로 우선: 0,1 / 2,3). 기본 'row' */
37
+ fill?: 'row' | 'col';
38
+ };
31
39
  /** 슬라이드 사이 간격(Tailwind gap 단위 px). 기본 16 */
32
40
  gap?: number;
33
41
  className?: string;
@@ -41,7 +49,7 @@ export interface LDCarouselProps {
41
49
  * 고급 커스터마이징이 필요하면 `LDCarousel.Root` 등 compound API를 직접 조합하세요.
42
50
  */
43
51
  declare const LDCarousel: {
44
- ({ slides, orientation, loop, autoplay, autoScroll, align, containScroll, options, arrowPosition, showDots, showCounter, slidesPerView, gap, className, style, viewportClassName, slideClassName, }: LDCarouselProps): import("react/jsx-runtime").JSX.Element;
52
+ ({ slides, orientation, loop, autoplay, autoScroll, align, containScroll, options, arrowPosition, showDots, showCounter, slidesPerView, grid, gap, className, style, viewportClassName, slideClassName, }: LDCarouselProps): import("react/jsx-runtime").JSX.Element;
45
53
  Root: ({ orientation, loop, autoplay, autoScroll, align, containScroll, options, gap, className, style, children, }: RootProps) => import("react/jsx-runtime").JSX.Element;
46
54
  Viewport: ({ className, children }: import("./CarouselBase.js").ViewportProps) => import("react/jsx-runtime").JSX.Element;
47
55
  Container: ({ className, style, children }: import("./CarouselBase.js").ContainerProps) => import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"LDCarousel.d.ts","sourceRoot":"","sources":["../../../src/components/LDCarousel/LDCarousel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAqB,EACnB,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,eAAe;IAC9B,uBAAuB;IACvB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,gCAAgC;IAChC,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,sBAAsB;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,QAAQ,CAAC,EAAE,OAAO,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrE,0DAA0D;IAC1D,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IACrC,sCAAsC;IACtC,KAAK,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3B,8FAA8F;IAC9F,aAAa,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,CAAC;IAC3C;+EAC2E;IAC3E,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,wCAAwC;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,QAAA,MAAM,UAAU;yMAkBb,eAAe;;;;;;;;;;CAyDjB,CAAC;AAYF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"LDCarousel.d.ts","sourceRoot":"","sources":["../../../src/components/LDCarousel/LDCarousel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACrE,OAAqB,EACnB,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,eAAe;IAC9B,uBAAuB;IACvB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,gCAAgC;IAChC,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,sBAAsB;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,QAAQ,CAAC,EAAE,OAAO,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrE,0DAA0D;IAC1D,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IACrC,sCAAsC;IACtC,KAAK,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3B,8FAA8F;IAC9F,aAAa,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,CAAC;IAC3C;+EAC2E;IAC3E,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,mCAAmC;IACnC,IAAI,CAAC,EAAE;QACL;8DACsD;QACtD,IAAI,EAAE,MAAM,CAAC;QACb,8EAA8E;QAC9E,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;KACtB,CAAC;IACF,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,wCAAwC;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,QAAA,MAAM,UAAU;+MAmBb,eAAe;;;;;;;;;;CAsFjB,CAAC;AAYF,eAAe,UAAU,CAAC"}
@@ -1,15 +1,27 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Fragment } from 'react';
3
4
  import CarouselBase from './CarouselBase.js';
4
5
  import cn from '../../utils/cn.js';
5
6
  /**
6
7
  * embla-carousel 기반 기본 캐러셀.
7
8
  * 고급 커스터마이징이 필요하면 `LDCarousel.Root` 등 compound API를 직접 조합하세요.
8
9
  */
9
- const LDCarousel = ({ slides, orientation = 'horizontal', loop = false, autoplay = false, autoScroll = false, align = 'start', containScroll = 'trimSnaps', options, arrowPosition = 'top', showDots = false, showCounter = false, slidesPerView = 'auto', gap = 16, className, style, viewportClassName, slideClassName, }) => {
10
+ const LDCarousel = ({ slides, orientation = 'horizontal', loop = false, autoplay = false, autoScroll = false, align = 'start', containScroll = 'trimSnaps', options, arrowPosition = 'top', showDots = false, showCounter = false, slidesPerView = 'auto', grid, gap = 16, className, style, viewportClassName, slideClassName, }) => {
10
11
  const isVertical = orientation === 'vertical';
11
- const total = slides.length;
12
- return (_jsx(CarouselBase.Root, { orientation: orientation, loop: loop, autoplay: autoplay, autoScroll: autoScroll, align: align, containScroll: containScroll, options: options, gap: gap, className: className, style: style, children: _jsxs("div", { className: "flex flex-col gap-3", children: [arrowPosition === 'top' && _jsx(CarouselBase.TopArrows, {}), _jsxs("div", { className: cn('flex items-center gap-3 w-full relative', isVertical && 'flex-col'), children: [arrowPosition === 'side' && _jsx(CarouselBase.Prev, {}), _jsx(CarouselBase.Viewport, { className: cn('w-full', viewportClassName), children: _jsx(CarouselBase.Container, { children: slides.map((slide, i) => (_jsx(CarouselBase.Slide, { slidesPerView: slidesPerView, index: i, total: total, className: slideClassName, children: slide }, i))) }) }), arrowPosition === 'side' && _jsx(CarouselBase.Next, {})] }), (showDots || showCounter) && (_jsxs("div", { className: "flex items-center justify-center gap-3", children: [showDots && (_jsx(CarouselBase.Dots, { className: isVertical ? 'flex-col' : undefined })), showCounter && _jsx(CarouselBase.Counter, {})] }))] }) }));
12
+ const rows = grid?.rows ?? 1;
13
+ const columnCount = Math.ceil(slides.length / rows);
14
+ const columns = rows <= 1
15
+ ? slides.map((_, i) => [i])
16
+ : Array.from({ length: columnCount }, (_, col) => Array.from({ length: rows }, (_, row) => grid?.fill === 'col' ? col * rows + row : row * columnCount + col).filter((i) => i < slides.length));
17
+ return (_jsx(CarouselBase.Root, { orientation: orientation, loop: loop, autoplay: autoplay, autoScroll: autoScroll, align: align, containScroll: containScroll, options: options, gap: gap, className: className, style: style, children: _jsxs("div", { className: "flex flex-col gap-3", children: [arrowPosition === 'top' && _jsx(CarouselBase.TopArrows, {}), _jsxs("div", { className: cn('flex items-center gap-3 w-full relative', isVertical && 'flex-col'), children: [arrowPosition === 'side' && _jsx(CarouselBase.Prev, {}), _jsx(CarouselBase.Viewport, { className: cn('w-full', viewportClassName), children: _jsx(CarouselBase.Container, { children: columns.map((column, i) => (_jsx(CarouselBase.Slide, { slidesPerView: slidesPerView, index: i, total: columns.length, className: slideClassName, children: rows <= 1 ? (slides[i]) : (
18
+ // 행 트랙을 균등 분할해야 열이 달라도 같은 행이 같은 선상에서 시작한다.
19
+ // (슬라이드끼리는 flex stretch로 이미 높이가 같음)
20
+ // items-start: 위치만 맞추고 카드 높이는 콘텐츠대로 둔다.
21
+ _jsx("div", { className: "grid h-full items-start", style: {
22
+ gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`,
23
+ rowGap: gap,
24
+ }, children: column.map((slideIndex) => (_jsx(Fragment, { children: slides[slideIndex] }, slideIndex))) })) }, i))) }) }), arrowPosition === 'side' && _jsx(CarouselBase.Next, {})] }), (showDots || showCounter) && (_jsxs("div", { className: "flex items-center justify-center gap-3", children: [showDots && (_jsx(CarouselBase.Dots, { className: isVertical ? 'flex-col' : undefined })), showCounter && _jsx(CarouselBase.Counter, {})] }))] }) }));
13
25
  };
14
26
  LDCarousel.Root = CarouselBase.Root;
15
27
  LDCarousel.Viewport = CarouselBase.Viewport;
@@ -0,0 +1,10 @@
1
+ import { type RegisterOptions } from 'react-hook-form';
2
+ import { type LDRateProps } from './LDRate.js';
3
+ export interface LDFormRateProps extends Omit<LDRateProps, 'value' | 'name' | 'onChange'> {
4
+ name: string;
5
+ options?: RegisterOptions;
6
+ customErrorMessage?: string;
7
+ }
8
+ declare const LDFormRate: ({ name, options, customErrorMessage, className, itemClassName, ...props }: LDFormRateProps) => import("react/jsx-runtime").JSX.Element;
9
+ export default LDFormRate;
10
+ //# sourceMappingURL=LDFormRate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LDFormRate.d.ts","sourceRoot":"","sources":["../../../src/components/LDRate/LDFormRate.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGvD,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEpD,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,WAAW,EACX,OAAO,GAAG,MAAM,GAAG,UAAU,CAC9B;IACC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,QAAA,MAAM,UAAU,GAAI,2EAOjB,eAAe,4CAuBjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import cn from '../../utils/cn.js';
4
+ import FormField from '../LDForm/LDFormField.js';
5
+ import LDRate from './LDRate.js';
6
+ const LDFormRate = ({ name, options, customErrorMessage = '', className, itemClassName, ...props }) => {
7
+ return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, children: ({ field, fieldState }) => (_jsx(LDRate, { ...props, value: field.value ?? 0, onChange: field.onChange, onBlur: field.onBlur, className: className, "aria-invalid": field['aria-invalid'], itemClassName: cn(fieldState.hasError && 'text-danger600', itemClassName) })) }));
8
+ };
9
+ export default LDFormRate;
@@ -0,0 +1,45 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export type LDRateSize = 'small' | 'medium' | 'large' | 'xlarge' | '2xlarge';
3
+ export interface LDRateProps {
4
+ /** controlled 값 */
5
+ value?: number;
6
+ /** 초기 값 (uncontrolled) */
7
+ defaultValue?: number;
8
+ /** 값 확정 콜백 */
9
+ onChange?: (value: number) => void;
10
+ /** 호버 값 변경 콜백 (마우스가 벗어나면 0으로 호출) */
11
+ onHoverChange?: (value: number) => void;
12
+ /** 별 개수 (기본 5) */
13
+ count?: number;
14
+ /** 읽기 전용 여부 (평균 평점 등 표시 용도, 상호작용 차단 및 스크린리더에 값 하나로 안내, 기본 false) */
15
+ readOnly?: boolean;
16
+ /** 반개 클릭 허용 여부 */
17
+ allowHalf?: boolean;
18
+ /** 현재 값과 동일한 지점을 다시 클릭하면 0으로 초기화 (기본 true) */
19
+ allowClear?: boolean;
20
+ /** 방향키/Home/End/Space/Enter 조작 허용 여부 (기본 true) */
21
+ keyboard?: boolean;
22
+ /** 크기 프리셋 (기본 'medium') */
23
+ size?: LDRateSize;
24
+ /** 별 대신 렌더할 커스텀 아이콘 */
25
+ icon?: ReactNode;
26
+ /** Root 래퍼(role="radiogroup")에 merge할 className */
27
+ className?: string;
28
+ /** 각 별 아이템(role="radio")에 merge할 className. 채운 별 색(text-yellow600)이 여기 붙어 svg로 상속되므로 색 override 시 사용 */
29
+ itemClassName?: string;
30
+ /** Root 래퍼(radiogroup)에 적용할 인라인 스타일 */
31
+ style?: CSSProperties;
32
+ /** 포커스 이벤트 핸들러 */
33
+ onFocus?: React.FocusEventHandler<HTMLDivElement>;
34
+ /** 블러 이벤트 핸들러 */
35
+ onBlur?: React.FocusEventHandler<HTMLDivElement>;
36
+ /** 키보드 이벤트 핸들러 */
37
+ onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
38
+ /** 에러 발생 시 true, 정상 시 false */
39
+ 'aria-invalid'?: boolean | 'true' | 'false';
40
+ /** 에러 메시지 요소의 id와 연결되어 스크린 리더에서 에러를 읽을 수 있게 함 */
41
+ 'aria-describedby'?: string;
42
+ }
43
+ declare const LDRate: ({ value, defaultValue, onChange, onHoverChange, count, readOnly, allowHalf, allowClear, keyboard, size, icon, className, itemClassName, style, onFocus, onBlur, onKeyDown, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, }: LDRateProps) => import("react/jsx-runtime").JSX.Element;
44
+ export default LDRate;
45
+ //# sourceMappingURL=LDRate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LDRate.d.ts","sourceRoot":"","sources":["../../../src/components/LDRate/LDRate.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3D,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AA6D7E,MAAM,WAAW,WAAW;IAC1B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uBAAuB;IACvB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,kBAAkB;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAClD,iBAAiB;IACjB,MAAM,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,kBAAkB;IAClB,SAAS,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;IACvD,+BAA+B;IAC/B,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC5C,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,QAAA,MAAM,MAAM,GAAI,gPAoBb,WAAW,4CA8Cb,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,33 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Star } from 'lucide-react';
4
+ import cn from '../../utils/cn.js';
5
+ import { renderIcon } from '../../utils/renderIcon.js';
6
+ import RateBase from './RateBase.js';
7
+ const sizeClasses = {
8
+ small: 'display14',
9
+ medium: 'display16',
10
+ large: 'display20',
11
+ xlarge: 'display28',
12
+ '2xlarge': 'display32',
13
+ };
14
+ // 채워진 별 색 (황색 고정)
15
+ const filledColorClass = 'text-yellow600';
16
+ // 빈 별 색
17
+ const emptyColorClass = 'text-neutral100';
18
+ const StarItem = ({ filled, halfFilled, hovered, allowHalf, icon, }) => {
19
+ const iconBaseClassName = cn('size-[1em] shrink-0');
20
+ const renderStar = (isFilled) => {
21
+ const colorClass = isFilled
22
+ ? 'fill-current'
23
+ : cn('fill-current', emptyColorClass);
24
+ return icon ? (renderIcon(icon, cn(iconBaseClassName, colorClass, 'ld-transition'))) : (_jsx(Star, { className: cn(iconBaseClassName, colorClass, 'ld-transition') }));
25
+ };
26
+ return (_jsxs("div", { className: cn('relative ld-transition', hovered && 'scale-110'), children: [renderStar(filled), allowHalf && (_jsx("div", { "aria-hidden": "true", className: "absolute inset-0 w-1/2 overflow-hidden pointer-events-none", children: renderStar(halfFilled) }))] }));
27
+ };
28
+ const LDRate = ({ value, defaultValue = 0, onChange, onHoverChange, count = 5, readOnly = false, allowHalf = false, allowClear = true, keyboard = true, size = 'medium', icon, className, itemClassName, style, onFocus, onBlur, onKeyDown, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedby, }) => {
29
+ const sizeClass = sizeClasses[size];
30
+ const itemWrapperClassName = cn(readOnly ? 'cursor-default' : 'cursor-pointer', 'ld-transition', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-lb500 focus-visible:ring-offset-2 rounded-xs', filledColorClass, itemClassName);
31
+ return (_jsx(RateBase.Root, { value: value, defaultValue: defaultValue, onChange: onChange, onHoverChange: onHoverChange, count: count, readOnly: readOnly, allowHalf: allowHalf, allowClear: allowClear, keyboard: keyboard, onFocus: onFocus, onBlur: onBlur, onKeyDown: onKeyDown, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, style: style, className: cn('flex flex-row w-fit shrink-0 items-center gap-2xs', sizeClass, className), itemClassName: itemWrapperClassName, children: ({ filled, halfFilled, hovered }) => (_jsx(StarItem, { filled: filled, halfFilled: halfFilled, hovered: hovered, allowHalf: allowHalf, icon: icon })) }));
32
+ };
33
+ export default LDRate;
@@ -0,0 +1,49 @@
1
+ import { type FocusEventHandler, type KeyboardEventHandler, type ReactNode } from 'react';
2
+ interface RateStarRenderProps {
3
+ /** 0-based 별 인덱스 */
4
+ index: number;
5
+ /** 별 전체가 채워지는지 */
6
+ filled: boolean;
7
+ /** 별의 왼쪽 절반이 채워지는지 */
8
+ halfFilled: boolean;
9
+ /** 이 별이 현재 호버 대상인지 */
10
+ hovered: boolean;
11
+ }
12
+ interface RootProps {
13
+ /** controlled 값 */
14
+ value?: number;
15
+ /** 초기 값 (uncontrolled) */
16
+ defaultValue?: number;
17
+ /** 값 확정 콜백 */
18
+ onChange?: (value: number) => void;
19
+ /** 호버 값 변경 콜백 (마우스가 벗어나면 0으로 호출) */
20
+ onHoverChange?: (value: number) => void;
21
+ /** 별 개수 */
22
+ count?: number;
23
+ /** 읽기 전용 여부 (평균 평점 등 표시 용도, 상호작용 차단) */
24
+ readOnly?: boolean;
25
+ /** 반개 클릭 허용 여부 */
26
+ allowHalf?: boolean;
27
+ /** 현재 값과 동일한 지점을 다시 클릭하면 0으로 초기화 */
28
+ allowClear?: boolean;
29
+ /** 방향키/Home/End/Space/Enter 조작 허용 여부 */
30
+ keyboard?: boolean;
31
+ onFocus?: FocusEventHandler<HTMLDivElement>;
32
+ onBlur?: FocusEventHandler<HTMLDivElement>;
33
+ onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
34
+ className?: string;
35
+ style?: React.CSSProperties;
36
+ /** 별 하나의 시각 표현을 렌더하는 render-prop */
37
+ children: (star: RateStarRenderProps) => ReactNode;
38
+ /** 각 Item(role="radio")에 그대로 전달할 className 패스스루 */
39
+ itemClassName?: string;
40
+ /** 에러 발생 시 true, 정상 시 false */
41
+ 'aria-invalid'?: boolean | 'true' | 'false';
42
+ /** 에러 메시지 요소의 id와 연결되어 스크린 리더에서 에러를 읽을 수 있게 함 */
43
+ 'aria-describedby'?: string;
44
+ }
45
+ export declare const RateBase: {
46
+ Root: ({ value, defaultValue, onChange, onHoverChange, count, readOnly, allowHalf, allowClear, keyboard, onFocus, onBlur, onKeyDown, className, style, children, itemClassName, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, }: RootProps) => import("react/jsx-runtime").JSX.Element;
47
+ };
48
+ export default RateBase;
49
+ //# sourceMappingURL=RateBase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RateBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDRate/RateBase.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAGf,UAAU,mBAAmB;IAC3B,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,sBAAsB;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,sBAAsB;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB;AAGD,UAAU,SAAS;IACjB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oCAAoC;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,SAAS,CAAC;IACnD,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC5C,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAsOD,eAAO,MAAM,QAAQ;yPAjNlB,SAAS;CAmNX,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,108 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useRef, useState, } from 'react';
4
+ const Root = ({ value, defaultValue = 0, onChange, onHoverChange, count = 5, readOnly = false, allowHalf = false, allowClear = true, keyboard = true, onFocus, onBlur, onKeyDown, className, style, children, itemClassName, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedby, }) => {
5
+ const [internalValue, setInternalValue] = useState(defaultValue);
6
+ const [hoverValue, setHoverValue] = useState(null);
7
+ const isControlled = value !== undefined;
8
+ const currentValue = isControlled ? value : internalValue;
9
+ const displayValue = hoverValue !== null ? hoverValue : currentValue;
10
+ const min = allowHalf ? 0.5 : 1;
11
+ const step = allowHalf ? 0.5 : 1;
12
+ const clamp = (n) => Math.min(Math.max(n, 0), count);
13
+ const selectValue = (candidate) => {
14
+ if (readOnly)
15
+ return;
16
+ const next = allowClear && candidate === currentValue ? 0 : candidate;
17
+ if (!isControlled)
18
+ setInternalValue(next);
19
+ onChange?.(next);
20
+ };
21
+ const updateHover = (candidate) => {
22
+ if (readOnly)
23
+ return;
24
+ setHoverValue(candidate);
25
+ if (candidate !== null)
26
+ onHoverChange?.(candidate);
27
+ };
28
+ const handleMouseLeave = () => {
29
+ if (readOnly)
30
+ return;
31
+ setHoverValue(null);
32
+ onHoverChange?.(0);
33
+ };
34
+ const handleKeyDown = (event, index) => {
35
+ if (!keyboard || readOnly)
36
+ return;
37
+ switch (event.key) {
38
+ case 'ArrowRight':
39
+ case 'ArrowUp':
40
+ event.preventDefault();
41
+ selectValue(clamp(currentValue + step));
42
+ break;
43
+ case 'ArrowLeft':
44
+ case 'ArrowDown':
45
+ event.preventDefault();
46
+ selectValue(clamp(currentValue - step));
47
+ break;
48
+ case 'Home':
49
+ event.preventDefault();
50
+ selectValue(min);
51
+ break;
52
+ case 'End':
53
+ event.preventDefault();
54
+ selectValue(count);
55
+ break;
56
+ case ' ':
57
+ case 'Enter':
58
+ event.preventDefault();
59
+ selectValue(index + 1);
60
+ break;
61
+ default:
62
+ break;
63
+ }
64
+ };
65
+ const rawActiveIndex = currentValue === 0 ? 0 : Math.ceil(currentValue) - 1;
66
+ const activeIndex = Number.isFinite(rawActiveIndex)
67
+ ? Math.min(Math.max(rawActiveIndex, 0), count - 1)
68
+ : 0;
69
+ const raw = Number.isFinite(displayValue) ? displayValue : 0;
70
+ const snapped = allowHalf ? Math.round(raw * 2) / 2 : Math.round(raw);
71
+ if (readOnly) {
72
+ return (_jsx("div", { role: "img", "aria-label": `${count}점 중 ${currentValue}점`, style: style, className: className, children: Array.from({ length: count }, (_, index) => {
73
+ const filled = snapped >= index + 1;
74
+ const halfFilled = snapped >= index + 0.5;
75
+ return (_jsx("div", { "aria-hidden": "true", className: itemClassName, children: children({ index, filled, halfFilled, hovered: false }) }, index));
76
+ }) }));
77
+ }
78
+ return (_jsx("div", { role: "radiogroup", "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, style: style, className: className, onMouseLeave: handleMouseLeave, onFocus: onFocus, onBlur: onBlur, onKeyDown: onKeyDown, children: Array.from({ length: count }, (_, index) => {
79
+ const filled = snapped >= index + 1;
80
+ const halfFilled = snapped >= index + 0.5;
81
+ const hovered = hoverValue !== null && Math.ceil(hoverValue) - 1 === index;
82
+ return (_jsx(Item, { index: index, count: count, allowHalf: allowHalf, isTabbable: index === activeIndex, isChecked: currentValue !== 0 && index === activeIndex, label: index === activeIndex && !Number.isInteger(currentValue)
83
+ ? `${currentValue}점`
84
+ : `${index + 1}점`, onSelect: selectValue, onHover: updateHover, onKeyDown: (event) => handleKeyDown(event, index), className: itemClassName, children: children({ index, filled, halfFilled, hovered }) }, index));
85
+ }) }));
86
+ };
87
+ const Item = ({ index, count, allowHalf, isTabbable, isChecked, label, onSelect, onHover, onKeyDown, className, children, }) => {
88
+ const ref = useRef(null);
89
+ const posinset = index + 1;
90
+ const getCandidate = (event) => {
91
+ if (!allowHalf)
92
+ return posinset;
93
+ const rect = ref.current.getBoundingClientRect();
94
+ const isLeftHalf = event.clientX - rect.left < rect.width / 2;
95
+ return isLeftHalf ? index + 0.5 : posinset;
96
+ };
97
+ const handleClick = (event) => {
98
+ onSelect(getCandidate(event));
99
+ };
100
+ const handleMouseMove = (event) => {
101
+ onHover(getCandidate(event));
102
+ };
103
+ return (_jsx("div", { ref: ref, role: "radio", "aria-checked": isChecked, "aria-posinset": posinset, "aria-setsize": count, "aria-label": label, tabIndex: isTabbable ? 0 : -1, className: className, onClick: handleClick, onMouseMove: handleMouseMove, onKeyDown: onKeyDown, children: children }));
104
+ };
105
+ export const RateBase = {
106
+ Root,
107
+ };
108
+ export default RateBase;
@@ -0,0 +1,46 @@
1
+ import * as React from 'react';
2
+ import { type ComponentProps, type ElementType, type ReactNode } from 'react';
3
+ import { type PolymorphicComponentProps } from '../../types/polymorphic.js';
4
+ import TabsBase from './TabsBase.js';
5
+ /** 탭 트리거 시각 스타일 */
6
+ export type LDTabsVariant = 'line' | 'card' | 'button';
7
+ /** 탭 리스트 위치 */
8
+ export type LDTabsPlacement = 'top' | 'left' | 'right';
9
+ /** 탭 트리거 크기 */
10
+ export type LDTabsSize = 'small' | 'medium' | 'large';
11
+ /** 탭 트리거 강조색 (활성·hover). Trigger에 개별 지정한다. mono/neutral 계열은 color와 무관하게 고정 */
12
+ export type LDTabsColor = 'point' | 'danger' | 'success' | 'warning';
13
+ /** LDTabs.Root props */
14
+ export interface LDTabsRootProps extends ComponentProps<typeof TabsBase.Root> {
15
+ /** 탭 트리거 시각 스타일. 기본 'line' */
16
+ variant?: LDTabsVariant;
17
+ /** 탭 리스트 위치. 기본 'top' */
18
+ placement?: LDTabsPlacement;
19
+ /** 탭 트리거 크기. 기본 'medium' */
20
+ size?: LDTabsSize;
21
+ }
22
+ /** LDTabs.List props */
23
+ export type LDTabsListProps = ComponentProps<typeof TabsBase.List>;
24
+ interface LDTabsTriggerOwnProps {
25
+ /** 활성 상태 강조색. 지정한 트리거에만 적용됩니다. 기본 'point' */
26
+ color?: LDTabsColor;
27
+ /** children 왼쪽에 렌더되는 아이콘. 크기는 size에 따라 자동 결정됩니다. */
28
+ icon?: ReactNode;
29
+ /** 탭 값 */
30
+ value: string;
31
+ /** 비활성화 여부 */
32
+ disabled?: boolean;
33
+ }
34
+ /** LDTabs.Trigger props */
35
+ export type LDTabsTriggerProps<T extends ElementType> = PolymorphicComponentProps<T, LDTabsTriggerOwnProps>;
36
+ type TriggerComponent = <T extends ElementType = 'button'>(props: LDTabsTriggerProps<T>) => React.ReactElement | null;
37
+ /** LDTabs.Content props */
38
+ export type LDTabsContentProps = ComponentProps<typeof TabsBase.Content>;
39
+ declare const LDTabs: {
40
+ Root: ({ variant, placement, size, className, ...props }: LDTabsRootProps) => import("react/jsx-runtime").JSX.Element;
41
+ List: ({ className, children, ...props }: LDTabsListProps) => import("react/jsx-runtime").JSX.Element;
42
+ Trigger: TriggerComponent;
43
+ Content: ({ className, children, ...props }: LDTabsContentProps) => import("react/jsx-runtime").JSX.Element;
44
+ };
45
+ export default LDTabs;
46
+ //# sourceMappingURL=LDTabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LDTabs.d.ts","sourceRoot":"","sources":["../../../src/components/LDTabs/LDTabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAGzE,OAAO,QAAQ,MAAM,YAAY,CAAC;AAKlC,mBAAmB;AACnB,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AACvD,eAAe;AACf,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AACvD,eAAe;AACf,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AACtD,8EAA8E;AAC9E,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAwBrE,wBAAwB;AACxB,MAAM,WAAW,eAAgB,SAAQ,cAAc,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC;IAC3E,8BAA8B;IAC9B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,yBAAyB;IACzB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,4BAA4B;IAC5B,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAwED,wBAAwB;AACxB,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AA+PnE,UAAU,qBAAqB;IAC7B,6CAA6C;IAC7C,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,oDAAoD;IACpD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,UAAU;IACV,KAAK,EAAE,MAAM,CAAC;IACd,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,2BAA2B;AAC3B,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,WAAW,IAClD,yBAAyB,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;AAEtD,KAAK,gBAAgB,GAAG,CAAC,CAAC,SAAS,WAAW,GAAG,QAAQ,EACvD,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,KACzB,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;AAgD/B,2BAA2B;AAC3B,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;AAkBzE,QAAA,MAAM,MAAM;8DApZT,eAAe;8CAmE+B,eAAe;;iDAiUZ,kBAAkB;CAqBrE,CAAC;AAEF,eAAe,MAAM,CAAC"}