@syncsnap/react 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -1
- package/dist/index.js +38 -9
- package/dist/index.js.map +1 -1
- package/dist/theme.css +1 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -77,5 +77,10 @@ declare function useSyncsnapJob(options?: UseSyncsnapJobOptions): UseSyncsnapJob
|
|
|
77
77
|
declare function createUploadUrl(jobId: string, options?: {
|
|
78
78
|
baseUrl?: string;
|
|
79
79
|
}): string;
|
|
80
|
+
/** Thrown when the Syncsnap API returns 429 Too Many Requests (rate limit exceeded). */
|
|
81
|
+
declare class SyncsnapRateLimitError extends Error {
|
|
82
|
+
readonly statusCode = 429;
|
|
83
|
+
constructor(message: string);
|
|
84
|
+
}
|
|
80
85
|
|
|
81
|
-
export { type CompletedJobResponse, type CreateJobResponse, type Job, type JobStatus, type PresignedUrlResponse, SyncsnapQrCode, type SyncsnapQrCodeProps, SyncsnapUploadButton, type SyncsnapUploadButtonProps, type UseSyncsnapJobOptions, type UseSyncsnapJobResult, createUploadUrl, useSyncsnapJob };
|
|
86
|
+
export { type CompletedJobResponse, type CreateJobResponse, type Job, type JobStatus, type PresignedUrlResponse, SyncsnapQrCode, type SyncsnapQrCodeProps, SyncsnapRateLimitError, SyncsnapUploadButton, type SyncsnapUploadButtonProps, type UseSyncsnapJobOptions, type UseSyncsnapJobResult, createUploadUrl, useSyncsnapJob };
|
package/dist/index.js
CHANGED
|
@@ -9,11 +9,22 @@ function createUploadUrl(jobId, options) {
|
|
|
9
9
|
url.searchParams.set("job_id", jobId);
|
|
10
10
|
return url.toString();
|
|
11
11
|
}
|
|
12
|
+
var SyncsnapRateLimitError = class _SyncsnapRateLimitError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.statusCode = 429;
|
|
16
|
+
this.name = "SyncsnapRateLimitError";
|
|
17
|
+
Object.setPrototypeOf(this, _SyncsnapRateLimitError.prototype);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
12
20
|
async function fetchJson(url, init) {
|
|
13
21
|
const res = await fetch(url, init);
|
|
14
22
|
const data = await res.json().catch(() => ({}));
|
|
15
23
|
if (!res.ok) {
|
|
16
24
|
const message = typeof data === "object" && data && "error" in data && data.error ? String(data.error) : `Syncsnap request failed (${res.status})`;
|
|
25
|
+
if (res.status === 429) {
|
|
26
|
+
throw new SyncsnapRateLimitError(message);
|
|
27
|
+
}
|
|
17
28
|
throw new Error(message);
|
|
18
29
|
}
|
|
19
30
|
return data;
|
|
@@ -318,7 +329,8 @@ function DialogContent({
|
|
|
318
329
|
maxWidth: "24rem",
|
|
319
330
|
width: "100%",
|
|
320
331
|
padding: "1rem",
|
|
321
|
-
backgroundColor: "
|
|
332
|
+
backgroundColor: "var(--background, #fff)",
|
|
333
|
+
color: "var(--foreground, #0a0a0a)",
|
|
322
334
|
borderRadius: "0.75rem",
|
|
323
335
|
boxShadow: "0 25px 50px -12px rgba(0,0,0,0.25)"
|
|
324
336
|
},
|
|
@@ -385,7 +397,7 @@ function DialogDescription({
|
|
|
385
397
|
}
|
|
386
398
|
|
|
387
399
|
// src/components/SyncsnapUploadButton.tsx
|
|
388
|
-
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
400
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
389
401
|
function SyncsnapUploadButton({
|
|
390
402
|
buttonText = "Start upload",
|
|
391
403
|
className,
|
|
@@ -443,8 +455,14 @@ function SyncsnapUploadButton({
|
|
|
443
455
|
const downloadUrl = completedResult?.result && typeof completedResult.result === "object" && completedResult.result !== null && "downloadUrl" in completedResult.result ? completedResult.result.downloadUrl : void 0;
|
|
444
456
|
return /* @__PURE__ */ jsxs2("div", { className, children: [
|
|
445
457
|
/* @__PURE__ */ jsx4(Button, { type: "button", onClick, disabled: isWaiting, children: isWaiting ? "Preparing..." : buttonText }),
|
|
446
|
-
error ? /* @__PURE__ */ jsx4("
|
|
447
|
-
|
|
458
|
+
error ? /* @__PURE__ */ jsx4("div", { style: { color: "#dc2626", marginTop: 8 }, children: error instanceof SyncsnapRateLimitError ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
459
|
+
/* @__PURE__ */ jsx4("p", { style: { fontWeight: 600, margin: 0 }, children: "Rate limit exceeded" }),
|
|
460
|
+
/* @__PURE__ */ jsx4("p", { style: { margin: "4px 0 0", fontSize: 14 }, children: error.message })
|
|
461
|
+
] }) : /* @__PURE__ */ jsx4("p", { style: { margin: 0 }, children: error.message }) }) : null,
|
|
462
|
+
completedError ? /* @__PURE__ */ jsx4("div", { style: { color: "#dc2626", marginTop: 8 }, children: completedError instanceof SyncsnapRateLimitError ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
463
|
+
/* @__PURE__ */ jsx4("p", { style: { fontWeight: 600, margin: 0 }, children: "Rate limit exceeded" }),
|
|
464
|
+
/* @__PURE__ */ jsx4("p", { style: { margin: "4px 0 0", fontSize: 14 }, children: completedError.message })
|
|
465
|
+
] }) : /* @__PURE__ */ jsx4("p", { style: { margin: 0 }, children: completedError.message }) }) : null,
|
|
448
466
|
downloadUrl ? /* @__PURE__ */ jsxs2(
|
|
449
467
|
"div",
|
|
450
468
|
{
|
|
@@ -516,17 +534,27 @@ function SyncsnapUploadButton({
|
|
|
516
534
|
)
|
|
517
535
|
}
|
|
518
536
|
),
|
|
519
|
-
status ? /* @__PURE__ */ jsxs2(
|
|
520
|
-
"
|
|
521
|
-
|
|
522
|
-
|
|
537
|
+
status ? /* @__PURE__ */ jsxs2(
|
|
538
|
+
"p",
|
|
539
|
+
{
|
|
540
|
+
style: {
|
|
541
|
+
margin: "8px 0 0",
|
|
542
|
+
fontSize: 14,
|
|
543
|
+
color: "var(--foreground, inherit)"
|
|
544
|
+
},
|
|
545
|
+
children: [
|
|
546
|
+
"Status: ",
|
|
547
|
+
status
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
) : null,
|
|
523
551
|
/* @__PURE__ */ jsxs2(
|
|
524
552
|
"p",
|
|
525
553
|
{
|
|
526
554
|
style: {
|
|
527
555
|
margin: "16px 0 0",
|
|
528
556
|
fontSize: 13,
|
|
529
|
-
color: "#64748b"
|
|
557
|
+
color: "var(--muted-foreground, #64748b)"
|
|
530
558
|
},
|
|
531
559
|
children: [
|
|
532
560
|
"Powered by",
|
|
@@ -553,6 +581,7 @@ function SyncsnapUploadButton({
|
|
|
553
581
|
}
|
|
554
582
|
export {
|
|
555
583
|
SyncsnapQrCode,
|
|
584
|
+
SyncsnapRateLimitError,
|
|
556
585
|
SyncsnapUploadButton,
|
|
557
586
|
createUploadUrl,
|
|
558
587
|
useSyncsnapJob
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/SyncsnapQrCode.tsx","../src/utils.ts","../src/components/SyncsnapUploadButton.tsx","../src/hooks/useSyncsnapJob.ts","../src/components/ui/button.tsx","../src/lib/utils.ts","../src/components/ui/dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport QRCode from 'qrcode';\nimport type { SyncsnapQrCodeProps } from '../types';\nimport { createUploadUrl } from '../utils';\n\nexport function SyncsnapQrCode({\n jobId,\n baseUrl,\n size = 240,\n className,\n errorCorrectionLevel = 'M',\n}: SyncsnapQrCodeProps) {\n const [dataUrl, setDataUrl] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n const url = createUploadUrl(jobId, { baseUrl });\n\n QRCode.toDataURL(url, {\n width: size,\n errorCorrectionLevel,\n })\n .then((value) => {\n if (!mounted) return;\n setDataUrl(value);\n setError(null);\n })\n .catch((err) => {\n if (!mounted) return;\n setDataUrl(null);\n setError(\n err instanceof Error ? err : new Error('Failed to generate QR')\n );\n });\n\n return () => {\n mounted = false;\n };\n }, [jobId, baseUrl, size, errorCorrectionLevel]);\n\n if (error) {\n return null;\n }\n\n if (!dataUrl) {\n return null;\n }\n\n return (\n <img\n src={dataUrl}\n alt=\"Syncsnap QR code\"\n width={size}\n height={size}\n className={className}\n style={{\n display: 'block',\n margin: '0 auto',\n width: size,\n height: size,\n }}\n />\n );\n}\n","export function createUploadUrl(\n jobId: string,\n options?: { baseUrl?: string }\n): string {\n const baseUrl = options?.baseUrl ?? 'https://upload.syncsnap.xyz/';\n const url = new URL(baseUrl);\n url.searchParams.set('job_id', jobId);\n return url.toString();\n}\n\nexport async function fetchJson<T>(\n url: string,\n init?: RequestInit\n): Promise<T> {\n const res = await fetch(url, init);\n const data = (await res.json().catch(() => ({}))) as T & {\n error?: string;\n };\n\n if (!res.ok) {\n const message =\n typeof data === 'object' && data && 'error' in data && data.error\n ? String(data.error)\n : `Syncsnap request failed (${res.status})`;\n throw new Error(message);\n }\n\n return data as T;\n}\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport type { Job, SyncsnapUploadButtonProps } from '../types';\nimport { SyncsnapQrCode } from './SyncsnapQrCode';\nimport { useSyncsnapJob } from '../hooks/useSyncsnapJob';\nimport { Button } from './ui/button';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from './ui/dialog';\n\ntype CompletionResult = { job: Job; result?: unknown };\ntype ResultWithDownloadUrl = { downloadUrl?: string };\n\nexport function SyncsnapUploadButton({\n buttonText = 'Start upload',\n className,\n qrSize = 240,\n qrBaseUrl,\n errorCorrectionLevel = 'M',\n onCompleted: userOnCompleted,\n onError: userOnError,\n ...options\n}: SyncsnapUploadButtonProps) {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [completedResult, setCompletedResult] =\n useState<CompletionResult | null>(null);\n const [completedError, setCompletedError] = useState<Error | null>(null);\n\n const handleCompleted = useCallback(\n (job: Job, result?: unknown) => {\n setCompletedResult({ job, result });\n setCompletedError(null);\n setDialogOpen(false);\n userOnCompleted?.(job, result);\n },\n [userOnCompleted]\n );\n\n const handleError = useCallback(\n (err: Error) => {\n setCompletedError(err);\n setCompletedResult(null);\n setDialogOpen(false);\n userOnError?.(err);\n },\n [userOnError]\n );\n\n const { jobId, status, start, isWaiting, error, reset } = useSyncsnapJob({\n ...options,\n onCompleted: handleCompleted,\n onError: handleError,\n });\n\n // Open dialog when we have a job id\n useEffect(() => {\n if (jobId) setDialogOpen(true);\n }, [jobId]);\n\n const onClick = useCallback(() => {\n setCompletedResult(null);\n setCompletedError(null);\n setDialogOpen(true);\n void start();\n }, [start]);\n\n const onOpenChange = useCallback(\n (open: boolean) => {\n setDialogOpen(open);\n if (!open) {\n reset();\n }\n },\n [reset]\n );\n\n const downloadUrl =\n completedResult?.result &&\n typeof completedResult.result === 'object' &&\n completedResult.result !== null &&\n 'downloadUrl' in completedResult.result\n ? (completedResult.result as ResultWithDownloadUrl).downloadUrl\n : undefined;\n\n return (\n <div className={className}>\n <Button type=\"button\" onClick={onClick} disabled={isWaiting}>\n {isWaiting ? 'Preparing...' : buttonText}\n </Button>\n {error ? (\n <p style={{ color: '#dc2626', marginTop: 8 }}>{error.message}</p>\n ) : null}\n {completedError ? (\n <p style={{ color: '#dc2626', marginTop: 8 }}>\n {completedError.message}\n </p>\n ) : null}\n {downloadUrl ? (\n <div\n style={{\n marginTop: 16,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n }}\n >\n <p style={{ margin: '0 0 8px', fontSize: 14, color: '#555' }}>\n Upload complete\n </p>\n <img\n src={downloadUrl}\n alt=\"Uploaded\"\n style={{\n maxWidth: '100%',\n height: 'auto',\n borderRadius: 8,\n border: '1px solid #e5e5e5',\n }}\n />\n </div>\n ) : null}\n <Dialog open={dialogOpen} onOpenChange={onOpenChange}>\n <DialogContent\n style={{\n display: 'grid',\n gridTemplateColumns: '1fr',\n justifyItems: 'center',\n }}\n >\n <DialogHeader>\n <DialogTitle>Scan to upload</DialogTitle>\n <DialogDescription>\n Scan this QR code with your phone to upload files\n </DialogDescription>\n </DialogHeader>\n {jobId ? (\n <div\n style={{\n width: '100%',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n textAlign: 'center',\n marginTop: 16,\n }}\n >\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n width: '100%',\n }}\n >\n <SyncsnapQrCode\n jobId={jobId}\n baseUrl={qrBaseUrl}\n size={qrSize}\n errorCorrectionLevel={errorCorrectionLevel}\n />\n </div>\n {status ? (\n <p style={{ margin: '8px 0 0', fontSize: 14 }}>\n Status: {status}\n </p>\n ) : null}\n <p\n style={{\n margin: '16px 0 0',\n fontSize: 13,\n color: '#64748b',\n }}\n >\n Powered by{' '}\n <a\n href=\"https://syncsnap.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n SyncSnap\n </a>\n </p>\n </div>\n ) : null}\n </DialogContent>\n </Dialog>\n </div>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type {\n CreateJobResponse,\n Job,\n UseSyncsnapJobOptions,\n UseSyncsnapJobResult,\n} from '../types';\nimport { fetchJson } from '../utils';\n\nfunction defaultGetJobUrl(jobId: string): string {\n return `/api/syncsnap/job/${encodeURIComponent(jobId)}`;\n}\n\nfunction defaultGetWaitForCompletionUrl(\n getJobUrl: (jobId: string) => string\n): (jobId: string) => string {\n return (jobId: string): string => {\n const base = getJobUrl(jobId).replace(/\\/$/, '');\n return `${base}/wait`;\n };\n}\n\ninterface WaitCompletionResponse {\n job: Job;\n result?: unknown;\n}\n\nexport function useSyncsnapJob(\n options: UseSyncsnapJobOptions = {}\n): UseSyncsnapJobResult {\n const getJobUrlFn = options.getJobUrl ?? defaultGetJobUrl;\n const {\n createJobUrl = '/api/syncsnap/job',\n getWaitForCompletionUrl = defaultGetWaitForCompletionUrl(getJobUrlFn),\n waitTimeoutMs = 120000,\n waitIntervalMs = 2000,\n autoStart = false,\n onJobCreated,\n onCompleted,\n onError,\n } = options;\n\n const [job, setJob] = useState<Job | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [isWaiting, setIsWaiting] = useState(false);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const start = useCallback(async () => {\n setError(null);\n abortControllerRef.current?.abort();\n abortControllerRef.current = new AbortController();\n const signal = abortControllerRef.current.signal;\n\n try {\n const created = await fetchJson<CreateJobResponse>(createJobUrl, {\n method: 'POST',\n });\n const createdJob: Job = {\n ...created,\n fileName: null,\n };\n setJob(createdJob);\n onJobCreated?.(created);\n\n const waitUrl = getWaitForCompletionUrl(created.id);\n const url = new URL(\n waitUrl,\n typeof window !== 'undefined'\n ? window.location.origin\n : 'http://localhost'\n );\n url.searchParams.set('timeoutMs', String(waitTimeoutMs));\n url.searchParams.set('intervalMs', String(waitIntervalMs));\n\n setIsWaiting(true);\n const { job: finalJob, result } = await fetchJson<WaitCompletionResponse>(\n url.toString(),\n {\n signal,\n }\n );\n setJob(null);\n setIsWaiting(false);\n onCompleted?.(finalJob, result);\n } catch (err) {\n setIsWaiting(false);\n setJob(null);\n if (signal.aborted) {\n return;\n }\n const error =\n err instanceof Error ? err : new Error('Syncsnap job failed');\n setError(error);\n onError?.(error);\n }\n }, [\n createJobUrl,\n getWaitForCompletionUrl,\n waitTimeoutMs,\n waitIntervalMs,\n onJobCreated,\n onCompleted,\n onError,\n ]);\n\n const reset = useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setJob(null);\n setIsWaiting(false);\n setError(null);\n }, []);\n\n useEffect(() => {\n if (autoStart) {\n void start();\n }\n }, [autoStart, start]);\n\n return {\n job,\n jobId: job?.id ?? null,\n status: job?.status ?? null,\n error,\n isWaiting,\n start,\n reset,\n };\n}\n","import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '../../lib/utils';\n\nconst buttonVariants = cva(\n \"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none\",\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',\n outline:\n 'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground',\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 dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',\n destructive:\n 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default:\n 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',\n xs: \"h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3',\n icon: 'size-8',\n 'icon-xs':\n \"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n 'icon-sm':\n 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',\n 'icon-lg': 'size-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n);\n\nconst Button = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }\n>(function Button(\n {\n className,\n variant = 'default',\n size = 'default',\n asChild = false,\n ...props\n },\n ref\n) {\n const Comp = asChild ? Slot.Root : 'button';\n\n return (\n <Comp\n ref={ref}\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n});\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n","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 * as React from 'react';\nimport * as DialogPrimitive from '@radix-ui/react-dialog';\n\nimport { cn } from '../../lib/utils';\nimport { Button } from './button';\nimport { XIcon } from 'lucide-react';\n\nfunction Dialog({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nconst DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n React.ComponentProps<typeof DialogPrimitive.Overlay>\n>(function DialogOverlay({ className, style, ...props }, ref) {\n return (\n <DialogPrimitive.Overlay\n ref={ref}\n data-slot=\"dialog-overlay\"\n className={cn(\n 'data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50',\n className\n )}\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 50,\n backgroundColor: 'rgba(0,0,0,0.5)',\n ...style,\n }}\n {...props}\n />\n );\n});\nDialogOverlay.displayName = 'DialogOverlay';\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n style,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal>\n <DialogOverlay />\n {/* Wrapper ensures dialog is centered on screen (flexbox avoids transform/containing-block issues) */}\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 50,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '1rem',\n pointerEvents: 'none',\n }}\n >\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n 'bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-sm ring-1 duration-100 sm:max-w-sm w-full outline-none',\n className\n )}\n style={{\n ...style,\n position: 'relative',\n pointerEvents: 'auto',\n maxWidth: '24rem',\n width: '100%',\n padding: '1rem',\n backgroundColor: 'white',\n borderRadius: '0.75rem',\n boxShadow: '0 25px 50px -12px rgba(0,0,0,0.25)',\n }}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close data-slot=\"dialog-close\" asChild>\n <Button\n variant=\"ghost\"\n className=\"absolute top-2 right-2\"\n size=\"icon-sm\"\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </Button>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </div>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn('gap-2 flex flex-col', className)}\n {...props}\n />\n );\n}\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: React.ComponentProps<'div'> & {\n showCloseButton?: boolean;\n}) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n 'bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close asChild>\n <Button variant=\"outline\">Close</Button>\n </DialogPrimitive.Close>\n )}\n </div>\n );\n}\n\nfunction DialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn('text-base leading-none font-medium', className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\n 'text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3',\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],"mappings":"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","names":["useCallback","useEffect","useState","useEffect","useState","useState","error","useEffect","jsx","Button","React","jsx","jsx","DialogOverlay","jsx","jsx","jsx","jsxs","useState","useCallback","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/SyncsnapQrCode.tsx","../src/utils.ts","../src/components/SyncsnapUploadButton.tsx","../src/hooks/useSyncsnapJob.ts","../src/components/ui/button.tsx","../src/lib/utils.ts","../src/components/ui/dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport QRCode from 'qrcode';\nimport type { SyncsnapQrCodeProps } from '../types';\nimport { createUploadUrl } from '../utils';\n\nexport function SyncsnapQrCode({\n jobId,\n baseUrl,\n size = 240,\n className,\n errorCorrectionLevel = 'M',\n}: SyncsnapQrCodeProps) {\n const [dataUrl, setDataUrl] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n const url = createUploadUrl(jobId, { baseUrl });\n\n QRCode.toDataURL(url, {\n width: size,\n errorCorrectionLevel,\n })\n .then((value) => {\n if (!mounted) return;\n setDataUrl(value);\n setError(null);\n })\n .catch((err) => {\n if (!mounted) return;\n setDataUrl(null);\n setError(\n err instanceof Error ? err : new Error('Failed to generate QR')\n );\n });\n\n return () => {\n mounted = false;\n };\n }, [jobId, baseUrl, size, errorCorrectionLevel]);\n\n if (error) {\n return null;\n }\n\n if (!dataUrl) {\n return null;\n }\n\n return (\n <img\n src={dataUrl}\n alt=\"Syncsnap QR code\"\n width={size}\n height={size}\n className={className}\n style={{\n display: 'block',\n margin: '0 auto',\n width: size,\n height: size,\n }}\n />\n );\n}\n","export function createUploadUrl(\n jobId: string,\n options?: { baseUrl?: string }\n): string {\n const baseUrl = options?.baseUrl ?? 'https://upload.syncsnap.xyz/';\n const url = new URL(baseUrl);\n url.searchParams.set('job_id', jobId);\n return url.toString();\n}\n\n/** Thrown when the Syncsnap API returns 429 Too Many Requests (rate limit exceeded). */\nexport class SyncsnapRateLimitError extends Error {\n readonly statusCode = 429;\n\n constructor(message: string) {\n super(message);\n this.name = 'SyncsnapRateLimitError';\n Object.setPrototypeOf(this, SyncsnapRateLimitError.prototype);\n }\n}\n\nexport async function fetchJson<T>(\n url: string,\n init?: RequestInit\n): Promise<T> {\n const res = await fetch(url, init);\n const data = (await res.json().catch(() => ({}))) as T & {\n error?: string;\n };\n\n if (!res.ok) {\n const message =\n typeof data === 'object' && data && 'error' in data && data.error\n ? String(data.error)\n : `Syncsnap request failed (${res.status})`;\n if (res.status === 429) {\n throw new SyncsnapRateLimitError(message);\n }\n throw new Error(message);\n }\n\n return data as T;\n}\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport type { Job, SyncsnapUploadButtonProps } from '../types';\nimport { SyncsnapQrCode } from './SyncsnapQrCode';\nimport { useSyncsnapJob } from '../hooks/useSyncsnapJob';\nimport { SyncsnapRateLimitError } from '../utils';\nimport { Button } from './ui/button';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from './ui/dialog';\n\ntype CompletionResult = { job: Job; result?: unknown };\ntype ResultWithDownloadUrl = { downloadUrl?: string };\n\nexport function SyncsnapUploadButton({\n buttonText = 'Start upload',\n className,\n qrSize = 240,\n qrBaseUrl,\n errorCorrectionLevel = 'M',\n onCompleted: userOnCompleted,\n onError: userOnError,\n ...options\n}: SyncsnapUploadButtonProps) {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [completedResult, setCompletedResult] =\n useState<CompletionResult | null>(null);\n const [completedError, setCompletedError] = useState<Error | null>(null);\n\n const handleCompleted = useCallback(\n (job: Job, result?: unknown) => {\n setCompletedResult({ job, result });\n setCompletedError(null);\n setDialogOpen(false);\n userOnCompleted?.(job, result);\n },\n [userOnCompleted]\n );\n\n const handleError = useCallback(\n (err: Error) => {\n setCompletedError(err);\n setCompletedResult(null);\n setDialogOpen(false);\n userOnError?.(err);\n },\n [userOnError]\n );\n\n const { jobId, status, start, isWaiting, error, reset } = useSyncsnapJob({\n ...options,\n onCompleted: handleCompleted,\n onError: handleError,\n });\n\n // Open dialog when we have a job id\n useEffect(() => {\n if (jobId) setDialogOpen(true);\n }, [jobId]);\n\n const onClick = useCallback(() => {\n setCompletedResult(null);\n setCompletedError(null);\n setDialogOpen(true);\n void start();\n }, [start]);\n\n const onOpenChange = useCallback(\n (open: boolean) => {\n setDialogOpen(open);\n if (!open) {\n reset();\n }\n },\n [reset]\n );\n\n const downloadUrl =\n completedResult?.result &&\n typeof completedResult.result === 'object' &&\n completedResult.result !== null &&\n 'downloadUrl' in completedResult.result\n ? (completedResult.result as ResultWithDownloadUrl).downloadUrl\n : undefined;\n\n return (\n <div className={className}>\n <Button type=\"button\" onClick={onClick} disabled={isWaiting}>\n {isWaiting ? 'Preparing...' : buttonText}\n </Button>\n {error ? (\n <div style={{ color: '#dc2626', marginTop: 8 }}>\n {error instanceof SyncsnapRateLimitError ? (\n <>\n <p style={{ fontWeight: 600, margin: 0 }}>Rate limit exceeded</p>\n <p style={{ margin: '4px 0 0', fontSize: 14 }}>{error.message}</p>\n </>\n ) : (\n <p style={{ margin: 0 }}>{error.message}</p>\n )}\n </div>\n ) : null}\n {completedError ? (\n <div style={{ color: '#dc2626', marginTop: 8 }}>\n {completedError instanceof SyncsnapRateLimitError ? (\n <>\n <p style={{ fontWeight: 600, margin: 0 }}>Rate limit exceeded</p>\n <p style={{ margin: '4px 0 0', fontSize: 14 }}>\n {completedError.message}\n </p>\n </>\n ) : (\n <p style={{ margin: 0 }}>{completedError.message}</p>\n )}\n </div>\n ) : null}\n {downloadUrl ? (\n <div\n style={{\n marginTop: 16,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n }}\n >\n <p style={{ margin: '0 0 8px', fontSize: 14, color: '#555' }}>\n Upload complete\n </p>\n <img\n src={downloadUrl}\n alt=\"Uploaded\"\n style={{\n maxWidth: '100%',\n height: 'auto',\n borderRadius: 8,\n border: '1px solid #e5e5e5',\n }}\n />\n </div>\n ) : null}\n <Dialog open={dialogOpen} onOpenChange={onOpenChange}>\n <DialogContent\n style={{\n display: 'grid',\n gridTemplateColumns: '1fr',\n justifyItems: 'center',\n }}\n >\n <DialogHeader>\n <DialogTitle>Scan to upload</DialogTitle>\n <DialogDescription>\n Scan this QR code with your phone to upload files\n </DialogDescription>\n </DialogHeader>\n {jobId ? (\n <div\n style={{\n width: '100%',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n textAlign: 'center',\n marginTop: 16,\n }}\n >\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n width: '100%',\n }}\n >\n <SyncsnapQrCode\n jobId={jobId}\n baseUrl={qrBaseUrl}\n size={qrSize}\n errorCorrectionLevel={errorCorrectionLevel}\n />\n </div>\n {status ? (\n <p\n style={{\n margin: '8px 0 0',\n fontSize: 14,\n color: 'var(--foreground, inherit)',\n }}\n >\n Status: {status}\n </p>\n ) : null}\n <p\n style={{\n margin: '16px 0 0',\n fontSize: 13,\n color: 'var(--muted-foreground, #64748b)',\n }}\n >\n Powered by{' '}\n <a\n href=\"https://syncsnap.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n SyncSnap\n </a>\n </p>\n </div>\n ) : null}\n </DialogContent>\n </Dialog>\n </div>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type {\n CreateJobResponse,\n Job,\n UseSyncsnapJobOptions,\n UseSyncsnapJobResult,\n} from '../types';\nimport { fetchJson } from '../utils';\n\nfunction defaultGetJobUrl(jobId: string): string {\n return `/api/syncsnap/job/${encodeURIComponent(jobId)}`;\n}\n\nfunction defaultGetWaitForCompletionUrl(\n getJobUrl: (jobId: string) => string\n): (jobId: string) => string {\n return (jobId: string): string => {\n const base = getJobUrl(jobId).replace(/\\/$/, '');\n return `${base}/wait`;\n };\n}\n\ninterface WaitCompletionResponse {\n job: Job;\n result?: unknown;\n}\n\nexport function useSyncsnapJob(\n options: UseSyncsnapJobOptions = {}\n): UseSyncsnapJobResult {\n const getJobUrlFn = options.getJobUrl ?? defaultGetJobUrl;\n const {\n createJobUrl = '/api/syncsnap/job',\n getWaitForCompletionUrl = defaultGetWaitForCompletionUrl(getJobUrlFn),\n waitTimeoutMs = 120000,\n waitIntervalMs = 2000,\n autoStart = false,\n onJobCreated,\n onCompleted,\n onError,\n } = options;\n\n const [job, setJob] = useState<Job | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [isWaiting, setIsWaiting] = useState(false);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const start = useCallback(async () => {\n setError(null);\n abortControllerRef.current?.abort();\n abortControllerRef.current = new AbortController();\n const signal = abortControllerRef.current.signal;\n\n try {\n const created = await fetchJson<CreateJobResponse>(createJobUrl, {\n method: 'POST',\n });\n const createdJob: Job = {\n ...created,\n fileName: null,\n };\n setJob(createdJob);\n onJobCreated?.(created);\n\n const waitUrl = getWaitForCompletionUrl(created.id);\n const url = new URL(\n waitUrl,\n typeof window !== 'undefined'\n ? window.location.origin\n : 'http://localhost'\n );\n url.searchParams.set('timeoutMs', String(waitTimeoutMs));\n url.searchParams.set('intervalMs', String(waitIntervalMs));\n\n setIsWaiting(true);\n const { job: finalJob, result } = await fetchJson<WaitCompletionResponse>(\n url.toString(),\n {\n signal,\n }\n );\n setJob(null);\n setIsWaiting(false);\n onCompleted?.(finalJob, result);\n } catch (err) {\n setIsWaiting(false);\n setJob(null);\n if (signal.aborted) {\n return;\n }\n const error =\n err instanceof Error ? err : new Error('Syncsnap job failed');\n setError(error);\n onError?.(error);\n }\n }, [\n createJobUrl,\n getWaitForCompletionUrl,\n waitTimeoutMs,\n waitIntervalMs,\n onJobCreated,\n onCompleted,\n onError,\n ]);\n\n const reset = useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setJob(null);\n setIsWaiting(false);\n setError(null);\n }, []);\n\n useEffect(() => {\n if (autoStart) {\n void start();\n }\n }, [autoStart, start]);\n\n return {\n job,\n jobId: job?.id ?? null,\n status: job?.status ?? null,\n error,\n isWaiting,\n start,\n reset,\n };\n}\n","import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '../../lib/utils';\n\nconst buttonVariants = cva(\n \"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none\",\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',\n outline:\n 'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground',\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 dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',\n destructive:\n 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default:\n 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',\n xs: \"h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3',\n icon: 'size-8',\n 'icon-xs':\n \"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n 'icon-sm':\n 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',\n 'icon-lg': 'size-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n);\n\nconst Button = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }\n>(function Button(\n {\n className,\n variant = 'default',\n size = 'default',\n asChild = false,\n ...props\n },\n ref\n) {\n const Comp = asChild ? Slot.Root : 'button';\n\n return (\n <Comp\n ref={ref}\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n});\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n","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 * as React from 'react';\nimport * as DialogPrimitive from '@radix-ui/react-dialog';\n\nimport { cn } from '../../lib/utils';\nimport { Button } from './button';\nimport { XIcon } from 'lucide-react';\n\nfunction Dialog({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nconst DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n React.ComponentProps<typeof DialogPrimitive.Overlay>\n>(function DialogOverlay({ className, style, ...props }, ref) {\n return (\n <DialogPrimitive.Overlay\n ref={ref}\n data-slot=\"dialog-overlay\"\n className={cn(\n 'data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50',\n className\n )}\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 50,\n backgroundColor: 'rgba(0,0,0,0.5)',\n ...style,\n }}\n {...props}\n />\n );\n});\nDialogOverlay.displayName = 'DialogOverlay';\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n style,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal>\n <DialogOverlay />\n {/* Wrapper ensures dialog is centered on screen (flexbox avoids transform/containing-block issues) */}\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 50,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '1rem',\n pointerEvents: 'none',\n }}\n >\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n 'bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-sm ring-1 duration-100 sm:max-w-sm w-full outline-none',\n className\n )}\n style={{\n ...style,\n position: 'relative',\n pointerEvents: 'auto',\n maxWidth: '24rem',\n width: '100%',\n padding: '1rem',\n backgroundColor: 'var(--background, #fff)',\n color: 'var(--foreground, #0a0a0a)',\n borderRadius: '0.75rem',\n boxShadow: '0 25px 50px -12px rgba(0,0,0,0.25)',\n }}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close data-slot=\"dialog-close\" asChild>\n <Button\n variant=\"ghost\"\n className=\"absolute top-2 right-2\"\n size=\"icon-sm\"\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </Button>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </div>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn('gap-2 flex flex-col', className)}\n {...props}\n />\n );\n}\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: React.ComponentProps<'div'> & {\n showCloseButton?: boolean;\n}) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n 'bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close asChild>\n <Button variant=\"outline\">Close</Button>\n </DialogPrimitive.Close>\n )}\n </div>\n );\n}\n\nfunction DialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn('text-base leading-none font-medium', className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\n 'text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3',\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],"mappings":"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","names":["useCallback","useEffect","useState","useEffect","useState","useState","error","useEffect","jsx","Button","React","jsx","jsx","DialogOverlay","jsx","jsx","jsx","jsxs","useState","useCallback","useEffect"]}
|
package/dist/theme.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncsnap/react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Syncsnap client SDK for React",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"lint:fix": "eslint . --fix",
|
|
23
23
|
"format": "prettier --write .",
|
|
24
24
|
"format:check": "prettier --check .",
|
|
25
|
-
"build": "tsup src/index.tsx --dts --format esm --out-dir dist --clean --sourcemap && node -
|
|
25
|
+
"build": "tsup src/index.tsx --dts --format esm --out-dir dist --clean --sourcemap && node scripts/copy-theme.cjs",
|
|
26
26
|
"publish": "npm publish --access public",
|
|
27
27
|
"publish:ci": "npm publish --provenance --access public",
|
|
28
28
|
"link": "npm run build && npm link",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
|
35
|
-
"url": "https://github.com/
|
|
35
|
+
"url": "https://github.com/syncsnapxyz/packages.git",
|
|
36
36
|
"directory": "react"
|
|
37
37
|
},
|
|
38
|
-
"homepage": "https://github.com/
|
|
38
|
+
"homepage": "https://github.com/syncsnapxyz/packages/react#readme",
|
|
39
39
|
"bugs": {
|
|
40
|
-
"url": "https://github.com/
|
|
40
|
+
"url": "https://github.com/syncsnapxyz/packages/react/issues"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|