@wishket/design-system 1.16.1 → 1.16.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.
@@ -5,10 +5,14 @@ export interface ProgressIndicatorProps {
5
5
  }
6
6
  /**
7
7
  * ProgressIndicator
8
- * @param {Object} props
9
- * @param {string} [props.className] - 컨테이너의 추가 클래스명
10
- * @param {string} [props.progressClassName] - 프로그레스 바의 추가 클래스명
11
- * @param {number} props.value - 진행률 값 (0-100 사이의 숫자)
8
+ *
9
+ * 진행 상태를 시각적으로 표시하는 프로그레스 컴포넌트입니다.
10
+ * Safari 브라우저에서의 성능 최적화를 위해 requestAnimationFrame을 사용하여 애니메이션을 구현했습니다.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <ProgressIndicator value={75} />
15
+ * <ProgressIndicator value={50} className="h-2" progressClassName="bg-secondary" />
16
+ * ```
12
17
  */
13
- declare const ProgressIndicator: ({ className, progressClassName, value, }: ProgressIndicatorProps) => import("react/jsx-runtime").JSX.Element;
14
- export { ProgressIndicator };
18
+ export declare const ProgressIndicator: ({ className, progressClassName, value, }: ProgressIndicatorProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,16 @@
1
- import{jsx as s}from"react/jsx-runtime";import{twMerge as r}from"tailwind-merge";
1
+ "use client";import{jsx as e}from"react/jsx-runtime";import{useRef as r}from"react";import{twMerge as s}from"tailwind-merge";import{useProgressAnimation as t}from"./useProgressAnimation.js";
2
2
  /**
3
3
  * ProgressIndicator
4
- * @param {Object} props
5
- * @param {string} [props.className] - 컨테이너의 추가 클래스명
6
- * @param {string} [props.progressClassName] - 프로그레스 바의 추가 클래스명
7
- * @param {number} props.value - 진행률 값 (0-100 사이의 숫자)
8
- */const e=({className:e,progressClassName:a,value:t})=>{const i={"--progress":Math.min(100,Math.max(0,t))-100+"%"};/*#__PURE__*/
9
- return s("div",{"data-testid":"design-system-progress-indicator",className:r("h-1 w-full overflow-hidden rounded-full",e),children:/*#__PURE__*/s("div",{className:"h-full bg-w-gray-100","data-testid":"design-system-progress-indicator--background",children:/*#__PURE__*/s("div",{"data-testid":"design-system-progress-indicator--progress",className:r("h-full translate-x-[var(--progress)] bg-primary transition-transform !duration-500",a),style:i})})})};export{e as ProgressIndicator};
4
+ *
5
+ * 진행 상태를 시각적으로 표시하는 프로그레스 컴포넌트입니다.
6
+ * Safari 브라우저에서의 성능 최적화를 위해 requestAnimationFrame을 사용하여 애니메이션을 구현했습니다.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * <ProgressIndicator value={75} />
11
+ * <ProgressIndicator value={50} className="h-2" progressClassName="bg-secondary" />
12
+ * ```
13
+ */const i=({className:i,progressClassName:a,value:d})=>{const l=r(null);
14
+ // 커스텀 훅을 사용하여 애니메이션 처리
15
+ t(d,l);/*#__PURE__*/
16
+ return e("div",{"data-testid":"design-system-progress-indicator",className:s("h-1 w-full overflow-hidden rounded-full",i),children:/*#__PURE__*/e("div",{className:"h-full bg-w-gray-100","data-testid":"design-system-progress-indicator--background",style:{WebkitTransformStyle:"preserve-3d",transformStyle:"preserve-3d"},children:/*#__PURE__*/e("div",{ref:l,"data-testid":"design-system-progress-indicator--progress",className:s("h-full",a,d>0?"bg-primary":"hidden"),style:{transform:"translate3d(-100%, 0, 0)",WebkitTransform:"translate3d(-100%, 0, 0)",willChange:"transform",WebkitBackfaceVisibility:"hidden",backfaceVisibility:"hidden"}})})})};export{i as ProgressIndicator};
@@ -0,0 +1,10 @@
1
+ import { RefObject } from 'react';
2
+ /**
3
+ * 프로그레스 애니메이션을 위한 커스텀 훅
4
+ * requestAnimationFrame을 사용하여 부드러운 애니메이션을 구현합니다.
5
+ *
6
+ * @param value - 0-100 사이의 진행률 값
7
+ * @param progressRef - 애니메이션을 적용할 DOM 요소의 ref
8
+ * @returns 클램핑된 값
9
+ */
10
+ export declare const useProgressAnimation: (value: number, progressRef: RefObject<HTMLDivElement | null>) => number;
@@ -0,0 +1,25 @@
1
+ import{useRef as r,useEffect as t}from"react";
2
+ // 애니메이션 관련 상수
3
+ const n=(n,e)=>{
4
+ // 값을 0-100 범위로 제한
5
+ const c=Math.min(100,Math.max(0,n)),u=r(void 0),a=r(void 0),o=r(-100),i=r(-100);
6
+ // 애니메이션 상태 관리를 위한 refs
7
+ return t((()=>{if(!e.current)return;const r=c-100,t=n=>{
8
+ // 첫 프레임에서 시작 시간과 값을 설정
9
+ a.current||(a.current=n,o.current=i.current);
10
+ // 경과 시간 계산
11
+ const c=n-a.current,m=Math.min(c/500,1),s=(d=m,1-Math.pow(1-d,4));var d;const v=o.current+(r-o.current)*s;i.current=v,
12
+ // DOM 업데이트
13
+ e.current&&(e.current.style.transform=`translate3d(${v}%, 0, 0)`),
14
+ // 애니메이션 계속 진행
15
+ m<1?u.current=requestAnimationFrame(t):a.current=void 0};// 0-100을 -100-0으로 변환
16
+ /**
17
+ * ease-out-quart 이징 함수
18
+ * cubic-bezier(0.25, 0.46, 0.45, 0.94)와 유사한 효과
19
+ */
20
+ // 클린업 함수
21
+ // 진행 중인 애니메이션 취소
22
+ return u.current&&(cancelAnimationFrame(u.current),a.current=void 0),
23
+ // 새 애니메이션 시작
24
+ u.current=requestAnimationFrame(t),()=>{u.current&&cancelAnimationFrame(u.current)}}),[c,e]),c};// ms
25
+ export{n as useProgressAnimation};
@@ -5,7 +5,8 @@ interface BackDropLiftContainerProps extends PropsWithChildren {
5
5
  isBackgroundBlack?: boolean;
6
6
  isPreventScroll?: boolean;
7
7
  isBottomSheet?: boolean;
8
+ isFullSize?: boolean;
8
9
  testId?: string;
9
10
  }
10
- declare const BackDropLiftContainer: ({ isOpen, onClose, children, isBackgroundBlack, isPreventScroll, isBottomSheet, testId, }: BackDropLiftContainerProps) => import("react/jsx-runtime").JSX.Element | null;
11
+ declare const BackDropLiftContainer: ({ isOpen, onClose, children, isBackgroundBlack, isPreventScroll, isBottomSheet, isFullSize, testId, }: BackDropLiftContainerProps) => import("react/jsx-runtime").JSX.Element | null;
11
12
  export { BackDropLiftContainer };
@@ -1,3 +1,3 @@
1
- "use client";import{jsxs as t,jsx as e}from"react/jsx-runtime";import{useState as i,useEffect as o}from"react";import{twJoin as r,twMerge as a}from"tailwind-merge";import{Box as n}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{BackDrop as s}from"../BackDrop/BackDrop.js";const l="duration-300",c=({isOpen:c,onClose:m,children:p,isBackgroundBlack:d=!0,isPreventScroll:u=!0,isBottomSheet:B=!1,testId:f})=>{const[y,k]=i(!1),[x,j]=i(!1);return o((()=>{c?(j(!0),requestAnimationFrame((()=>k(!0)))):k(!1)}),[c]),x||c?/*#__PURE__*/t(n,{className:r("fixed inset-0 z-30 flex justify-center transition-opacity",l,B?"items-end":"items-center",y?"opacity-100":"opacity-0"),"data-testid":f||"design-system--backdrop-lift-container",children:[
2
- /*#__PURE__*/e(s,{onClick:m,isBlack:d,preventScroll:u}),
3
- /*#__PURE__*/e(n,{className:a("z-30 transition-all ease-in",l,B&&"w-full",y?"translate-y-0 opacity-100":"translate-y-full opacity-0"),onTransitionEnd:()=>{c||j(!1)},children:p})]}):null};export{c as BackDropLiftContainer};
1
+ "use client";import{jsxs as t,jsx as e}from"react/jsx-runtime";import{useState as i,useEffect as o}from"react";import{twJoin as r,twMerge as s}from"tailwind-merge";import{Box as a}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{BackDrop as n}from"../BackDrop/BackDrop.js";const l="duration-300",c=({isOpen:c,onClose:m,children:p,isBackgroundBlack:d=!0,isPreventScroll:u=!0,isBottomSheet:B=!1,isFullSize:f=!1,testId:y})=>{const[k,x]=i(!1),[j,h]=i(!1);return o((()=>{c?(h(!0),requestAnimationFrame((()=>x(!0)))):x(!1)}),[c]),j||c?/*#__PURE__*/t(a,{className:r("fixed inset-0 z-30 flex justify-center transition-opacity",l,B?"items-end":"items-center",k?"opacity-100":"opacity-0"),"data-testid":y||"design-system--backdrop-lift-container",children:[
2
+ /*#__PURE__*/e(n,{onClick:m,isBlack:d,preventScroll:u}),
3
+ /*#__PURE__*/e(a,{className:s("z-30 transition-all ease-in",l,(B||f)&&"w-full",k?"translate-y-0 opacity-100":"translate-y-full opacity-0"),onTransitionEnd:()=>{c||h(!1)},children:p})]}):null};export{c as BackDropLiftContainer};
@@ -1,4 +1,4 @@
1
- import{jsx as o,jsxs as e}from"react/jsx-runtime";import{BackDropLiftContainer as r}from"../BackDropLiftContainer/BackDropLiftContainer.js";import{BottomModalContainer as t}from"../BottomModalContainer/BottomModalContainer.js";import{FullModalContainer as l}from"../FullModalContainer/FullModalContainer.js";import{ModalContainer as i}from"../ModalContainer/ModalContainer.js";import{Portal as n}from"../Portal/Portal.js";import"tailwind-merge";import{Box as a}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";
1
+ import{jsx as o,jsxs as e}from"react/jsx-runtime";import{BackDropLiftContainer as l}from"../BackDropLiftContainer/BackDropLiftContainer.js";import{BottomModalContainer as r}from"../BottomModalContainer/BottomModalContainer.js";import{FullModalContainer as t}from"../FullModalContainer/FullModalContainer.js";import{ModalContainer as i}from"../ModalContainer/ModalContainer.js";import{Portal as n}from"../Portal/Portal.js";import"tailwind-merge";import{Box as a}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";
2
2
  /**
3
3
  * 모달 창을 표시하는 컴포넌트입니다.
4
4
  *
@@ -31,5 +31,5 @@ import{jsx as o,jsxs as e}from"react/jsx-runtime";import{BackDropLiftContainer a
31
31
  * <Modal isOpen={isOpen} variant="bottom" onClose={handleClose}>
32
32
  * <div>바텀 시트 내용</div>
33
33
  * </Modal>
34
- */const s=({isOpen:s,rootId:d,variant:m="default",size:c="md",overflow:p="auto",isBackgroundBlack:u=!0,isFixedHeight:f,isPreventScroll:B=!0,onClose:C,needCleanup:h=!0,children:j})=>{const x="bottom"===m,g="full"===m;/*#__PURE__*/
35
- return o(n,{rootId:d,needCleanup:h&&!d,children:/*#__PURE__*/e(r,{isOpen:s,onClose:C,testId:"design-system--modal",isBackgroundBlack:u,isPreventScroll:B,isBottomSheet:x,children:["default"===m&&/*#__PURE__*/o(a,{className:"full"===c?"px-5":"",children:/*#__PURE__*/o(i,{size:c,overflow:p,children:j})}),g&&/*#__PURE__*/o(l,{children:j}),x&&C&&/*#__PURE__*/o(t,{onClose:C,isFixedHeight:f,children:j})]})})};export{s as Modal};
34
+ */const s=({isOpen:s,rootId:d,variant:m="default",size:u="md",overflow:c="auto",isBackgroundBlack:f=!0,isFixedHeight:p,isPreventScroll:B=!0,onClose:C,needCleanup:h=!0,children:j})=>{const x="bottom"===m,F="full"===m;/*#__PURE__*/
35
+ return o(n,{rootId:d,needCleanup:h&&!d,children:/*#__PURE__*/e(l,{isOpen:s,onClose:C,testId:"design-system--modal",isBackgroundBlack:f,isPreventScroll:B,isBottomSheet:x,isFullSize:"full"===u,children:["default"===m&&/*#__PURE__*/o(a,{className:"full"===u?"w-full px-5":"",children:/*#__PURE__*/o(i,{size:u,overflow:c,children:j})}),F&&/*#__PURE__*/o(t,{children:j}),x&&C&&/*#__PURE__*/o(r,{onClose:C,isFixedHeight:p,children:j})]})})};export{s as Modal};
@@ -1,2 +1,4 @@
1
- "use strict";var s=require("react/jsx-runtime"),r=require("tailwind-merge");exports.ProgressIndicator=({className:e,progressClassName:a,value:t})=>{const i={"--progress":Math.min(100,Math.max(0,t))-100+"%"};/*#__PURE__*/
2
- return s.jsx("div",{"data-testid":"design-system-progress-indicator",className:r.twMerge("h-1 w-full overflow-hidden rounded-full",e),children:/*#__PURE__*/s.jsx("div",{className:"h-full bg-w-gray-100","data-testid":"design-system-progress-indicator--background",children:/*#__PURE__*/s.jsx("div",{"data-testid":"design-system-progress-indicator--progress",className:r.twMerge("h-full translate-x-[var(--progress)] bg-primary transition-transform !duration-500",a),style:i})})})};
1
+ "use client";"use strict";var e=require("react/jsx-runtime"),r=require("react"),s=require("tailwind-merge"),i=require("./useProgressAnimation.js");exports.ProgressIndicator=({className:t,progressClassName:a,value:d})=>{const n=r.useRef(null);
2
+ // 커스텀 훅을 사용하여 애니메이션 처리
3
+ i.useProgressAnimation(d,n);/*#__PURE__*/
4
+ return e.jsx("div",{"data-testid":"design-system-progress-indicator",className:s.twMerge("h-1 w-full overflow-hidden rounded-full",t),children:/*#__PURE__*/e.jsx("div",{className:"h-full bg-w-gray-100","data-testid":"design-system-progress-indicator--background",style:{WebkitTransformStyle:"preserve-3d",transformStyle:"preserve-3d"},children:/*#__PURE__*/e.jsx("div",{ref:n,"data-testid":"design-system-progress-indicator--progress",className:s.twMerge("h-full",a,d>0?"bg-primary":"hidden"),style:{transform:"translate3d(-100%, 0, 0)",WebkitTransform:"translate3d(-100%, 0, 0)",willChange:"transform",WebkitBackfaceVisibility:"hidden",backfaceVisibility:"hidden"}})})})};
@@ -0,0 +1,24 @@
1
+ "use strict";var r=require("react");
2
+ // 애니메이션 관련 상수
3
+ exports.useProgressAnimation=(e,t)=>{
4
+ // 값을 0-100 범위로 제한
5
+ const n=Math.min(100,Math.max(0,e)),u=r.useRef(void 0),c=r.useRef(void 0),a=r.useRef(-100),s=r.useRef(-100);
6
+ // 애니메이션 상태 관리를 위한 refs
7
+ return r.useEffect((()=>{if(!t.current)return;const r=n-100,e=n=>{
8
+ // 첫 프레임에서 시작 시간과 값을 설정
9
+ c.current||(c.current=n,a.current=s.current);
10
+ // 경과 시간 계산
11
+ const i=n-c.current,o=Math.min(i/500,1),m=(f=o,1-Math.pow(1-f,4));var f;const v=a.current+(r-a.current)*m;s.current=v,
12
+ // DOM 업데이트
13
+ t.current&&(t.current.style.transform=`translate3d(${v}%, 0, 0)`),
14
+ // 애니메이션 계속 진행
15
+ o<1?u.current=requestAnimationFrame(e):c.current=void 0};// 0-100을 -100-0으로 변환
16
+ /**
17
+ * ease-out-quart 이징 함수
18
+ * cubic-bezier(0.25, 0.46, 0.45, 0.94)와 유사한 효과
19
+ */
20
+ // 클린업 함수
21
+ // 진행 중인 애니메이션 취소
22
+ return u.current&&(cancelAnimationFrame(u.current),c.current=void 0),
23
+ // 새 애니메이션 시작
24
+ u.current=requestAnimationFrame(e),()=>{u.current&&cancelAnimationFrame(u.current)}}),[n,t]),n};
@@ -1,3 +1,3 @@
1
- "use client";"use strict";var e=require("react/jsx-runtime"),t=require("react"),r=require("tailwind-merge"),i=require("../../Base/Layouts/Box/Box.js");require("../../Base/Layouts/FullBleed/FullBleed.js");var s=require("../BackDrop/BackDrop.js");const a="duration-300";exports.BackDropLiftContainer=({isOpen:n,onClose:o,children:l,isBackgroundBlack:c=!0,isPreventScroll:u=!0,isBottomSheet:d=!1,testId:B})=>{const[p,x]=t.useState(!1),[y,m]=t.useState(!1);return t.useEffect((()=>{n?(m(!0),requestAnimationFrame((()=>x(!0)))):x(!1)}),[n]),y||n?/*#__PURE__*/e.jsxs(i.Box,{className:r.twJoin("fixed inset-0 z-30 flex justify-center transition-opacity",a,d?"items-end":"items-center",p?"opacity-100":"opacity-0"),"data-testid":B||"design-system--backdrop-lift-container",children:[
1
+ "use client";"use strict";var e=require("react/jsx-runtime"),t=require("react"),i=require("tailwind-merge"),r=require("../../Base/Layouts/Box/Box.js");require("../../Base/Layouts/FullBleed/FullBleed.js");var s=require("../BackDrop/BackDrop.js");const a="duration-300";exports.BackDropLiftContainer=({isOpen:n,onClose:o,children:l,isBackgroundBlack:c=!0,isPreventScroll:u=!0,isBottomSheet:d=!1,isFullSize:B=!1,testId:p})=>{const[x,y]=t.useState(!1),[m,f]=t.useState(!1);return t.useEffect((()=>{n?(f(!0),requestAnimationFrame((()=>y(!0)))):y(!1)}),[n]),m||n?/*#__PURE__*/e.jsxs(r.Box,{className:i.twJoin("fixed inset-0 z-30 flex justify-center transition-opacity",a,d?"items-end":"items-center",x?"opacity-100":"opacity-0"),"data-testid":p||"design-system--backdrop-lift-container",children:[
2
2
  /*#__PURE__*/e.jsx(s.BackDrop,{onClick:o,isBlack:c,preventScroll:u}),
3
- /*#__PURE__*/e.jsx(i.Box,{className:r.twMerge("z-30 transition-all ease-in",a,d&&"w-full",p?"translate-y-0 opacity-100":"translate-y-full opacity-0"),onTransitionEnd:()=>{n||m(!1)},children:l})]}):null};
3
+ /*#__PURE__*/e.jsx(r.Box,{className:i.twMerge("z-30 transition-all ease-in",a,(d||B)&&"w-full",x?"translate-y-0 opacity-100":"translate-y-full opacity-0"),onTransitionEnd:()=>{n||f(!1)},children:l})]}):null};
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("react/jsx-runtime"),o=require("../BackDropLiftContainer/BackDropLiftContainer.js"),r=require("../BottomModalContainer/BottomModalContainer.js"),l=require("../FullModalContainer/FullModalContainer.js"),i=require("../ModalContainer/ModalContainer.js"),t=require("../Portal/Portal.js");require("tailwind-merge");var a=require("../../Base/Layouts/Box/Box.js");require("../../Base/Layouts/FullBleed/FullBleed.js");exports.Modal=({isOpen:n,rootId:s,variant:d="default",size:u="md",overflow:c="auto",isBackgroundBlack:B=!0,isFixedHeight:C,isPreventScroll:j=!0,onClose:x,needCleanup:m=!0,children:h})=>{const M="bottom"===d,f="full"===d,p="default"===d,q=m&&!s;/*#__PURE__*/
2
- return e.jsx(t.Portal,{rootId:s,needCleanup:q,children:/*#__PURE__*/e.jsxs(o.BackDropLiftContainer,{isOpen:n,onClose:x,testId:"design-system--modal",isBackgroundBlack:B,isPreventScroll:j,isBottomSheet:M,children:[p&&/*#__PURE__*/e.jsx(a.Box,{className:"full"===u?"px-5":"",children:/*#__PURE__*/e.jsx(i.ModalContainer,{size:u,overflow:c,children:h})}),f&&/*#__PURE__*/e.jsx(l.FullModalContainer,{children:h}),M&&x&&/*#__PURE__*/e.jsx(r.BottomModalContainer,{onClose:x,isFixedHeight:C,children:h})]})})};
1
+ "use strict";var e=require("react/jsx-runtime"),o=require("../BackDropLiftContainer/BackDropLiftContainer.js"),r=require("../BottomModalContainer/BottomModalContainer.js"),l=require("../FullModalContainer/FullModalContainer.js"),i=require("../ModalContainer/ModalContainer.js"),t=require("../Portal/Portal.js");require("tailwind-merge");var a=require("../../Base/Layouts/Box/Box.js");require("../../Base/Layouts/FullBleed/FullBleed.js");exports.Modal=({isOpen:n,rootId:s,variant:d="default",size:u="md",overflow:c="auto",isBackgroundBlack:B=!0,isFixedHeight:C,isPreventScroll:j=!0,onClose:x,needCleanup:f=!0,children:m})=>{const h="bottom"===d,M="full"===d,p="default"===d,q=f&&!s;/*#__PURE__*/
2
+ return e.jsx(t.Portal,{rootId:s,needCleanup:q,children:/*#__PURE__*/e.jsxs(o.BackDropLiftContainer,{isOpen:n,onClose:x,testId:"design-system--modal",isBackgroundBlack:B,isPreventScroll:j,isBottomSheet:h,isFullSize:"full"===u,children:[p&&/*#__PURE__*/e.jsx(a.Box,{className:"full"===u?"w-full px-5":"",children:/*#__PURE__*/e.jsx(i.ModalContainer,{size:u,overflow:c,children:m})}),M&&/*#__PURE__*/e.jsx(l.FullModalContainer,{children:m}),h&&x&&/*#__PURE__*/e.jsx(r.BottomModalContainer,{onClose:x,isFixedHeight:C,children:m})]})})};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wishket/design-system",
3
- "version": "1.16.1",
3
+ "version": "1.16.2",
4
4
  "type": "module",
5
5
  "description": "Wishket Design System",
6
6
  "main": "dist/index.js",