@jbpark/ui-kit 3.4.0 → 3.6.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 (39) hide show
  1. package/dist/components/atoms/float-button/back-top.mjs +2 -7
  2. package/dist/components/atoms/float-button/back-top.mjs.map +1 -1
  3. package/dist/components/atoms/input/search.d.mts.map +1 -1
  4. package/dist/components/atoms/input/search.mjs +3 -6
  5. package/dist/components/atoms/input/search.mjs.map +1 -1
  6. package/dist/components/atoms/popover.d.mts.map +1 -1
  7. package/dist/components/atoms/popover.mjs +71 -19
  8. package/dist/components/atoms/popover.mjs.map +1 -1
  9. package/dist/components/atoms/skeleton/button.d.mts +1 -1
  10. package/dist/components/atoms/skeleton/button.d.mts.map +1 -1
  11. package/dist/components/atoms/skeleton/button.mjs +5 -2
  12. package/dist/components/atoms/skeleton/button.mjs.map +1 -1
  13. package/dist/components/atoms/skeleton/node.d.mts +1 -1
  14. package/dist/components/atoms/skeleton/node.d.mts.map +1 -1
  15. package/dist/components/atoms/skeleton/node.mjs +5 -2
  16. package/dist/components/atoms/skeleton/node.mjs.map +1 -1
  17. package/dist/components/molecules/marquees/item.d.mts.map +1 -1
  18. package/dist/components/molecules/marquees/item.mjs +6 -11
  19. package/dist/components/molecules/marquees/item.mjs.map +1 -1
  20. package/dist/components/molecules/upload.d.mts.map +1 -1
  21. package/dist/components/molecules/upload.mjs +19 -27
  22. package/dist/components/molecules/upload.mjs.map +1 -1
  23. package/dist/components/organisms/drawer.d.mts.map +1 -1
  24. package/dist/components/organisms/drawer.mjs +37 -13
  25. package/dist/components/organisms/drawer.mjs.map +1 -1
  26. package/dist/components/organisms/list/list.mjs +4 -9
  27. package/dist/components/organisms/list/list.mjs.map +1 -1
  28. package/dist/components/organisms/modal.d.mts +1 -0
  29. package/dist/components/organisms/modal.d.mts.map +1 -1
  30. package/dist/components/organisms/modal.mjs +13 -8
  31. package/dist/components/organisms/modal.mjs.map +1 -1
  32. package/dist/components/organisms/swiper/swiper.d.mts.map +1 -1
  33. package/dist/components/organisms/swiper/swiper.mjs +5 -1
  34. package/dist/components/organisms/swiper/swiper.mjs.map +1 -1
  35. package/dist/components/organisms/toast.d.mts.map +1 -1
  36. package/dist/components/organisms/toast.mjs +12 -8
  37. package/dist/components/organisms/toast.mjs.map +1 -1
  38. package/dist/style.css +138 -0
  39. package/package.json +2 -3
@@ -5,19 +5,14 @@ import FloatButton from "./float-button.mjs";
5
5
  import { ArrowUp } from "lucide-react";
6
6
  import { useRef } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
- import { useWindowScroll } from "@jbpark/use-hooks";
8
+ import { useMergedRef, useWindowScroll } from "@jbpark/use-hooks";
9
9
 
10
10
  //#region src/components/atoms/float-button/back-top.tsx
11
11
  const BackTop = ({ ref, visibilityHeight = 450, className, onClick, ...props }) => {
12
12
  const buttonRef = useRef(null);
13
13
  const { y } = useWindowScroll(buttonRef);
14
- const setRefs = (node) => {
15
- buttonRef.current = node;
16
- if (typeof ref === "function") ref(node);
17
- else if (ref) ref.current = node;
18
- };
19
14
  return /* @__PURE__ */ jsx(FloatButton, {
20
- ref: setRefs,
15
+ ref: useMergedRef(buttonRef, ref),
21
16
  "aria-label": "맨 위로",
22
17
  icon: /* @__PURE__ */ jsx(ArrowUp, {}),
23
18
  className: cn(className, (!y || visibilityHeight > y) && "hidden"),
@@ -1 +1 @@
1
- {"version":3,"file":"back-top.mjs","names":[],"sources":["../../../../src/components/atoms/float-button/back-top.tsx"],"sourcesContent":["'use client';\n\nimport { type MouseEvent, useRef } 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 ref,\n visibilityHeight = 450,\n className,\n onClick,\n ...props\n}: Props) => {\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n // Track/scroll whichever window actually renders this button — not\n // necessarily the host `window`, since this can be portaled into an\n // iframe (e.g. live-editor's Renderer).\n const { y } = useWindowScroll(buttonRef);\n\n const setRefs = (node: HTMLButtonElement | null) => {\n buttonRef.current = node;\n\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n };\n\n return (\n <FloatButton\n ref={setRefs}\n aria-label=\"맨 위로\"\n icon={<ArrowUp />}\n className={cn(\n className,\n (!y || visibilityHeight > y) && 'hidden',\n //\n )}\n onClick={e => {\n const view = buttonRef.current?.ownerDocument.defaultView ?? window;\n view.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,KACA,mBAAmB,KACnB,WACA,SACA,GAAG,YACQ;CACX,MAAM,YAAY,OAA0B,KAAK;CAKjD,MAAM,EAAE,MAAM,gBAAgB,UAAU;CAExC,MAAM,WAAW,SAAmC;AAClD,YAAU,UAAU;AAEpB,MAAI,OAAO,QAAQ,WACjB,KAAI,KAAK;WACA,IACT,KAAI,UAAU;;AAIlB,QACE,oBAAC;EACC,KAAK;EACL,cAAW;EACX,MAAM,oBAAC,YAAU;EACjB,WAAW,GACT,YACC,CAAC,KAAK,mBAAmB,MAAM,SAEjC;EACD,UAAS,MAAK;AAEZ,IADa,UAAU,SAAS,cAAc,eAAe,QACxD,SAAS;IAAE,MAAM;IAAG,KAAK;IAAG,UAAU;IAAU,CAAC;AACtD,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 { type MouseEvent, useRef } from 'react';\n\nimport { useMergedRef, 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 ref,\n visibilityHeight = 450,\n className,\n onClick,\n ...props\n}: Props) => {\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n // Track/scroll whichever window actually renders this button — not\n // necessarily the host `window`, since this can be portaled into an\n // iframe (e.g. live-editor's Renderer).\n const { y } = useWindowScroll(buttonRef);\n\n const mergedRef = useMergedRef(buttonRef, ref);\n\n return (\n <FloatButton\n ref={mergedRef}\n aria-label=\"맨 위로\"\n icon={<ArrowUp />}\n className={cn(\n className,\n (!y || visibilityHeight > y) && 'hidden',\n //\n )}\n onClick={e => {\n const view = buttonRef.current?.ownerDocument.defaultView ?? window;\n view.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,KACA,mBAAmB,KACnB,WACA,SACA,GAAG,YACQ;CACX,MAAM,YAAY,OAA0B,KAAK;CAKjD,MAAM,EAAE,MAAM,gBAAgB,UAAU;AAIxC,QACE,oBAAC;EACC,KAJc,aAAa,WAAW,IAAI;EAK1C,cAAW;EACX,MAAM,oBAAC,YAAU;EACjB,WAAW,GACT,YACC,CAAC,KAAK,mBAAmB,MAAM,SAEjC;EACD,UAAS,MAAK;AAEZ,IADa,UAAU,SAAS,cAAc,eAAe,QACxD,SAAS;IAAE,MAAM;IAAG,KAAK;IAAG,UAAU;IAAU,CAAC;AACtD,aAAU,EAAE;;EAEd,GAAI;GACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.mts","names":[],"sources":["../../../../src/components/atoms/input/search.tsx"],"mappings":";;;UAaiB,KAAA,SAAc,KAAA,CAAM,qBAAA;EACnC,UAAA;EACA,QAAA,IACE,CAAA,EAAG,KAAA,CAAM,WAAA,CAAY,gBAAA;IAAsB,MAAA;MAAU,KAAA;IAAA;EAAA;EAEvD,QAAA,IAAY,KAAA;AAAA;AAAA,cAGR,MAAA;EAAA;;;;;;;;;;;KAWH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"search.d.mts","names":[],"sources":["../../../../src/components/atoms/input/search.tsx"],"mappings":";;;UAciB,KAAA,SAAc,KAAA,CAAM,qBAAA;EACnC,UAAA;EACA,QAAA,IACE,CAAA,EAAG,KAAA,CAAM,WAAA,CAAY,gBAAA;IAAsB,MAAA;MAAU,KAAA;IAAA;EAAA;EAEvD,QAAA,IAAY,KAAA;AAAA;AAAA,cAGR,MAAA;EAAA;;;;;;;;;;;KAWH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -6,16 +6,13 @@ import Button from "../../../Button.mjs";
6
6
  import { CircleX, Search } from "lucide-react";
7
7
  import { useRef, useState } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { useMergedRef } from "@jbpark/use-hooks";
9
10
 
10
11
  //#region src/components/atoms/input/search.tsx
11
12
  const { Input: Core } = input_exports;
12
13
  const Search$1 = ({ ref, className, defaultValue, value, disabled, allowClear = true, onChange, onKeyDown: _onKeyDown, onSearch: _onSearch, ...props }) => {
13
14
  const inputRef = useRef(null);
14
- const setRefs = (node) => {
15
- inputRef.current = node;
16
- if (typeof ref === "function") ref(node);
17
- else if (ref) ref.current = node;
18
- };
15
+ const mergedRef = useMergedRef(inputRef, ref);
19
16
  const [uncontrolledHasValue, setUncontrolledHasValue] = useState(!!defaultValue);
20
17
  const hasValue = value !== void 0 ? !!value : uncontrolledHasValue;
21
18
  const onClear = () => {
@@ -36,7 +33,7 @@ const Search$1 = ({ ref, className, defaultValue, value, disabled, allowClear =
36
33
  className: cn("relative grow", "inline-flex items-center"),
37
34
  children: [/* @__PURE__ */ jsx(Core, {
38
35
  ...props,
39
- ref: setRefs,
36
+ ref: mergedRef,
40
37
  inputMode: "search",
41
38
  type: "search",
42
39
  enterKeyHint: "search",
@@ -1 +1 @@
1
- {"version":3,"file":"search.mjs","names":["input","Search","SearchOutlined"],"sources":["../../../../src/components/atoms/input/search.tsx"],"sourcesContent":["'use client';\n\nimport { useRef, useState } from 'react';\n\nimport { CircleX, Search as SearchOutlined } from 'lucide-react';\n\nimport { input } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../button';\n\nconst { Input: Core } = input;\n\nexport interface Props extends React.ComponentPropsWithRef<'input'> {\n allowClear?: boolean;\n onChange?: (\n e: React.ChangeEvent<HTMLInputElement> | { target: { value: string } },\n ) => void;\n onSearch?: (value: string) => void;\n}\n\nconst Search = ({\n ref,\n className,\n defaultValue,\n value,\n disabled,\n allowClear = true,\n onChange,\n onKeyDown: _onKeyDown,\n onSearch: _onSearch,\n ...props\n}: Props) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const setRefs = (node: HTMLInputElement | null) => {\n inputRef.current = node;\n\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n };\n\n const [uncontrolledHasValue, setUncontrolledHasValue] =\n useState(!!defaultValue);\n const hasValue = value !== undefined ? !!value : uncontrolledHasValue;\n\n const onClear = () => {\n if (!inputRef.current) {\n return;\n }\n\n if (value === undefined) {\n inputRef.current.value = '';\n setUncontrolledHasValue(false);\n }\n\n onChange?.({ target: { value: '' } });\n };\n\n const onSearch = () => {\n if (disabled) {\n return;\n }\n if (inputRef.current) {\n _onSearch?.(inputRef.current.value);\n }\n };\n\n return (\n <div\n className={cn(\n 'flex items-center',\n 'rounded-md',\n className,\n //\n )}\n >\n <div\n className={cn(\n 'relative grow',\n 'inline-flex items-center',\n //\n )}\n >\n <Core\n {...props}\n ref={setRefs}\n inputMode=\"search\"\n type=\"search\"\n enterKeyHint=\"search\"\n disabled={disabled}\n className={cn(\n 'rounded-r-none',\n '[&::-webkit-search-cancel-button]:hidden',\n '[&::-webkit-search-decoration]:hidden',\n //\n )}\n value={value}\n defaultValue={defaultValue}\n onChange={e => {\n if (value === undefined) {\n setUncontrolledHasValue(!!e.target.value);\n }\n onChange?.(e);\n }}\n onKeyDown={e => {\n _onKeyDown?.(e);\n if (e.key === 'Enter') {\n onSearch();\n }\n }}\n />\n <button\n type=\"button\"\n aria-label=\"지우기\"\n disabled={disabled}\n className={cn(\n 'absolute right-2',\n 'shrink-0 cursor-pointer',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n (!allowClear || !hasValue) && 'hidden',\n )}\n onClick={onClear}\n >\n <CircleX className=\"size-4\" />\n </button>\n </div>\n <Button\n icon={<SearchOutlined />}\n disabled={disabled}\n className={cn(\n 'rounded-l-none',\n 'size-9',\n //\n )}\n onClick={onSearch}\n />\n </div>\n );\n};\n\nSearch.displayName = 'Search';\n\nexport default Search;\n"],"mappings":";;;;;;;;;;AAWA,MAAM,EAAE,OAAO,SAASA;AAUxB,MAAMC,YAAU,EACd,KACA,WACA,cACA,OACA,UACA,aAAa,MACb,UACA,WAAW,YACX,UAAU,WACV,GAAG,YACQ;CACX,MAAM,WAAW,OAAyB,KAAK;CAE/C,MAAM,WAAW,SAAkC;AACjD,WAAS,UAAU;AAEnB,MAAI,OAAO,QAAQ,WACjB,KAAI,KAAK;WACA,IACT,KAAI,UAAU;;CAIlB,MAAM,CAAC,sBAAsB,2BAC3B,SAAS,CAAC,CAAC,aAAa;CAC1B,MAAM,WAAW,UAAU,SAAY,CAAC,CAAC,QAAQ;CAEjD,MAAM,gBAAgB;AACpB,MAAI,CAAC,SAAS,QACZ;AAGF,MAAI,UAAU,QAAW;AACvB,YAAS,QAAQ,QAAQ;AACzB,2BAAwB,MAAM;;AAGhC,aAAW,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;;CAGvC,MAAM,iBAAiB;AACrB,MAAI,SACF;AAEF,MAAI,SAAS,QACX,aAAY,SAAS,QAAQ,MAAM;;AAIvC,QACE,qBAAC;EACC,WAAW,GACT,qBACA,cACA,UAED;aAED,qBAAC;GACC,WAAW,GACT,iBACA,2BAED;cAED,oBAAC;IACC,GAAI;IACJ,KAAK;IACL,WAAU;IACV,MAAK;IACL,cAAa;IACH;IACV,WAAW,GACT,kBACA,4CACA,wCAED;IACM;IACO;IACd,WAAU,MAAK;AACb,SAAI,UAAU,OACZ,yBAAwB,CAAC,CAAC,EAAE,OAAO,MAAM;AAE3C,gBAAW,EAAE;;IAEf,YAAW,MAAK;AACd,kBAAa,EAAE;AACf,SAAI,EAAE,QAAQ,QACZ,WAAU;;KAGd,EACF,oBAAC;IACC,MAAK;IACL,cAAW;IACD;IACV,WAAW,GACT,oBACA,2BACA,oDACC,CAAC,cAAc,CAAC,aAAa,SAC/B;IACD,SAAS;cAET,oBAAC,WAAQ,WAAU,WAAW;KACvB;IACL,EACN,oBAAC;GACC,MAAM,oBAACC,WAAiB;GACd;GACV,WAAW,GACT,kBACA,SAED;GACD,SAAS;IACT;GACE;;AAIV,SAAO,cAAc"}
1
+ {"version":3,"file":"search.mjs","names":["input","Search","SearchOutlined"],"sources":["../../../../src/components/atoms/input/search.tsx"],"sourcesContent":["'use client';\n\nimport { useRef, useState } from 'react';\n\nimport { useMergedRef } from '@jbpark/use-hooks';\nimport { CircleX, Search as SearchOutlined } from 'lucide-react';\n\nimport { input } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../button';\n\nconst { Input: Core } = input;\n\nexport interface Props extends React.ComponentPropsWithRef<'input'> {\n allowClear?: boolean;\n onChange?: (\n e: React.ChangeEvent<HTMLInputElement> | { target: { value: string } },\n ) => void;\n onSearch?: (value: string) => void;\n}\n\nconst Search = ({\n ref,\n className,\n defaultValue,\n value,\n disabled,\n allowClear = true,\n onChange,\n onKeyDown: _onKeyDown,\n onSearch: _onSearch,\n ...props\n}: Props) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const mergedRef = useMergedRef(inputRef, ref);\n\n const [uncontrolledHasValue, setUncontrolledHasValue] =\n useState(!!defaultValue);\n const hasValue = value !== undefined ? !!value : uncontrolledHasValue;\n\n const onClear = () => {\n if (!inputRef.current) {\n return;\n }\n\n if (value === undefined) {\n inputRef.current.value = '';\n setUncontrolledHasValue(false);\n }\n\n onChange?.({ target: { value: '' } });\n };\n\n const onSearch = () => {\n if (disabled) {\n return;\n }\n if (inputRef.current) {\n _onSearch?.(inputRef.current.value);\n }\n };\n\n return (\n <div\n className={cn(\n 'flex items-center',\n 'rounded-md',\n className,\n //\n )}\n >\n <div\n className={cn(\n 'relative grow',\n 'inline-flex items-center',\n //\n )}\n >\n <Core\n {...props}\n ref={mergedRef}\n inputMode=\"search\"\n type=\"search\"\n enterKeyHint=\"search\"\n disabled={disabled}\n className={cn(\n 'rounded-r-none',\n '[&::-webkit-search-cancel-button]:hidden',\n '[&::-webkit-search-decoration]:hidden',\n //\n )}\n value={value}\n defaultValue={defaultValue}\n onChange={e => {\n if (value === undefined) {\n setUncontrolledHasValue(!!e.target.value);\n }\n onChange?.(e);\n }}\n onKeyDown={e => {\n _onKeyDown?.(e);\n if (e.key === 'Enter') {\n onSearch();\n }\n }}\n />\n <button\n type=\"button\"\n aria-label=\"지우기\"\n disabled={disabled}\n className={cn(\n 'absolute right-2',\n 'shrink-0 cursor-pointer',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n (!allowClear || !hasValue) && 'hidden',\n )}\n onClick={onClear}\n >\n <CircleX className=\"size-4\" />\n </button>\n </div>\n <Button\n icon={<SearchOutlined />}\n disabled={disabled}\n className={cn(\n 'rounded-l-none',\n 'size-9',\n //\n )}\n onClick={onSearch}\n />\n </div>\n );\n};\n\nSearch.displayName = 'Search';\n\nexport default Search;\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,EAAE,OAAO,SAASA;AAUxB,MAAMC,YAAU,EACd,KACA,WACA,cACA,OACA,UACA,aAAa,MACb,UACA,WAAW,YACX,UAAU,WACV,GAAG,YACQ;CACX,MAAM,WAAW,OAAyB,KAAK;CAE/C,MAAM,YAAY,aAAa,UAAU,IAAI;CAE7C,MAAM,CAAC,sBAAsB,2BAC3B,SAAS,CAAC,CAAC,aAAa;CAC1B,MAAM,WAAW,UAAU,SAAY,CAAC,CAAC,QAAQ;CAEjD,MAAM,gBAAgB;AACpB,MAAI,CAAC,SAAS,QACZ;AAGF,MAAI,UAAU,QAAW;AACvB,YAAS,QAAQ,QAAQ;AACzB,2BAAwB,MAAM;;AAGhC,aAAW,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;;CAGvC,MAAM,iBAAiB;AACrB,MAAI,SACF;AAEF,MAAI,SAAS,QACX,aAAY,SAAS,QAAQ,MAAM;;AAIvC,QACE,qBAAC;EACC,WAAW,GACT,qBACA,cACA,UAED;aAED,qBAAC;GACC,WAAW,GACT,iBACA,2BAED;cAED,oBAAC;IACC,GAAI;IACJ,KAAK;IACL,WAAU;IACV,MAAK;IACL,cAAa;IACH;IACV,WAAW,GACT,kBACA,4CACA,wCAED;IACM;IACO;IACd,WAAU,MAAK;AACb,SAAI,UAAU,OACZ,yBAAwB,CAAC,CAAC,EAAE,OAAO,MAAM;AAE3C,gBAAW,EAAE;;IAEf,YAAW,MAAK;AACd,kBAAa,EAAE;AACf,SAAI,EAAE,QAAQ,QACZ,WAAU;;KAGd,EACF,oBAAC;IACC,MAAK;IACL,cAAW;IACD;IACV,WAAW,GACT,oBACA,2BACA,oDACC,CAAC,cAAc,CAAC,aAAa,SAC/B;IACD,SAAS;cAET,oBAAC,WAAQ,WAAU,WAAW;KACvB;IACL,EACN,oBAAC;GACC,MAAM,oBAACC,WAAiB;GACd;GACV,WAAW,GACT,kBACA,SAED;GACD,SAAS;IACT;GACE;;AAIV,SAAO,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"popover.d.mts","names":[],"sources":["../../../src/components/atoms/popover.tsx"],"mappings":";;;KASK,SAAA;AAAA,UAcY,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA;EAGN,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,SAAA,GAAY,SAAA;EACZ,OAAA,EAAS,KAAA,CAAM,SAAA;EACf,IAAA;EACA,WAAA;EACA,YAAA,IAAgB,IAAA;AAAA;AAAA,cA4GZ,OAAA;EAAW,KAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA,QAAA;EAAA,IAAA,EAAA,KAAA;EAAA,WAAA;EAAA,YAAA;EAAA,GAAA;AAAA,GAUd,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"popover.d.mts","names":[],"sources":["../../../src/components/atoms/popover.tsx"],"mappings":";;;KASK,SAAA;AAAA,UAcY,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA;EAGN,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,SAAA,GAAY,SAAA;EACZ,OAAA,EAAS,KAAA,CAAM,SAAA;EACf,IAAA;EACA,WAAA;EACA,YAAA,IAAgB,IAAA;AAAA;AAAA,cA6JZ,OAAA;EAAW,KAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA,QAAA;EAAA,IAAA,EAAA,KAAA;EAAA,WAAA;EAAA,YAAA;EAAA,GAAA;AAAA,GAUd,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -86,27 +86,79 @@ const fillColorBySide = {
86
86
  left: "after:border-l-8 after:border-l-popover",
87
87
  right: "after:border-r-8 after:border-r-popover"
88
88
  };
89
- const offsetAxisBySide = {
90
- top: "x",
91
- bottom: "x",
92
- left: "y",
93
- right: "y"
94
- };
95
- const startEdgeByAxis = {
96
- x: "left",
97
- y: "top"
98
- };
99
- const endEdgeByAxis = {
100
- x: "right",
101
- y: "bottom"
89
+ const POSITION_CLASSES = {
90
+ top: {
91
+ start: {
92
+ wrapper: "top-full left-4",
93
+ before: "before:top-0 before:left-0",
94
+ after: "after:-top-px after:left-px"
95
+ },
96
+ center: {
97
+ wrapper: "top-full left-1/2 -translate-x-1/2",
98
+ before: "before:top-0 before:left-1/2 before:-translate-x-1/2",
99
+ after: "after:-top-px after:left-1/2 after:-translate-x-1/2"
100
+ },
101
+ end: {
102
+ wrapper: "top-full right-4",
103
+ before: "before:top-0 before:right-0",
104
+ after: "after:-top-px after:right-px"
105
+ }
106
+ },
107
+ bottom: {
108
+ start: {
109
+ wrapper: "bottom-full left-4",
110
+ before: "before:bottom-0 before:left-0",
111
+ after: "after:-bottom-px after:left-px"
112
+ },
113
+ center: {
114
+ wrapper: "bottom-full left-1/2 -translate-x-1/2",
115
+ before: "before:bottom-0 before:left-1/2 before:-translate-x-1/2",
116
+ after: "after:-bottom-px after:left-1/2 after:-translate-x-1/2"
117
+ },
118
+ end: {
119
+ wrapper: "bottom-full right-4",
120
+ before: "before:bottom-0 before:right-0",
121
+ after: "after:-bottom-px after:right-px"
122
+ }
123
+ },
124
+ left: {
125
+ start: {
126
+ wrapper: "left-full top-4",
127
+ before: "before:left-0 before:top-0",
128
+ after: "after:-left-px after:top-px"
129
+ },
130
+ center: {
131
+ wrapper: "left-full top-1/2 -translate-y-1/2",
132
+ before: "before:left-0 before:top-1/2 before:-translate-y-1/2",
133
+ after: "after:-left-px after:top-1/2 after:-translate-y-1/2"
134
+ },
135
+ end: {
136
+ wrapper: "left-full bottom-4",
137
+ before: "before:left-0 before:bottom-0",
138
+ after: "after:-left-px after:bottom-px"
139
+ }
140
+ },
141
+ right: {
142
+ start: {
143
+ wrapper: "right-full top-4",
144
+ before: "before:right-0 before:top-0",
145
+ after: "after:-right-px after:top-px"
146
+ },
147
+ center: {
148
+ wrapper: "right-full top-1/2 -translate-y-1/2",
149
+ before: "before:right-0 before:top-1/2 before:-translate-y-1/2",
150
+ after: "after:-right-px after:top-1/2 after:-translate-y-1/2"
151
+ },
152
+ end: {
153
+ wrapper: "right-full bottom-4",
154
+ before: "before:right-0 before:bottom-0",
155
+ after: "after:-right-px after:bottom-px"
156
+ }
157
+ }
102
158
  };
103
159
  const getArrowClassName = (side, align) => {
104
- const axis = offsetAxisBySide[side];
105
- const alignEdge = align === "start" ? startEdgeByAxis[axis] : align === "end" ? endEdgeByAxis[axis] : null;
106
- const positionAlign = alignEdge ? `${alignEdge}-4` : `${startEdgeByAxis[axis]}-1/2 -translate-${axis}-1/2`;
107
- const beforeAlign = alignEdge ? `before:${alignEdge}-0` : `before:${startEdgeByAxis[axis]}-1/2 before:-translate-${axis}-1/2`;
108
- const afterAlign = alignEdge ? `after:${alignEdge}-px` : `after:${startEdgeByAxis[axis]}-1/2 after:-translate-${axis}-1/2`;
109
- return cn(`absolute ${positionAlign} ${side}-full`, beforeBase, `before:${side}-0`, beforeAlign, borderShapeBySide[side], borderColorBySide[side], afterBase, `after:-${side}-px`, afterAlign, fillShapeBySide[side], fillColorBySide[side]);
160
+ const { wrapper, before, after } = POSITION_CLASSES[side][align];
161
+ return cn("absolute", wrapper, beforeBase, before, borderShapeBySide[side], borderColorBySide[side], afterBase, after, fillShapeBySide[side], fillColorBySide[side]);
110
162
  };
111
163
  const Popover = ({ title, placement = "top", className, content, children, open: _open, defaultOpen, onOpenChange, ...props }) => {
112
164
  const [open, setOpen] = useControllableState({
@@ -1 +1 @@
1
- {"version":3,"file":"popover.mjs","names":["popover"],"sources":["../../../src/components/atoms/popover.tsx"],"sourcesContent":["import { useControllableState } from '@jbpark/use-hooks';\n\nimport { popover } from '@repo/ui/core';\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Typography from './typography';\n\nconst { Popover: CorePopover, PopoverContent, PopoverTrigger } = popover;\n\ntype Placement =\n | 'top'\n | 'left'\n | 'right'\n | 'bottom'\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight'\n | 'leftTop'\n | 'leftBottom'\n | 'rightTop'\n | 'rightBottom';\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title' | 'content'\n> {\n title?: React.ReactNode;\n placement?: Placement;\n content: React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\n\nconst placementMap: Record<Placement, { side: Side; align: Align }> = {\n top: { side: 'top', align: 'center' },\n left: { side: 'left', align: 'center' },\n right: { side: 'right', align: 'center' },\n bottom: { side: 'bottom', align: 'center' },\n topLeft: { side: 'top', align: 'start' },\n topRight: { side: 'top', align: 'end' },\n bottomLeft: { side: 'bottom', align: 'start' },\n bottomRight: { side: 'bottom', align: 'end' },\n leftTop: { side: 'left', align: 'start' },\n leftBottom: { side: 'left', align: 'end' },\n rightTop: { side: 'right', align: 'start' },\n rightBottom: { side: 'right', align: 'end' },\n};\n\nconst beforeBase = 'before:content-[\"\"] before:absolute before:h-0 before:w-0';\nconst afterBase = 'after:content-[\"\"] after:absolute after:h-0 after:w-0';\n\nconst vBorderShape =\n 'before:border-l-[9px] before:border-r-[9px] before:border-l-transparent before:border-r-transparent';\nconst hBorderShape =\n 'before:border-t-[9px] before:border-b-[9px] before:border-t-transparent before:border-b-transparent';\nconst vFillShape =\n 'after:border-l-8 after:border-r-8 after:border-l-transparent after:border-r-transparent';\nconst hFillShape =\n 'after:border-t-8 after:border-b-8 after:border-t-transparent after:border-b-transparent';\n\n// Top/bottom placements draw a vertical-edge triangle (border-l/border-r) —\n// the arrow points up/down, so its left/right edges form the point. Left/\n// right placements draw the horizontal-edge equivalent.\nconst borderShapeBySide: Record<Side, string> = {\n top: vBorderShape,\n bottom: vBorderShape,\n left: hBorderShape,\n right: hBorderShape,\n};\nconst fillShapeBySide: Record<Side, string> = {\n top: vFillShape,\n bottom: vFillShape,\n left: hFillShape,\n right: hFillShape,\n};\nconst borderColorBySide: Record<Side, string> = {\n top: 'before:border-t-[9px] before:border-t-border',\n bottom: 'before:border-b-[9px] before:border-b-border',\n left: 'before:border-l-[9px] before:border-l-border',\n right: 'before:border-r-[9px] before:border-r-border',\n};\nconst fillColorBySide: Record<Side, string> = {\n top: 'after:border-t-8 after:border-t-popover',\n bottom: 'after:border-b-8 after:border-b-popover',\n left: 'after:border-l-8 after:border-l-popover',\n right: 'after:border-r-8 after:border-r-popover',\n};\n\n// `side` picks which edge of the content the arrow sits against; `align`\n// slides it along that edge. The offset axis (x for top/bottom, y for\n// left/right) is perpendicular to `side` — `align: 'center'` centers the\n// arrow with a translate, while `start`/`end` pin it 16px from that edge.\nconst offsetAxisBySide: Record<Side, 'x' | 'y'> = {\n top: 'x',\n bottom: 'x',\n left: 'y',\n right: 'y',\n};\nconst startEdgeByAxis = { x: 'left', y: 'top' } as const;\nconst endEdgeByAxis = { x: 'right', y: 'bottom' } as const;\n\nconst getArrowClassName = (side: Side, align: Align) => {\n const axis = offsetAxisBySide[side];\n const alignEdge =\n align === 'start'\n ? startEdgeByAxis[axis]\n : align === 'end'\n ? endEdgeByAxis[axis]\n : null;\n\n const positionAlign = alignEdge\n ? `${alignEdge}-4`\n : `${startEdgeByAxis[axis]}-1/2 -translate-${axis}-1/2`;\n const beforeAlign = alignEdge\n ? `before:${alignEdge}-0`\n : `before:${startEdgeByAxis[axis]}-1/2 before:-translate-${axis}-1/2`;\n const afterAlign = alignEdge\n ? `after:${alignEdge}-px`\n : `after:${startEdgeByAxis[axis]}-1/2 after:-translate-${axis}-1/2`;\n\n return cn(\n `absolute ${positionAlign} ${side}-full`,\n beforeBase,\n `before:${side}-0`,\n beforeAlign,\n borderShapeBySide[side],\n borderColorBySide[side],\n afterBase,\n `after:-${side}-px`,\n afterAlign,\n fillShapeBySide[side],\n fillColorBySide[side],\n );\n};\n\nconst Popover = ({\n title,\n placement = 'top',\n className,\n content,\n children,\n open: _open,\n defaultOpen,\n onOpenChange,\n ...props\n}: Props) => {\n const [open, setOpen] = useControllableState<boolean>({\n value: _open,\n defaultValue: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n const { side, align } = placementMap[placement];\n\n return (\n <CorePopover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n {...props}\n align={align}\n side={side}\n sideOffset={16}\n className={cn('relative w-auto', className)}\n >\n {renderConditional(title, v => (\n <Typography.Title level={6}>{v}</Typography.Title>\n ))}\n {content}\n <div className={getArrowClassName(side, align)} />\n </PopoverContent>\n </CorePopover>\n );\n};\n\nexport default Popover;\n"],"mappings":";;;;;;;AAOA,MAAM,EAAE,SAAS,aAAa,gBAAgB,mBAAmBA;AA+BjE,MAAM,eAAgE;CACpE,KAAK;EAAE,MAAM;EAAO,OAAO;EAAU;CACrC,MAAM;EAAE,MAAM;EAAQ,OAAO;EAAU;CACvC,OAAO;EAAE,MAAM;EAAS,OAAO;EAAU;CACzC,QAAQ;EAAE,MAAM;EAAU,OAAO;EAAU;CAC3C,SAAS;EAAE,MAAM;EAAO,OAAO;EAAS;CACxC,UAAU;EAAE,MAAM;EAAO,OAAO;EAAO;CACvC,YAAY;EAAE,MAAM;EAAU,OAAO;EAAS;CAC9C,aAAa;EAAE,MAAM;EAAU,OAAO;EAAO;CAC7C,SAAS;EAAE,MAAM;EAAQ,OAAO;EAAS;CACzC,YAAY;EAAE,MAAM;EAAQ,OAAO;EAAO;CAC1C,UAAU;EAAE,MAAM;EAAS,OAAO;EAAS;CAC3C,aAAa;EAAE,MAAM;EAAS,OAAO;EAAO;CAC7C;AAED,MAAM,aAAa;AACnB,MAAM,YAAY;AAElB,MAAM,eACJ;AACF,MAAM,eACJ;AACF,MAAM,aACJ;AACF,MAAM,aACJ;AAKF,MAAM,oBAA0C;CAC9C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AACD,MAAM,kBAAwC;CAC5C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AACD,MAAM,oBAA0C;CAC9C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AACD,MAAM,kBAAwC;CAC5C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AAMD,MAAM,mBAA4C;CAChD,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AACD,MAAM,kBAAkB;CAAE,GAAG;CAAQ,GAAG;CAAO;AAC/C,MAAM,gBAAgB;CAAE,GAAG;CAAS,GAAG;CAAU;AAEjD,MAAM,qBAAqB,MAAY,UAAiB;CACtD,MAAM,OAAO,iBAAiB;CAC9B,MAAM,YACJ,UAAU,UACN,gBAAgB,QAChB,UAAU,QACR,cAAc,QACd;CAER,MAAM,gBAAgB,YAClB,GAAG,UAAU,MACb,GAAG,gBAAgB,MAAM,kBAAkB,KAAK;CACpD,MAAM,cAAc,YAChB,UAAU,UAAU,MACpB,UAAU,gBAAgB,MAAM,yBAAyB,KAAK;CAClE,MAAM,aAAa,YACf,SAAS,UAAU,OACnB,SAAS,gBAAgB,MAAM,wBAAwB,KAAK;AAEhE,QAAO,GACL,YAAY,cAAc,GAAG,KAAK,QAClC,YACA,UAAU,KAAK,KACf,aACA,kBAAkB,OAClB,kBAAkB,OAClB,WACA,UAAU,KAAK,MACf,YACA,gBAAgB,OAChB,gBAAgB,MACjB;;AAGH,MAAM,WAAW,EACf,OACA,YAAY,OACZ,WACA,SACA,UACA,MAAM,OACN,aACA,cACA,GAAG,YACQ;CACX,MAAM,CAAC,MAAM,WAAW,qBAA8B;EACpD,OAAO;EACP,cAAc,eAAe;EAC7B,UAAU;EACX,CAAC;CAEF,MAAM,EAAE,MAAM,UAAU,aAAa;AAErC,QACE,qBAAC;EAAkB;EAAM,cAAc;aACrC,oBAAC;GAAe;GAAS;IAA0B,EACnD,qBAAC;GACC,GAAI;GACG;GACD;GACN,YAAY;GACZ,WAAW,GAAG,mBAAmB,UAAU;;IAE1C,kBAAkB,QAAO,MACxB,oBAAC,WAAW;KAAM,OAAO;eAAI;MAAqB,CAClD;IACD;IACD,oBAAC,SAAI,WAAW,kBAAkB,MAAM,MAAM,GAAI;;IACnC;GACL"}
1
+ {"version":3,"file":"popover.mjs","names":["popover"],"sources":["../../../src/components/atoms/popover.tsx"],"sourcesContent":["import { useControllableState } from '@jbpark/use-hooks';\n\nimport { popover } from '@repo/ui/core';\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Typography from './typography';\n\nconst { Popover: CorePopover, PopoverContent, PopoverTrigger } = popover;\n\ntype Placement =\n | 'top'\n | 'left'\n | 'right'\n | 'bottom'\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight'\n | 'leftTop'\n | 'leftBottom'\n | 'rightTop'\n | 'rightBottom';\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title' | 'content'\n> {\n title?: React.ReactNode;\n placement?: Placement;\n content: React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\n\nconst placementMap: Record<Placement, { side: Side; align: Align }> = {\n top: { side: 'top', align: 'center' },\n left: { side: 'left', align: 'center' },\n right: { side: 'right', align: 'center' },\n bottom: { side: 'bottom', align: 'center' },\n topLeft: { side: 'top', align: 'start' },\n topRight: { side: 'top', align: 'end' },\n bottomLeft: { side: 'bottom', align: 'start' },\n bottomRight: { side: 'bottom', align: 'end' },\n leftTop: { side: 'left', align: 'start' },\n leftBottom: { side: 'left', align: 'end' },\n rightTop: { side: 'right', align: 'start' },\n rightBottom: { side: 'right', align: 'end' },\n};\n\nconst beforeBase = 'before:content-[\"\"] before:absolute before:h-0 before:w-0';\nconst afterBase = 'after:content-[\"\"] after:absolute after:h-0 after:w-0';\n\nconst vBorderShape =\n 'before:border-l-[9px] before:border-r-[9px] before:border-l-transparent before:border-r-transparent';\nconst hBorderShape =\n 'before:border-t-[9px] before:border-b-[9px] before:border-t-transparent before:border-b-transparent';\nconst vFillShape =\n 'after:border-l-8 after:border-r-8 after:border-l-transparent after:border-r-transparent';\nconst hFillShape =\n 'after:border-t-8 after:border-b-8 after:border-t-transparent after:border-b-transparent';\n\n// Top/bottom placements draw a vertical-edge triangle (border-l/border-r) —\n// the arrow points up/down, so its left/right edges form the point. Left/\n// right placements draw the horizontal-edge equivalent.\nconst borderShapeBySide: Record<Side, string> = {\n top: vBorderShape,\n bottom: vBorderShape,\n left: hBorderShape,\n right: hBorderShape,\n};\nconst fillShapeBySide: Record<Side, string> = {\n top: vFillShape,\n bottom: vFillShape,\n left: hFillShape,\n right: hFillShape,\n};\nconst borderColorBySide: Record<Side, string> = {\n top: 'before:border-t-[9px] before:border-t-border',\n bottom: 'before:border-b-[9px] before:border-b-border',\n left: 'before:border-l-[9px] before:border-l-border',\n right: 'before:border-r-[9px] before:border-r-border',\n};\nconst fillColorBySide: Record<Side, string> = {\n top: 'after:border-t-8 after:border-t-popover',\n bottom: 'after:border-b-8 after:border-b-popover',\n left: 'after:border-l-8 after:border-l-popover',\n right: 'after:border-r-8 after:border-r-popover',\n};\n\n// Tailwind v4 only extracts class candidates that appear as *literal*\n// strings in source — none of these ever do if built via\n// `` `${side}-full` `` style interpolation, so they'd silently never make\n// it into the generated CSS. This table exists purely so every class the\n// arrow can need appears literally somewhere in this file.\nconst POSITION_CLASSES: Record<\n Side,\n Record<Align, { wrapper: string; before: string; after: string }>\n> = {\n top: {\n start: {\n wrapper: 'top-full left-4',\n before: 'before:top-0 before:left-0',\n after: 'after:-top-px after:left-px',\n },\n center: {\n wrapper: 'top-full left-1/2 -translate-x-1/2',\n before: 'before:top-0 before:left-1/2 before:-translate-x-1/2',\n after: 'after:-top-px after:left-1/2 after:-translate-x-1/2',\n },\n end: {\n wrapper: 'top-full right-4',\n before: 'before:top-0 before:right-0',\n after: 'after:-top-px after:right-px',\n },\n },\n bottom: {\n start: {\n wrapper: 'bottom-full left-4',\n before: 'before:bottom-0 before:left-0',\n after: 'after:-bottom-px after:left-px',\n },\n center: {\n wrapper: 'bottom-full left-1/2 -translate-x-1/2',\n before: 'before:bottom-0 before:left-1/2 before:-translate-x-1/2',\n after: 'after:-bottom-px after:left-1/2 after:-translate-x-1/2',\n },\n end: {\n wrapper: 'bottom-full right-4',\n before: 'before:bottom-0 before:right-0',\n after: 'after:-bottom-px after:right-px',\n },\n },\n left: {\n start: {\n wrapper: 'left-full top-4',\n before: 'before:left-0 before:top-0',\n after: 'after:-left-px after:top-px',\n },\n center: {\n wrapper: 'left-full top-1/2 -translate-y-1/2',\n before: 'before:left-0 before:top-1/2 before:-translate-y-1/2',\n after: 'after:-left-px after:top-1/2 after:-translate-y-1/2',\n },\n end: {\n wrapper: 'left-full bottom-4',\n before: 'before:left-0 before:bottom-0',\n after: 'after:-left-px after:bottom-px',\n },\n },\n right: {\n start: {\n wrapper: 'right-full top-4',\n before: 'before:right-0 before:top-0',\n after: 'after:-right-px after:top-px',\n },\n center: {\n wrapper: 'right-full top-1/2 -translate-y-1/2',\n before: 'before:right-0 before:top-1/2 before:-translate-y-1/2',\n after: 'after:-right-px after:top-1/2 after:-translate-y-1/2',\n },\n end: {\n wrapper: 'right-full bottom-4',\n before: 'before:right-0 before:bottom-0',\n after: 'after:-right-px after:bottom-px',\n },\n },\n};\n\nconst getArrowClassName = (side: Side, align: Align) => {\n const { wrapper, before, after } = POSITION_CLASSES[side][align];\n\n return cn(\n 'absolute',\n wrapper,\n beforeBase,\n before,\n borderShapeBySide[side],\n borderColorBySide[side],\n afterBase,\n after,\n fillShapeBySide[side],\n fillColorBySide[side],\n );\n};\n\nconst Popover = ({\n title,\n placement = 'top',\n className,\n content,\n children,\n open: _open,\n defaultOpen,\n onOpenChange,\n ...props\n}: Props) => {\n const [open, setOpen] = useControllableState<boolean>({\n value: _open,\n defaultValue: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n const { side, align } = placementMap[placement];\n\n return (\n <CorePopover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n {...props}\n align={align}\n side={side}\n sideOffset={16}\n className={cn('relative w-auto', className)}\n >\n {renderConditional(title, v => (\n <Typography.Title level={6}>{v}</Typography.Title>\n ))}\n {content}\n <div className={getArrowClassName(side, align)} />\n </PopoverContent>\n </CorePopover>\n );\n};\n\nexport default Popover;\n"],"mappings":";;;;;;;AAOA,MAAM,EAAE,SAAS,aAAa,gBAAgB,mBAAmBA;AA+BjE,MAAM,eAAgE;CACpE,KAAK;EAAE,MAAM;EAAO,OAAO;EAAU;CACrC,MAAM;EAAE,MAAM;EAAQ,OAAO;EAAU;CACvC,OAAO;EAAE,MAAM;EAAS,OAAO;EAAU;CACzC,QAAQ;EAAE,MAAM;EAAU,OAAO;EAAU;CAC3C,SAAS;EAAE,MAAM;EAAO,OAAO;EAAS;CACxC,UAAU;EAAE,MAAM;EAAO,OAAO;EAAO;CACvC,YAAY;EAAE,MAAM;EAAU,OAAO;EAAS;CAC9C,aAAa;EAAE,MAAM;EAAU,OAAO;EAAO;CAC7C,SAAS;EAAE,MAAM;EAAQ,OAAO;EAAS;CACzC,YAAY;EAAE,MAAM;EAAQ,OAAO;EAAO;CAC1C,UAAU;EAAE,MAAM;EAAS,OAAO;EAAS;CAC3C,aAAa;EAAE,MAAM;EAAS,OAAO;EAAO;CAC7C;AAED,MAAM,aAAa;AACnB,MAAM,YAAY;AAElB,MAAM,eACJ;AACF,MAAM,eACJ;AACF,MAAM,aACJ;AACF,MAAM,aACJ;AAKF,MAAM,oBAA0C;CAC9C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AACD,MAAM,kBAAwC;CAC5C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AACD,MAAM,oBAA0C;CAC9C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AACD,MAAM,kBAAwC;CAC5C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AAOD,MAAM,mBAGF;CACF,KAAK;EACH,OAAO;GACL,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,QAAQ;GACN,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,KAAK;GACH,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACF;CACD,QAAQ;EACN,OAAO;GACL,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,QAAQ;GACN,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,KAAK;GACH,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACF;CACD,MAAM;EACJ,OAAO;GACL,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,QAAQ;GACN,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,KAAK;GACH,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACF;CACD,OAAO;EACL,OAAO;GACL,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,QAAQ;GACN,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACD,KAAK;GACH,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACF;CACF;AAED,MAAM,qBAAqB,MAAY,UAAiB;CACtD,MAAM,EAAE,SAAS,QAAQ,UAAU,iBAAiB,MAAM;AAE1D,QAAO,GACL,YACA,SACA,YACA,QACA,kBAAkB,OAClB,kBAAkB,OAClB,WACA,OACA,gBAAgB,OAChB,gBAAgB,MACjB;;AAGH,MAAM,WAAW,EACf,OACA,YAAY,OACZ,WACA,SACA,UACA,MAAM,OACN,aACA,cACA,GAAG,YACQ;CACX,MAAM,CAAC,MAAM,WAAW,qBAA8B;EACpD,OAAO;EACP,cAAc,eAAe;EAC7B,UAAU;EACX,CAAC;CAEF,MAAM,EAAE,MAAM,UAAU,aAAa;AAErC,QACE,qBAAC;EAAkB;EAAM,cAAc;aACrC,oBAAC;GAAe;GAAS;IAA0B,EACnD,qBAAC;GACC,GAAI;GACG;GACD;GACN,YAAY;GACZ,WAAW,GAAG,mBAAmB,UAAU;;IAE1C,kBAAkB,QAAO,MACxB,oBAAC,WAAW;KAAM,OAAO;eAAI;MAAqB,CAClD;IACD;IACD,oBAAC,SAAI,WAAW,kBAAkB,MAAM,MAAM,GAAI;;IACnC;GACL"}
@@ -3,7 +3,7 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/atoms/skeleton/button.d.ts
5
5
  declare const Button: ({
6
- className,
6
+ classNames,
7
7
  ...props
8
8
  }: Props) => react_jsx_runtime0.JSX.Element;
9
9
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"mappings":";;;;cAIM,MAAA;EAAU,SAAA;EAAA,GAAA;AAAA,GAAyB,KAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"button.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"mappings":";;;;cAIM,MAAA;EAAU,UAAA;EAAA,GAAA;AAAA,GAA0B,KAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -3,10 +3,13 @@ import Skeleton from "./skeleton.mjs";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
 
5
5
  //#region src/components/atoms/skeleton/button.tsx
6
- const Button = ({ className, ...props }) => {
6
+ const Button = ({ classNames, ...props }) => {
7
7
  return /* @__PURE__ */ jsx(Skeleton, {
8
8
  ...props,
9
- className: cn("h-9 w-15", "rounded-2xl", className)
9
+ classNames: {
10
+ ...classNames,
11
+ item: cn("h-9 w-15", "rounded-2xl", classNames?.item)
12
+ }
10
13
  });
11
14
  };
12
15
 
@@ -1 +1 @@
1
- {"version":3,"file":"button.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Button = ({ className, ...props }: SkeletonProps) => {\n return (\n <Skeleton\n {...props}\n className={cn(\n 'h-9 w-15',\n 'rounded-2xl',\n className,\n //\n )}\n />\n );\n};\nexport default Button;\n"],"mappings":";;;;;AAIA,MAAM,UAAU,EAAE,WAAW,GAAG,YAA2B;AACzD,QACE,oBAAC;EACC,GAAI;EACJ,WAAW,GACT,YACA,eACA,UAED;GACD"}
1
+ {"version":3,"file":"button.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Button = ({ classNames, ...props }: SkeletonProps) => {\n return (\n <Skeleton\n {...props}\n classNames={{\n ...classNames,\n item: cn(\n 'h-9 w-15',\n 'rounded-2xl',\n classNames?.item,\n //\n ),\n }}\n />\n );\n};\nexport default Button;\n"],"mappings":";;;;;AAIA,MAAM,UAAU,EAAE,YAAY,GAAG,YAA2B;AAC1D,QACE,oBAAC;EACC,GAAI;EACJ,YAAY;GACV,GAAG;GACH,MAAM,GACJ,YACA,eACA,YAAY,KAEb;GACF;GACD"}
@@ -3,7 +3,7 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/atoms/skeleton/node.d.ts
5
5
  declare const Node: ({
6
- className,
6
+ classNames,
7
7
  ...props
8
8
  }: Props) => react_jsx_runtime0.JSX.Element;
9
9
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"mappings":";;;;cAIM,IAAA;EAAQ,SAAA;EAAA,GAAA;AAAA,GAAyB,KAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"node.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"mappings":";;;;cAIM,IAAA;EAAQ,UAAA;EAAA,GAAA;AAAA,GAA0B,KAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -3,11 +3,14 @@ import Skeleton from "./skeleton.mjs";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
 
5
5
  //#region src/components/atoms/skeleton/node.tsx
6
- const Node = ({ className, ...props }) => {
6
+ const Node = ({ classNames, ...props }) => {
7
7
  return /* @__PURE__ */ jsx(Skeleton, {
8
8
  ...props,
9
9
  avatar: false,
10
- className: cn("h-50 w-full min-w-80", "rounded-3xl", className)
10
+ classNames: {
11
+ ...classNames,
12
+ item: cn("h-50 w-full min-w-80", "rounded-3xl", classNames?.item)
13
+ }
11
14
  });
12
15
  };
13
16
 
@@ -1 +1 @@
1
- {"version":3,"file":"node.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Node = ({ className, ...props }: SkeletonProps) => {\n return (\n <Skeleton\n {...props}\n avatar={false}\n className={cn(\n 'h-50 w-full min-w-80',\n 'rounded-3xl',\n className,\n //\n )}\n />\n );\n};\nexport default Node;\n"],"mappings":";;;;;AAIA,MAAM,QAAQ,EAAE,WAAW,GAAG,YAA2B;AACvD,QACE,oBAAC;EACC,GAAI;EACJ,QAAQ;EACR,WAAW,GACT,wBACA,eACA,UAED;GACD"}
1
+ {"version":3,"file":"node.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Node = ({ classNames, ...props }: SkeletonProps) => {\n return (\n <Skeleton\n {...props}\n avatar={false}\n classNames={{\n ...classNames,\n item: cn(\n 'h-50 w-full min-w-80',\n 'rounded-3xl',\n classNames?.item,\n //\n ),\n }}\n />\n );\n};\nexport default Node;\n"],"mappings":";;;;;AAIA,MAAM,QAAQ,EAAE,YAAY,GAAG,YAA2B;AACxD,QACE,oBAAC;EACC,GAAI;EACJ,QAAQ;EACR,YAAY;GACV,GAAG;GACH,MAAM,GACJ,wBACA,eACA,YAAY,KAEb;GACF;GACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"item.d.mts","names":[],"sources":["../../../../src/components/molecules/marquees/item.tsx"],"mappings":";;;UAOiB,SAAA;EACf,GAAA,GAAM,KAAA,CAAM,GAAA;EACZ,KAAA;EACA,QAAA;EACA,KAAA;EACA,YAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;AAAA;AAAA,UAGF,KAAA,SACP,IAAA,CAAK,KAAA,CAAM,wBAAA,iBAAyC,SAAA;EAC5D,KAAA;AAAA;AAAA,cAGI,IAAA;EAAQ,KAAA,EAAA,MAAA;EAAA,KAAA;EAAA,QAAA;EAAA,KAAA,EAAA,MAAA;EAAA,YAAA;EAAA;AAAA,GAOX,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"item.d.mts","names":[],"sources":["../../../../src/components/molecules/marquees/item.tsx"],"mappings":";;;UAQiB,SAAA;EACf,GAAA,GAAM,KAAA,CAAM,GAAA;EACZ,KAAA;EACA,QAAA;EACA,KAAA;EACA,YAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;AAAA;AAAA,UAGF,KAAA,SACP,IAAA,CAAK,KAAA,CAAM,wBAAA,iBAAyC,SAAA;EAC5D,KAAA;AAAA;AAAA,cAGI,IAAA;EAAQ,KAAA,EAAA,MAAA;EAAA,KAAA;EAAA,QAAA;EAAA,KAAA,EAAA,MAAA;EAAA,YAAA;EAAA;AAAA,GAOX,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useEffect, useRef, useState } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { useEventListener } from "@jbpark/use-hooks";
5
6
  import { useGSAP } from "@gsap/react";
6
7
  import { gsap } from "gsap";
7
8
 
@@ -70,17 +71,11 @@ const Item = ({ width: _width, speed = 100, autoFill = false, pause: _pause = fa
70
71
  useEffect(() => {
71
72
  setRepeatCount(autoFill ? typeof autoFill === "boolean" ? 100 : autoFill : 0);
72
73
  }, [autoFill]);
73
- useEffect(() => {
74
- const onResize = () => {
75
- if (!tweenRef.current || !containerRef.current) return;
76
- if (isPaused) tweenRef.current.pause();
77
- else tweenRef.current.play();
78
- };
79
- window.addEventListener("resize", onResize);
80
- return () => {
81
- window.removeEventListener("resize", onResize);
82
- };
83
- }, [isPaused]);
74
+ useEventListener("resize", () => {
75
+ if (!tweenRef.current || !containerRef.current) return;
76
+ if (isPaused) tweenRef.current.pause();
77
+ else tweenRef.current.play();
78
+ });
84
79
  return /* @__PURE__ */ jsx("div", {
85
80
  className: "flex overflow-hidden",
86
81
  ...hoverEvents,
@@ -1 +1 @@
1
- {"version":3,"file":"item.mjs","names":[],"sources":["../../../../src/components/molecules/marquees/item.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\nimport { useGSAP } from '@gsap/react';\nimport { gsap } from 'gsap';\n\nexport interface ItemProps {\n key?: React.Key;\n speed?: number;\n autoFill?: boolean | number;\n pause?: boolean;\n pauseOnHover?: boolean;\n children?: React.ReactNode;\n}\n\nexport interface Props\n extends Omit<React.ComponentPropsWithoutRef<'div'>, 'key'>, ItemProps {\n width: string | number;\n}\n\nconst Item = ({\n width: _width,\n speed = 100,\n autoFill = false,\n pause: _pause = false,\n pauseOnHover = false,\n children,\n}: Props) => {\n const itemRefs = useRef<HTMLDivElement[]>([]);\n const containerRef = useRef<HTMLDivElement>(null);\n const tweenRef = useRef<gsap.core.Tween | null>(null);\n\n const [width, setWidth] = useState<string | number>(_width);\n const [pause, setPause] = useState(false);\n const [repeatCount, setRepeatCount] = useState(\n autoFill ? (typeof autoFill === 'boolean' ? 100 : autoFill) : 0,\n );\n\n const isPaused = _pause || pause;\n\n const hoverEvents = pauseOnHover\n ? {\n onMouseEnter: () => {\n setPause(true);\n },\n onMouseLeave: () => {\n setPause(false);\n },\n }\n : {};\n\n useEffect(() => {\n if (\n !autoFill ||\n !children ||\n !itemRefs.current[0] ||\n typeof width === 'string'\n ) {\n return;\n }\n\n const itemWidth = itemRefs.current[0].offsetWidth;\n\n if (itemWidth >= width) {\n setWidth(itemWidth);\n setRepeatCount(0);\n return;\n }\n\n let totalWidth = 0;\n let repeatCount = 0;\n\n while (totalWidth < width) {\n totalWidth += itemWidth;\n repeatCount += 1;\n }\n\n setWidth(totalWidth);\n setRepeatCount(repeatCount - 1);\n }, [autoFill, width, children]);\n\n useEffect(() => {\n setWidth(_width);\n }, [_width]);\n\n useGSAP(\n () => {\n if (!containerRef.current || typeof width === 'string') {\n return;\n }\n\n if (tweenRef.current) {\n tweenRef.current.kill();\n }\n\n tweenRef.current = gsap.fromTo(\n containerRef.current,\n { x: 0 },\n {\n x: -width,\n duration: width / speed,\n repeat: -1,\n ease: 'linear',\n },\n );\n\n return () => {\n tweenRef.current?.kill();\n };\n },\n {\n scope: containerRef,\n dependencies: [width, speed],\n },\n );\n\n useEffect(() => {\n if (!tweenRef.current) {\n return;\n }\n\n if (isPaused) {\n tweenRef.current.pause();\n } else {\n tweenRef.current.play();\n }\n }, [isPaused]);\n\n useEffect(() => {\n setRepeatCount(\n autoFill ? (typeof autoFill === 'boolean' ? 100 : autoFill) : 0,\n );\n }, [autoFill]);\n\n useEffect(() => {\n const onResize = () => {\n if (!tweenRef.current || !containerRef.current) {\n return;\n }\n\n if (isPaused) {\n tweenRef.current.pause();\n } else {\n tweenRef.current.play();\n }\n };\n\n window.addEventListener('resize', onResize);\n\n return () => {\n window.removeEventListener('resize', onResize);\n };\n }, [isPaused]);\n\n return (\n <div\n className=\"flex overflow-hidden\"\n {...hoverEvents}\n //\n >\n <div ref={containerRef} className=\"flex flex-nowrap\">\n {[...Array(2)].map((_, index) => (\n <div\n key={index}\n style={{ minWidth: width }}\n className=\"flex flex-nowrap\"\n >\n <div\n ref={el => {\n if (el) {\n itemRefs.current[index] = el;\n }\n }}\n >\n {children}\n </div>\n {[\n ...Array(typeof autoFill === 'number' ? autoFill : repeatCount),\n ].map((_, i) => (\n <div key={i}>{children}</div>\n ))}\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default Item;\n"],"mappings":";;;;;;;;AAqBA,MAAM,QAAQ,EACZ,OAAO,QACP,QAAQ,KACR,WAAW,OACX,OAAO,SAAS,OAChB,eAAe,OACf,eACW;CACX,MAAM,WAAW,OAAyB,EAAE,CAAC;CAC7C,MAAM,eAAe,OAAuB,KAAK;CACjD,MAAM,WAAW,OAA+B,KAAK;CAErD,MAAM,CAAC,OAAO,YAAY,SAA0B,OAAO;CAC3D,MAAM,CAAC,OAAO,YAAY,SAAS,MAAM;CACzC,MAAM,CAAC,aAAa,kBAAkB,SACpC,WAAY,OAAO,aAAa,YAAY,MAAM,WAAY,EAC/D;CAED,MAAM,WAAW,UAAU;CAE3B,MAAM,cAAc,eAChB;EACE,oBAAoB;AAClB,YAAS,KAAK;;EAEhB,oBAAoB;AAClB,YAAS,MAAM;;EAElB,GACD,EAAE;AAEN,iBAAgB;AACd,MACE,CAAC,YACD,CAAC,YACD,CAAC,SAAS,QAAQ,MAClB,OAAO,UAAU,SAEjB;EAGF,MAAM,YAAY,SAAS,QAAQ,GAAG;AAEtC,MAAI,aAAa,OAAO;AACtB,YAAS,UAAU;AACnB,kBAAe,EAAE;AACjB;;EAGF,IAAI,aAAa;EACjB,IAAI,cAAc;AAElB,SAAO,aAAa,OAAO;AACzB,iBAAc;AACd,kBAAe;;AAGjB,WAAS,WAAW;AACpB,iBAAe,cAAc,EAAE;IAC9B;EAAC;EAAU;EAAO;EAAS,CAAC;AAE/B,iBAAgB;AACd,WAAS,OAAO;IACf,CAAC,OAAO,CAAC;AAEZ,eACQ;AACJ,MAAI,CAAC,aAAa,WAAW,OAAO,UAAU,SAC5C;AAGF,MAAI,SAAS,QACX,UAAS,QAAQ,MAAM;AAGzB,WAAS,UAAU,KAAK,OACtB,aAAa,SACb,EAAE,GAAG,GAAG,EACR;GACE,GAAG,CAAC;GACJ,UAAU,QAAQ;GAClB,QAAQ;GACR,MAAM;GACP,CACF;AAED,eAAa;AACX,YAAS,SAAS,MAAM;;IAG5B;EACE,OAAO;EACP,cAAc,CAAC,OAAO,MAAM;EAC7B,CACF;AAED,iBAAgB;AACd,MAAI,CAAC,SAAS,QACZ;AAGF,MAAI,SACF,UAAS,QAAQ,OAAO;MAExB,UAAS,QAAQ,MAAM;IAExB,CAAC,SAAS,CAAC;AAEd,iBAAgB;AACd,iBACE,WAAY,OAAO,aAAa,YAAY,MAAM,WAAY,EAC/D;IACA,CAAC,SAAS,CAAC;AAEd,iBAAgB;EACd,MAAM,iBAAiB;AACrB,OAAI,CAAC,SAAS,WAAW,CAAC,aAAa,QACrC;AAGF,OAAI,SACF,UAAS,QAAQ,OAAO;OAExB,UAAS,QAAQ,MAAM;;AAI3B,SAAO,iBAAiB,UAAU,SAAS;AAE3C,eAAa;AACX,UAAO,oBAAoB,UAAU,SAAS;;IAE/C,CAAC,SAAS,CAAC;AAEd,QACE,oBAAC;EACC,WAAU;EACV,GAAI;YAGJ,oBAAC;GAAI,KAAK;GAAc,WAAU;aAC/B,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,KAAK,GAAG,UACrB,qBAAC;IAEC,OAAO,EAAE,UAAU,OAAO;IAC1B,WAAU;eAEV,oBAAC;KACC,MAAK,OAAM;AACT,UAAI,GACF,UAAS,QAAQ,SAAS;;KAI7B;MACG,EACL,CACC,GAAG,MAAM,OAAO,aAAa,WAAW,WAAW,YAAY,CAChE,CAAC,KAAK,GAAG,MACR,oBAAC,SAAa,YAAJ,EAAmB,CAC7B;MAjBG,MAkBD,CACN;IACE;GACF"}
1
+ {"version":3,"file":"item.mjs","names":[],"sources":["../../../../src/components/molecules/marquees/item.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\nimport { useGSAP } from '@gsap/react';\nimport { useEventListener } from '@jbpark/use-hooks';\nimport { gsap } from 'gsap';\n\nexport interface ItemProps {\n key?: React.Key;\n speed?: number;\n autoFill?: boolean | number;\n pause?: boolean;\n pauseOnHover?: boolean;\n children?: React.ReactNode;\n}\n\nexport interface Props\n extends Omit<React.ComponentPropsWithoutRef<'div'>, 'key'>, ItemProps {\n width: string | number;\n}\n\nconst Item = ({\n width: _width,\n speed = 100,\n autoFill = false,\n pause: _pause = false,\n pauseOnHover = false,\n children,\n}: Props) => {\n const itemRefs = useRef<HTMLDivElement[]>([]);\n const containerRef = useRef<HTMLDivElement>(null);\n const tweenRef = useRef<gsap.core.Tween | null>(null);\n\n const [width, setWidth] = useState<string | number>(_width);\n const [pause, setPause] = useState(false);\n const [repeatCount, setRepeatCount] = useState(\n autoFill ? (typeof autoFill === 'boolean' ? 100 : autoFill) : 0,\n );\n\n const isPaused = _pause || pause;\n\n const hoverEvents = pauseOnHover\n ? {\n onMouseEnter: () => {\n setPause(true);\n },\n onMouseLeave: () => {\n setPause(false);\n },\n }\n : {};\n\n useEffect(() => {\n if (\n !autoFill ||\n !children ||\n !itemRefs.current[0] ||\n typeof width === 'string'\n ) {\n return;\n }\n\n const itemWidth = itemRefs.current[0].offsetWidth;\n\n if (itemWidth >= width) {\n setWidth(itemWidth);\n setRepeatCount(0);\n return;\n }\n\n let totalWidth = 0;\n let repeatCount = 0;\n\n while (totalWidth < width) {\n totalWidth += itemWidth;\n repeatCount += 1;\n }\n\n setWidth(totalWidth);\n setRepeatCount(repeatCount - 1);\n }, [autoFill, width, children]);\n\n useEffect(() => {\n setWidth(_width);\n }, [_width]);\n\n useGSAP(\n () => {\n if (!containerRef.current || typeof width === 'string') {\n return;\n }\n\n if (tweenRef.current) {\n tweenRef.current.kill();\n }\n\n tweenRef.current = gsap.fromTo(\n containerRef.current,\n { x: 0 },\n {\n x: -width,\n duration: width / speed,\n repeat: -1,\n ease: 'linear',\n },\n );\n\n return () => {\n tweenRef.current?.kill();\n };\n },\n {\n scope: containerRef,\n dependencies: [width, speed],\n },\n );\n\n useEffect(() => {\n if (!tweenRef.current) {\n return;\n }\n\n if (isPaused) {\n tweenRef.current.pause();\n } else {\n tweenRef.current.play();\n }\n }, [isPaused]);\n\n useEffect(() => {\n setRepeatCount(\n autoFill ? (typeof autoFill === 'boolean' ? 100 : autoFill) : 0,\n );\n }, [autoFill]);\n\n useEventListener('resize', () => {\n if (!tweenRef.current || !containerRef.current) {\n return;\n }\n\n if (isPaused) {\n tweenRef.current.pause();\n } else {\n tweenRef.current.play();\n }\n });\n\n return (\n <div\n className=\"flex overflow-hidden\"\n {...hoverEvents}\n //\n >\n <div ref={containerRef} className=\"flex flex-nowrap\">\n {[...Array(2)].map((_, index) => (\n <div\n key={index}\n style={{ minWidth: width }}\n className=\"flex flex-nowrap\"\n >\n <div\n ref={el => {\n if (el) {\n itemRefs.current[index] = el;\n }\n }}\n >\n {children}\n </div>\n {[\n ...Array(typeof autoFill === 'number' ? autoFill : repeatCount),\n ].map((_, i) => (\n <div key={i}>{children}</div>\n ))}\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default Item;\n"],"mappings":";;;;;;;;;AAsBA,MAAM,QAAQ,EACZ,OAAO,QACP,QAAQ,KACR,WAAW,OACX,OAAO,SAAS,OAChB,eAAe,OACf,eACW;CACX,MAAM,WAAW,OAAyB,EAAE,CAAC;CAC7C,MAAM,eAAe,OAAuB,KAAK;CACjD,MAAM,WAAW,OAA+B,KAAK;CAErD,MAAM,CAAC,OAAO,YAAY,SAA0B,OAAO;CAC3D,MAAM,CAAC,OAAO,YAAY,SAAS,MAAM;CACzC,MAAM,CAAC,aAAa,kBAAkB,SACpC,WAAY,OAAO,aAAa,YAAY,MAAM,WAAY,EAC/D;CAED,MAAM,WAAW,UAAU;CAE3B,MAAM,cAAc,eAChB;EACE,oBAAoB;AAClB,YAAS,KAAK;;EAEhB,oBAAoB;AAClB,YAAS,MAAM;;EAElB,GACD,EAAE;AAEN,iBAAgB;AACd,MACE,CAAC,YACD,CAAC,YACD,CAAC,SAAS,QAAQ,MAClB,OAAO,UAAU,SAEjB;EAGF,MAAM,YAAY,SAAS,QAAQ,GAAG;AAEtC,MAAI,aAAa,OAAO;AACtB,YAAS,UAAU;AACnB,kBAAe,EAAE;AACjB;;EAGF,IAAI,aAAa;EACjB,IAAI,cAAc;AAElB,SAAO,aAAa,OAAO;AACzB,iBAAc;AACd,kBAAe;;AAGjB,WAAS,WAAW;AACpB,iBAAe,cAAc,EAAE;IAC9B;EAAC;EAAU;EAAO;EAAS,CAAC;AAE/B,iBAAgB;AACd,WAAS,OAAO;IACf,CAAC,OAAO,CAAC;AAEZ,eACQ;AACJ,MAAI,CAAC,aAAa,WAAW,OAAO,UAAU,SAC5C;AAGF,MAAI,SAAS,QACX,UAAS,QAAQ,MAAM;AAGzB,WAAS,UAAU,KAAK,OACtB,aAAa,SACb,EAAE,GAAG,GAAG,EACR;GACE,GAAG,CAAC;GACJ,UAAU,QAAQ;GAClB,QAAQ;GACR,MAAM;GACP,CACF;AAED,eAAa;AACX,YAAS,SAAS,MAAM;;IAG5B;EACE,OAAO;EACP,cAAc,CAAC,OAAO,MAAM;EAC7B,CACF;AAED,iBAAgB;AACd,MAAI,CAAC,SAAS,QACZ;AAGF,MAAI,SACF,UAAS,QAAQ,OAAO;MAExB,UAAS,QAAQ,MAAM;IAExB,CAAC,SAAS,CAAC;AAEd,iBAAgB;AACd,iBACE,WAAY,OAAO,aAAa,YAAY,MAAM,WAAY,EAC/D;IACA,CAAC,SAAS,CAAC;AAEd,kBAAiB,gBAAgB;AAC/B,MAAI,CAAC,SAAS,WAAW,CAAC,aAAa,QACrC;AAGF,MAAI,SACF,UAAS,QAAQ,OAAO;MAExB,UAAS,QAAQ,MAAM;GAEzB;AAEF,QACE,oBAAC;EACC,WAAU;EACV,GAAI;YAGJ,oBAAC;GAAI,KAAK;GAAc,WAAU;aAC/B,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,KAAK,GAAG,UACrB,qBAAC;IAEC,OAAO,EAAE,UAAU,OAAO;IAC1B,WAAU;eAEV,oBAAC;KACC,MAAK,OAAM;AACT,UAAI,GACF,UAAS,QAAQ,SAAS;;KAI7B;MACG,EACL,CACC,GAAG,MAAM,OAAO,aAAa,WAAW,WAAW,YAAY,CAChE,CAAC,KAAK,GAAG,MACR,oBAAC,SAAa,YAAJ,EAAmB,CAC7B;MAjBG,MAkBD,CACN;IACE;GACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.mts","names":[],"sources":["../../../src/components/molecules/upload.tsx"],"mappings":";;;UAWiB,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"}
1
+ {"version":3,"file":"upload.d.mts","names":[],"sources":["../../../src/components/molecules/upload.tsx"],"mappings":";;;UAeiB,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"}
@@ -3,25 +3,21 @@
3
3
  import { cn } from "../../utils.mjs";
4
4
  import Button from "../../Button.mjs";
5
5
  import { Upload, X } from "lucide-react";
6
- import { useId, useState } from "react";
6
+ import { useId } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
- import { useFileToDataUrl } from "@jbpark/use-hooks";
8
+ import { useControllableState, useFileDrop, useFileToDataUrl } from "@jbpark/use-hooks";
9
9
 
10
10
  //#region src/components/molecules/upload.tsx
11
11
  const isImage = (file) => /^data:image\//.test(file.url) || /\.(png|jpe?g|gif|webp|svg)$/i.test(file.name);
12
12
  const Upload$1 = ({ defaultValue = [], value: _value, multiple = true, accept = "image/*", maxCount, disabled, className, classNames, onChange: _onChange = () => {} }) => {
13
13
  const inputId = useId();
14
14
  const readAsDataUrl = useFileToDataUrl();
15
- const [isDragOver, setIsDragOver] = useState(false);
16
- const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
17
- const controlled = _value !== void 0;
18
- const files = controlled ? _value : uncontrolledValue;
19
- const onChange = (next) => {
20
- if (!controlled) setUncontrolledValue(next);
21
- _onChange(next);
22
- };
23
- const addFiles = async (fileList) => {
24
- const incoming = Array.from(fileList);
15
+ const [files, setFiles] = useControllableState({
16
+ value: _value,
17
+ defaultValue,
18
+ onChange: _onChange
19
+ });
20
+ const addFiles = async (incoming) => {
25
21
  const remaining = typeof maxCount === "number" ? Math.max(0, maxCount - files.length) : incoming.length;
26
22
  const accepted = incoming.slice(0, remaining);
27
23
  const uploaded = await Promise.all(accepted.map(async (file) => ({
@@ -29,27 +25,23 @@ const Upload$1 = ({ defaultValue = [], value: _value, multiple = true, accept =
29
25
  name: file.name,
30
26
  url: await readAsDataUrl(file)
31
27
  })));
32
- onChange([...files, ...uploaded]);
28
+ setFiles([...files, ...uploaded]);
33
29
  };
34
30
  const removeFile = (uid) => {
35
- onChange(files.filter((file) => file.uid !== uid));
31
+ setFiles(files.filter((file) => file.uid !== uid));
36
32
  };
33
+ const { dropRef, isDragging } = useFileDrop({
34
+ accept,
35
+ multiple,
36
+ disabled,
37
+ onDrop: addFiles
38
+ });
37
39
  return /* @__PURE__ */ jsxs("div", {
38
40
  className: cn("flex flex-col gap-3", className),
39
41
  children: [/* @__PURE__ */ jsxs("label", {
42
+ ref: dropRef,
40
43
  htmlFor: inputId,
41
- onDragOver: (e) => {
42
- e.preventDefault();
43
- if (!disabled) setIsDragOver(true);
44
- },
45
- onDragLeave: () => setIsDragOver(false),
46
- onDrop: (e) => {
47
- e.preventDefault();
48
- setIsDragOver(false);
49
- if (disabled) return;
50
- if (e.dataTransfer.files.length) addFiles(e.dataTransfer.files);
51
- },
52
- 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),
44
+ 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", isDragging && "border-primary bg-accent", disabled && "pointer-events-none cursor-not-allowed opacity-50", classNames?.dropzone),
53
45
  children: [
54
46
  /* @__PURE__ */ jsx(Upload, { className: "size-6" }),
55
47
  /* @__PURE__ */ jsxs("span", { children: [
@@ -65,7 +57,7 @@ const Upload$1 = ({ defaultValue = [], value: _value, multiple = true, accept =
65
57
  disabled,
66
58
  className: "hidden",
67
59
  onChange: (e) => {
68
- if (e.target.files?.length) addFiles(e.target.files);
60
+ if (e.target.files?.length) addFiles(Array.from(e.target.files));
69
61
  e.target.value = "";
70
62
  }
71
63
  })
@@ -1 +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\nimport Button from '../atoms/button';\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=\"text\"\n shape=\"circle\"\n size=\"small\"\n icon={<X className=\"size-4\" />}\n onClick={() => removeFile(file.uid)}\n className=\"text-muted-foreground hover:text-foreground shrink-0\"\n aria-label={`Remove ${file.name}`}\n />\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nexport default Upload;\n"],"mappings":";;;;;;;;;;AAiCA,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,OAAM;MACN,MAAK;MACL,MAAM,oBAAC,KAAE,WAAU,WAAW;MAC9B,eAAe,WAAW,KAAK,IAAI;MACnC,WAAU;MACV,cAAY,UAAU,KAAK;OAC3B;;MAvBG,KAAK,IAwBP,CACL;IACC;GAEH"}
1
+ {"version":3,"file":"upload.mjs","names":["Upload","UploadIcon"],"sources":["../../../src/components/molecules/upload.tsx"],"sourcesContent":["'use client';\n\nimport { useId } from 'react';\n\nimport {\n useControllableState,\n useFileDrop,\n useFileToDataUrl,\n} from '@jbpark/use-hooks';\nimport { Upload as UploadIcon, X } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\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 [files, setFiles] = useControllableState<UploadFile[]>({\n value: _value,\n defaultValue,\n onChange: _onChange,\n });\n\n const addFiles = async (incoming: File[]) => {\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 setFiles([...files, ...uploaded]);\n };\n\n const removeFile = (uid: string) => {\n setFiles(files.filter(file => file.uid !== uid));\n };\n\n const { dropRef, isDragging } = useFileDrop<HTMLLabelElement>({\n accept,\n multiple,\n disabled,\n onDrop: addFiles,\n });\n\n return (\n <div\n className={cn(\n 'flex flex-col gap-3',\n className,\n //\n )}\n >\n <label\n ref={dropRef}\n htmlFor={inputId}\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 isDragging && '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(Array.from(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=\"text\"\n shape=\"circle\"\n size=\"small\"\n icon={<X className=\"size-4\" />}\n onClick={() => removeFile(file.uid)}\n className=\"text-muted-foreground hover:text-foreground shrink-0\"\n aria-label={`Remove ${file.name}`}\n />\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nexport default Upload;\n"],"mappings":";;;;;;;;;;AAqCA,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,OAAO,YAAY,qBAAmC;EAC3D,OAAO;EACP;EACA,UAAU;EACX,CAAC;CAEF,MAAM,WAAW,OAAO,aAAqB;EAC3C,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;;CAGlD,MAAM,EAAE,SAAS,eAAe,YAA8B;EAC5D;EACA;EACA;EACA,QAAQ;EACT,CAAC;AAEF,QACE,qBAAC;EACC,WAAW,GACT,uBACA,UAED;aAED,qBAAC;GACC,KAAK;GACL,SAAS;GACT,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,MAAM,KAAK,EAAE,OAAO,MAAM,CAAC;AAEtC,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,OAAM;MACN,MAAK;MACL,MAAM,oBAAC,KAAE,WAAU,WAAW;MAC9B,eAAe,WAAW,KAAK,IAAI;MACnC,WAAU;MACV,cAAY,UAAU,KAAK;OAC3B;;MAvBG,KAAK,IAwBP,CACL;IACC;GAEH"}
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";;;UA0CiB,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,cA8BI,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"}