@px-ui/ui 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/assets/Lato-Bold.ttf +0 -0
- package/dist/assets/Lato-Light.ttf +0 -0
- package/dist/index.css +11 -1
- package/dist/index.js +15 -15
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 PX-UI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
File without changes
|
|
File without changes
|
package/dist/index.css
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
@import "tailwindcss" prefix(ppx);
|
|
2
1
|
@import "tw-animate-css";
|
|
3
2
|
@import "shadcn/tailwind.css";
|
|
4
3
|
|
|
@@ -49,6 +48,17 @@
|
|
|
49
48
|
--font-sans: "Lato R", system-ui, sans-serif;
|
|
50
49
|
--font-sans-sb: "Lato SB", system-ui, sans-serif;
|
|
51
50
|
--font-sans-b: "Lato B", system-ui, sans-serif;
|
|
51
|
+
--breakpoint-ppx-sm: 40rem;
|
|
52
|
+
--breakpoint-ppx-md: 48rem;
|
|
53
|
+
--breakpoint-ppx-lg: 64rem;
|
|
54
|
+
--breakpoint-ppx-xl: 80rem;
|
|
55
|
+
--breakpoint-ppx-2xl: 96rem;
|
|
56
|
+
--tracking-ppx-tighter: -0.05em;
|
|
57
|
+
--tracking-ppx-tight: -0.025em;
|
|
58
|
+
--tracking-ppx-normal: 0em;
|
|
59
|
+
--tracking-ppx-wide: 0.025em;
|
|
60
|
+
--tracking-ppx-wider: 0.05em;
|
|
61
|
+
--tracking-ppx-widest: 0.1em;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
:root {
|
package/dist/index.js
CHANGED
|
@@ -14,25 +14,25 @@ function cn(...inputs) {
|
|
|
14
14
|
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/components/button.tsx
|
|
17
|
-
const buttonVariants = cva("
|
|
17
|
+
const buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
|
|
18
18
|
variants: {
|
|
19
19
|
variant: {
|
|
20
|
-
default: "
|
|
21
|
-
outline: "
|
|
22
|
-
secondary: "
|
|
23
|
-
ghost: "
|
|
24
|
-
destructive: "
|
|
25
|
-
link: "
|
|
20
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
|
21
|
+
outline: "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
22
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
23
|
+
ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
24
|
+
destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
|
25
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
26
26
|
},
|
|
27
27
|
size: {
|
|
28
|
-
default: "
|
|
29
|
-
xs: "
|
|
30
|
-
sm: "
|
|
31
|
-
lg: "
|
|
32
|
-
icon: "
|
|
33
|
-
"icon-xs": "
|
|
34
|
-
"icon-sm": "
|
|
35
|
-
"icon-lg": "
|
|
28
|
+
default: "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2",
|
|
29
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
30
|
+
sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5",
|
|
31
|
+
lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2",
|
|
32
|
+
icon: "size-9",
|
|
33
|
+
"icon-xs": "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
34
|
+
"icon-sm": "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
|
|
35
|
+
"icon-lg": "size-10"
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
defaultVariants: {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["ButtonPrimitive","entry","uploadedFile: FileUploadItem","failedFile: FileUploadItem","results: FileUploadItem[]","newErrors: string[]","validFiles: FileUploadItem[]","initializedFiles: FileUploadItem[]","React"],"sources":["../src/lib/utils.ts","../src/components/button.tsx","../src/providers/px-ui-provider.tsx","../src/hooks/use-debounce.ts","../src/hooks/use-intersection-observer.ts","../src/hooks/use-infinite-scroll.ts","../src/hooks/use-async-options.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-mobile.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@px-ui/ui/lib/utils\"\n\nconst buttonVariants = cva(\n \"ppx:group/button ppx:inline-flex ppx:shrink-0 ppx:items-center ppx:justify-center ppx:rounded-md ppx:border ppx:border-transparent ppx:bg-clip-padding ppx:text-sm ppx:font-medium ppx:whitespace-nowrap ppx:transition-all ppx:outline-none ppx:select-none ppx:focus-visible:border-ring ppx:focus-visible:ring-3 ppx:focus-visible:ring-ring/50 ppx:active:not-aria-[haspopup]:translate-y-px ppx:disabled:pointer-events-none ppx:disabled:opacity-50 ppx:aria-invalid:border-destructive ppx:aria-invalid:ring-3 ppx:aria-invalid:ring-destructive/20 ppx:dark:aria-invalid:border-destructive/50 ppx:dark:aria-invalid:ring-destructive/40 ppx:[&_svg]:pointer-events-none ppx:[&_svg]:shrink-0 ppx:[&_svg:not([class*=size-])]:size-4\",\n {\n variants: {\n variant: {\n default: \"ppx:bg-primary ppx:text-primary-foreground ppx:hover:bg-primary/80\",\n outline:\n \"ppx:border-border ppx:bg-background ppx:shadow-xs ppx:hover:bg-muted ppx:hover:text-foreground ppx:aria-expanded:bg-muted ppx:aria-expanded:text-foreground ppx:dark:border-input ppx:dark:bg-input/30 ppx:dark:hover:bg-input/50\",\n secondary:\n \"ppx:bg-secondary ppx:text-secondary-foreground ppx:hover:bg-secondary/80 ppx:aria-expanded:bg-secondary ppx:aria-expanded:text-secondary-foreground\",\n ghost:\n \"ppx:hover:bg-muted ppx:hover:text-foreground ppx:aria-expanded:bg-muted ppx:aria-expanded:text-foreground ppx:dark:hover:bg-muted/50\",\n destructive:\n \"ppx:bg-destructive/10 ppx:text-destructive ppx:hover:bg-destructive/20 ppx:focus-visible:border-destructive/40 ppx:focus-visible:ring-destructive/20 ppx:dark:bg-destructive/20 ppx:dark:hover:bg-destructive/30 ppx:dark:focus-visible:ring-destructive/40\",\n link: \"ppx:text-primary ppx:underline-offset-4 ppx:hover:underline\",\n },\n size: {\n default:\n \"ppx:h-9 ppx:gap-1.5 ppx:px-2.5 ppx:in-data-[slot=button-group]:rounded-md ppx:has-data-[icon=inline-end]:pe-2 ppx:has-data-[icon=inline-start]:ps-2\",\n xs: \"ppx:h-6 ppx:gap-1 ppx:rounded-[min(var(--radius-md),8px)] ppx:px-2 ppx:text-xs ppx:in-data-[slot=button-group]:rounded-md ppx:has-data-[icon=inline-end]:pe-1.5 ppx:has-data-[icon=inline-start]:ps-1.5 ppx:[&_svg:not([class*=size-])]:size-3\",\n sm: \"ppx:h-8 ppx:gap-1 ppx:rounded-[min(var(--radius-md),10px)] ppx:px-2.5 ppx:in-data-[slot=button-group]:rounded-md ppx:has-data-[icon=inline-end]:pe-1.5 ppx:has-data-[icon=inline-start]:ps-1.5\",\n lg: \"ppx:h-10 ppx:gap-1.5 ppx:px-2.5 ppx:has-data-[icon=inline-end]:pe-2 ppx:has-data-[icon=inline-start]:ps-2\",\n icon: \"ppx:size-9\",\n \"icon-xs\":\n \"ppx:size-6 ppx:rounded-[min(var(--radius-md),8px)] ppx:in-data-[slot=button-group]:rounded-md ppx:[&_svg:not([class*=size-])]:size-3\",\n \"icon-sm\":\n \"ppx:size-8 ppx:rounded-[min(var(--radius-md),10px)] ppx:in-data-[slot=button-group]:rounded-md\",\n \"icon-lg\": \"ppx:size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import { createContext } from \"react\";\n\nconst PXUIContext = createContext(null);\n\nexport function PXUIProvider(props: React.PropsWithChildren) {\n return <PXUIContext.Provider value={null}>{props.children}</PXUIContext.Provider>;\n}\n","import { useEffect, useEffectEvent, useRef } from \"react\";\n\nexport default function useDebounce<T>(\n callback: () => void,\n delay: number,\n deps: React.DependencyList,\n) {\n const timeout = useRef<ReturnType<typeof setTimeout> | null>(null);\n const cb = useEffectEvent(callback);\n\n useEffect(() => {\n if (timeout.current) {\n clearTimeout(timeout.current);\n }\n\n timeout.current = setTimeout(() => {\n cb();\n timeout.current = null;\n }, delay);\n\n return () => {\n if (timeout.current) {\n clearTimeout(timeout.current);\n timeout.current = null;\n }\n };\n }, [...deps, delay]);\n}\n","import React from \"react\";\n\nexport interface UseIntersectionObserverOptions {\n threshold?: number | number[];\n root?: Element | Document | null;\n rootMargin?: string;\n}\n\nexport type UseIntersectionObserverReturn = [\n (node: Element | null) => void,\n IntersectionObserverEntry | null,\n];\n\nexport function useIntersectionObserver(\n options: UseIntersectionObserverOptions = {},\n): UseIntersectionObserverReturn {\n const { threshold = 1, root = null, rootMargin = \"0px\" } = options;\n const [entry, setEntry] = React.useState<IntersectionObserverEntry | null>(\n null,\n );\n\n const previousObserver = React.useRef<IntersectionObserver | null>(null);\n\n const customRef = React.useCallback(\n (node: Element | null) => {\n if (previousObserver.current) {\n previousObserver.current.disconnect();\n previousObserver.current = null;\n }\n\n if (node?.nodeType === Node.ELEMENT_NODE) {\n const observer = new IntersectionObserver(\n ([entry]: IntersectionObserverEntry[]) => {\n setEntry(entry ?? null);\n },\n { threshold, root, rootMargin },\n );\n\n observer.observe(node);\n previousObserver.current = observer;\n }\n },\n [threshold, root, rootMargin],\n );\n\n return [customRef, entry] as const;\n}\n","import { useEffect, useEffectEvent } from \"react\";\nimport {\n useIntersectionObserver,\n type UseIntersectionObserverOptions,\n} from \"./use-intersection-observer\";\n\nconst DEFAULT_DELAY_IN_MS = 100;\n\nexport type UseInfiniteScrollHookArgs = Pick<\n UseIntersectionObserverOptions,\n \"rootMargin\" | \"threshold\"\n> & {\n isLoadingMore: boolean;\n hasMore: boolean;\n onLoadMore: () => unknown;\n disabled?: boolean;\n};\n\nfunction useInfiniteScroll({\n isLoadingMore,\n hasMore,\n onLoadMore,\n rootMargin,\n disabled,\n threshold = 0,\n}: UseInfiniteScrollHookArgs) {\n const [ref, entry] = useIntersectionObserver({\n rootMargin,\n threshold,\n });\n const isVisible = Boolean(entry?.isIntersecting);\n\n const onLoadMoreEvent = useEffectEvent(() => {\n onLoadMore();\n });\n\n useEffect(() => {\n if (disabled) return;\n\n if (isVisible && hasMore && !isLoadingMore && !disabled) {\n const timer = setTimeout(() => {\n onLoadMoreEvent();\n }, DEFAULT_DELAY_IN_MS);\n\n return () => {\n clearTimeout(timer);\n };\n }\n }, [isVisible, isLoadingMore, hasMore, disabled]);\n\n return [ref] as const;\n}\n\nexport default useInfiniteScroll;\n","import { useRef } from \"react\";\nimport { useInfiniteQuery, type QueryKey } from \"@tanstack/react-query\";\n\ntype LoadOptionsData<TData> = {\n options: TData[];\n hasMore: boolean;\n};\n\ntype LoadOptionsReturn<TData> = {\n data: LoadOptionsData<TData>;\n error: any;\n};\n\ntype LoadOptionsFn<TData> = (params: {\n search: string;\n page: number;\n signal: AbortSignal;\n}) => Promise<LoadOptionsReturn<TData>>;\n\nexport function useAsyncOptions<TData = any>(\n params: {\n cacheKey: QueryKey;\n loader: LoadOptionsFn<TData>;\n },\n {\n isOpen,\n inputValue,\n }: {\n isOpen: boolean;\n inputValue: string;\n },\n) {\n const isFetchedAfterMount = useRef(false);\n\n const query = useInfiniteQuery({\n queryKey: [...params.cacheKey, inputValue],\n queryFn: async ({ pageParam, signal }) => {\n const { error, data } = await params.loader({\n search: inputValue,\n page: pageParam,\n signal,\n });\n\n if (error) {\n throw new Error(error);\n }\n\n return data;\n },\n enabled: isOpen,\n initialPageParam: 1,\n staleTime: () => (isFetchedAfterMount.current ? Infinity : 0),\n getNextPageParam: (lastPage, allPages) =>\n lastPage.hasMore ? allPages.length + 1 : undefined,\n retry: false,\n });\n\n if (query.isFetchedAfterMount && !isFetchedAfterMount.current) {\n isFetchedAfterMount.current = true;\n }\n\n const items = query.data?.pages.flatMap((page) => page.options);\n\n const handleLoadMore = () => {\n query.fetchNextPage();\n };\n\n return {\n items,\n isLoading: query.isLoading,\n isLoadingMore: query.isFetchingNextPage,\n hasMore: query.hasNextPage,\n isError: query.isError,\n onLoadMore: handleLoadMore,\n _query: query,\n };\n}\n\nexport type LoadOptionsConfig<TData> = {\n cacheKey: QueryKey;\n loader: LoadOptionsFn<TData>;\n};\n\nexport function defineLoadOptions<TData = any>(\n loadOptions: LoadOptionsConfig<TData>,\n) {\n return loadOptions;\n}\n\nexport type InferOption<T> =\n T extends LoadOptionsConfig<infer TData> ? TData : never;\nexport type InferOptions<T> =\n T extends LoadOptionsConfig<infer TData> ? TData[] : never;\n","import {\n type ChangeEvent,\n type DragEvent,\n type InputHTMLAttributes,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type FileMetadata = {\n name: string;\n size: number;\n type: string;\n url: string;\n id: string;\n};\n\nexport type UploadStatus = \"idle\" | \"uploading\" | \"complete\" | \"error\";\n\nexport type FileUploadItem = {\n file: File | FileMetadata;\n id: string;\n preview?: string;\n progress: number;\n status: UploadStatus;\n error?: string;\n uploadedUrl?: string;\n};\n\nexport type PresignedUrlResponse = {\n /** The S3 bucket URL to POST to */\n url: string;\n /** The full accessible path after upload (may include signed query params) */\n full_path: string;\n /** The S3 object key (e.g., \"uuid/filename.pdf\") */\n key?: string;\n /** Access control level */\n acl?: string;\n /** Expected response status from S3 */\n success_action_status?: string;\n /** Content-Type for the upload */\n \"Content-Type\"?: string;\n /** Base64-encoded policy document */\n policy?: string;\n /** AWS credential string */\n \"x-amz-credential\"?: string;\n /** AWS signing algorithm */\n \"x-amz-algorithm\"?: string;\n /** AWS request date */\n \"x-amz-date\"?: string;\n /** AWS request signature */\n \"x-amz-signature\"?: string;\n /** Additional fields */\n [key: string]: unknown;\n};\n\nexport type UploadConfig = {\n /**\n * Function to get a presigned URL for uploading\n */\n getPresignedUrl: (params: {\n filename: string;\n contentType: string;\n size: number;\n signal?: AbortSignal;\n }) => Promise<{\n result?: PresignedUrlResponse | null;\n error?: unknown;\n }>;\n\n /**\n * Function to upload the file to the storage\n */\n uploadFile: (\n url: string,\n file: File,\n presignedData: PresignedUrlResponse,\n onProgress?: (progress: number) => void,\n signal?: AbortSignal,\n ) => Promise<{\n result?: { url: string; [key: string]: unknown };\n error?: unknown;\n }>;\n\n /**\n * Whether to auto-upload files when they are added\n * @default true\n */\n autoUpload?: boolean;\n\n /**\n * Called when a single file upload completes\n */\n onUploadComplete?: (file: FileUploadItem) => void;\n\n /**\n * Called when a single file upload fails\n */\n onUploadError?: (file: FileUploadItem, error: unknown) => void;\n\n /**\n * Called when all files finish uploading\n */\n onAllUploadsComplete?: (files: FileUploadItem[]) => void;\n};\n\nexport type UseFileUploadOptions = {\n maxFiles?: number;\n maxSize?: number;\n minSize?: number;\n accept?: string;\n multiple?: boolean;\n initialFiles?: FileMetadata[];\n onFilesChange?: (files: FileUploadItem[]) => void;\n onFileAdd?: (addedFile: FileUploadItem) => void;\n onFileRemove?: (removedFile: FileUploadItem) => void;\n upload?: UploadConfig;\n};\n\nexport type UseFileUploadReturn = {\n // State\n files: FileUploadItem[];\n isDragging: boolean;\n isUploading: boolean;\n errors: string[];\n\n // Core Actions\n addFiles: (files: FileList | File[]) => void;\n removeFile: (id: string) => void;\n clearFiles: () => void;\n clearErrors: () => void;\n\n // Form integration\n reset: (newFiles?: FileMetadata[]) => void;\n setFiles: (\n files: FileUploadItem[] | ((prev: FileUploadItem[]) => FileUploadItem[]),\n ) => void;\n instanceKey: number;\n\n // Upload Actions\n uploadFiles: (files?: FileUploadItem[]) => Promise<FileUploadItem[]>;\n retryUpload: (id: string) => Promise<void>;\n cancelUpload: (id: string) => void;\n\n // Drag/Drop + Input\n handleDragEnter: (e: DragEvent<HTMLElement>) => void;\n handleDragLeave: (e: DragEvent<HTMLElement>) => void;\n handleDragOver: (e: DragEvent<HTMLElement>) => void;\n handleDrop: (e: DragEvent<HTMLElement>) => void;\n handleFileChange: (e: ChangeEvent<HTMLInputElement>) => void;\n openFileDialog: () => void;\n getInputProps: (\n props?: InputHTMLAttributes<HTMLInputElement>,\n ) => InputHTMLAttributes<HTMLInputElement> & {\n // biome-ignore lint/suspicious/noExplicitAny: intentional for cross-React ref compatibility\n ref: any;\n };\n};\n\n// Helper function to format bytes to human-readable format\nexport const formatBytes = (bytes: number, decimals = 2): string => {\n if (bytes === 0) return \"0 Bytes\";\n\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return Number.parseFloat((bytes / k ** i).toFixed(dm)) + sizes[i];\n};\n\n/**\n * Extract error message from various error formats, including S3 XML errors\n */\nfunction extractErrorMessage(error: unknown): string {\n if (typeof error === \"string\") {\n return error;\n }\n\n if (error instanceof Error) {\n // Check if it's an S3 XML error in the message\n const xmlMatch = error.message.match(/<Message>(.*?)<\\/Message>/);\n if (xmlMatch) {\n return xmlMatch[1];\n }\n return error.message;\n }\n\n // Handle objects with message property\n if (error && typeof error === \"object\") {\n // Check for responseText with XML\n if (\"responseText\" in error && typeof error.responseText === \"string\") {\n const xmlMatch = error.responseText.match(/<Message>(.*?)<\\/Message>/);\n if (xmlMatch) {\n return xmlMatch[1];\n }\n }\n\n // Check for body with XML\n if (\"body\" in error && typeof error.body === \"string\") {\n const xmlMatch = error.body.match(/<Message>(.*?)<\\/Message>/);\n if (xmlMatch) {\n return xmlMatch[1];\n }\n }\n\n // Standard message property\n if (\"message\" in error && typeof error.message === \"string\") {\n return error.message;\n }\n\n // Check for error property\n if (\"error\" in error) {\n return extractErrorMessage(error.error);\n }\n }\n\n return \"Upload failed\";\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport const useFileUpload = (\n options: UseFileUploadOptions = {},\n): UseFileUploadReturn => {\n const { upload, ...baseOptions } = options;\n const autoUpload = upload?.autoUpload ?? true;\n\n const [files, setFilesState] = useState<FileUploadItem[]>(\n (baseOptions.initialFiles ?? []).map((file) => ({\n file,\n id: file.id,\n preview: file.url,\n progress: 100,\n status: \"complete\" as const,\n uploadedUrl: file.url,\n })),\n );\n const [isUploading, setIsUploading] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n const [errors, setErrors] = useState<string[]>([]);\n const [instanceKey, setInstanceKey] = useState(0);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const abortControllersRef = useRef<Map<string, AbortController>>(new Map());\n\n // Helper to cancel all ongoing uploads\n const cancelAllUploads = useCallback(() => {\n for (const controller of abortControllersRef.current.values()) {\n controller.abort();\n }\n abortControllersRef.current.clear();\n }, []);\n\n const {\n maxFiles = Number.POSITIVE_INFINITY,\n maxSize = Number.POSITIVE_INFINITY,\n minSize = 4 * 1024,\n accept = \"*\",\n multiple = false,\n onFilesChange,\n onFileAdd,\n onFileRemove,\n } = baseOptions;\n\n const validateFile = useCallback(\n (file: File): string | null => {\n if (file.size > maxSize) {\n return `File \"${file.name}\" exceeds the maximum size of ${formatBytes(maxSize)}.`;\n }\n\n if (file.size < minSize) {\n return `File \"${file.name}\" is below the minimum size of ${formatBytes(minSize)}.`;\n }\n\n if (accept !== \"*\") {\n const acceptedTypes = accept.split(\",\").map((type) => type.trim());\n const fileType = file.type || \"\";\n const fileExtension = `.${file.name.split(\".\").pop()}`;\n\n const isAccepted = acceptedTypes.some((type) => {\n if (type.startsWith(\".\")) {\n return fileExtension.toLowerCase() === type.toLowerCase();\n }\n if (type.endsWith(\"/*\")) {\n const baseType = type.split(\"/\")[0];\n return fileType.startsWith(`${baseType}/`);\n }\n return fileType === type;\n });\n\n if (!isAccepted) {\n return `File \"${file.name}\" is not an accepted file type.`;\n }\n }\n\n return null;\n },\n [accept, maxSize, minSize],\n );\n\n const createPreview = useCallback((file: File): string | undefined => {\n if (file.type.startsWith(\"image/\")) {\n return URL.createObjectURL(file);\n }\n return undefined;\n }, []);\n\n const generateUniqueId = useCallback((file: File): string => {\n return `${file.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }, []);\n\n const uploadSingleFile = useCallback(\n async (fileWithStatus: FileUploadItem): Promise<FileUploadItem> => {\n if (!upload) {\n return {\n ...fileWithStatus,\n status: \"error\",\n error: \"No upload config provided\",\n };\n }\n\n const file = fileWithStatus.file as File;\n if (!(file instanceof File)) {\n // Already uploaded file (FileMetadata)\n return { ...fileWithStatus, status: \"complete\", progress: 100 };\n }\n\n const abortController = new AbortController();\n abortControllersRef.current.set(fileWithStatus.id, abortController);\n\n try {\n // Update status to uploading\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id\n ? { ...f, status: \"uploading\" as const, progress: 0 }\n : f,\n ),\n );\n\n // Step 1: Get presigned URL\n const { result: presignedResult, error: presignedError } =\n await upload.getPresignedUrl({\n filename: file.name,\n contentType: file.type,\n size: file.size,\n signal: abortController.signal,\n });\n\n if (presignedError || !presignedResult) {\n throw presignedError || new Error(\"Failed to get presigned URL\");\n }\n\n // Update progress after getting presigned URL\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id ? { ...f, progress: 10 } : f,\n ),\n );\n\n // Step 2: Upload file\n const { result: uploadResult, error: uploadError } =\n await upload.uploadFile(\n presignedResult.url,\n file,\n presignedResult,\n (progress) => {\n // Scale progress from 10-99 (leave room for final 100%)\n const scaledProgress = Math.min(10 + progress * 0.89, 99);\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id\n ? { ...f, progress: Math.round(scaledProgress) }\n : f,\n ),\n );\n },\n abortController.signal,\n );\n\n if (uploadError) {\n throw uploadError;\n }\n\n if (!uploadResult?.url) {\n throw new Error(\"Upload failed, no URL was returned\");\n }\n\n // Ensure progress hits 100% before changing status\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id ? { ...f, progress: 100 } : f,\n ),\n );\n\n // Small delay to show 100% before marking complete\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n const uploadedFile: FileUploadItem = {\n ...fileWithStatus,\n status: \"complete\",\n progress: 100,\n uploadedUrl: uploadResult.url,\n };\n\n setFilesState((prev) =>\n prev.map((f) => (f.id === fileWithStatus.id ? uploadedFile : f)),\n );\n\n upload.onUploadComplete?.(uploadedFile);\n\n return uploadedFile;\n } catch (error) {\n // Check if the upload was cancelled via AbortController\n const isAborted =\n error instanceof Error &&\n (error.name === \"AbortError\" || abortController.signal.aborted);\n\n if (isAborted) {\n // Upload was cancelled - return idle state\n const cancelledFile: FileUploadItem = {\n ...fileWithStatus,\n status: \"idle\",\n progress: 0,\n };\n return cancelledFile;\n }\n\n const errorMessage = extractErrorMessage(error);\n const failedFile: FileUploadItem = {\n ...fileWithStatus,\n status: \"error\",\n error: errorMessage,\n };\n\n setFilesState((prev) =>\n prev.map((f) => (f.id === fileWithStatus.id ? failedFile : f)),\n );\n\n upload.onUploadError?.(failedFile, error);\n\n return failedFile;\n } finally {\n abortControllersRef.current.delete(fileWithStatus.id);\n }\n },\n [upload],\n );\n\n const uploadFiles = useCallback(\n async (filesToUpload?: FileUploadItem[]): Promise<FileUploadItem[]> => {\n const targetFiles =\n filesToUpload ?? files.filter((f) => f.status === \"idle\");\n\n if (targetFiles.length === 0) return [];\n\n setIsUploading(true);\n const results: FileUploadItem[] = [];\n\n for (const file of targetFiles) {\n const result = await uploadSingleFile(file);\n results.push(result);\n }\n\n setIsUploading(false);\n upload?.onAllUploadsComplete?.(results);\n\n return results;\n },\n [files, uploadSingleFile, upload],\n );\n\n const addFiles = useCallback(\n (newFiles: FileList | File[]) => {\n if (!newFiles || newFiles.length === 0) return;\n\n const newFilesArray = Array.from(newFiles);\n const newErrors: string[] = [];\n\n // Clear existing errors\n setErrors([]);\n\n // In single file mode, clear existing files first\n if (!multiple) {\n setFilesState((prev) => {\n for (const file of prev) {\n if (file.preview && file.file instanceof File) {\n URL.revokeObjectURL(file.preview);\n }\n }\n return [];\n });\n }\n\n // Check if adding these files would exceed maxFiles\n if (\n multiple &&\n maxFiles !== Number.POSITIVE_INFINITY &&\n files.length + newFilesArray.length > maxFiles\n ) {\n newErrors.push(`You can only upload a maximum of ${maxFiles} files.`);\n setErrors(newErrors);\n return;\n }\n\n const validFiles: FileUploadItem[] = [];\n\n for (const file of newFilesArray) {\n // Check for duplicates in multiple mode\n if (multiple) {\n const isDuplicate = files.some(\n (existingFile) =>\n existingFile.file.name === file.name &&\n existingFile.file.size === file.size,\n );\n if (isDuplicate) continue;\n }\n\n const error = validateFile(file);\n if (error) {\n newErrors.push(error);\n continue;\n }\n\n validFiles.push({\n file,\n id: generateUniqueId(file),\n preview: createPreview(file),\n progress: 0,\n status: \"idle\",\n });\n }\n\n if (validFiles.length > 0) {\n // Call onFileAdd callback for each file\n if (onFileAdd) {\n for (const file of validFiles) {\n onFileAdd(file);\n }\n }\n\n setFilesState((prev) => {\n const updatedFiles = !multiple ? validFiles : [...prev, ...validFiles];\n onFilesChange?.(updatedFiles);\n return updatedFiles;\n });\n\n // Auto-upload if configured\n if (autoUpload && upload) {\n // Use setTimeout to ensure state is updated before uploading\n setTimeout(() => {\n uploadFiles(validFiles);\n }, 0);\n }\n }\n\n if (newErrors.length > 0) {\n setErrors(newErrors);\n }\n\n // Reset input value\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n },\n [\n files,\n maxFiles,\n multiple,\n validateFile,\n createPreview,\n generateUniqueId,\n onFilesChange,\n onFileAdd,\n autoUpload,\n upload,\n uploadFiles,\n ],\n );\n\n const removeFile = useCallback(\n (id: string) => {\n // Cancel any ongoing upload\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n setFilesState((prev) => {\n const fileToRemove = prev.find((file) => file.id === id);\n if (fileToRemove) {\n // Call onFileRemove callback before removing\n onFileRemove?.(fileToRemove);\n\n if (fileToRemove.preview && fileToRemove.file instanceof File) {\n URL.revokeObjectURL(fileToRemove.preview);\n }\n }\n\n const newFiles = prev.filter((file) => file.id !== id);\n onFilesChange?.(newFiles);\n return newFiles;\n });\n },\n [onFilesChange, onFileRemove],\n );\n\n const clearFiles = useCallback(() => {\n cancelAllUploads();\n\n setFilesState((prev) => {\n for (const file of prev) {\n // Call onFileRemove for each file\n onFileRemove?.(file);\n\n if (file.preview && file.file instanceof File) {\n URL.revokeObjectURL(file.preview);\n }\n }\n return [];\n });\n\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n\n setErrors([]);\n onFilesChange?.([]);\n }, [cancelAllUploads, onFilesChange, onFileRemove]);\n\n const clearErrors = useCallback(() => {\n setErrors([]);\n }, []);\n\n const reset = useCallback(\n (newFiles?: FileMetadata[]) => {\n cancelAllUploads();\n\n // Revoke all previews\n for (const file of files) {\n if (file.preview && file.file instanceof File) {\n URL.revokeObjectURL(file.preview);\n }\n }\n\n // Reset input\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n\n // Clear errors\n setErrors([]);\n\n // Set new files or clear\n const initializedFiles: FileUploadItem[] = (newFiles ?? []).map(\n (file) => ({\n file,\n id: file.id,\n preview: file.url,\n progress: 100,\n status: \"complete\" as const,\n uploadedUrl: file.url,\n }),\n );\n\n setFilesState(initializedFiles);\n onFilesChange?.(initializedFiles);\n\n // Increment instance key to force remount\n setInstanceKey((prev) => prev + 1);\n },\n [cancelAllUploads, files, onFilesChange],\n );\n\n const setFiles = useCallback(\n (\n newFiles:\n | FileUploadItem[]\n | ((prev: FileUploadItem[]) => FileUploadItem[]),\n ) => {\n setFilesState((prev) => {\n const nextFiles =\n typeof newFiles === \"function\" ? newFiles(prev) : newFiles;\n onFilesChange?.(nextFiles);\n return nextFiles;\n });\n },\n [onFilesChange],\n );\n\n const retryUpload = useCallback(\n async (id: string) => {\n const file = files.find((f) => f.id === id);\n if (file && file.status === \"error\") {\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === id\n ? { ...f, status: \"idle\" as const, error: undefined }\n : f,\n ),\n );\n await uploadSingleFile({ ...file, status: \"idle\", error: undefined });\n }\n },\n [files, uploadSingleFile],\n );\n\n const cancelUpload = useCallback((id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === id ? { ...f, status: \"idle\" as const, progress: 0 } : f,\n ),\n );\n }, []);\n\n const handleDragEnter = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(true);\n }, []);\n\n const handleDragLeave = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.currentTarget.contains(e.relatedTarget as Node)) return;\n setIsDragging(false);\n }, []);\n\n const handleDragOver = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n }, []);\n\n const handleDrop = useCallback(\n (e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n\n if (inputRef.current?.disabled) return;\n\n if (e.dataTransfer.files?.length > 0) {\n if (!multiple) {\n addFiles([e.dataTransfer.files[0]]);\n } else {\n addFiles(e.dataTransfer.files);\n }\n }\n },\n [addFiles, multiple],\n );\n\n const handleFileChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files?.length) {\n addFiles(e.target.files);\n }\n },\n [addFiles],\n );\n\n const openFileDialog = useCallback(() => {\n inputRef.current?.click();\n }, []);\n\n const getInputProps = useCallback(\n (props: InputHTMLAttributes<HTMLInputElement> = {}) => ({\n ...props,\n accept: props.accept || accept,\n multiple: props.multiple !== undefined ? props.multiple : multiple,\n onChange: handleFileChange,\n // biome-ignore lint/suspicious/noExplicitAny: intentional\n ref: inputRef as any,\n type: \"file\" as const,\n }),\n [accept, multiple, handleFileChange],\n );\n\n return {\n // State\n files,\n isDragging,\n isUploading,\n errors,\n\n // Core Actions\n addFiles,\n removeFile,\n clearFiles,\n clearErrors,\n\n // Form integration\n reset,\n setFiles,\n instanceKey,\n\n // Upload Actions\n uploadFiles,\n retryUpload,\n cancelUpload,\n\n // Drag/Drop + Input\n handleDragEnter,\n handleDragLeave,\n handleDragOver,\n handleDrop,\n handleFileChange,\n openFileDialog,\n getInputProps,\n };\n};\n\n// Legacy type exports for backwards compatibility\nexport type FileWithPreview = FileUploadItem;\nexport type FileWithUploadStatus = FileUploadItem;\nexport type FileUploadOptions = UseFileUploadOptions;\nexport type FileUploadWithUploaderOptions = UseFileUploadOptions;\n","import * as React from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(\n undefined,\n );\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return !!isMobile;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["ButtonPrimitive","entry","uploadedFile: FileUploadItem","failedFile: FileUploadItem","results: FileUploadItem[]","newErrors: string[]","validFiles: FileUploadItem[]","initializedFiles: FileUploadItem[]","React"],"sources":["../src/lib/utils.ts","../src/components/button.tsx","../src/providers/px-ui-provider.tsx","../src/hooks/use-debounce.ts","../src/hooks/use-intersection-observer.ts","../src/hooks/use-infinite-scroll.ts","../src/hooks/use-async-options.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-mobile.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@px-ui/ui/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2\",\n xs: \"h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5\",\n lg: \"h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2\",\n icon: \"size-9\",\n \"icon-xs\":\n \"size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\":\n \"size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import { createContext } from \"react\";\n\nconst PXUIContext = createContext(null);\n\nexport function PXUIProvider(props: React.PropsWithChildren) {\n return <PXUIContext.Provider value={null}>{props.children}</PXUIContext.Provider>;\n}\n","import { useEffect, useEffectEvent, useRef } from \"react\";\n\nexport default function useDebounce<T>(\n callback: () => void,\n delay: number,\n deps: React.DependencyList,\n) {\n const timeout = useRef<ReturnType<typeof setTimeout> | null>(null);\n const cb = useEffectEvent(callback);\n\n useEffect(() => {\n if (timeout.current) {\n clearTimeout(timeout.current);\n }\n\n timeout.current = setTimeout(() => {\n cb();\n timeout.current = null;\n }, delay);\n\n return () => {\n if (timeout.current) {\n clearTimeout(timeout.current);\n timeout.current = null;\n }\n };\n }, [...deps, delay]);\n}\n","import React from \"react\";\n\nexport interface UseIntersectionObserverOptions {\n threshold?: number | number[];\n root?: Element | Document | null;\n rootMargin?: string;\n}\n\nexport type UseIntersectionObserverReturn = [\n (node: Element | null) => void,\n IntersectionObserverEntry | null,\n];\n\nexport function useIntersectionObserver(\n options: UseIntersectionObserverOptions = {},\n): UseIntersectionObserverReturn {\n const { threshold = 1, root = null, rootMargin = \"0px\" } = options;\n const [entry, setEntry] = React.useState<IntersectionObserverEntry | null>(\n null,\n );\n\n const previousObserver = React.useRef<IntersectionObserver | null>(null);\n\n const customRef = React.useCallback(\n (node: Element | null) => {\n if (previousObserver.current) {\n previousObserver.current.disconnect();\n previousObserver.current = null;\n }\n\n if (node?.nodeType === Node.ELEMENT_NODE) {\n const observer = new IntersectionObserver(\n ([entry]: IntersectionObserverEntry[]) => {\n setEntry(entry ?? null);\n },\n { threshold, root, rootMargin },\n );\n\n observer.observe(node);\n previousObserver.current = observer;\n }\n },\n [threshold, root, rootMargin],\n );\n\n return [customRef, entry] as const;\n}\n","import { useEffect, useEffectEvent } from \"react\";\nimport {\n useIntersectionObserver,\n type UseIntersectionObserverOptions,\n} from \"./use-intersection-observer\";\n\nconst DEFAULT_DELAY_IN_MS = 100;\n\nexport type UseInfiniteScrollHookArgs = Pick<\n UseIntersectionObserverOptions,\n \"rootMargin\" | \"threshold\"\n> & {\n isLoadingMore: boolean;\n hasMore: boolean;\n onLoadMore: () => unknown;\n disabled?: boolean;\n};\n\nfunction useInfiniteScroll({\n isLoadingMore,\n hasMore,\n onLoadMore,\n rootMargin,\n disabled,\n threshold = 0,\n}: UseInfiniteScrollHookArgs) {\n const [ref, entry] = useIntersectionObserver({\n rootMargin,\n threshold,\n });\n const isVisible = Boolean(entry?.isIntersecting);\n\n const onLoadMoreEvent = useEffectEvent(() => {\n onLoadMore();\n });\n\n useEffect(() => {\n if (disabled) return;\n\n if (isVisible && hasMore && !isLoadingMore && !disabled) {\n const timer = setTimeout(() => {\n onLoadMoreEvent();\n }, DEFAULT_DELAY_IN_MS);\n\n return () => {\n clearTimeout(timer);\n };\n }\n }, [isVisible, isLoadingMore, hasMore, disabled]);\n\n return [ref] as const;\n}\n\nexport default useInfiniteScroll;\n","import { useRef } from \"react\";\nimport { useInfiniteQuery, type QueryKey } from \"@tanstack/react-query\";\n\ntype LoadOptionsData<TData> = {\n options: TData[];\n hasMore: boolean;\n};\n\ntype LoadOptionsReturn<TData> = {\n data: LoadOptionsData<TData>;\n error: any;\n};\n\ntype LoadOptionsFn<TData> = (params: {\n search: string;\n page: number;\n signal: AbortSignal;\n}) => Promise<LoadOptionsReturn<TData>>;\n\nexport function useAsyncOptions<TData = any>(\n params: {\n cacheKey: QueryKey;\n loader: LoadOptionsFn<TData>;\n },\n {\n isOpen,\n inputValue,\n }: {\n isOpen: boolean;\n inputValue: string;\n },\n) {\n const isFetchedAfterMount = useRef(false);\n\n const query = useInfiniteQuery({\n queryKey: [...params.cacheKey, inputValue],\n queryFn: async ({ pageParam, signal }) => {\n const { error, data } = await params.loader({\n search: inputValue,\n page: pageParam,\n signal,\n });\n\n if (error) {\n throw new Error(error);\n }\n\n return data;\n },\n enabled: isOpen,\n initialPageParam: 1,\n staleTime: () => (isFetchedAfterMount.current ? Infinity : 0),\n getNextPageParam: (lastPage, allPages) =>\n lastPage.hasMore ? allPages.length + 1 : undefined,\n retry: false,\n });\n\n if (query.isFetchedAfterMount && !isFetchedAfterMount.current) {\n isFetchedAfterMount.current = true;\n }\n\n const items = query.data?.pages.flatMap((page) => page.options);\n\n const handleLoadMore = () => {\n query.fetchNextPage();\n };\n\n return {\n items,\n isLoading: query.isLoading,\n isLoadingMore: query.isFetchingNextPage,\n hasMore: query.hasNextPage,\n isError: query.isError,\n onLoadMore: handleLoadMore,\n _query: query,\n };\n}\n\nexport type LoadOptionsConfig<TData> = {\n cacheKey: QueryKey;\n loader: LoadOptionsFn<TData>;\n};\n\nexport function defineLoadOptions<TData = any>(\n loadOptions: LoadOptionsConfig<TData>,\n) {\n return loadOptions;\n}\n\nexport type InferOption<T> =\n T extends LoadOptionsConfig<infer TData> ? TData : never;\nexport type InferOptions<T> =\n T extends LoadOptionsConfig<infer TData> ? TData[] : never;\n","import {\n type ChangeEvent,\n type DragEvent,\n type InputHTMLAttributes,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type FileMetadata = {\n name: string;\n size: number;\n type: string;\n url: string;\n id: string;\n};\n\nexport type UploadStatus = \"idle\" | \"uploading\" | \"complete\" | \"error\";\n\nexport type FileUploadItem = {\n file: File | FileMetadata;\n id: string;\n preview?: string;\n progress: number;\n status: UploadStatus;\n error?: string;\n uploadedUrl?: string;\n};\n\nexport type PresignedUrlResponse = {\n /** The S3 bucket URL to POST to */\n url: string;\n /** The full accessible path after upload (may include signed query params) */\n full_path: string;\n /** The S3 object key (e.g., \"uuid/filename.pdf\") */\n key?: string;\n /** Access control level */\n acl?: string;\n /** Expected response status from S3 */\n success_action_status?: string;\n /** Content-Type for the upload */\n \"Content-Type\"?: string;\n /** Base64-encoded policy document */\n policy?: string;\n /** AWS credential string */\n \"x-amz-credential\"?: string;\n /** AWS signing algorithm */\n \"x-amz-algorithm\"?: string;\n /** AWS request date */\n \"x-amz-date\"?: string;\n /** AWS request signature */\n \"x-amz-signature\"?: string;\n /** Additional fields */\n [key: string]: unknown;\n};\n\nexport type UploadConfig = {\n /**\n * Function to get a presigned URL for uploading\n */\n getPresignedUrl: (params: {\n filename: string;\n contentType: string;\n size: number;\n signal?: AbortSignal;\n }) => Promise<{\n result?: PresignedUrlResponse | null;\n error?: unknown;\n }>;\n\n /**\n * Function to upload the file to the storage\n */\n uploadFile: (\n url: string,\n file: File,\n presignedData: PresignedUrlResponse,\n onProgress?: (progress: number) => void,\n signal?: AbortSignal,\n ) => Promise<{\n result?: { url: string; [key: string]: unknown };\n error?: unknown;\n }>;\n\n /**\n * Whether to auto-upload files when they are added\n * @default true\n */\n autoUpload?: boolean;\n\n /**\n * Called when a single file upload completes\n */\n onUploadComplete?: (file: FileUploadItem) => void;\n\n /**\n * Called when a single file upload fails\n */\n onUploadError?: (file: FileUploadItem, error: unknown) => void;\n\n /**\n * Called when all files finish uploading\n */\n onAllUploadsComplete?: (files: FileUploadItem[]) => void;\n};\n\nexport type UseFileUploadOptions = {\n maxFiles?: number;\n maxSize?: number;\n minSize?: number;\n accept?: string;\n multiple?: boolean;\n initialFiles?: FileMetadata[];\n onFilesChange?: (files: FileUploadItem[]) => void;\n onFileAdd?: (addedFile: FileUploadItem) => void;\n onFileRemove?: (removedFile: FileUploadItem) => void;\n upload?: UploadConfig;\n};\n\nexport type UseFileUploadReturn = {\n // State\n files: FileUploadItem[];\n isDragging: boolean;\n isUploading: boolean;\n errors: string[];\n\n // Core Actions\n addFiles: (files: FileList | File[]) => void;\n removeFile: (id: string) => void;\n clearFiles: () => void;\n clearErrors: () => void;\n\n // Form integration\n reset: (newFiles?: FileMetadata[]) => void;\n setFiles: (\n files: FileUploadItem[] | ((prev: FileUploadItem[]) => FileUploadItem[]),\n ) => void;\n instanceKey: number;\n\n // Upload Actions\n uploadFiles: (files?: FileUploadItem[]) => Promise<FileUploadItem[]>;\n retryUpload: (id: string) => Promise<void>;\n cancelUpload: (id: string) => void;\n\n // Drag/Drop + Input\n handleDragEnter: (e: DragEvent<HTMLElement>) => void;\n handleDragLeave: (e: DragEvent<HTMLElement>) => void;\n handleDragOver: (e: DragEvent<HTMLElement>) => void;\n handleDrop: (e: DragEvent<HTMLElement>) => void;\n handleFileChange: (e: ChangeEvent<HTMLInputElement>) => void;\n openFileDialog: () => void;\n getInputProps: (\n props?: InputHTMLAttributes<HTMLInputElement>,\n ) => InputHTMLAttributes<HTMLInputElement> & {\n // biome-ignore lint/suspicious/noExplicitAny: intentional for cross-React ref compatibility\n ref: any;\n };\n};\n\n// Helper function to format bytes to human-readable format\nexport const formatBytes = (bytes: number, decimals = 2): string => {\n if (bytes === 0) return \"0 Bytes\";\n\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return Number.parseFloat((bytes / k ** i).toFixed(dm)) + sizes[i];\n};\n\n/**\n * Extract error message from various error formats, including S3 XML errors\n */\nfunction extractErrorMessage(error: unknown): string {\n if (typeof error === \"string\") {\n return error;\n }\n\n if (error instanceof Error) {\n // Check if it's an S3 XML error in the message\n const xmlMatch = error.message.match(/<Message>(.*?)<\\/Message>/);\n if (xmlMatch) {\n return xmlMatch[1];\n }\n return error.message;\n }\n\n // Handle objects with message property\n if (error && typeof error === \"object\") {\n // Check for responseText with XML\n if (\"responseText\" in error && typeof error.responseText === \"string\") {\n const xmlMatch = error.responseText.match(/<Message>(.*?)<\\/Message>/);\n if (xmlMatch) {\n return xmlMatch[1];\n }\n }\n\n // Check for body with XML\n if (\"body\" in error && typeof error.body === \"string\") {\n const xmlMatch = error.body.match(/<Message>(.*?)<\\/Message>/);\n if (xmlMatch) {\n return xmlMatch[1];\n }\n }\n\n // Standard message property\n if (\"message\" in error && typeof error.message === \"string\") {\n return error.message;\n }\n\n // Check for error property\n if (\"error\" in error) {\n return extractErrorMessage(error.error);\n }\n }\n\n return \"Upload failed\";\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport const useFileUpload = (\n options: UseFileUploadOptions = {},\n): UseFileUploadReturn => {\n const { upload, ...baseOptions } = options;\n const autoUpload = upload?.autoUpload ?? true;\n\n const [files, setFilesState] = useState<FileUploadItem[]>(\n (baseOptions.initialFiles ?? []).map((file) => ({\n file,\n id: file.id,\n preview: file.url,\n progress: 100,\n status: \"complete\" as const,\n uploadedUrl: file.url,\n })),\n );\n const [isUploading, setIsUploading] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n const [errors, setErrors] = useState<string[]>([]);\n const [instanceKey, setInstanceKey] = useState(0);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const abortControllersRef = useRef<Map<string, AbortController>>(new Map());\n\n // Helper to cancel all ongoing uploads\n const cancelAllUploads = useCallback(() => {\n for (const controller of abortControllersRef.current.values()) {\n controller.abort();\n }\n abortControllersRef.current.clear();\n }, []);\n\n const {\n maxFiles = Number.POSITIVE_INFINITY,\n maxSize = Number.POSITIVE_INFINITY,\n minSize = 4 * 1024,\n accept = \"*\",\n multiple = false,\n onFilesChange,\n onFileAdd,\n onFileRemove,\n } = baseOptions;\n\n const validateFile = useCallback(\n (file: File): string | null => {\n if (file.size > maxSize) {\n return `File \"${file.name}\" exceeds the maximum size of ${formatBytes(maxSize)}.`;\n }\n\n if (file.size < minSize) {\n return `File \"${file.name}\" is below the minimum size of ${formatBytes(minSize)}.`;\n }\n\n if (accept !== \"*\") {\n const acceptedTypes = accept.split(\",\").map((type) => type.trim());\n const fileType = file.type || \"\";\n const fileExtension = `.${file.name.split(\".\").pop()}`;\n\n const isAccepted = acceptedTypes.some((type) => {\n if (type.startsWith(\".\")) {\n return fileExtension.toLowerCase() === type.toLowerCase();\n }\n if (type.endsWith(\"/*\")) {\n const baseType = type.split(\"/\")[0];\n return fileType.startsWith(`${baseType}/`);\n }\n return fileType === type;\n });\n\n if (!isAccepted) {\n return `File \"${file.name}\" is not an accepted file type.`;\n }\n }\n\n return null;\n },\n [accept, maxSize, minSize],\n );\n\n const createPreview = useCallback((file: File): string | undefined => {\n if (file.type.startsWith(\"image/\")) {\n return URL.createObjectURL(file);\n }\n return undefined;\n }, []);\n\n const generateUniqueId = useCallback((file: File): string => {\n return `${file.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }, []);\n\n const uploadSingleFile = useCallback(\n async (fileWithStatus: FileUploadItem): Promise<FileUploadItem> => {\n if (!upload) {\n return {\n ...fileWithStatus,\n status: \"error\",\n error: \"No upload config provided\",\n };\n }\n\n const file = fileWithStatus.file as File;\n if (!(file instanceof File)) {\n // Already uploaded file (FileMetadata)\n return { ...fileWithStatus, status: \"complete\", progress: 100 };\n }\n\n const abortController = new AbortController();\n abortControllersRef.current.set(fileWithStatus.id, abortController);\n\n try {\n // Update status to uploading\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id\n ? { ...f, status: \"uploading\" as const, progress: 0 }\n : f,\n ),\n );\n\n // Step 1: Get presigned URL\n const { result: presignedResult, error: presignedError } =\n await upload.getPresignedUrl({\n filename: file.name,\n contentType: file.type,\n size: file.size,\n signal: abortController.signal,\n });\n\n if (presignedError || !presignedResult) {\n throw presignedError || new Error(\"Failed to get presigned URL\");\n }\n\n // Update progress after getting presigned URL\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id ? { ...f, progress: 10 } : f,\n ),\n );\n\n // Step 2: Upload file\n const { result: uploadResult, error: uploadError } =\n await upload.uploadFile(\n presignedResult.url,\n file,\n presignedResult,\n (progress) => {\n // Scale progress from 10-99 (leave room for final 100%)\n const scaledProgress = Math.min(10 + progress * 0.89, 99);\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id\n ? { ...f, progress: Math.round(scaledProgress) }\n : f,\n ),\n );\n },\n abortController.signal,\n );\n\n if (uploadError) {\n throw uploadError;\n }\n\n if (!uploadResult?.url) {\n throw new Error(\"Upload failed, no URL was returned\");\n }\n\n // Ensure progress hits 100% before changing status\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === fileWithStatus.id ? { ...f, progress: 100 } : f,\n ),\n );\n\n // Small delay to show 100% before marking complete\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n const uploadedFile: FileUploadItem = {\n ...fileWithStatus,\n status: \"complete\",\n progress: 100,\n uploadedUrl: uploadResult.url,\n };\n\n setFilesState((prev) =>\n prev.map((f) => (f.id === fileWithStatus.id ? uploadedFile : f)),\n );\n\n upload.onUploadComplete?.(uploadedFile);\n\n return uploadedFile;\n } catch (error) {\n // Check if the upload was cancelled via AbortController\n const isAborted =\n error instanceof Error &&\n (error.name === \"AbortError\" || abortController.signal.aborted);\n\n if (isAborted) {\n // Upload was cancelled - return idle state\n const cancelledFile: FileUploadItem = {\n ...fileWithStatus,\n status: \"idle\",\n progress: 0,\n };\n return cancelledFile;\n }\n\n const errorMessage = extractErrorMessage(error);\n const failedFile: FileUploadItem = {\n ...fileWithStatus,\n status: \"error\",\n error: errorMessage,\n };\n\n setFilesState((prev) =>\n prev.map((f) => (f.id === fileWithStatus.id ? failedFile : f)),\n );\n\n upload.onUploadError?.(failedFile, error);\n\n return failedFile;\n } finally {\n abortControllersRef.current.delete(fileWithStatus.id);\n }\n },\n [upload],\n );\n\n const uploadFiles = useCallback(\n async (filesToUpload?: FileUploadItem[]): Promise<FileUploadItem[]> => {\n const targetFiles =\n filesToUpload ?? files.filter((f) => f.status === \"idle\");\n\n if (targetFiles.length === 0) return [];\n\n setIsUploading(true);\n const results: FileUploadItem[] = [];\n\n for (const file of targetFiles) {\n const result = await uploadSingleFile(file);\n results.push(result);\n }\n\n setIsUploading(false);\n upload?.onAllUploadsComplete?.(results);\n\n return results;\n },\n [files, uploadSingleFile, upload],\n );\n\n const addFiles = useCallback(\n (newFiles: FileList | File[]) => {\n if (!newFiles || newFiles.length === 0) return;\n\n const newFilesArray = Array.from(newFiles);\n const newErrors: string[] = [];\n\n // Clear existing errors\n setErrors([]);\n\n // In single file mode, clear existing files first\n if (!multiple) {\n setFilesState((prev) => {\n for (const file of prev) {\n if (file.preview && file.file instanceof File) {\n URL.revokeObjectURL(file.preview);\n }\n }\n return [];\n });\n }\n\n // Check if adding these files would exceed maxFiles\n if (\n multiple &&\n maxFiles !== Number.POSITIVE_INFINITY &&\n files.length + newFilesArray.length > maxFiles\n ) {\n newErrors.push(`You can only upload a maximum of ${maxFiles} files.`);\n setErrors(newErrors);\n return;\n }\n\n const validFiles: FileUploadItem[] = [];\n\n for (const file of newFilesArray) {\n // Check for duplicates in multiple mode\n if (multiple) {\n const isDuplicate = files.some(\n (existingFile) =>\n existingFile.file.name === file.name &&\n existingFile.file.size === file.size,\n );\n if (isDuplicate) continue;\n }\n\n const error = validateFile(file);\n if (error) {\n newErrors.push(error);\n continue;\n }\n\n validFiles.push({\n file,\n id: generateUniqueId(file),\n preview: createPreview(file),\n progress: 0,\n status: \"idle\",\n });\n }\n\n if (validFiles.length > 0) {\n // Call onFileAdd callback for each file\n if (onFileAdd) {\n for (const file of validFiles) {\n onFileAdd(file);\n }\n }\n\n setFilesState((prev) => {\n const updatedFiles = !multiple ? validFiles : [...prev, ...validFiles];\n onFilesChange?.(updatedFiles);\n return updatedFiles;\n });\n\n // Auto-upload if configured\n if (autoUpload && upload) {\n // Use setTimeout to ensure state is updated before uploading\n setTimeout(() => {\n uploadFiles(validFiles);\n }, 0);\n }\n }\n\n if (newErrors.length > 0) {\n setErrors(newErrors);\n }\n\n // Reset input value\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n },\n [\n files,\n maxFiles,\n multiple,\n validateFile,\n createPreview,\n generateUniqueId,\n onFilesChange,\n onFileAdd,\n autoUpload,\n upload,\n uploadFiles,\n ],\n );\n\n const removeFile = useCallback(\n (id: string) => {\n // Cancel any ongoing upload\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n setFilesState((prev) => {\n const fileToRemove = prev.find((file) => file.id === id);\n if (fileToRemove) {\n // Call onFileRemove callback before removing\n onFileRemove?.(fileToRemove);\n\n if (fileToRemove.preview && fileToRemove.file instanceof File) {\n URL.revokeObjectURL(fileToRemove.preview);\n }\n }\n\n const newFiles = prev.filter((file) => file.id !== id);\n onFilesChange?.(newFiles);\n return newFiles;\n });\n },\n [onFilesChange, onFileRemove],\n );\n\n const clearFiles = useCallback(() => {\n cancelAllUploads();\n\n setFilesState((prev) => {\n for (const file of prev) {\n // Call onFileRemove for each file\n onFileRemove?.(file);\n\n if (file.preview && file.file instanceof File) {\n URL.revokeObjectURL(file.preview);\n }\n }\n return [];\n });\n\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n\n setErrors([]);\n onFilesChange?.([]);\n }, [cancelAllUploads, onFilesChange, onFileRemove]);\n\n const clearErrors = useCallback(() => {\n setErrors([]);\n }, []);\n\n const reset = useCallback(\n (newFiles?: FileMetadata[]) => {\n cancelAllUploads();\n\n // Revoke all previews\n for (const file of files) {\n if (file.preview && file.file instanceof File) {\n URL.revokeObjectURL(file.preview);\n }\n }\n\n // Reset input\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n\n // Clear errors\n setErrors([]);\n\n // Set new files or clear\n const initializedFiles: FileUploadItem[] = (newFiles ?? []).map(\n (file) => ({\n file,\n id: file.id,\n preview: file.url,\n progress: 100,\n status: \"complete\" as const,\n uploadedUrl: file.url,\n }),\n );\n\n setFilesState(initializedFiles);\n onFilesChange?.(initializedFiles);\n\n // Increment instance key to force remount\n setInstanceKey((prev) => prev + 1);\n },\n [cancelAllUploads, files, onFilesChange],\n );\n\n const setFiles = useCallback(\n (\n newFiles:\n | FileUploadItem[]\n | ((prev: FileUploadItem[]) => FileUploadItem[]),\n ) => {\n setFilesState((prev) => {\n const nextFiles =\n typeof newFiles === \"function\" ? newFiles(prev) : newFiles;\n onFilesChange?.(nextFiles);\n return nextFiles;\n });\n },\n [onFilesChange],\n );\n\n const retryUpload = useCallback(\n async (id: string) => {\n const file = files.find((f) => f.id === id);\n if (file && file.status === \"error\") {\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === id\n ? { ...f, status: \"idle\" as const, error: undefined }\n : f,\n ),\n );\n await uploadSingleFile({ ...file, status: \"idle\", error: undefined });\n }\n },\n [files, uploadSingleFile],\n );\n\n const cancelUpload = useCallback((id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n setFilesState((prev) =>\n prev.map((f) =>\n f.id === id ? { ...f, status: \"idle\" as const, progress: 0 } : f,\n ),\n );\n }, []);\n\n const handleDragEnter = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(true);\n }, []);\n\n const handleDragLeave = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.currentTarget.contains(e.relatedTarget as Node)) return;\n setIsDragging(false);\n }, []);\n\n const handleDragOver = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n }, []);\n\n const handleDrop = useCallback(\n (e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n\n if (inputRef.current?.disabled) return;\n\n if (e.dataTransfer.files?.length > 0) {\n if (!multiple) {\n addFiles([e.dataTransfer.files[0]]);\n } else {\n addFiles(e.dataTransfer.files);\n }\n }\n },\n [addFiles, multiple],\n );\n\n const handleFileChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files?.length) {\n addFiles(e.target.files);\n }\n },\n [addFiles],\n );\n\n const openFileDialog = useCallback(() => {\n inputRef.current?.click();\n }, []);\n\n const getInputProps = useCallback(\n (props: InputHTMLAttributes<HTMLInputElement> = {}) => ({\n ...props,\n accept: props.accept || accept,\n multiple: props.multiple !== undefined ? props.multiple : multiple,\n onChange: handleFileChange,\n // biome-ignore lint/suspicious/noExplicitAny: intentional\n ref: inputRef as any,\n type: \"file\" as const,\n }),\n [accept, multiple, handleFileChange],\n );\n\n return {\n // State\n files,\n isDragging,\n isUploading,\n errors,\n\n // Core Actions\n addFiles,\n removeFile,\n clearFiles,\n clearErrors,\n\n // Form integration\n reset,\n setFiles,\n instanceKey,\n\n // Upload Actions\n uploadFiles,\n retryUpload,\n cancelUpload,\n\n // Drag/Drop + Input\n handleDragEnter,\n handleDragLeave,\n handleDragOver,\n handleDrop,\n handleFileChange,\n openFileDialog,\n getInputProps,\n };\n};\n\n// Legacy type exports for backwards compatibility\nexport type FileWithPreview = FileUploadItem;\nexport type FileWithUploadStatus = FileUploadItem;\nexport type FileUploadOptions = UseFileUploadOptions;\nexport type FileUploadWithUploaderOptions = UseFileUploadOptions;\n","import * as React from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(\n undefined,\n );\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return !!isMobile;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@px-ui/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "A modern React component library built with Tailwind CSS and shadcn/ui",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -18,13 +18,6 @@
|
|
|
18
18
|
"./styles.css": "./dist/index.css",
|
|
19
19
|
"./fonts.css": "./dist/assets/fonts.css"
|
|
20
20
|
},
|
|
21
|
-
"scripts": {
|
|
22
|
-
"lint": "eslint src --ext .ts,.tsx",
|
|
23
|
-
"build": "tsdown",
|
|
24
|
-
"dev": "tsdown --watch",
|
|
25
|
-
"typecheck": "tsc --noEmit",
|
|
26
|
-
"prepublishOnly": "pnpm run build"
|
|
27
|
-
},
|
|
28
21
|
"keywords": [
|
|
29
22
|
"react",
|
|
30
23
|
"components",
|
|
@@ -85,5 +78,12 @@
|
|
|
85
78
|
"tsdown": "^0.16.4",
|
|
86
79
|
"typescript": "^5.9.3",
|
|
87
80
|
"typescript-eslint": "^8.54.0"
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
84
|
+
"update-conflicts": "node scripts/update-conflicts.js",
|
|
85
|
+
"build": "tsdown",
|
|
86
|
+
"dev": "tsdown --watch",
|
|
87
|
+
"typecheck": "tsc --noEmit"
|
|
88
88
|
}
|
|
89
|
-
}
|
|
89
|
+
}
|