@jbpark/ui-kit 2.12.0 → 3.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.
Files changed (47) hide show
  1. package/dist/Button.mjs +0 -1
  2. package/dist/Button.mjs.map +1 -1
  3. package/dist/components/atoms/date-picker.d.mts +20 -0
  4. package/dist/components/atoms/date-picker.d.mts.map +1 -0
  5. package/dist/components/atoms/date-picker.mjs +41 -0
  6. package/dist/components/atoms/date-picker.mjs.map +1 -0
  7. package/dist/components/atoms/float-button/back-top.mjs +3 -3
  8. package/dist/components/atoms/float-button/back-top.mjs.map +1 -1
  9. package/dist/components/atoms/index.d.mts +1 -0
  10. package/dist/components/atoms/radio/context.mjs +21 -0
  11. package/dist/components/atoms/radio/context.mjs.map +1 -0
  12. package/dist/components/atoms/radio/group.d.mts.map +1 -1
  13. package/dist/components/atoms/radio/group.mjs +25 -2
  14. package/dist/components/atoms/radio/group.mjs.map +1 -1
  15. package/dist/components/atoms/radio/radio.d.mts +7 -0
  16. package/dist/components/atoms/radio/radio.d.mts.map +1 -1
  17. package/dist/components/atoms/radio/radio.mjs +23 -19
  18. package/dist/components/atoms/radio/radio.mjs.map +1 -1
  19. package/dist/components/molecules/index.d.mts +2 -1
  20. package/dist/components/molecules/upload.d.mts +37 -0
  21. package/dist/components/molecules/upload.d.mts.map +1 -0
  22. package/dist/components/molecules/upload.mjs +101 -0
  23. package/dist/components/molecules/upload.mjs.map +1 -0
  24. package/dist/components/organisms/drawer.d.mts.map +1 -1
  25. package/dist/components/organisms/drawer.mjs +9 -2
  26. package/dist/components/organisms/drawer.mjs.map +1 -1
  27. package/dist/components/organisms/list/list.d.mts +7 -0
  28. package/dist/components/organisms/list/list.d.mts.map +1 -1
  29. package/dist/components/organisms/list/list.mjs +1 -1
  30. package/dist/components/organisms/list/list.mjs.map +1 -1
  31. package/dist/components/organisms/swiper/swiper.d.mts +17 -5
  32. package/dist/components/organisms/swiper/swiper.d.mts.map +1 -1
  33. package/dist/components/organisms/swiper/swiper.mjs +7 -12
  34. package/dist/components/organisms/swiper/swiper.mjs.map +1 -1
  35. package/dist/core/badge.d.mts +1 -1
  36. package/dist/core/button.d.mts +3 -3
  37. package/dist/core/button.mjs +1 -1
  38. package/dist/core/calendar.d.mts +30 -0
  39. package/dist/core/calendar.d.mts.map +1 -0
  40. package/dist/core/calendar.mjs +136 -0
  41. package/dist/core/calendar.mjs.map +1 -0
  42. package/dist/core.d.mts +2 -1
  43. package/dist/core.mjs +2 -1
  44. package/dist/index.d.mts +3 -1
  45. package/dist/index.mjs +3 -1
  46. package/dist/style.css +262 -0
  47. package/package.json +4 -3
package/dist/Button.mjs CHANGED
@@ -55,7 +55,6 @@ const Button = ({ icon, className, type = "default", variant, size = "middle", c
55
55
  "border-(--btn-border)"
56
56
  ] : ["text-(--btn-bg)", "border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]"]), className),
57
57
  onMouseDown: (e) => {
58
- e.preventDefault();
59
58
  onMouseDown?.(e);
60
59
  },
61
60
  ...props,
@@ -1 +1 @@
1
- {"version":3,"file":"Button.mjs","names":["button.Button"],"sources":["../src/components/atoms/button.tsx"],"sourcesContent":["'use client';\n\nimport { LoaderCircle } from 'lucide-react';\n\nimport { button } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nconst Core = button.Button;\ntype ButtonProps = button.Props;\n\ntype PresetColors =\n | 'blue'\n | 'purple'\n | 'cyan'\n | 'green'\n | 'magenta'\n | 'pink'\n | 'red'\n | 'orange'\n | 'yellow'\n | 'volcano'\n | 'geekblue'\n | 'lime'\n | 'gold';\n\nexport interface Props extends Omit<ButtonProps, 'size' | 'variant' | 'type'> {\n icon?: React.ReactNode;\n block?: boolean;\n danger?: boolean;\n disabled?: boolean;\n size?: 'small' | 'middle' | 'large';\n type?: 'primary' | 'default' | 'dashed' | 'text' | 'link';\n variant?: 'solid' | 'outlined' | 'dashed' | 'filled' | 'text' | 'link';\n shape?: 'default' | 'circle' | 'round';\n color?: PresetColors | 'default' | 'primary' | 'danger';\n loading?: boolean | { icon: React.ReactNode };\n}\n\nconst variantClasses: Record<string, string> = {\n solid: '',\n outlined: cn(\n 'border border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n dashed: cn(\n 'border border-dashed border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n filled: cn('bg-muted text-foreground', 'hover:bg-muted/80'),\n text: cn('bg-transparent text-foreground', 'hover:bg-accent'),\n link: cn(\n 'bg-transparent text-primary',\n 'underline-offset-4 hover:underline',\n 'hover:bg-primary/10',\n ),\n};\n\nconst typeToVariant: Record<string, string> = {\n primary: 'solid',\n default: 'outlined',\n dashed: 'dashed',\n text: 'text',\n link: 'link',\n};\n\nconst sizesClasses: Record<string, string> = {\n small: 'h-6 px-3 text-sm',\n middle: 'h-8 px-4 text-base',\n large: 'h-10 px-5 text-lg',\n};\n\nconst iconClasses: Record<string, string> = {\n small: `size-6 [&_svg:not([class*='size-'])]:size-3`,\n middle: `size-8 [&_svg:not([class*='size-'])]:size-4`,\n large: `size-10 [&_svg:not([class*='size-'])]:size-5`,\n};\n\nconst shapesClasses = {\n default: 'rounded-sm',\n circle: 'rounded-full',\n round: 'rounded-2xl',\n};\n\nconst Button = ({\n icon,\n className,\n type = 'default',\n variant,\n size = 'middle',\n color = 'default',\n shape = 'default',\n block = false,\n disabled,\n loading,\n danger,\n children,\n onMouseDown,\n ...props\n}: Props) => {\n const iconOnly = icon && !children;\n const computedColor = danger ? 'danger' : color;\n const colored = computedColor && computedColor !== 'default';\n const resolvedVariant = variant ?? typeToVariant[type] ?? 'solid';\n\n const displayIcon = loading ? (\n typeof loading === 'object' ? (\n loading.icon\n ) : (\n <LoaderCircle className=\"animate-spin\" />\n )\n ) : (\n icon\n );\n\n return (\n <Core\n disabled={disabled}\n variant=\"default\"\n data-color={computedColor}\n className={cn(\n 'inline-flex items-center justify-center gap-x-2',\n 'rounded-lg',\n 'cursor-pointer',\n 'h-auto py-0',\n 'transition-all',\n variantClasses[resolvedVariant],\n sizesClasses[size],\n iconOnly && ['p-0', iconClasses[size]],\n shapesClasses[shape || 'default'],\n block && 'w-full',\n colored &&\n (resolvedVariant === 'solid'\n ? [\n 'bg-(--btn-bg)',\n 'hover:bg-(--btn-bg-hover)',\n 'active:bg-(--btn-bg-active)',\n 'text-(--btn-fg)',\n 'border-(--btn-border)',\n ]\n : [\n 'text-(--btn-bg)',\n 'border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n //\n ]),\n className,\n //\n )}\n onMouseDown={e => {\n e.preventDefault();\n onMouseDown?.(e);\n }}\n {...props}\n >\n {displayIcon}\n {children}\n </Core>\n );\n};\n\nexport default Button;\n"],"mappings":";;;;;;;;AAOA,MAAM,OAAOA;AA+Bb,MAAM,iBAAyC;CAC7C,OAAO;CACP,UAAU,GACR,yEACA,iCACA,kBACD;CACD,QAAQ,GACN,uFACA,iCACA,kBACD;CACD,QAAQ,GAAG,4BAA4B,oBAAoB;CAC3D,MAAM,GAAG,kCAAkC,kBAAkB;CAC7D,MAAM,GACJ,+BACA,sCACA,sBACD;CACF;AAED,MAAM,gBAAwC;CAC5C,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM;CACP;AAED,MAAM,eAAuC;CAC3C,OAAO;CACP,QAAQ;CACR,OAAO;CACR;AAED,MAAM,cAAsC;CAC1C,OAAO;CACP,QAAQ;CACR,OAAO;CACR;AAED,MAAM,gBAAgB;CACpB,SAAS;CACT,QAAQ;CACR,OAAO;CACR;AAED,MAAM,UAAU,EACd,MACA,WACA,OAAO,WACP,SACA,OAAO,UACP,QAAQ,WACR,QAAQ,WACR,QAAQ,OACR,UACA,SACA,QACA,UACA,aACA,GAAG,YACQ;CACX,MAAM,WAAW,QAAQ,CAAC;CAC1B,MAAM,gBAAgB,SAAS,WAAW;CAC1C,MAAM,UAAU,iBAAiB,kBAAkB;CACnD,MAAM,kBAAkB,WAAW,cAAc,SAAS;CAE1D,MAAM,cAAc,UAClB,OAAO,YAAY,WACjB,QAAQ,OAER,oBAAC,gBAAa,WAAU,iBAAiB,GAG3C;AAGF,QACE,qBAAC;EACW;EACV,SAAQ;EACR,cAAY;EACZ,WAAW,GACT,mDACA,cACA,kBACA,eACA,kBACA,eAAe,kBACf,aAAa,OACb,YAAY,CAAC,OAAO,YAAY,MAAM,EACtC,cAAc,SAAS,YACvB,SAAS,UACT,YACG,oBAAoB,UACjB;GACE;GACA;GACA;GACA;GACA;GACD,GACD,CACE,mBACA,iEAED,GACP,UAED;EACD,cAAa,MAAK;AAChB,KAAE,gBAAgB;AAClB,iBAAc,EAAE;;EAElB,GAAI;aAEH,aACA;GACI"}
1
+ {"version":3,"file":"Button.mjs","names":["button.Button"],"sources":["../src/components/atoms/button.tsx"],"sourcesContent":["'use client';\n\nimport { LoaderCircle } from 'lucide-react';\n\nimport { button } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nconst Core = button.Button;\ntype ButtonProps = button.Props;\n\ntype PresetColors =\n | 'blue'\n | 'purple'\n | 'cyan'\n | 'green'\n | 'magenta'\n | 'pink'\n | 'red'\n | 'orange'\n | 'yellow'\n | 'volcano'\n | 'geekblue'\n | 'lime'\n | 'gold';\n\nexport interface Props extends Omit<ButtonProps, 'size' | 'variant' | 'type'> {\n icon?: React.ReactNode;\n block?: boolean;\n danger?: boolean;\n disabled?: boolean;\n size?: 'small' | 'middle' | 'large';\n type?: 'primary' | 'default' | 'dashed' | 'text' | 'link';\n variant?: 'solid' | 'outlined' | 'dashed' | 'filled' | 'text' | 'link';\n shape?: 'default' | 'circle' | 'round';\n color?: PresetColors | 'default' | 'primary' | 'danger';\n loading?: boolean | { icon: React.ReactNode };\n}\n\nconst variantClasses: Record<string, string> = {\n solid: '',\n outlined: cn(\n 'border border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n dashed: cn(\n 'border border-dashed border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n filled: cn('bg-muted text-foreground', 'hover:bg-muted/80'),\n text: cn('bg-transparent text-foreground', 'hover:bg-accent'),\n link: cn(\n 'bg-transparent text-primary',\n 'underline-offset-4 hover:underline',\n 'hover:bg-primary/10',\n ),\n};\n\nconst typeToVariant: Record<string, string> = {\n primary: 'solid',\n default: 'outlined',\n dashed: 'dashed',\n text: 'text',\n link: 'link',\n};\n\nconst sizesClasses: Record<string, string> = {\n small: 'h-6 px-3 text-sm',\n middle: 'h-8 px-4 text-base',\n large: 'h-10 px-5 text-lg',\n};\n\nconst iconClasses: Record<string, string> = {\n small: `size-6 [&_svg:not([class*='size-'])]:size-3`,\n middle: `size-8 [&_svg:not([class*='size-'])]:size-4`,\n large: `size-10 [&_svg:not([class*='size-'])]:size-5`,\n};\n\nconst shapesClasses = {\n default: 'rounded-sm',\n circle: 'rounded-full',\n round: 'rounded-2xl',\n};\n\nconst Button = ({\n icon,\n className,\n type = 'default',\n variant,\n size = 'middle',\n color = 'default',\n shape = 'default',\n block = false,\n disabled,\n loading,\n danger,\n children,\n onMouseDown,\n ...props\n}: Props) => {\n const iconOnly = icon && !children;\n const computedColor = danger ? 'danger' : color;\n const colored = computedColor && computedColor !== 'default';\n const resolvedVariant = variant ?? typeToVariant[type] ?? 'solid';\n\n const displayIcon = loading ? (\n typeof loading === 'object' ? (\n loading.icon\n ) : (\n <LoaderCircle className=\"animate-spin\" />\n )\n ) : (\n icon\n );\n\n return (\n <Core\n disabled={disabled}\n variant=\"default\"\n data-color={computedColor}\n className={cn(\n 'inline-flex items-center justify-center gap-x-2',\n 'rounded-lg',\n 'cursor-pointer',\n 'h-auto py-0',\n 'transition-all',\n variantClasses[resolvedVariant],\n sizesClasses[size],\n iconOnly && ['p-0', iconClasses[size]],\n shapesClasses[shape || 'default'],\n block && 'w-full',\n colored &&\n (resolvedVariant === 'solid'\n ? [\n 'bg-(--btn-bg)',\n 'hover:bg-(--btn-bg-hover)',\n 'active:bg-(--btn-bg-active)',\n 'text-(--btn-fg)',\n 'border-(--btn-border)',\n ]\n : [\n 'text-(--btn-bg)',\n 'border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n //\n ]),\n className,\n //\n )}\n onMouseDown={e => {\n onMouseDown?.(e);\n }}\n {...props}\n >\n {displayIcon}\n {children}\n </Core>\n );\n};\n\nexport default Button;\n"],"mappings":";;;;;;;;AAOA,MAAM,OAAOA;AA+Bb,MAAM,iBAAyC;CAC7C,OAAO;CACP,UAAU,GACR,yEACA,iCACA,kBACD;CACD,QAAQ,GACN,uFACA,iCACA,kBACD;CACD,QAAQ,GAAG,4BAA4B,oBAAoB;CAC3D,MAAM,GAAG,kCAAkC,kBAAkB;CAC7D,MAAM,GACJ,+BACA,sCACA,sBACD;CACF;AAED,MAAM,gBAAwC;CAC5C,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM;CACP;AAED,MAAM,eAAuC;CAC3C,OAAO;CACP,QAAQ;CACR,OAAO;CACR;AAED,MAAM,cAAsC;CAC1C,OAAO;CACP,QAAQ;CACR,OAAO;CACR;AAED,MAAM,gBAAgB;CACpB,SAAS;CACT,QAAQ;CACR,OAAO;CACR;AAED,MAAM,UAAU,EACd,MACA,WACA,OAAO,WACP,SACA,OAAO,UACP,QAAQ,WACR,QAAQ,WACR,QAAQ,OACR,UACA,SACA,QACA,UACA,aACA,GAAG,YACQ;CACX,MAAM,WAAW,QAAQ,CAAC;CAC1B,MAAM,gBAAgB,SAAS,WAAW;CAC1C,MAAM,UAAU,iBAAiB,kBAAkB;CACnD,MAAM,kBAAkB,WAAW,cAAc,SAAS;CAE1D,MAAM,cAAc,UAClB,OAAO,YAAY,WACjB,QAAQ,OAER,oBAAC,gBAAa,WAAU,iBAAiB,GAG3C;AAGF,QACE,qBAAC;EACW;EACV,SAAQ;EACR,cAAY;EACZ,WAAW,GACT,mDACA,cACA,kBACA,eACA,kBACA,eAAe,kBACf,aAAa,OACb,YAAY,CAAC,OAAO,YAAY,MAAM,EACtC,cAAc,SAAS,YACvB,SAAS,UACT,YACG,oBAAoB,UACjB;GACE;GACA;GACA;GACA;GACA;GACD,GACD,CACE,mBACA,iEAED,GACP,UAED;EACD,cAAa,MAAK;AAChB,iBAAc,EAAE;;EAElB,GAAI;aAEH,aACA;GACI"}
@@ -0,0 +1,20 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+
3
+ //#region src/components/atoms/date-picker.d.ts
4
+ interface Props {
5
+ defaultValue?: Date;
6
+ value?: Date;
7
+ placeholder?: string;
8
+ className?: string;
9
+ onChange?: (date: Date | undefined) => void;
10
+ }
11
+ declare const DatePicker: ({
12
+ defaultValue,
13
+ value: _value,
14
+ placeholder,
15
+ className,
16
+ onChange: _onChange
17
+ }: Props) => react_jsx_runtime0.JSX.Element;
18
+ //#endregion
19
+ export { DatePicker };
20
+ //# sourceMappingURL=date-picker.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-picker.d.mts","names":[],"sources":["../../../src/components/atoms/date-picker.tsx"],"mappings":";;;UAeU,KAAA;EACR,YAAA,GAAe,IAAA;EACf,KAAA,GAAQ,IAAA;EACR,WAAA;EACA,SAAA;EACA,QAAA,IAAY,IAAA,EAAM,IAAA;AAAA;AAAA,cAGd,UAAA;EAAc,YAAA;EAAA,KAAA,EAAA,MAAA;EAAA,WAAA;EAAA,SAAA;EAAA,QAAA,EAAA;AAAA,GAMjB,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,41 @@
1
+ 'use client';
2
+
3
+ import { cn } from "../../utils.mjs";
4
+ import { button_exports } from "../../core/button.mjs";
5
+ import { calendar_exports } from "../../core/calendar.mjs";
6
+ import Popover from "./popover.mjs";
7
+ import { CalendarIcon } from "lucide-react";
8
+ import { useState } from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { format } from "date-fns";
11
+
12
+ //#region src/components/atoms/date-picker.tsx
13
+ const { Calendar } = calendar_exports;
14
+ const { buttonVariants } = button_exports;
15
+ const DatePicker = ({ defaultValue, value: _value, placeholder = "Pick a date", className, onChange: _onChange = () => {} }) => {
16
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
17
+ const controlled = _value !== void 0;
18
+ const value = controlled ? _value : uncontrolledValue;
19
+ const onChange = (date) => {
20
+ if (!controlled) setUncontrolledValue(date);
21
+ _onChange(date);
22
+ };
23
+ return /* @__PURE__ */ jsx(Popover, {
24
+ placement: "bottomLeft",
25
+ content: /* @__PURE__ */ jsx(Calendar, {
26
+ mode: "single",
27
+ selected: value,
28
+ onSelect: onChange
29
+ }),
30
+ children: /* @__PURE__ */ jsxs("button", {
31
+ type: "button",
32
+ "data-empty": !value,
33
+ className: cn(buttonVariants({ variant: "outline" }), "w-full justify-start text-left font-normal", "data-[empty=true]:text-muted-foreground", className),
34
+ children: [/* @__PURE__ */ jsx(CalendarIcon, {}), value ? format(value, "PPP") : placeholder]
35
+ })
36
+ });
37
+ };
38
+
39
+ //#endregion
40
+ export { DatePicker as default };
41
+ //# sourceMappingURL=date-picker.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-picker.mjs","names":["calendar","button"],"sources":["../../../src/components/atoms/date-picker.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\n\nimport { format } from 'date-fns';\nimport { CalendarIcon } from 'lucide-react';\n\nimport { button, calendar } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport Popover from './popover';\n\nconst { Calendar } = calendar;\nconst { buttonVariants } = button;\n\ninterface Props {\n defaultValue?: Date;\n value?: Date;\n placeholder?: string;\n className?: string;\n onChange?: (date: Date | undefined) => void;\n}\n\nconst DatePicker = ({\n defaultValue,\n value: _value,\n placeholder = 'Pick a date',\n className,\n onChange: _onChange = () => {},\n}: Props) => {\n const [uncontrolledValue, setUncontrolledValue] = useState<Date | undefined>(\n defaultValue,\n );\n\n const controlled = _value !== undefined;\n const value = controlled ? _value : uncontrolledValue;\n\n const onChange = (date: Date | undefined) => {\n if (!controlled) {\n setUncontrolledValue(date);\n }\n _onChange(date);\n };\n\n return (\n <Popover\n placement=\"bottomLeft\"\n content={<Calendar mode=\"single\" selected={value} onSelect={onChange} />}\n >\n <button\n type=\"button\"\n data-empty={!value}\n className={cn(\n buttonVariants({ variant: 'outline' }),\n 'w-full justify-start text-left font-normal',\n 'data-[empty=true]:text-muted-foreground',\n className,\n //\n )}\n >\n <CalendarIcon />\n {value ? format(value, 'PPP') : placeholder}\n </button>\n </Popover>\n );\n};\n\nexport default DatePicker;\nexport type { Props };\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,EAAE,aAAaA;AACrB,MAAM,EAAE,mBAAmBC;AAU3B,MAAM,cAAc,EAClB,cACA,OAAO,QACP,cAAc,eACd,WACA,UAAU,kBAAkB,SACjB;CACX,MAAM,CAAC,mBAAmB,wBAAwB,SAChD,aACD;CAED,MAAM,aAAa,WAAW;CAC9B,MAAM,QAAQ,aAAa,SAAS;CAEpC,MAAM,YAAY,SAA2B;AAC3C,MAAI,CAAC,WACH,sBAAqB,KAAK;AAE5B,YAAU,KAAK;;AAGjB,QACE,oBAAC;EACC,WAAU;EACV,SAAS,oBAAC;GAAS,MAAK;GAAS,UAAU;GAAO,UAAU;IAAY;YAExE,qBAAC;GACC,MAAK;GACL,cAAY,CAAC;GACb,WAAW,GACT,eAAe,EAAE,SAAS,WAAW,CAAC,EACtC,8CACA,2CACA,UAED;cAED,oBAAC,iBAAe,EACf,QAAQ,OAAO,OAAO,MAAM,GAAG;IACzB;GACD"}
@@ -4,17 +4,17 @@ import { cn } from "../../../utils.mjs";
4
4
  import FloatButton from "./float-button.mjs";
5
5
  import { ArrowUp } from "lucide-react";
6
6
  import { jsx } from "react/jsx-runtime";
7
- import { useWindowScroll } from "@uidotdev/usehooks";
7
+ import { useWindowScroll } from "@jbpark/use-hooks";
8
8
 
9
9
  //#region src/components/atoms/float-button/back-top.tsx
10
10
  const BackTop = ({ visibilityHeight = 450, className, onClick, ...props }) => {
11
- const [{ y }, scrollTo] = useWindowScroll();
11
+ const { y } = useWindowScroll();
12
12
  return /* @__PURE__ */ jsx(FloatButton, {
13
13
  "aria-label": "맨 위로",
14
14
  icon: /* @__PURE__ */ jsx(ArrowUp, {}),
15
15
  className: cn(className, (!y || visibilityHeight > y) && "hidden"),
16
16
  onClick: (e) => {
17
- scrollTo({
17
+ window.scrollTo({
18
18
  left: 0,
19
19
  top: 0,
20
20
  behavior: "smooth"
@@ -1 +1 @@
1
- {"version":3,"file":"back-top.mjs","names":[],"sources":["../../../../src/components/atoms/float-button/back-top.tsx"],"sourcesContent":["'use client';\n\nimport { MouseEvent } from 'react';\n\nimport { useWindowScroll } from '@uidotdev/usehooks';\nimport { ArrowUp } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { type Props as ButtonProps } from '../button';\nimport FloatButton from './float-button';\n\nexport interface Props extends ButtonProps {\n visibilityHeight?: number;\n onClick?: (e: MouseEvent<HTMLElement>) => void;\n}\n\nconst BackTop = ({\n visibilityHeight = 450,\n className,\n onClick,\n ...props\n}: Props) => {\n const [{ y }, scrollTo] = useWindowScroll();\n\n return (\n <FloatButton\n aria-label=\"맨 위로\"\n icon={<ArrowUp />}\n className={cn(\n className,\n (!y || visibilityHeight > y) && 'hidden',\n //\n )}\n onClick={e => {\n scrollTo({ left: 0, top: 0, behavior: 'smooth' });\n onClick?.(e);\n }}\n {...props}\n />\n );\n};\n\nexport default BackTop;\n"],"mappings":";;;;;;;;;AAiBA,MAAM,WAAW,EACf,mBAAmB,KACnB,WACA,SACA,GAAG,YACQ;CACX,MAAM,CAAC,EAAE,KAAK,YAAY,iBAAiB;AAE3C,QACE,oBAAC;EACC,cAAW;EACX,MAAM,oBAAC,YAAU;EACjB,WAAW,GACT,YACC,CAAC,KAAK,mBAAmB,MAAM,SAEjC;EACD,UAAS,MAAK;AACZ,YAAS;IAAE,MAAM;IAAG,KAAK;IAAG,UAAU;IAAU,CAAC;AACjD,aAAU,EAAE;;EAEd,GAAI;GACJ"}
1
+ {"version":3,"file":"back-top.mjs","names":[],"sources":["../../../../src/components/atoms/float-button/back-top.tsx"],"sourcesContent":["'use client';\n\nimport { MouseEvent } from 'react';\n\nimport { useWindowScroll } from '@jbpark/use-hooks';\nimport { ArrowUp } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { type Props as ButtonProps } from '../button';\nimport FloatButton from './float-button';\n\nexport interface Props extends ButtonProps {\n visibilityHeight?: number;\n onClick?: (e: MouseEvent<HTMLElement>) => void;\n}\n\nconst BackTop = ({\n visibilityHeight = 450,\n className,\n onClick,\n ...props\n}: Props) => {\n const { y } = useWindowScroll();\n\n return (\n <FloatButton\n aria-label=\"맨 위로\"\n icon={<ArrowUp />}\n className={cn(\n className,\n (!y || visibilityHeight > y) && 'hidden',\n //\n )}\n onClick={e => {\n window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });\n onClick?.(e);\n }}\n {...props}\n />\n );\n};\n\nexport default BackTop;\n"],"mappings":";;;;;;;;;AAiBA,MAAM,WAAW,EACf,mBAAmB,KACnB,WACA,SACA,GAAG,YACQ;CACX,MAAM,EAAE,MAAM,iBAAiB;AAE/B,QACE,oBAAC;EACC,cAAW;EACX,MAAM,oBAAC,YAAU;EACjB,WAAW,GACT,YACC,CAAC,KAAK,mBAAmB,MAAM,SAEjC;EACD,UAAS,MAAK;AACZ,UAAO,SAAS;IAAE,MAAM;IAAG,KAAK;IAAG,UAAU;IAAU,CAAC;AACxD,aAAU,EAAE;;EAEd,GAAI;GACJ"}
@@ -3,6 +3,7 @@ import Tag from "../../Tag.mjs";
3
3
  import Typography from "../../Typography.mjs";
4
4
  import { Checkbox } from "./checkbox/index.mjs";
5
5
  import { ColorPicker } from "./color-picker.mjs";
6
+ import { DatePicker } from "./date-picker.mjs";
6
7
  import { FloatButton } from "./float-button/index.mjs";
7
8
  import { Input } from "./input/index.mjs";
8
9
  import { Popover } from "./popover.mjs";
@@ -0,0 +1,21 @@
1
+ 'use client';
2
+
3
+ import { createContext } from "react";
4
+
5
+ //#region src/components/atoms/radio/context.tsx
6
+ /**
7
+ * Internal only — not exported from the package entry points.
8
+ *
9
+ * `true` when a `Radio` is rendered inside a `RadioGroup` that already owns a
10
+ * single shared `RadioGroupPrimitive.Root`. In that case each `Radio` renders
11
+ * only its `RadioGroupItem` so that Radix can manage roving focus (arrow-key
12
+ * navigation) across every option of the group.
13
+ *
14
+ * `false` (default) means the `Radio` is standalone and has to wrap itself in
15
+ * its own `Root` to stay functional.
16
+ */
17
+ const RadioGroupContext = createContext(false);
18
+
19
+ //#endregion
20
+ export { RadioGroupContext };
21
+ //# sourceMappingURL=context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../../../../src/components/atoms/radio/context.tsx"],"sourcesContent":["'use client';\n\nimport { createContext } from 'react';\n\n/**\n * Internal only — not exported from the package entry points.\n *\n * `true` when a `Radio` is rendered inside a `RadioGroup` that already owns a\n * single shared `RadioGroupPrimitive.Root`. In that case each `Radio` renders\n * only its `RadioGroupItem` so that Radix can manage roving focus (arrow-key\n * navigation) across every option of the group.\n *\n * `false` (default) means the `Radio` is standalone and has to wrap itself in\n * its own `Root` to stay functional.\n */\nexport const RadioGroupContext = createContext(false);\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,oBAAoB,cAAc,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"group.d.mts","names":[],"sources":["../../../../src/components/atoms/radio/group.tsx"],"mappings":";;;KASY,WAAA;AAAA,KAEP,MAAA;EACH,KAAA;EACA,KAAA,EAAO,WAAA;EACP,QAAA;AAAA;AAAA,KAGG,OAAA,qCAA4C,MAAA;AAAA,UAEhC,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA;EAGN,OAAA,GAAU,OAAA;EACV,WAAA;EACA,SAAA;EACA,UAAA,GAAa,MAAA;EACb,YAAA,GAAe,WAAA;EACf,KAAA,GAAQ,WAAA;EACR,UAAA;EACA,WAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA,IAAY,KAAA,EAAO,WAAA;AAAA;AAAA,cAGf,UAAA;EAAc,WAAA;EAAA,SAAA;EAAA,SAAA;EAAA,UAAA;EAAA,OAAA,EAAA,QAAA;EAAA,UAAA;EAAA,WAAA;EAAA,IAAA;EAAA,QAAA;EAAA,YAAA;EAAA,KAAA,EAAA,MAAA;EAAA,QAAA,EAAA,SAAA;EAAA,GAAA;AAAA,GAcjB,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"group.d.mts","names":[],"sources":["../../../../src/components/atoms/radio/group.tsx"],"mappings":";;;KAaY,WAAA;AAAA,KAEP,MAAA;EACH,KAAA;EACA,KAAA,EAAO,WAAA;EACP,QAAA;AAAA;AAAA,KAGG,OAAA,qCAA4C,MAAA;AAAA,UAEhC,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA;EAGN,OAAA,GAAU,OAAA;EACV,WAAA;EACA,SAAA;EACA,UAAA,GAAa,MAAA;EACb,YAAA,GAAe,WAAA;EACf,KAAA,GAAQ,WAAA;EACR,UAAA;EACA,WAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA,IAAY,KAAA,EAAO,WAAA;AAAA;AAAA,cAGf,UAAA;EAAc,WAAA;EAAA,SAAA;EAAA,SAAA;EAAA,UAAA;EAAA,OAAA,EAAA,QAAA;EAAA,UAAA;EAAA,WAAA;EAAA,IAAA;EAAA,QAAA;EAAA,YAAA;EAAA,KAAA,EAAA,MAAA;EAAA,QAAA,EAAA,SAAA;EAAA,GAAA;AAAA,GAcjB,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1,12 +1,15 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../../utils.mjs";
4
+ import { radio_group_exports } from "../../../core/radio-group.mjs";
4
5
  import Button from "../../../Button.mjs";
6
+ import { RadioGroupContext } from "./context.mjs";
5
7
  import Radio from "./radio.mjs";
6
- import { useState } from "react";
8
+ import { useId, useState } from "react";
7
9
  import { jsx } from "react/jsx-runtime";
8
10
 
9
11
  //#region src/components/atoms/radio/group.tsx
12
+ const { RadioGroup: Core } = radio_group_exports;
10
13
  const RadioGroup = ({ orientation = "horizontal", placement = "left", className, classNames = {}, options: _options = [], optionType = "default", buttonStyle = "solid", size, disabled, defaultValue, value: _value, onChange: _onChange = () => {}, ...props }) => {
11
14
  const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
12
15
  const controlled = _value !== void 0;
@@ -21,7 +24,16 @@ const RadioGroup = ({ orientation = "horizontal", placement = "left", className,
21
24
  if (!controlled) setUncontrolledValue(optionValue);
22
25
  _onChange(optionValue);
23
26
  };
24
- return /* @__PURE__ */ jsx("ul", {
27
+ const baseId = useId();
28
+ const getOptionId = (index) => `${baseId}-${index}`;
29
+ const checkedIndex = options.findIndex((item) => item.value === value);
30
+ const checkedId = checkedIndex === -1 ? "" : getOptionId(checkedIndex);
31
+ const onValueChange = (optionId) => {
32
+ const item = options.find((_, index) => getOptionId(index) === optionId);
33
+ if (!item) return;
34
+ onChange(true, item.value);
35
+ };
36
+ const list = /* @__PURE__ */ jsx("ul", {
25
37
  ...props,
26
38
  className: cn("flex gap-4", className, orientation === "vertical" && "flex-col", isButton && "gap-0"),
27
39
  children: options.map((item, index) => {
@@ -36,6 +48,7 @@ const RadioGroup = ({ orientation = "horizontal", placement = "left", className,
36
48
  onClick: () => onChange(true, item.value),
37
49
  children: item.label
38
50
  }) : /* @__PURE__ */ jsx(Radio, {
51
+ id: getOptionId(index),
39
52
  placement,
40
53
  className: cn(classNames?.item),
41
54
  value: item.value,
@@ -47,6 +60,16 @@ const RadioGroup = ({ orientation = "horizontal", placement = "left", className,
47
60
  }, String(item.value));
48
61
  })
49
62
  });
63
+ if (isButton) return list;
64
+ return /* @__PURE__ */ jsx(RadioGroupContext.Provider, {
65
+ value: true,
66
+ children: /* @__PURE__ */ jsx(Core, {
67
+ className: "block",
68
+ value: checkedId,
69
+ onValueChange,
70
+ children: list
71
+ })
72
+ });
50
73
  };
51
74
 
52
75
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"group.mjs","names":[],"sources":["../../../../src/components/atoms/radio/group.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../button';\nimport Radio from './radio';\n\nexport type OptionValue = string | number | boolean;\n\ntype Option = {\n label: string;\n value: OptionValue;\n disabled?: boolean;\n};\n\ntype Options = string[] | number[] | boolean[] | Option[];\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'ul'>,\n 'onChange' | 'defaultValue' | 'value'\n> {\n options?: Options;\n orientation?: 'vertical' | 'horizontal';\n placement?: 'left' | 'right';\n classNames?: Record<string, string>;\n defaultValue?: OptionValue;\n value?: OptionValue;\n optionType?: 'default' | 'button';\n buttonStyle?: 'solid' | 'outlined';\n size?: 'small' | 'middle' | 'large';\n disabled?: boolean;\n onChange?: (value: OptionValue) => void;\n}\n\nconst RadioGroup = ({\n orientation = 'horizontal',\n placement = 'left',\n className,\n classNames = {},\n options: _options = [],\n optionType = 'default',\n buttonStyle = 'solid',\n size,\n disabled,\n defaultValue,\n value: _value,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [uncontrolledValue, setUncontrolledValue] = useState<\n OptionValue | undefined\n >(defaultValue);\n\n const controlled = _value !== undefined;\n const value = controlled ? _value : uncontrolledValue;\n\n const options: Option[] = _options.map(item =>\n typeof item === 'object'\n ? item\n : {\n label: `${item}`,\n value: item,\n },\n );\n\n const isButton = optionType === 'button';\n\n const onChange = (checked: boolean, optionValue: OptionValue) => {\n if (!checked) {\n return;\n }\n if (!controlled) {\n setUncontrolledValue(optionValue);\n }\n _onChange(optionValue);\n };\n\n return (\n <ul\n {...props}\n className={cn(\n 'flex gap-4',\n className,\n orientation === 'vertical' && 'flex-col',\n isButton && 'gap-0',\n )}\n >\n {options.map((item: Option, index) => {\n const checked = value === item.value;\n\n return (\n <li\n key={String(item.value)}\n className={cn('flex', classNames?.wrapper)}\n >\n {isButton ? (\n <Button\n variant={checked ? buttonStyle : 'outlined'}\n size={size}\n className={cn(\n 'rounded-none',\n index === 0 && 'rounded-l-lg',\n index === options.length - 1 && 'rounded-r-lg',\n checked && buttonStyle === 'outlined' && 'border-primary',\n )}\n disabled={disabled || item.disabled}\n onClick={() => onChange(true, item.value)}\n >\n {item.label}\n </Button>\n ) : (\n <Radio\n placement={placement}\n className={cn(classNames?.item)}\n value={item.value}\n checked={checked}\n disabled={disabled || item.disabled}\n onChange={checked => onChange(checked, item.value)}\n >\n {item.label}\n </Radio>\n )}\n </li>\n );\n })}\n </ul>\n );\n};\n\nexport default RadioGroup;\n"],"mappings":";;;;;;;;;AAoCA,MAAM,cAAc,EAClB,cAAc,cACd,YAAY,QACZ,WACA,aAAa,EAAE,EACf,SAAS,WAAW,EAAE,EACtB,aAAa,WACb,cAAc,SACd,MACA,UACA,cACA,OAAO,QACP,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,mBAAmB,wBAAwB,SAEhD,aAAa;CAEf,MAAM,aAAa,WAAW;CAC9B,MAAM,QAAQ,aAAa,SAAS;CAEpC,MAAM,UAAoB,SAAS,KAAI,SACrC,OAAO,SAAS,WACZ,OACA;EACE,OAAO,GAAG;EACV,OAAO;EACR,CACN;CAED,MAAM,WAAW,eAAe;CAEhC,MAAM,YAAY,SAAkB,gBAA6B;AAC/D,MAAI,CAAC,QACH;AAEF,MAAI,CAAC,WACH,sBAAqB,YAAY;AAEnC,YAAU,YAAY;;AAGxB,QACE,oBAAC;EACC,GAAI;EACJ,WAAW,GACT,cACA,WACA,gBAAgB,cAAc,YAC9B,YAAY,QACb;YAEA,QAAQ,KAAK,MAAc,UAAU;GACpC,MAAM,UAAU,UAAU,KAAK;AAE/B,UACE,oBAAC;IAEC,WAAW,GAAG,QAAQ,YAAY,QAAQ;cAEzC,WACC,oBAAC;KACC,SAAS,UAAU,cAAc;KAC3B;KACN,WAAW,GACT,gBACA,UAAU,KAAK,gBACf,UAAU,QAAQ,SAAS,KAAK,gBAChC,WAAW,gBAAgB,cAAc,iBAC1C;KACD,UAAU,YAAY,KAAK;KAC3B,eAAe,SAAS,MAAM,KAAK,MAAM;eAExC,KAAK;MACC,GAET,oBAAC;KACY;KACX,WAAW,GAAG,YAAY,KAAK;KAC/B,OAAO,KAAK;KACH;KACT,UAAU,YAAY,KAAK;KAC3B,WAAU,YAAW,SAAS,SAAS,KAAK,MAAM;eAEjD,KAAK;MACA;MA5BL,OAAO,KAAK,MAAM,CA8BpB;IAEP;GACC"}
1
+ {"version":3,"file":"group.mjs","names":["radio"],"sources":["../../../../src/components/atoms/radio/group.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState } from 'react';\n\nimport { radio } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../button';\nimport { RadioGroupContext } from './context';\nimport Radio from './radio';\n\nconst { RadioGroup: Core } = radio;\n\nexport type OptionValue = string | number | boolean;\n\ntype Option = {\n label: string;\n value: OptionValue;\n disabled?: boolean;\n};\n\ntype Options = string[] | number[] | boolean[] | Option[];\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'ul'>,\n 'onChange' | 'defaultValue' | 'value'\n> {\n options?: Options;\n orientation?: 'vertical' | 'horizontal';\n placement?: 'left' | 'right';\n classNames?: Record<string, string>;\n defaultValue?: OptionValue;\n value?: OptionValue;\n optionType?: 'default' | 'button';\n buttonStyle?: 'solid' | 'outlined';\n size?: 'small' | 'middle' | 'large';\n disabled?: boolean;\n onChange?: (value: OptionValue) => void;\n}\n\nconst RadioGroup = ({\n orientation = 'horizontal',\n placement = 'left',\n className,\n classNames = {},\n options: _options = [],\n optionType = 'default',\n buttonStyle = 'solid',\n size,\n disabled,\n defaultValue,\n value: _value,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [uncontrolledValue, setUncontrolledValue] = useState<\n OptionValue | undefined\n >(defaultValue);\n\n const controlled = _value !== undefined;\n const value = controlled ? _value : uncontrolledValue;\n\n const options: Option[] = _options.map(item =>\n typeof item === 'object'\n ? item\n : {\n label: `${item}`,\n value: item,\n },\n );\n\n const isButton = optionType === 'button';\n\n const onChange = (checked: boolean, optionValue: OptionValue) => {\n if (!checked) {\n return;\n }\n if (!controlled) {\n setUncontrolledValue(optionValue);\n }\n _onChange(optionValue);\n };\n\n // A single Radix radiogroup root owns every option so that arrow keys move\n // focus across the whole group. Radix addresses items by string value, so\n // each option gets a deterministic id derived from a stable base id.\n const baseId = useId();\n const getOptionId = (index: number) => `${baseId}-${index}`;\n const checkedIndex = options.findIndex(item => item.value === value);\n const checkedId = checkedIndex === -1 ? '' : getOptionId(checkedIndex);\n\n const onValueChange = (optionId: string) => {\n const item = options.find((_, index) => getOptionId(index) === optionId);\n\n if (!item) {\n return;\n }\n\n onChange(true, item.value);\n };\n\n const list = (\n <ul\n {...props}\n className={cn(\n 'flex gap-4',\n className,\n orientation === 'vertical' && 'flex-col',\n isButton && 'gap-0',\n )}\n >\n {options.map((item: Option, index) => {\n const checked = value === item.value;\n\n return (\n <li\n key={String(item.value)}\n className={cn('flex', classNames?.wrapper)}\n >\n {isButton ? (\n <Button\n variant={checked ? buttonStyle : 'outlined'}\n size={size}\n className={cn(\n 'rounded-none',\n index === 0 && 'rounded-l-lg',\n index === options.length - 1 && 'rounded-r-lg',\n checked && buttonStyle === 'outlined' && 'border-primary',\n )}\n disabled={disabled || item.disabled}\n onClick={() => onChange(true, item.value)}\n >\n {item.label}\n </Button>\n ) : (\n <Radio\n id={getOptionId(index)}\n placement={placement}\n className={cn(classNames?.item)}\n value={item.value}\n checked={checked}\n disabled={disabled || item.disabled}\n onChange={checked => onChange(checked, item.value)}\n >\n {item.label}\n </Radio>\n )}\n </li>\n );\n })}\n </ul>\n );\n\n // `optionType='button'` renders `Button`s instead of radios, so it keeps the\n // plain list and stays out of the Radix radiogroup entirely.\n if (isButton) {\n return list;\n }\n\n return (\n <RadioGroupContext.Provider value={true}>\n <Core className=\"block\" value={checkedId} onValueChange={onValueChange}>\n {list}\n </Core>\n </RadioGroupContext.Provider>\n );\n};\n\nexport default RadioGroup;\n"],"mappings":";;;;;;;;;;;AAWA,MAAM,EAAE,YAAY,SAASA;AA6B7B,MAAM,cAAc,EAClB,cAAc,cACd,YAAY,QACZ,WACA,aAAa,EAAE,EACf,SAAS,WAAW,EAAE,EACtB,aAAa,WACb,cAAc,SACd,MACA,UACA,cACA,OAAO,QACP,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,mBAAmB,wBAAwB,SAEhD,aAAa;CAEf,MAAM,aAAa,WAAW;CAC9B,MAAM,QAAQ,aAAa,SAAS;CAEpC,MAAM,UAAoB,SAAS,KAAI,SACrC,OAAO,SAAS,WACZ,OACA;EACE,OAAO,GAAG;EACV,OAAO;EACR,CACN;CAED,MAAM,WAAW,eAAe;CAEhC,MAAM,YAAY,SAAkB,gBAA6B;AAC/D,MAAI,CAAC,QACH;AAEF,MAAI,CAAC,WACH,sBAAqB,YAAY;AAEnC,YAAU,YAAY;;CAMxB,MAAM,SAAS,OAAO;CACtB,MAAM,eAAe,UAAkB,GAAG,OAAO,GAAG;CACpD,MAAM,eAAe,QAAQ,WAAU,SAAQ,KAAK,UAAU,MAAM;CACpE,MAAM,YAAY,iBAAiB,KAAK,KAAK,YAAY,aAAa;CAEtE,MAAM,iBAAiB,aAAqB;EAC1C,MAAM,OAAO,QAAQ,MAAM,GAAG,UAAU,YAAY,MAAM,KAAK,SAAS;AAExE,MAAI,CAAC,KACH;AAGF,WAAS,MAAM,KAAK,MAAM;;CAG5B,MAAM,OACJ,oBAAC;EACC,GAAI;EACJ,WAAW,GACT,cACA,WACA,gBAAgB,cAAc,YAC9B,YAAY,QACb;YAEA,QAAQ,KAAK,MAAc,UAAU;GACpC,MAAM,UAAU,UAAU,KAAK;AAE/B,UACE,oBAAC;IAEC,WAAW,GAAG,QAAQ,YAAY,QAAQ;cAEzC,WACC,oBAAC;KACC,SAAS,UAAU,cAAc;KAC3B;KACN,WAAW,GACT,gBACA,UAAU,KAAK,gBACf,UAAU,QAAQ,SAAS,KAAK,gBAChC,WAAW,gBAAgB,cAAc,iBAC1C;KACD,UAAU,YAAY,KAAK;KAC3B,eAAe,SAAS,MAAM,KAAK,MAAM;eAExC,KAAK;MACC,GAET,oBAAC;KACC,IAAI,YAAY,MAAM;KACX;KACX,WAAW,GAAG,YAAY,KAAK;KAC/B,OAAO,KAAK;KACH;KACT,UAAU,YAAY,KAAK;KAC3B,WAAU,YAAW,SAAS,SAAS,KAAK,MAAM;eAEjD,KAAK;MACA;MA7BL,OAAO,KAAK,MAAM,CA+BpB;IAEP;GACC;AAKP,KAAI,SACF,QAAO;AAGT,QACE,oBAAC,kBAAkB;EAAS,OAAO;YACjC,oBAAC;GAAK,WAAU;GAAQ,OAAO;GAA0B;aACtD;IACI;GACoB"}
@@ -11,6 +11,12 @@ interface Props extends Omit<React.ComponentPropsWithoutRef<typeof Core>, 'onCha
11
11
  checked?: boolean;
12
12
  value?: OptionValue;
13
13
  disabled?: boolean;
14
+ /**
15
+ * Id shared by the underlying control and its label. Generated internally
16
+ * when omitted. `RadioGroup` passes a deterministic id so that the group's
17
+ * single Radix root can address each option.
18
+ */
19
+ id?: string;
14
20
  icons?: {
15
21
  checked: React.ReactNode;
16
22
  unchecked: React.ReactNode;
@@ -26,6 +32,7 @@ declare const Radio: ({
26
32
  disabled,
27
33
  defaultChecked,
28
34
  checked: _checked,
35
+ id: _id,
29
36
  onChange: _onChange,
30
37
  ...props
31
38
  }: Props) => react_jsx_runtime0.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"radio.d.mts","names":[],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"mappings":";;;;;;cAWoB,IAAA,SAAI,UAAA;AAAA,UAGP,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA,QAAgC,IAAA;EAGtC,SAAA;EACA,cAAA;EACA,OAAA;EACA,KAAA,GAAQ,WAAA;EACR,QAAA;EACA,KAAA;IAAU,OAAA,EAAS,KAAA,CAAM,SAAA;IAAW,SAAA,EAAW,KAAA,CAAM,SAAA;EAAA;EACrD,QAAA,IAAY,OAAA;AAAA;AAAA,cAGR,KAAA;EAAS,SAAA;EAAA,KAAA,EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,KAAA;EAAA,QAAA;EAAA,cAAA;EAAA,OAAA,EAAA,QAAA;EAAA,QAAA,EAAA,SAAA;EAAA,GAAA;AAAA,GAWZ,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"radio.d.mts","names":[],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"mappings":";;;;;;cAYoB,IAAA,SAAI,UAAA;AAAA,UAGP,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA,QAAgC,IAAA;EAGtC,SAAA;EACA,cAAA;EACA,OAAA;EACA,KAAA,GAAQ,WAAA;EACR,QAAA;EAXsB;;AAGxB;;;EAcE,EAAA;EACA,KAAA;IAAU,OAAA,EAAS,KAAA,CAAM,SAAA;IAAW,SAAA,EAAW,KAAA,CAAM,SAAA;EAAA;EACrD,QAAA,IAAY,OAAA;AAAA;AAAA,cAGR,KAAA;EAAS,SAAA;EAAA,KAAA,EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,KAAA;EAAA,QAAA;EAAA,cAAA;EAAA,OAAA,EAAA,QAAA;EAAA,EAAA,EAAA,GAAA;EAAA,QAAA,EAAA,SAAA;EAAA,GAAA;AAAA,GAYZ,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -3,16 +3,19 @@
3
3
  import { cn } from "../../../utils.mjs";
4
4
  import { field_exports } from "../../../core/field.mjs";
5
5
  import { radio_group_exports } from "../../../core/radio-group.mjs";
6
+ import { RadioGroupContext } from "./context.mjs";
6
7
  import { Circle, CircleCheck } from "lucide-react";
7
- import { useId, useState } from "react";
8
+ import { useContext, useId, useState } from "react";
8
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
10
 
10
11
  //#region src/components/atoms/radio/radio.tsx
11
12
  const { RadioGroup: Core, RadioGroupItem: Item } = radio_group_exports;
12
13
  const { Field, FieldLabel } = field_exports;
13
- const Radio = ({ placement = "left", value: _value = "", children, className, icons, disabled, defaultChecked, checked: _checked, onChange: _onChange = () => {}, ...props }) => {
14
+ const Radio = ({ placement = "left", value: _value = "", children, className, icons, disabled, defaultChecked, checked: _checked, id: _id, onChange: _onChange = () => {}, ...props }) => {
14
15
  const [uncontrolledChecked, setUncontrolledChecked] = useState(defaultChecked || false);
15
- const id = useId();
16
+ const generatedId = useId();
17
+ const id = _id ?? generatedId;
18
+ const grouped = useContext(RadioGroupContext);
16
19
  const controlled = _checked !== void 0;
17
20
  const checked = controlled ? _checked : uncontrolledChecked;
18
21
  const cursorClassName = disabled ? "cursor-not-allowed" : "cursor-pointer";
@@ -21,6 +24,21 @@ const Radio = ({ placement = "left", value: _value = "", children, className, ic
21
24
  if (!controlled) setUncontrolledChecked(next);
22
25
  _onChange(next);
23
26
  };
27
+ const renderField = /* @__PURE__ */ jsxs(Field, {
28
+ orientation: "horizontal",
29
+ className: cn("flex gap-2", placement === "right" && "flex-row-reverse"),
30
+ "data-disabled": disabled,
31
+ children: [/* @__PURE__ */ jsx(Item, {
32
+ value: id,
33
+ id,
34
+ checked,
35
+ disabled
36
+ }), /* @__PURE__ */ jsx(FieldLabel, {
37
+ htmlFor: id,
38
+ className: cursorClassName,
39
+ children
40
+ })]
41
+ });
24
42
  const renderContent = icons ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
25
43
  /* @__PURE__ */ jsx("input", {
26
44
  id,
@@ -53,24 +71,10 @@ const Radio = ({ placement = "left", value: _value = "", children, className, ic
53
71
  htmlFor: id,
54
72
  children
55
73
  })
56
- ] }) : /* @__PURE__ */ jsx(Core, {
74
+ ] }) : grouped ? renderField : /* @__PURE__ */ jsx(Core, {
57
75
  value: checked ? id : "",
58
76
  onValueChange: () => onChange(true),
59
- children: /* @__PURE__ */ jsxs(Field, {
60
- orientation: "horizontal",
61
- className: cn("flex gap-2", placement === "right" && "flex-row-reverse"),
62
- "data-disabled": disabled,
63
- children: [/* @__PURE__ */ jsx(Item, {
64
- value: id,
65
- id,
66
- checked,
67
- disabled
68
- }), /* @__PURE__ */ jsx(FieldLabel, {
69
- htmlFor: id,
70
- className: cursorClassName,
71
- children
72
- })]
73
- })
77
+ children: renderField
74
78
  });
75
79
  return /* @__PURE__ */ jsx("div", {
76
80
  className: cn("flex items-center", icons && placement === "right" && "flex-row-reverse", cursorClassName, className),
@@ -1 +1 @@
1
- {"version":3,"file":"radio.mjs","names":["radio","field"],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState } from 'react';\n\nimport { Circle, CircleCheck } from 'lucide-react';\n\nimport { field, radio } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport { type OptionValue } from './group';\n\nconst { RadioGroup: Core, RadioGroupItem: Item } = radio;\nconst { Field, FieldLabel } = field;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<typeof Core>,\n 'onChange' | 'value'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n disabled?: boolean;\n icons?: { checked: React.ReactNode; unchecked: React.ReactNode };\n onChange?: (checked: boolean) => void;\n}\n\nconst Radio = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [uncontrolledChecked, setUncontrolledChecked] = useState<boolean>(\n defaultChecked || false,\n );\n\n const id = useId();\n const controlled = _checked !== undefined;\n const checked = controlled ? _checked : uncontrolledChecked;\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n if (!controlled) {\n setUncontrolledChecked(next);\n }\n _onChange(next);\n };\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"radio\"\n checked={checked}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n role=\"radio\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n document.getElementById(id)?.click();\n }}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n document.getElementById(id)?.click();\n }\n }}\n >\n {checked\n ? (icons.checked ?? <CircleCheck />)\n : (icons.unchecked ?? <Circle />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : (\n <Core value={checked ? id : ''} onValueChange={() => onChange(true)}>\n <Field\n orientation=\"horizontal\"\n className={cn(\n 'flex gap-2',\n placement === 'right' && 'flex-row-reverse',\n )}\n data-disabled={disabled}\n >\n <Item value={id} id={id} checked={checked} disabled={disabled} />\n <FieldLabel htmlFor={id} className={cursorClassName}>\n {children}\n </FieldLabel>\n </Field>\n </Core>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center',\n icons && placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Radio;\n"],"mappings":";;;;;;;;;;AAWA,MAAM,EAAE,YAAY,MAAM,gBAAgB,SAASA;AACnD,MAAM,EAAE,OAAO,eAAeC;AAe9B,MAAM,SAAS,EACb,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,qBAAqB,0BAA0B,SACpD,kBAAkB,MACnB;CAED,MAAM,KAAK,OAAO;CAClB,MAAM,aAAa,aAAa;CAChC,MAAM,UAAU,aAAa,WAAW;CAExC,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;AAClC,MAAI,SACF;AAGF,MAAI,CAAC,WACH,wBAAuB,KAAK;AAE9B,YAAU,KAAK;;CAGjB,MAAM,gBAAgB,QACpB;EACE,oBAAC;GACK;GACJ;GACA,MAAK;GACI;GACT,WAAU,MAAK;AACb,aAAS,EAAE,OAAO,QAAQ;;IAE5B;EACF,oBAAC;GACC,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,eAAe;AACb,aAAS,eAAe,GAAG,EAAE,OAAO;;GAEtC,YAAW,MAAK;AACd,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,OAAE,gBAAgB;AAClB,cAAS,eAAe,GAAG,EAAE,OAAO;;;aAIvC,UACI,MAAM,WAAW,oBAAC,gBAAc,GAChC,MAAM,aAAa,oBAAC,WAAS;IAC7B;EACN,YACC,oBAAC;GACC,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,SAAS;GAER;IACK;KAET,GAEH,oBAAC;EAAK,OAAO,UAAU,KAAK;EAAI,qBAAqB,SAAS,KAAK;YACjE,qBAAC;GACC,aAAY;GACZ,WAAW,GACT,cACA,cAAc,WAAW,mBAC1B;GACD,iBAAe;cAEf,oBAAC;IAAK,OAAO;IAAQ;IAAa;IAAmB;KAAY,EACjE,oBAAC;IAAW,SAAS;IAAI,WAAW;IACjC;KACU;IACP;GACH;AAGT,QACE,oBAAC;EACC,WAAW,GACT,qBACA,SAAS,cAAc,WAAW,oBAClC,iBACA,UAED;EACD,GAAI;YAEH;GACG"}
1
+ {"version":3,"file":"radio.mjs","names":["radio","field"],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"sourcesContent":["'use client';\n\nimport { useContext, useId, useState } from 'react';\n\nimport { Circle, CircleCheck } from 'lucide-react';\n\nimport { field, radio } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport { RadioGroupContext } from './context';\nimport { type OptionValue } from './group';\n\nconst { RadioGroup: Core, RadioGroupItem: Item } = radio;\nconst { Field, FieldLabel } = field;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<typeof Core>,\n 'onChange' | 'value'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n disabled?: boolean;\n /**\n * Id shared by the underlying control and its label. Generated internally\n * when omitted. `RadioGroup` passes a deterministic id so that the group's\n * single Radix root can address each option.\n */\n id?: string;\n icons?: { checked: React.ReactNode; unchecked: React.ReactNode };\n onChange?: (checked: boolean) => void;\n}\n\nconst Radio = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n id: _id,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [uncontrolledChecked, setUncontrolledChecked] = useState<boolean>(\n defaultChecked || false,\n );\n\n const generatedId = useId();\n const id = _id ?? generatedId;\n const grouped = useContext(RadioGroupContext);\n const controlled = _checked !== undefined;\n const checked = controlled ? _checked : uncontrolledChecked;\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n if (!controlled) {\n setUncontrolledChecked(next);\n }\n _onChange(next);\n };\n\n // When rendered inside a `RadioGroup`, the group owns the single shared\n // `Core` (Radix radiogroup root) so that arrow keys move focus across every\n // option. A standalone `Radio` still has to provide its own root.\n const renderField = (\n <Field\n orientation=\"horizontal\"\n className={cn('flex gap-2', placement === 'right' && 'flex-row-reverse')}\n data-disabled={disabled}\n >\n <Item value={id} id={id} checked={checked} disabled={disabled} />\n <FieldLabel htmlFor={id} className={cursorClassName}>\n {children}\n </FieldLabel>\n </Field>\n );\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"radio\"\n checked={checked}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n role=\"radio\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n document.getElementById(id)?.click();\n }}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n document.getElementById(id)?.click();\n }\n }}\n >\n {checked\n ? (icons.checked ?? <CircleCheck />)\n : (icons.unchecked ?? <Circle />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : grouped ? (\n renderField\n ) : (\n <Core value={checked ? id : ''} onValueChange={() => onChange(true)}>\n {renderField}\n </Core>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center',\n icons && placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Radio;\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,EAAE,YAAY,MAAM,gBAAgB,SAASA;AACnD,MAAM,EAAE,OAAO,eAAeC;AAqB9B,MAAM,SAAS,EACb,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,IAAI,KACJ,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,qBAAqB,0BAA0B,SACpD,kBAAkB,MACnB;CAED,MAAM,cAAc,OAAO;CAC3B,MAAM,KAAK,OAAO;CAClB,MAAM,UAAU,WAAW,kBAAkB;CAC7C,MAAM,aAAa,aAAa;CAChC,MAAM,UAAU,aAAa,WAAW;CAExC,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;AAClC,MAAI,SACF;AAGF,MAAI,CAAC,WACH,wBAAuB,KAAK;AAE9B,YAAU,KAAK;;CAMjB,MAAM,cACJ,qBAAC;EACC,aAAY;EACZ,WAAW,GAAG,cAAc,cAAc,WAAW,mBAAmB;EACxE,iBAAe;aAEf,oBAAC;GAAK,OAAO;GAAQ;GAAa;GAAmB;IAAY,EACjE,oBAAC;GAAW,SAAS;GAAI,WAAW;GACjC;IACU;GACP;CAGV,MAAM,gBAAgB,QACpB;EACE,oBAAC;GACK;GACJ;GACA,MAAK;GACI;GACT,WAAU,MAAK;AACb,aAAS,EAAE,OAAO,QAAQ;;IAE5B;EACF,oBAAC;GACC,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,eAAe;AACb,aAAS,eAAe,GAAG,EAAE,OAAO;;GAEtC,YAAW,MAAK;AACd,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,OAAE,gBAAgB;AAClB,cAAS,eAAe,GAAG,EAAE,OAAO;;;aAIvC,UACI,MAAM,WAAW,oBAAC,gBAAc,GAChC,MAAM,aAAa,oBAAC,WAAS;IAC7B;EACN,YACC,oBAAC;GACC,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,SAAS;GAER;IACK;KAET,GACD,UACF,cAEA,oBAAC;EAAK,OAAO,UAAU,KAAK;EAAI,qBAAqB,SAAS,KAAK;YAChE;GACI;AAGT,QACE,oBAAC;EACC,WAAW,GACT,qBACA,SAAS,cAAc,WAAW,oBAClC,iBACA,UAED;EACD,GAAI;YAEH;GACG"}
@@ -6,4 +6,5 @@ import Space from "../../Space.mjs";
6
6
  import { Collapse } from "./collapse.mjs";
7
7
  import { Dropdown } from "./dropdown.mjs";
8
8
  import { Marquees } from "./marquees/index.mjs";
9
- import { Splitter } from "./splitter/index.mjs";
9
+ import { Splitter } from "./splitter/index.mjs";
10
+ import { Upload, UploadFile } from "./upload.mjs";
@@ -0,0 +1,37 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+
3
+ //#region src/components/molecules/upload.d.ts
4
+ interface UploadFile {
5
+ uid: string;
6
+ name: string;
7
+ url: string;
8
+ }
9
+ interface Props {
10
+ defaultValue?: UploadFile[];
11
+ value?: UploadFile[];
12
+ multiple?: boolean;
13
+ accept?: string;
14
+ maxCount?: number;
15
+ disabled?: boolean;
16
+ className?: string;
17
+ classNames?: {
18
+ dropzone?: string;
19
+ list?: string;
20
+ item?: string;
21
+ };
22
+ onChange?: (files: UploadFile[]) => void;
23
+ }
24
+ declare const Upload: ({
25
+ defaultValue,
26
+ value: _value,
27
+ multiple,
28
+ accept,
29
+ maxCount,
30
+ disabled,
31
+ className,
32
+ classNames,
33
+ onChange: _onChange
34
+ }: Props) => react_jsx_runtime0.JSX.Element;
35
+ //#endregion
36
+ export { Upload, UploadFile };
37
+ //# sourceMappingURL=upload.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.mts","names":[],"sources":["../../../src/components/molecules/upload.tsx"],"mappings":";;;UASiB,UAAA;EACf,GAAA;EACA,IAAA;EACA,GAAA;AAAA;AAAA,UAGe,KAAA;EACf,YAAA,GAAe,UAAA;EACf,KAAA,GAAQ,UAAA;EACR,QAAA;EACA,MAAA;EACA,QAAA;EACA,QAAA;EACA,SAAA;EACA,UAAA;IACE,QAAA;IACA,IAAA;IACA,IAAA;EAAA;EAEF,QAAA,IAAY,KAAA,EAAO,UAAA;AAAA;AAAA,cAOf,MAAA;EAAU,YAAA;EAAA,KAAA,EAAA,MAAA;EAAA,QAAA;EAAA,MAAA;EAAA,QAAA;EAAA,QAAA;EAAA,SAAA;EAAA,UAAA;EAAA,QAAA,EAAA;AAAA,GAUb,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,101 @@
1
+ 'use client';
2
+
3
+ import { cn } from "../../utils.mjs";
4
+ import { Upload, X } from "lucide-react";
5
+ import { useId, useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { useFileToDataUrl } from "@jbpark/use-hooks";
8
+
9
+ //#region src/components/molecules/upload.tsx
10
+ const isImage = (file) => /^data:image\//.test(file.url) || /\.(png|jpe?g|gif|webp|svg)$/i.test(file.name);
11
+ const Upload$1 = ({ defaultValue = [], value: _value, multiple = true, accept = "image/*", maxCount, disabled, className, classNames, onChange: _onChange = () => {} }) => {
12
+ const inputId = useId();
13
+ const readAsDataUrl = useFileToDataUrl();
14
+ const [isDragOver, setIsDragOver] = useState(false);
15
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
16
+ const controlled = _value !== void 0;
17
+ const files = controlled ? _value : uncontrolledValue;
18
+ const onChange = (next) => {
19
+ if (!controlled) setUncontrolledValue(next);
20
+ _onChange(next);
21
+ };
22
+ const addFiles = async (fileList) => {
23
+ const incoming = Array.from(fileList);
24
+ const remaining = typeof maxCount === "number" ? Math.max(0, maxCount - files.length) : incoming.length;
25
+ const accepted = incoming.slice(0, remaining);
26
+ const uploaded = await Promise.all(accepted.map(async (file) => ({
27
+ uid: `${file.name}-${file.lastModified}-${file.size}`,
28
+ name: file.name,
29
+ url: await readAsDataUrl(file)
30
+ })));
31
+ onChange([...files, ...uploaded]);
32
+ };
33
+ const removeFile = (uid) => {
34
+ onChange(files.filter((file) => file.uid !== uid));
35
+ };
36
+ return /* @__PURE__ */ jsxs("div", {
37
+ className: cn("flex flex-col gap-3", className),
38
+ children: [/* @__PURE__ */ jsxs("label", {
39
+ htmlFor: inputId,
40
+ onDragOver: (e) => {
41
+ e.preventDefault();
42
+ if (!disabled) setIsDragOver(true);
43
+ },
44
+ onDragLeave: () => setIsDragOver(false),
45
+ onDrop: (e) => {
46
+ e.preventDefault();
47
+ setIsDragOver(false);
48
+ if (disabled) return;
49
+ if (e.dataTransfer.files.length) addFiles(e.dataTransfer.files);
50
+ },
51
+ className: cn("flex cursor-pointer flex-col items-center justify-center gap-2", "rounded-md border border-dashed p-6 text-center", "text-muted-foreground text-sm", "transition-colors", isDragOver && "border-primary bg-accent", disabled && "pointer-events-none cursor-not-allowed opacity-50", classNames?.dropzone),
52
+ children: [
53
+ /* @__PURE__ */ jsx(Upload, { className: "size-6" }),
54
+ /* @__PURE__ */ jsxs("span", { children: [
55
+ "Click or drag file",
56
+ multiple ? "s" : "",
57
+ " to upload"
58
+ ] }),
59
+ /* @__PURE__ */ jsx("input", {
60
+ id: inputId,
61
+ type: "file",
62
+ accept,
63
+ multiple,
64
+ disabled,
65
+ className: "hidden",
66
+ onChange: (e) => {
67
+ if (e.target.files?.length) addFiles(e.target.files);
68
+ e.target.value = "";
69
+ }
70
+ })
71
+ ]
72
+ }), files.length > 0 && /* @__PURE__ */ jsx("ul", {
73
+ className: cn("flex flex-col gap-2", classNames?.list),
74
+ children: files.map((file) => /* @__PURE__ */ jsxs("li", {
75
+ className: cn("flex items-center gap-2 rounded-md border p-2", classNames?.item),
76
+ children: [
77
+ isImage(file) && /* @__PURE__ */ jsx("img", {
78
+ src: file.url,
79
+ alt: "",
80
+ className: "size-10 shrink-0 rounded object-cover"
81
+ }),
82
+ /* @__PURE__ */ jsx("span", {
83
+ className: "flex-1 truncate text-sm",
84
+ children: file.name
85
+ }),
86
+ /* @__PURE__ */ jsx("button", {
87
+ type: "button",
88
+ onClick: () => removeFile(file.uid),
89
+ className: "text-muted-foreground hover:text-foreground shrink-0",
90
+ "aria-label": `Remove ${file.name}`,
91
+ children: /* @__PURE__ */ jsx(X, { className: "size-4" })
92
+ })
93
+ ]
94
+ }, file.uid))
95
+ })]
96
+ });
97
+ };
98
+
99
+ //#endregion
100
+ export { Upload$1 as default };
101
+ //# sourceMappingURL=upload.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.mjs","names":["Upload","UploadIcon"],"sources":["../../../src/components/molecules/upload.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState } from 'react';\n\nimport { useFileToDataUrl } from '@jbpark/use-hooks';\nimport { Upload as UploadIcon, X } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nexport interface UploadFile {\n uid: string;\n name: string;\n url: string;\n}\n\nexport interface Props {\n defaultValue?: UploadFile[];\n value?: UploadFile[];\n multiple?: boolean;\n accept?: string;\n maxCount?: number;\n disabled?: boolean;\n className?: string;\n classNames?: {\n dropzone?: string;\n list?: string;\n item?: string;\n };\n onChange?: (files: UploadFile[]) => void;\n}\n\nconst isImage = (file: UploadFile) =>\n /^data:image\\//.test(file.url) ||\n /\\.(png|jpe?g|gif|webp|svg)$/i.test(file.name);\n\nconst Upload = ({\n defaultValue = [],\n value: _value,\n multiple = true,\n accept = 'image/*',\n maxCount,\n disabled,\n className,\n classNames,\n onChange: _onChange = () => {},\n}: Props) => {\n const inputId = useId();\n const readAsDataUrl = useFileToDataUrl();\n const [isDragOver, setIsDragOver] = useState(false);\n const [uncontrolledValue, setUncontrolledValue] =\n useState<UploadFile[]>(defaultValue);\n\n const controlled = _value !== undefined;\n const files = controlled ? _value : uncontrolledValue;\n\n const onChange = (next: UploadFile[]) => {\n if (!controlled) {\n setUncontrolledValue(next);\n }\n _onChange(next);\n };\n\n const addFiles = async (fileList: FileList) => {\n const incoming = Array.from(fileList);\n const remaining =\n typeof maxCount === 'number'\n ? Math.max(0, maxCount - files.length)\n : incoming.length;\n\n const accepted = incoming.slice(0, remaining);\n\n const uploaded = await Promise.all(\n accepted.map(async file => ({\n uid: `${file.name}-${file.lastModified}-${file.size}`,\n name: file.name,\n url: await readAsDataUrl(file),\n })),\n );\n\n onChange([...files, ...uploaded]);\n };\n\n const removeFile = (uid: string) => {\n onChange(files.filter(file => file.uid !== uid));\n };\n\n return (\n <div\n className={cn(\n 'flex flex-col gap-3',\n className,\n //\n )}\n >\n <label\n htmlFor={inputId}\n onDragOver={e => {\n e.preventDefault();\n if (!disabled) {\n setIsDragOver(true);\n }\n }}\n onDragLeave={() => setIsDragOver(false)}\n onDrop={e => {\n e.preventDefault();\n setIsDragOver(false);\n\n if (disabled) {\n return;\n }\n\n if (e.dataTransfer.files.length) {\n addFiles(e.dataTransfer.files);\n }\n }}\n className={cn(\n 'flex cursor-pointer flex-col items-center justify-center gap-2',\n 'rounded-md border border-dashed p-6 text-center',\n 'text-muted-foreground text-sm',\n 'transition-colors',\n isDragOver && 'border-primary bg-accent',\n disabled && 'pointer-events-none cursor-not-allowed opacity-50',\n classNames?.dropzone,\n //\n )}\n >\n <UploadIcon className=\"size-6\" />\n <span>Click or drag file{multiple ? 's' : ''} to upload</span>\n <input\n id={inputId}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n className=\"hidden\"\n onChange={e => {\n if (e.target.files?.length) {\n addFiles(e.target.files);\n }\n e.target.value = '';\n }}\n />\n </label>\n\n {files.length > 0 && (\n <ul\n className={cn(\n 'flex flex-col gap-2',\n classNames?.list,\n //\n )}\n >\n {files.map(file => (\n <li\n key={file.uid}\n className={cn(\n 'flex items-center gap-2 rounded-md border p-2',\n classNames?.item,\n //\n )}\n >\n {isImage(file) && (\n <img\n src={file.url}\n alt=\"\"\n className=\"size-10 shrink-0 rounded object-cover\"\n />\n )}\n <span className=\"flex-1 truncate text-sm\">{file.name}</span>\n <button\n type=\"button\"\n onClick={() => removeFile(file.uid)}\n className=\"text-muted-foreground hover:text-foreground shrink-0\"\n aria-label={`Remove ${file.name}`}\n >\n <X className=\"size-4\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nexport default Upload;\n"],"mappings":";;;;;;;;;AA+BA,MAAM,WAAW,SACf,gBAAgB,KAAK,KAAK,IAAI,IAC9B,+BAA+B,KAAK,KAAK,KAAK;AAEhD,MAAMA,YAAU,EACd,eAAe,EAAE,EACjB,OAAO,QACP,WAAW,MACX,SAAS,WACT,UACA,UACA,WACA,YACA,UAAU,kBAAkB,SACjB;CACX,MAAM,UAAU,OAAO;CACvB,MAAM,gBAAgB,kBAAkB;CACxC,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM;CACnD,MAAM,CAAC,mBAAmB,wBACxB,SAAuB,aAAa;CAEtC,MAAM,aAAa,WAAW;CAC9B,MAAM,QAAQ,aAAa,SAAS;CAEpC,MAAM,YAAY,SAAuB;AACvC,MAAI,CAAC,WACH,sBAAqB,KAAK;AAE5B,YAAU,KAAK;;CAGjB,MAAM,WAAW,OAAO,aAAuB;EAC7C,MAAM,WAAW,MAAM,KAAK,SAAS;EACrC,MAAM,YACJ,OAAO,aAAa,WAChB,KAAK,IAAI,GAAG,WAAW,MAAM,OAAO,GACpC,SAAS;EAEf,MAAM,WAAW,SAAS,MAAM,GAAG,UAAU;EAE7C,MAAM,WAAW,MAAM,QAAQ,IAC7B,SAAS,IAAI,OAAM,UAAS;GAC1B,KAAK,GAAG,KAAK,KAAK,GAAG,KAAK,aAAa,GAAG,KAAK;GAC/C,MAAM,KAAK;GACX,KAAK,MAAM,cAAc,KAAK;GAC/B,EAAE,CACJ;AAED,WAAS,CAAC,GAAG,OAAO,GAAG,SAAS,CAAC;;CAGnC,MAAM,cAAc,QAAgB;AAClC,WAAS,MAAM,QAAO,SAAQ,KAAK,QAAQ,IAAI,CAAC;;AAGlD,QACE,qBAAC;EACC,WAAW,GACT,uBACA,UAED;aAED,qBAAC;GACC,SAAS;GACT,aAAY,MAAK;AACf,MAAE,gBAAgB;AAClB,QAAI,CAAC,SACH,eAAc,KAAK;;GAGvB,mBAAmB,cAAc,MAAM;GACvC,SAAQ,MAAK;AACX,MAAE,gBAAgB;AAClB,kBAAc,MAAM;AAEpB,QAAI,SACF;AAGF,QAAI,EAAE,aAAa,MAAM,OACvB,UAAS,EAAE,aAAa,MAAM;;GAGlC,WAAW,GACT,kEACA,mDACA,iCACA,qBACA,cAAc,4BACd,YAAY,qDACZ,YAAY,SAEb;;IAED,oBAACC,UAAW,WAAU,WAAW;IACjC,qBAAC;KAAK;KAAmB,WAAW,MAAM;KAAG;QAAiB;IAC9D,oBAAC;KACC,IAAI;KACJ,MAAK;KACG;KACE;KACA;KACV,WAAU;KACV,WAAU,MAAK;AACb,UAAI,EAAE,OAAO,OAAO,OAClB,UAAS,EAAE,OAAO,MAAM;AAE1B,QAAE,OAAO,QAAQ;;MAEnB;;IACI,EAEP,MAAM,SAAS,KACd,oBAAC;GACC,WAAW,GACT,uBACA,YAAY,KAEb;aAEA,MAAM,KAAI,SACT,qBAAC;IAEC,WAAW,GACT,iDACA,YAAY,KAEb;;KAEA,QAAQ,KAAK,IACZ,oBAAC;MACC,KAAK,KAAK;MACV,KAAI;MACJ,WAAU;OACV;KAEJ,oBAAC;MAAK,WAAU;gBAA2B,KAAK;OAAY;KAC5D,oBAAC;MACC,MAAK;MACL,eAAe,WAAW,KAAK,IAAI;MACnC,WAAU;MACV,cAAY,UAAU,KAAK;gBAE3B,oBAAC,KAAE,WAAU,WAAW;OACjB;;MAtBJ,KAAK,IAuBP,CACL;IACC;GAEH"}
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";;;UAoBiB,KAAA;EACf,IAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,QAAA;EACA,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,SAAA;EACA,IAAA;EACA,YAAA;EACA,SAAA;EACA,SAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EACA,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,UAAA;IACE,IAAA;IACA,OAAA;IACA,SAAA;IACA,MAAA;IACA,KAAA;IACA,KAAA;IACA,KAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,SAAA,GAAY,WAAA;EACZ,OAAA;AAAA;AAAA,cAqBI,MAAA;EAAU,IAAA;EAAA,KAAA;EAAA,KAAA;EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,SAAA;EAAA,IAAA;EAAA,YAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA,IAAA;EAAA,SAAA;EAAA,UAAA;EAAA,KAAA;EAAA,QAAA;EAAA,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAqBb,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";;;UA4BiB,KAAA;EACf,IAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,QAAA;EACA,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,SAAA;EACA,IAAA;EACA,YAAA;EACA,SAAA;EACA,SAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EACA,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,UAAA;IACE,IAAA;IACA,OAAA;IACA,SAAA;IACA,MAAA;IACA,KAAA;IACA,KAAA;IACA,KAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,SAAA,GAAY,WAAA;EACZ,OAAA;AAAA;AAAA,cAqBI,MAAA;EAAU,IAAA;EAAA,KAAA;EAAA,KAAA;EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,SAAA;EAAA,IAAA;EAAA,YAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA,IAAA;EAAA,SAAA;EAAA,UAAA;EAAA,KAAA;EAAA,QAAA;EAAA,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAqBb,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -9,6 +9,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
9
9
 
10
10
  //#region src/components/organisms/drawer.tsx
11
11
  const { DrawerContent, Drawer: DrawerCore, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle } = drawer_exports;
12
+ let maskLessOverlayCount = 0;
13
+ let originalBodyPointerEvents = null;
12
14
  const SIZES = {
13
15
  small: "30%",
14
16
  medium: "50%",
@@ -22,13 +24,18 @@ const getSizeStyles = (direction, size) => {
22
24
  const Drawer = ({ open, title, extra, footer, closable = true, closeIcon, direction = "bottom", size = "medium", maskClosable = true, handlebar = true, draggable = false, rounded = false, mask = true, className, classNames, style, children, container, onClose, ...props }) => {
23
25
  useEffect(() => {
24
26
  if (!open || mask) return;
25
- const originalPointerEvents = document.body.style.pointerEvents;
27
+ if (maskLessOverlayCount === 0) originalBodyPointerEvents = document.body.style.pointerEvents;
28
+ maskLessOverlayCount += 1;
26
29
  const raf = window.requestAnimationFrame(() => {
27
30
  document.body.style.pointerEvents = "auto";
28
31
  });
29
32
  return () => {
30
33
  window.cancelAnimationFrame(raf);
31
- document.body.style.pointerEvents = originalPointerEvents;
34
+ maskLessOverlayCount -= 1;
35
+ if (maskLessOverlayCount === 0) {
36
+ document.body.style.pointerEvents = originalBodyPointerEvents ?? "";
37
+ originalBodyPointerEvents = null;
38
+ }
32
39
  };
33
40
  }, [open, mask]);
34
41
  return /* @__PURE__ */ jsx(DrawerCore, {