@petnow/ui 5.0.0 → 5.1.0
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.
- package/CHANGELOG.md +39 -0
- package/dist/Popup-B2Q-le-6.js.map +1 -1
- package/dist/src/components/v0/checkbox/Checkbox.d.ts +3 -2
- package/dist/v0/checkbox.js +4 -3
- package/dist/v0/checkbox.js.map +1 -1
- package/dist/v0/tabs.js +7 -8
- package/dist/v0/tabs.js.map +1 -1
- package/dist/v0/toggle.js.map +1 -1
- package/package.json +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.0
|
|
4
|
+
|
|
5
|
+
### Changes
|
|
6
|
+
|
|
7
|
+
- **v0 `Checkbox` checked colors use semantic tokens.** The background is `surface-primary-accent` and the
|
|
8
|
+
check mark is `icon-prominent-neutral`. Both keep their value (`#ff592c`, `#ffffff`) in the Petnow theme;
|
|
9
|
+
the background follows the Petify theme's accent. The unchecked colors stay on `petnow-grey-primary`
|
|
10
|
+
(`#c5c8cd`) and `petnow-grey-secondary` (`#8b919a`), because no semantic token has those values.
|
|
11
|
+
- v0 `Checkbox` shows a focus ring on keyboard focus (`focus-visible`, `border-prominent-accent`). It is an
|
|
12
|
+
outline, so a consumer `focus-visible:ring-*` is drawn under it. Pass `focus-visible:outline-none` to keep
|
|
13
|
+
only your own ring.
|
|
14
|
+
- v0 `Checkbox` has a transparent border. The border used to be the background color, so it looks the same
|
|
15
|
+
unless a consumer overrode only the background; then the 1px `#c5c8cd` border is gone.
|
|
16
|
+
|
|
17
|
+
### Fixes
|
|
18
|
+
|
|
19
|
+
- v0 `Checkbox` `className` now overrides the default classes. It was merged before them, so a conflicting
|
|
20
|
+
class such as `bg-*` lost and consumers had to add `!important` modifiers. A conflicting class that was
|
|
21
|
+
silently ignored before (`size-*`, `rounded-*`, `bg-*`, `border-*` without `!`) now takes effect.
|
|
22
|
+
- v0 `Checkbox` passes the remaining `<input>` attributes (`name`, `required`, `aria-invalid`,
|
|
23
|
+
`aria-describedby`, …) to its `<input>`. `isChecked` and `onChange(checked: boolean)` are unchanged.
|
|
24
|
+
- Removed the v0 `Checkbox` `before:` classes. The pseudo-element stayed at `opacity-0`, so it never
|
|
25
|
+
rendered.
|
|
26
|
+
|
|
27
|
+
## 5.0.1
|
|
28
|
+
|
|
29
|
+
### Fixes
|
|
30
|
+
|
|
31
|
+
- `@petnow/ui` and `@petnow/ui/v0/tabs` load in Node again (test runners, SSR without a bundler). v0 `Tabs`
|
|
32
|
+
imported `keen-slider/react`, which Node ESM cannot resolve because keen-slider has no `exports` map, and
|
|
33
|
+
`keen-slider/keen-slider.min.css`, which Node cannot import. It now imports `keen-slider/react.js`, and the
|
|
34
|
+
keen-slider styles are Tailwind utilities on the slider elements, so they come from the consumer's Tailwind
|
|
35
|
+
build like every other component class. `dist/index.css` is still optional for `Tabs`.
|
|
36
|
+
|
|
37
|
+
### Internal
|
|
38
|
+
|
|
39
|
+
- CI imports every built `dist` module with Node (`pnpm check:dist`).
|
|
40
|
+
- `storybook-static/` is git-ignored.
|
|
41
|
+
|
|
3
42
|
## 5.0.0
|
|
4
43
|
|
|
5
44
|
Consumers own Tailwind, and the package stops leaking global styles. See
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popup-B2Q-le-6.js","names":[],"sources":["../src/components/ui/dialog.tsx","../src/components/v1/popup/Popup.tsx"],"sourcesContent":["import { Dialog as DialogPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/utils/TailwindUtil\";\n\nconst Dialog = DialogPrimitive.Root;\nconst DialogTrigger = DialogPrimitive.Trigger;\nconst DialogPortal = DialogPrimitive.Portal;\nconst DialogClose = DialogPrimitive.Close;\n\nconst DialogOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-[#2c2f34]/40 duration-200\",\n className,\n )}\n {...props}\n />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-surface-base-neutral-1 fixed top-1/2 left-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg p-6 shadow-lg duration-200 outline-none\",\n className,\n )}\n {...props}\n />\n </DialogPortal>\n));\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nfunction DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex flex-col gap-2\", className)} {...props} />;\n}\n\nfunction DialogFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex flex-col gap-2 sm:flex-row sm:justify-end\", className)} {...props} />;\n}\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title ref={ref} className={cn(\"text-lg font-semibold\", className)} {...props} />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-text-prominent-neutral-3 text-sm\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"../../../utils/TailwindUtil\";\nimport { CTAButton } from \"../cta-button/CTAButton\";\n\nimport { Dialog, DialogContent, DialogDescription, DialogTitle } from \"@/components/ui/dialog\";\n\ntype PopupAction = {\n label: string | React.ReactNode;\n icon?: React.ComponentType<{ className?: string }>;\n onClick?: () => void;\n};\n\nexport interface PopupProps {\n isOpen: boolean;\n setIsOpen: (isOpen: boolean) => void;\n onClose?: () => void;\n title?: string | React.ReactNode;\n description?: string | React.ReactNode;\n content?: React.ReactNode;\n confirm?: PopupAction;\n cancel?: PopupAction;\n preventEasyClose?: boolean;\n className?: string;\n}\n\nconst Popup = ({\n isOpen,\n setIsOpen,\n onClose,\n title,\n description,\n content,\n confirm,\n cancel,\n preventEasyClose = false,\n className,\n}: PopupProps) => {\n const handleClose = () => {\n setIsOpen(false);\n onClose?.();\n };\n\n const handleConfirmAction = (action?: PopupAction) => () => {\n action?.onClick?.();\n };\n\n const handleCancelAction = (action?: PopupAction) => () => {\n action?.onClick?.();\n handleClose();\n };\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (preventEasyClose && !nextOpen) {\n return;\n }\n\n if (!nextOpen) {\n onClose?.();\n }\n\n setIsOpen(nextOpen);\n };\n\n return (\n <Dialog open={isOpen} onOpenChange={handleOpenChange}>\n <DialogContent\n onEscapeKeyDown={preventEasyClose ? (event) => event.preventDefault() : undefined}\n onInteractOutside={preventEasyClose ? (event) => event.preventDefault() : undefined}\n className={cn(\n \"bg-surface-base-neutral-1 flex max-h-[440px] w-[300px] max-w-[300px] flex-col gap-4 overflow-hidden rounded-[16px] p-4\",\n className,\n )}\n >\n <div className=\"flex w-full flex-col gap-2 overflow-y-auto\">\n {title && <DialogTitle className=\"text-title-18-bold text-text-prominent-neutral-4\">{title}</DialogTitle>}\n {description && (\n <div className=\"overflow-y-auto\">\n <DialogDescription className=\"text-body-16-medium text-text-prominent-neutral-3\">\n {description}\n </DialogDescription>\n </div>\n )}\n {content && <div className=\"overflow-y-auto\">{content}</div>}\n </div>\n {(confirm || cancel) && (\n <div className=\"flex w-full flex-col gap-2\">\n {confirm && (\n <CTAButton\n label={confirm.label}\n icon={confirm.icon}\n size=\"medium\"\n hierarchy=\"primary\"\n onClick={handleConfirmAction(confirm)}\n />\n )}\n {cancel && (\n <CTAButton\n label={cancel.label}\n icon={cancel.icon}\n size=\"medium\"\n hierarchy=\"tertiary\"\n onClick={handleCancelAction(cancel)}\n />\n )}\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nexport { Popup };\n"],"mappings":";;;;;;;AAKA,IAAM,IAAS,EAAgB;AACT,EAAgB;AACtC,IAAM,IAAe,EAAgB;AACjB,EAAgB;AAEpC,IAAM,IAAgB,EAAM,YAGzB,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,EAAgB,SAAjB;CACO;CACL,WAAW,
|
|
1
|
+
{"version":3,"file":"Popup-B2Q-le-6.js","names":[],"sources":["../src/components/ui/dialog.tsx","../src/components/v1/popup/Popup.tsx"],"sourcesContent":["import { Dialog as DialogPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/utils/TailwindUtil\";\n\nconst Dialog = DialogPrimitive.Root;\nconst DialogTrigger = DialogPrimitive.Trigger;\nconst DialogPortal = DialogPrimitive.Portal;\nconst DialogClose = DialogPrimitive.Close;\n\nconst DialogOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n // TODO(PROD-662): 오버레이(dim) 시맨틱 토큰이 없어 기존 색을 유지한다. 토큰 추가 후 교체.\n // eslint-disable-next-line design-tokens/no-hardcoded-color\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-[#2c2f34]/40 duration-200\",\n className,\n )}\n {...props}\n />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-surface-base-neutral-1 fixed top-1/2 left-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg p-6 shadow-lg duration-200 outline-none\",\n className,\n )}\n {...props}\n />\n </DialogPortal>\n));\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nfunction DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex flex-col gap-2\", className)} {...props} />;\n}\n\nfunction DialogFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex flex-col gap-2 sm:flex-row sm:justify-end\", className)} {...props} />;\n}\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title ref={ref} className={cn(\"text-lg font-semibold\", className)} {...props} />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-text-prominent-neutral-3 text-sm\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"../../../utils/TailwindUtil\";\nimport { CTAButton } from \"../cta-button/CTAButton\";\n\nimport { Dialog, DialogContent, DialogDescription, DialogTitle } from \"@/components/ui/dialog\";\n\ntype PopupAction = {\n label: string | React.ReactNode;\n icon?: React.ComponentType<{ className?: string }>;\n onClick?: () => void;\n};\n\nexport interface PopupProps {\n isOpen: boolean;\n setIsOpen: (isOpen: boolean) => void;\n onClose?: () => void;\n title?: string | React.ReactNode;\n description?: string | React.ReactNode;\n content?: React.ReactNode;\n confirm?: PopupAction;\n cancel?: PopupAction;\n preventEasyClose?: boolean;\n className?: string;\n}\n\nconst Popup = ({\n isOpen,\n setIsOpen,\n onClose,\n title,\n description,\n content,\n confirm,\n cancel,\n preventEasyClose = false,\n className,\n}: PopupProps) => {\n const handleClose = () => {\n setIsOpen(false);\n onClose?.();\n };\n\n const handleConfirmAction = (action?: PopupAction) => () => {\n action?.onClick?.();\n };\n\n const handleCancelAction = (action?: PopupAction) => () => {\n action?.onClick?.();\n handleClose();\n };\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (preventEasyClose && !nextOpen) {\n return;\n }\n\n if (!nextOpen) {\n onClose?.();\n }\n\n setIsOpen(nextOpen);\n };\n\n return (\n <Dialog open={isOpen} onOpenChange={handleOpenChange}>\n <DialogContent\n onEscapeKeyDown={preventEasyClose ? (event) => event.preventDefault() : undefined}\n onInteractOutside={preventEasyClose ? (event) => event.preventDefault() : undefined}\n className={cn(\n \"bg-surface-base-neutral-1 flex max-h-[440px] w-[300px] max-w-[300px] flex-col gap-4 overflow-hidden rounded-[16px] p-4\",\n className,\n )}\n >\n <div className=\"flex w-full flex-col gap-2 overflow-y-auto\">\n {title && <DialogTitle className=\"text-title-18-bold text-text-prominent-neutral-4\">{title}</DialogTitle>}\n {description && (\n <div className=\"overflow-y-auto\">\n <DialogDescription className=\"text-body-16-medium text-text-prominent-neutral-3\">\n {description}\n </DialogDescription>\n </div>\n )}\n {content && <div className=\"overflow-y-auto\">{content}</div>}\n </div>\n {(confirm || cancel) && (\n <div className=\"flex w-full flex-col gap-2\">\n {confirm && (\n <CTAButton\n label={confirm.label}\n icon={confirm.icon}\n size=\"medium\"\n hierarchy=\"primary\"\n onClick={handleConfirmAction(confirm)}\n />\n )}\n {cancel && (\n <CTAButton\n label={cancel.label}\n icon={cancel.icon}\n size=\"medium\"\n hierarchy=\"tertiary\"\n onClick={handleCancelAction(cancel)}\n />\n )}\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nexport { Popup };\n"],"mappings":";;;;;;;AAKA,IAAM,IAAS,EAAgB;AACT,EAAgB;AACtC,IAAM,IAAe,EAAgB;AACjB,EAAgB;AAEpC,IAAM,IAAgB,EAAM,YAGzB,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,EAAgB,SAAjB;CACO;CACL,WAAW,EAGT,2KACA,CACF;CACA,GAAI;AACL,CAAA,CACF;AACD,EAAc,cAAc,EAAgB,QAAQ;AAEpD,IAAM,IAAgB,EAAM,YAGzB,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,CAAgB,CAAA,GAChB,kBAAC,EAAgB,SAAjB;CACO;CACL,WAAW,EACT,4RACA,CACF;CACA,GAAI;AACL,CAAA,CACW,EAAA,CAAA,CACf;AACD,EAAc,cAAc,EAAgB,QAAQ;AAUpD,IAAM,IAAc,EAAM,YAGvB,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,EAAgB,OAAjB;CAA4B;CAAK,WAAW,EAAG,yBAAyB,CAAS;CAAG,GAAI;AAAQ,CAAA,CACjG;AACD,EAAY,cAAc,EAAgB,MAAM;AAEhD,IAAM,IAAoB,EAAM,YAG7B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,EAAgB,aAAjB;CACO;CACL,WAAW,EAAG,yCAAyC,CAAS;CAChE,GAAI;AACL,CAAA,CACF;AACD,EAAkB,cAAc,EAAgB,YAAY;;;AC3C5D,IAAM,KAAS,EACb,WACA,cACA,YACA,UACA,gBACA,YACA,YACA,WACA,sBAAmB,IACnB,mBACgB;CAChB,IAAM,UAAoB;EAExB,AADA,EAAU,EAAK,GACf,IAAU;CACZ;CAuBA,OACE,kBAAC,GAAD;EAAQ,MAAM;EAAQ,eAbE,MAAsB;GAC1C,KAAoB,CAAC,MAIpB,KACH,IAAU,GAGZ,EAAU,CAAQ;EACpB;YAII,kBAAC,GAAD;GACE,iBAAiB,KAAoB,MAAU,EAAM,eAAe,IAAI,KAAA;GACxE,mBAAmB,KAAoB,MAAU,EAAM,eAAe,IAAI,KAAA;GAC1E,WAAW,EACT,0HACA,CACF;aANF,CAQE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KAAS,kBAAC,GAAD;MAAa,WAAU;gBAAoD;KAAmB,CAAA;KACvG,KACC,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OAAmB,WAAU;iBAC1B;MACgB,CAAA;KAChB,CAAA;KAEN,KAAW,kBAAC,OAAD;MAAK,WAAU;gBAAmB;KAAa,CAAA;IACxD;QACH,KAAW,MACX,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KACC,kBAAC,GAAD;KACE,OAAO,EAAQ;KACf,MAAM,EAAQ;KACd,MAAK;KACL,WAAU;KACV,WAlDe,YAA+B;MAC1D,GAAQ,UAAU;KACpB,EAgDuB,CAAoB,CAAO;IACrC,CAAA,GAEF,KACC,kBAAC,GAAD;KACE,OAAO,EAAO;KACd,MAAM,EAAO;KACb,MAAK;KACL,WAAU;KACV,WAvDc,YAA+B;MAEzD,AADA,GAAQ,UAAU,GAClB,EAAY;KACd,EAoDuB,CAAmB,CAAM;IACnC,CAAA,CAEA;KAEM;;CACT,CAAA;AAEZ"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
interface Props extends Omit<ComponentPropsWithoutRef<"input">, "type" | "checked" | "onChange"> {
|
|
2
3
|
className?: string;
|
|
3
4
|
id?: string;
|
|
4
5
|
onChange?: (newValue: boolean) => void;
|
|
5
6
|
disabled?: boolean;
|
|
6
7
|
isChecked?: boolean;
|
|
7
8
|
}
|
|
8
|
-
declare const Checkbox: ({ className, id, onChange, disabled, isChecked }: Props) => import("react").JSX.Element;
|
|
9
|
+
declare const Checkbox: ({ className, id, onChange, disabled, isChecked, ...inputProps }: Props) => import("react").JSX.Element;
|
|
9
10
|
export default Checkbox;
|
package/dist/v0/checkbox.js
CHANGED
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
import { t as e } from "../TailwindUtil-DiNvXuNl.js";
|
|
3
3
|
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/v0/checkbox/Checkbox.tsx
|
|
5
|
-
var r = ({ className: r, id: i, onChange: a, disabled: o, isChecked: s }) => /* @__PURE__ */ n("label", {
|
|
5
|
+
var r = ({ className: r, id: i, onChange: a, disabled: o, isChecked: s, ...c }) => /* @__PURE__ */ n("label", {
|
|
6
6
|
className: "relative flex h-min w-min cursor-pointer items-center rounded-full",
|
|
7
7
|
htmlFor: i,
|
|
8
8
|
children: [/* @__PURE__ */ t("input", {
|
|
9
|
+
...c,
|
|
9
10
|
type: "checkbox",
|
|
10
11
|
disabled: o,
|
|
11
|
-
className: e(
|
|
12
|
+
className: e("peer bg-petnow-grey-primary checked:bg-surface-primary-accent focus-visible:outline-border-prominent-accent relative size-6 cursor-pointer appearance-none rounded-xl border border-transparent transition-all focus-visible:outline-2 focus-visible:outline-offset-2", r),
|
|
12
13
|
id: i,
|
|
13
14
|
checked: s,
|
|
14
15
|
onChange: (e) => {
|
|
15
16
|
a?.(e.target.checked);
|
|
16
17
|
}
|
|
17
18
|
}), /* @__PURE__ */ t("span", {
|
|
18
|
-
className: "text-petnow-grey-secondary pointer-events-none absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 transition
|
|
19
|
+
className: "text-petnow-grey-secondary peer-checked:text-icon-prominent-neutral pointer-events-none absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 transition",
|
|
19
20
|
children: /* @__PURE__ */ t("svg", {
|
|
20
21
|
xmlns: "http://www.w3.org/2000/svg",
|
|
21
22
|
className: "h-4 w-4",
|
package/dist/v0/checkbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.js","names":[],"sources":["../../src/components/v0/checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../../../utils/TailwindUtil\";\n\ninterface Props {\n className?: string;\n id?: string;\n onChange?: (newValue: boolean) => void;\n disabled?: boolean;\n isChecked?: boolean;\n}\n\nconst Checkbox = ({ className, id, onChange, disabled, isChecked }: Props) => {\n return (\n <label className=\"relative flex h-min w-min cursor-pointer items-center rounded-full\" htmlFor={id}>\n <input\n type=\"checkbox\"\n disabled={disabled}\n className={cn(\n
|
|
1
|
+
{"version":3,"file":"checkbox.js","names":[],"sources":["../../src/components/v0/checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../../../utils/TailwindUtil\";\n\nimport type { ComponentPropsWithoutRef } from \"react\";\n\ninterface Props extends Omit<ComponentPropsWithoutRef<\"input\">, \"type\" | \"checked\" | \"onChange\"> {\n className?: string;\n id?: string;\n onChange?: (newValue: boolean) => void;\n disabled?: boolean;\n isChecked?: boolean;\n}\n\nconst Checkbox = ({ className, id, onChange, disabled, isChecked, ...inputProps }: Props) => {\n return (\n <label className=\"relative flex h-min w-min cursor-pointer items-center rounded-full\" htmlFor={id}>\n <input\n {...inputProps}\n type=\"checkbox\"\n disabled={disabled}\n className={cn(\n \"peer bg-petnow-grey-primary checked:bg-surface-primary-accent focus-visible:outline-border-prominent-accent relative size-6 cursor-pointer appearance-none rounded-xl border border-transparent transition-all focus-visible:outline-2 focus-visible:outline-offset-2\",\n className,\n )}\n id={id}\n checked={isChecked}\n onChange={(event) => {\n onChange?.(event.target.checked);\n }}\n />\n <span className=\"text-petnow-grey-secondary peer-checked:text-icon-prominent-neutral pointer-events-none absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 transition\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n stroke=\"currentColor\"\n strokeWidth=\"1\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n clipRule=\"evenodd\"\n ></path>\n </svg>\n </span>\n </label>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;AAcA,IAAM,KAAY,EAAE,cAAW,OAAI,aAAU,aAAU,cAAW,GAAG,QAEjE,kBAAC,SAAD;CAAO,WAAU;CAAqE,SAAS;WAA/F,CACE,kBAAC,SAAD;EACE,GAAI;EACJ,MAAK;EACK;EACV,WAAW,EACT,yQACA,CACF;EACI;EACJ,SAAS;EACT,WAAW,MAAU;GACnB,IAAW,EAAM,OAAO,OAAO;EACjC;CACD,CAAA,GACD,kBAAC,QAAD;EAAM,WAAU;YACd,kBAAC,OAAD;GACE,OAAM;GACN,WAAU;GACV,SAAQ;GACR,MAAK;GACL,QAAO;GACP,aAAY;aAEZ,kBAAC,QAAD;IACE,UAAS;IACT,GAAE;IACF,UAAS;GACJ,CAAA;EACJ,CAAA;CACD,CAAA,CACD"}
|
package/dist/v0/tabs.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as e } from "../TailwindUtil-DiNvXuNl.js";
|
|
3
3
|
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import "keen-slider/keen-slider.min.css";
|
|
4
|
+
import { useKeenSlider as r } from "keen-slider/react.js";
|
|
5
|
+
import { useEffect as i, useRef as a, useState as o } from "react";
|
|
7
6
|
//#region src/components/v0/tabs/Tabs.tsx
|
|
8
7
|
var s = ({ className: s, tabList: c, isCuratedcontent: l, unswipeableContent: u, defaultIndex: d = 0, onTabChange: f, disabled: p, allowScrollToSection: m = !0 }) => {
|
|
9
|
-
let [h, g] =
|
|
10
|
-
|
|
8
|
+
let [h, g] = o(d), _ = a(null), v = a(h), y = a(f);
|
|
9
|
+
i(() => {
|
|
11
10
|
v.current = h, y.current = f;
|
|
12
11
|
});
|
|
13
|
-
let [b, x] =
|
|
12
|
+
let [b, x] = r({
|
|
14
13
|
initial: d,
|
|
15
14
|
drag: !p,
|
|
16
15
|
dragEnded: (e) => {
|
|
@@ -59,9 +58,9 @@ var s = ({ className: s, tabList: c, isCuratedcontent: l, unswipeableContent: u,
|
|
|
59
58
|
u,
|
|
60
59
|
/* @__PURE__ */ t("div", {
|
|
61
60
|
ref: b,
|
|
62
|
-
className: "keen-slider",
|
|
61
|
+
className: "keen-slider relative flex w-full touch-pan-y content-start overflow-hidden select-none [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none]",
|
|
63
62
|
children: c.map((e) => /* @__PURE__ */ t("div", {
|
|
64
|
-
className: "keen-slider__slide",
|
|
63
|
+
className: "keen-slider__slide relative min-h-full w-full overflow-hidden",
|
|
65
64
|
children: e.content
|
|
66
65
|
}, e.key))
|
|
67
66
|
})
|
package/dist/v0/tabs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","names":[],"sources":["../../src/components/v0/tabs/Tabs.tsx"],"sourcesContent":["\"use client\";\n\
|
|
1
|
+
{"version":3,"file":"tabs.js","names":[],"sources":["../../src/components/v0/tabs/Tabs.tsx"],"sourcesContent":["\"use client\";\n\n// keen-slider has no `exports` map, so Node ESM needs the full file name. The CommonJS build loads\n// in Node ESM, Jest and bundlers alike; `react.es.js` breaks CommonJS test runners.\nimport { useKeenSlider } from \"keen-slider/react.js\";\nimport { ReactNode, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"../../../utils/TailwindUtil\";\n\ninterface TabItem {\n readonly displayName: string;\n readonly key: string;\n readonly content: ReactNode;\n}\n\ninterface Props<T extends TabItem> {\n tabList: Readonly<T[]>;\n isCuratedcontent?: true;\n unswipeableContent?: ReactNode;\n defaultIndex?: number;\n onTabChange?: (index: number) => void;\n disabled?: boolean;\n className?: {\n tab?: string;\n tabTitle?: string;\n selectedUnderline?: string;\n underline?: string;\n };\n allowScrollToSection?: boolean;\n}\n\nconst Tabs = <T extends TabItem>({\n className,\n tabList,\n isCuratedcontent,\n unswipeableContent,\n defaultIndex = 0,\n onTabChange,\n disabled,\n allowScrollToSection = true,\n}: Props<T>) => {\n const [currentTabIndex, setCurrentTabIndex] = useState<number>(defaultIndex);\n const TabRef = useRef<HTMLDivElement>(null);\n // keen-slider keeps the callbacks it was created with, so they read the latest values from refs.\n const currentTabIndexRef = useRef(currentTabIndex);\n const onTabChangeRef = useRef(onTabChange);\n\n useEffect(() => {\n currentTabIndexRef.current = currentTabIndex;\n onTabChangeRef.current = onTabChange;\n });\n\n // When a swipe is released, keen-slider has already started snapping and `animator.targetIdx`\n // holds the tab it lands on, so the tab changes once per swipe, as with react-swipeable-views.\n const [sliderRef, slider] = useKeenSlider<HTMLDivElement>({\n initial: defaultIndex,\n drag: !disabled,\n dragEnded: (instance) => {\n const index = instance.track.absToRel(instance.animator.targetIdx ?? instance.track.details.abs);\n if (index === currentTabIndexRef.current) return;\n setCurrentTabIndex(index);\n onTabChangeRef.current?.(index);\n },\n });\n\n const scrollToSection = (elementRef: React.RefObject<HTMLDivElement | null>) => {\n if (elementRef.current) {\n window.scrollTo({\n top: elementRef.current.offsetTop - 50,\n behavior: \"smooth\",\n });\n }\n };\n\n const handleTabClick = (index: number) => {\n setCurrentTabIndex(index);\n currentTabIndexRef.current = index;\n if (allowScrollToSection) scrollToSection(TabRef);\n slider.current?.moveToIdx(index);\n onTabChange?.(index);\n };\n\n const underlineStyle = () => {\n const listLength = tabList.length;\n const widthPercent = 100 / listLength;\n return {\n width: `${widthPercent}%`,\n left: `${currentTabIndex * widthPercent}%`,\n };\n };\n\n return (\n <div ref={TabRef} className=\"w-full\">\n <div\n className={cn(\n className?.tab,\n `z-50 mb-[20px] flex w-full flex-col bg-white ${isCuratedcontent && \"sticky top-[50px]\"}`,\n )}\n >\n <div className=\"flex\">\n {tabList.map((tab, index) => (\n <div key={tab.key} className=\"flex flex-1 flex-col\">\n <button\n className={cn(\n className?.tabTitle,\n `cursor-pointer ${\n currentTabIndex === index\n ? \"text-petnow-grey-30 text-label-large\"\n : \"text-petnow-grey-70 text-body-large disabled:opacity-40\"\n }`,\n )}\n onClick={() => handleTabClick(index)}\n disabled={disabled}\n >\n {tab.displayName}\n </button>\n </div>\n ))}\n </div>\n <div\n className={cn(\n className?.underline,\n `relative h-[2px] w-full ${disabled ? \"bg-petnow-grey-70/40\" : \"bg-petnow-grey-70\"}`,\n )}\n >\n <div\n className={cn(\n className?.selectedUnderline,\n \"bg-petnow-grey-30 absolute h-[2px] transition-all duration-200\",\n )}\n style={underlineStyle()}\n />\n </div>\n </div>\n\n {unswipeableContent}\n\n {/*\n keen-slider.min.css as utilities, so the consumer's Tailwind build emits them and Node never\n imports CSS. Tabs never sets the reverse or vertical options, so their rules are left out.\n */}\n <div\n ref={sliderRef}\n className=\"keen-slider relative flex w-full touch-pan-y content-start overflow-hidden select-none [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none]\"\n >\n {tabList.map((tab) => (\n <div key={tab.key} className=\"keen-slider__slide relative min-h-full w-full overflow-hidden\">\n {tab.content}\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default Tabs;\n"],"mappings":";;;;;;AA+BA,IAAM,KAA2B,EAC/B,cACA,YACA,qBACA,uBACA,kBAAe,GACf,gBACA,aACA,0BAAuB,SACT;CACd,IAAM,CAAC,GAAiB,KAAsB,EAAiB,CAAY,GACrE,IAAS,EAAuB,IAAI,GAEpC,IAAqB,EAAO,CAAe,GAC3C,IAAiB,EAAO,CAAW;CAEzC,QAAgB;EAEd,AADA,EAAmB,UAAU,GAC7B,EAAe,UAAU;CAC3B,CAAC;CAID,IAAM,CAAC,GAAW,KAAU,EAA8B;EACxD,SAAS;EACT,MAAM,CAAC;EACP,YAAY,MAAa;GACvB,IAAM,IAAQ,EAAS,MAAM,SAAS,EAAS,SAAS,aAAa,EAAS,MAAM,QAAQ,GAAG;GAC3F,MAAU,EAAmB,YACjC,EAAmB,CAAK,GACxB,EAAe,UAAU,CAAK;EAChC;CACF,CAAC,GAEK,KAAmB,MAAuD;EAC9E,AAAI,EAAW,WACb,OAAO,SAAS;GACd,KAAK,EAAW,QAAQ,YAAY;GACpC,UAAU;EACZ,CAAC;CAEL,GAEM,KAAkB,MAAkB;EAKxC,AAJA,EAAmB,CAAK,GACxB,EAAmB,UAAU,GACzB,KAAsB,EAAgB,CAAM,GAChD,EAAO,SAAS,UAAU,CAAK,GAC/B,IAAc,CAAK;CACrB;CAWA,OACE,kBAAC,OAAD;EAAK,KAAK;EAAQ,WAAU;YAA5B;GACE,kBAAC,OAAD;IACE,WAAW,EACT,GAAW,KACX,gDAAgD,KAAoB,qBACtE;cAJF,CAME,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAQ,KAAK,GAAK,MACjB,kBAAC,OAAD;MAAmB,WAAU;gBAC3B,kBAAC,UAAD;OACE,WAAW,EACT,GAAW,UACX,kBACE,MAAoB,IAChB,yCACA,2DAER;OACA,eAAe,EAAe,CAAK;OACzB;iBAET,EAAI;MACC,CAAA;KACL,GAfK,EAAI,GAeT,CACN;IACE,CAAA,GACL,kBAAC,OAAD;KACE,WAAW,EACT,GAAW,WACX,2BAA2B,IAAW,yBAAyB,qBACjE;eAEA,kBAAC,OAAD;MACE,WAAW,EACT,GAAW,mBACX,gEACF;MACA,cAhDmB;OAE3B,IAAM,IAAe,MADF,EAAQ;OAE3B,OAAO;QACL,OAAO,GAAG,EAAa;QACvB,MAAM,GAAG,IAAkB,EAAa;OAC1C;MACF,EAyCiB,CAAe;KACvB,CAAA;IACE,CAAA,CACF;;GAEJ;GAMD,kBAAC,OAAD;IACE,KAAK;IACL,WAAU;cAET,EAAQ,KAAK,MACZ,kBAAC,OAAD;KAAmB,WAAU;eAC1B,EAAI;IACF,GAFK,EAAI,GAET,CACN;GACE,CAAA;EACF;;AAET"}
|
package/dist/v0/toggle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle.js","names":[],"sources":["../../src/components/v0/toggle/Toggle.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../../../utils/TailwindUtil\";\n\ninterface Props {\n className?: string;\n id?: string;\n name?: string;\n onChange: () => void;\n disabled?: boolean;\n isChecked?: boolean;\n}\n\nconst Toggle = ({ className, id, name, onChange, disabled, isChecked }: Props) => {\n return (\n <label htmlFor={id} className=\"relative inline-flex cursor-pointer items-center\">\n <input\n type=\"checkbox\"\n disabled={disabled}\n checked={isChecked}\n id={id}\n name={name}\n className=\"peer sr-only\"\n onChange={onChange}\n />\n <div\n className={cn(\n className,\n \"bg-surface-base-neutral-4 peer-checked:bg-surface-primary-accent h-[32px] w-[52px] rounded-full duration-[250ms] peer-focus:outline-none after:absolute after:start-[2px] after:top-[3px] after:size-[26px] after:rounded-full after:bg-white after:shadow-[0_3px_8px_0_rgba(0,0,0,0.15)] after:transition-all after:duration-[250ms] after:content-[''] peer-checked:after:translate-x-[calc(100%-4px)] peer-checked:after:border-white\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n />\n </label>\n );\n};\n\nexport default Toggle;\n"],"mappings":";;;;AAaA,IAAM,KAAU,EAAE,cAAW,OAAI,SAAM,aAAU,aAAU,mBAEvD,kBAAC,SAAD;CAAO,SAAS;CAAI,WAAU;WAA9B,CACE,kBAAC,SAAD;EACE,MAAK;EACK;EACV,SAAS;EACL;EACE;EACN,WAAU;EACA;CACX,CAAA,GACD,kBAAC,OAAD,EACE,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"toggle.js","names":[],"sources":["../../src/components/v0/toggle/Toggle.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../../../utils/TailwindUtil\";\n\ninterface Props {\n className?: string;\n id?: string;\n name?: string;\n onChange: () => void;\n disabled?: boolean;\n isChecked?: boolean;\n}\n\nconst Toggle = ({ className, id, name, onChange, disabled, isChecked }: Props) => {\n return (\n <label htmlFor={id} className=\"relative inline-flex cursor-pointer items-center\">\n <input\n type=\"checkbox\"\n disabled={disabled}\n checked={isChecked}\n id={id}\n name={name}\n className=\"peer sr-only\"\n onChange={onChange}\n />\n <div\n className={cn(\n className,\n // TODO(PROD-662): 그림자(shadow) 토큰이 없어 기존 값을 유지한다. 토큰 추가 후 교체.\n // eslint-disable-next-line design-tokens/no-hardcoded-color\n \"bg-surface-base-neutral-4 peer-checked:bg-surface-primary-accent h-[32px] w-[52px] rounded-full duration-[250ms] peer-focus:outline-none after:absolute after:start-[2px] after:top-[3px] after:size-[26px] after:rounded-full after:bg-white after:shadow-[0_3px_8px_0_rgba(0,0,0,0.15)] after:transition-all after:duration-[250ms] after:content-[''] peer-checked:after:translate-x-[calc(100%-4px)] peer-checked:after:border-white\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n />\n </label>\n );\n};\n\nexport default Toggle;\n"],"mappings":";;;;AAaA,IAAM,KAAU,EAAE,cAAW,OAAI,SAAM,aAAU,aAAU,mBAEvD,kBAAC,SAAD;CAAO,SAAS;CAAI,WAAU;WAA9B,CACE,kBAAC,SAAD;EACE,MAAK;EACK;EACV,SAAS;EACL;EACE;EACN,WAAU;EACA;CACX,CAAA,GACD,kBAAC,OAAD,EACE,WAAW,EACT,GAGA,4aACA,KAAY,+BACd,EACD,CAAA,CACI"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@petnow/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@11.1.3",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "tsc && vite build && pnpm run build:css",
|
|
8
8
|
"build:css": "node -e \"require('fs').copyFileSync('src/styles/components.css', 'dist/index.css')\"",
|
|
9
|
-
"
|
|
10
|
-
"lint
|
|
9
|
+
"check:dist": "node scripts/check-dist-node.mjs",
|
|
10
|
+
"lint": "eslint . --report-unused-disable-directives",
|
|
11
|
+
"lint:fix": "eslint . --fix",
|
|
11
12
|
"storybook": "storybook dev -p 6006",
|
|
12
13
|
"build-storybook": "storybook build",
|
|
13
14
|
"format": "prettier . --check",
|
|
@@ -23,8 +24,10 @@
|
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@chromatic-com/storybook": "^5.0.2",
|
|
27
|
+
"@eslint/js": "10.0.1",
|
|
26
28
|
"@storybook/addon-docs": "10.3.1",
|
|
27
29
|
"@storybook/addon-links": "10.3.1",
|
|
30
|
+
"@storybook/addon-mcp": "10.6.2",
|
|
28
31
|
"@storybook/addon-onboarding": "10.3.1",
|
|
29
32
|
"@storybook/react": "10.3.1",
|
|
30
33
|
"@storybook/react-vite": "10.4.1",
|
|
@@ -40,16 +43,17 @@
|
|
|
40
43
|
"@typescript-eslint/parser": "^8.59.4",
|
|
41
44
|
"@vitejs/plugin-react": "^6.0.1",
|
|
42
45
|
"eslint": "^10.5.0",
|
|
43
|
-
"eslint-plugin-import": "
|
|
46
|
+
"eslint-plugin-import-x": "4.17.1",
|
|
44
47
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
45
48
|
"eslint-plugin-react-refresh": "^0.5.2",
|
|
46
49
|
"eslint-plugin-storybook": "10.4.1",
|
|
50
|
+
"globals": "^17.13.0",
|
|
47
51
|
"identity-obj-proxy": "^3.0.0",
|
|
48
52
|
"jest": "^30.3.0",
|
|
49
53
|
"jest-environment-jsdom": "^30.4.1",
|
|
50
54
|
"jest-transformer-svg": "^2.1.0",
|
|
51
55
|
"magic-string": "^0.30.21",
|
|
52
|
-
"postcss": "^8.5.
|
|
56
|
+
"postcss": "^8.5.32",
|
|
53
57
|
"prettier": "^3.6.2",
|
|
54
58
|
"prettier-plugin-tailwindcss": "^0.6.14",
|
|
55
59
|
"react": "^19.2.7",
|