@loword/loword-design-system 0.0.14 → 0.0.16

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.
@@ -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;;;;;;;;;;CAyFjB,CAAC;AAYF,eAAe,UAAU,CAAC"}
@@ -1,15 +1,25 @@
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: cn(arrowPosition === 'side' && !isVertical && 'ld-carousel--nav-gutter-x', 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', isVertical &&
18
+ arrowPosition === 'side' &&
19
+ 'ld-carousel__nav-clearance-y'), 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]) : (_jsx("div", { className: "grid h-full items-start", style: {
20
+ gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`,
21
+ rowGap: gap,
22
+ }, 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
23
  };
14
24
  LDCarousel.Root = CarouselBase.Root;
15
25
  LDCarousel.Viewport = CarouselBase.Viewport;
package/dist/index.css CHANGED
@@ -2144,9 +2144,6 @@
2144
2144
  .border-danger600 {
2145
2145
  border-color: var(--color-danger600);
2146
2146
  }
2147
- .border-gray-200 {
2148
- border-color: var(--color-gray-200);
2149
- }
2150
2147
  .border-lb500 {
2151
2148
  border-color: var(--color-lb500);
2152
2149
  }
@@ -2914,6 +2911,9 @@
2914
2911
  .outline-danger600 {
2915
2912
  outline-color: var(--color-danger600);
2916
2913
  }
2914
+ .outline-gray-200 {
2915
+ outline-color: var(--color-gray-200);
2916
+ }
2917
2917
  .outline-lb500 {
2918
2918
  outline-color: var(--color-lb500);
2919
2919
  }
@@ -5402,6 +5402,15 @@
5402
5402
  }
5403
5403
  }
5404
5404
  @layer components {
5405
+ .ld-carousel {
5406
+ --ld-carousel-nav-size: 50px;
5407
+ }
5408
+ .ld-carousel--nav-gutter-x {
5409
+ padding-inline: calc(var(--ld-carousel-nav-size) / 2);
5410
+ }
5411
+ .ld-carousel__nav-clearance-y {
5412
+ margin-block: calc(var(--ld-carousel-nav-size) / 2);
5413
+ }
5405
5414
  .ld-carousel__viewport {
5406
5415
  overflow: hidden;
5407
5416
  }
@@ -5411,43 +5420,53 @@
5411
5420
  .ld-carousel__nav {
5412
5421
  position: absolute;
5413
5422
  top: 50%;
5414
- transform: translateY(-50%);
5423
+ z-index: 10;
5415
5424
  display: flex;
5416
5425
  align-items: center;
5417
5426
  justify-content: center;
5418
- padding: 0;
5419
- background: transparent;
5420
- z-index: 10;
5427
+ background: var(--color-white);
5421
5428
  cursor: pointer;
5422
- transition: all 300ms ease-out;
5423
5429
  border-radius: 9999px;
5424
- width: 32px;
5425
- height: 32px;
5430
+ flex-shrink: 0;
5431
+ width: var(--ld-carousel-nav-size);
5432
+ height: var(--ld-carousel-nav-size);
5433
+ transition: all 300ms ease-out;
5434
+ --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
5435
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
5436
+ }
5437
+ @media (max-width: calc(768px - 1px)) {
5438
+ .ld-carousel {
5439
+ --ld-carousel-nav-size: 40px;
5440
+ }
5441
+ .ld-carousel__nav svg {
5442
+ width: 20px;
5443
+ height: 20px;
5444
+ }
5426
5445
  }
5427
5446
  .ld-carousel__nav:disabled {
5428
- opacity: 0.4;
5429
5447
  cursor: not-allowed;
5448
+ color: var(--color-neutral400);
5430
5449
  }
5431
5450
  .ld-carousel__nav:first-child {
5432
- left: -1%;
5451
+ left: 0;
5452
+ transform: translate(-50%, -50%);
5433
5453
  }
5434
5454
  .ld-carousel__nav:last-child {
5435
- right: -1%;
5436
- }
5437
- .ld-carousel__nav--vertical {
5438
- transform: translateX(-50%);
5455
+ right: 0;
5456
+ transform: translate(50%, -50%);
5439
5457
  }
5440
5458
  .ld-carousel__nav--vertical:first-child {
5441
- top: -1%;
5442
- bottom: auto;
5459
+ top: 0;
5443
5460
  left: 50%;
5444
5461
  right: auto;
5462
+ transform: translate(-50%, -50%);
5445
5463
  }
5446
5464
  .ld-carousel__nav--vertical:last-child {
5447
5465
  top: auto;
5448
- bottom: -1%;
5466
+ bottom: 0;
5449
5467
  left: 50%;
5450
5468
  right: auto;
5469
+ transform: translate(-50%, 50%);
5451
5470
  }
5452
5471
  }
5453
5472
  @property --tw-translate-x {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loword/loword-design-system",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "로워드 디자인 시스템 컴포넌트 패키지(Tailwind v4)",
5
5
  "keywords": [
6
6
  "react",
@@ -1,4 +1,16 @@
1
1
  @layer components {
2
+ .ld-carousel {
3
+ --ld-carousel-nav-size: 50px;
4
+ }
5
+
6
+ .ld-carousel--nav-gutter-x {
7
+ padding-inline: calc(var(--ld-carousel-nav-size) / 2);
8
+ }
9
+
10
+ .ld-carousel__nav-clearance-y {
11
+ margin-block: calc(var(--ld-carousel-nav-size) / 2);
12
+ }
13
+
2
14
  .ld-carousel__viewport {
3
15
  overflow: hidden;
4
16
  }
@@ -10,48 +22,58 @@
10
22
  .ld-carousel__nav {
11
23
  position: absolute;
12
24
  top: 50%;
13
- transform: translateY(-50%);
25
+ z-index: 10;
14
26
  display: flex;
15
27
  align-items: center;
16
28
  justify-content: center;
17
- padding: 0;
18
- background: transparent;
19
- z-index: 10;
29
+ background: var(--color-white);
20
30
  cursor: pointer;
21
- transition: all 300ms ease-out;
22
31
  border-radius: 9999px;
23
- width: 32px;
24
- height: 32px;
32
+ flex-shrink: 0;
33
+ width: var(--ld-carousel-nav-size);
34
+ height: var(--ld-carousel-nav-size);
35
+ transition: all 300ms ease-out;
36
+ @apply shadow-lg;
37
+ }
38
+
39
+ @variant mobile {
40
+ .ld-carousel {
41
+ --ld-carousel-nav-size: 40px;
42
+ }
43
+
44
+ .ld-carousel__nav svg {
45
+ width: 20px;
46
+ height: 20px;
47
+ }
25
48
  }
26
49
 
27
50
  .ld-carousel__nav:disabled {
28
- opacity: 0.4;
29
51
  cursor: not-allowed;
52
+ color: var(--color-neutral400);
30
53
  }
31
54
 
32
55
  .ld-carousel__nav:first-child {
33
- left: -1%;
56
+ left: 0;
57
+ transform: translate(-50%, -50%);
34
58
  }
35
59
 
36
60
  .ld-carousel__nav:last-child {
37
- right: -1%;
38
- }
39
-
40
- .ld-carousel__nav--vertical {
41
- transform: translateX(-50%);
61
+ right: 0;
62
+ transform: translate(50%, -50%);
42
63
  }
43
64
 
44
65
  .ld-carousel__nav--vertical:first-child {
45
- top: -1%;
46
- bottom: auto;
66
+ top: 0;
47
67
  left: 50%;
48
68
  right: auto;
69
+ transform: translate(-50%, -50%);
49
70
  }
50
71
 
51
72
  .ld-carousel__nav--vertical:last-child {
52
73
  top: auto;
53
- bottom: -1%;
74
+ bottom: 0;
54
75
  left: 50%;
55
76
  right: auto;
77
+ transform: translate(-50%, 50%);
56
78
  }
57
79
  }