@signiphi/page-assembly 0.2.0-beta.1

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.js ADDED
@@ -0,0 +1,1872 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React7 = require('react');
6
+ var reactDnd = require('react-dnd');
7
+ var reactDndHtml5Backend = require('react-dnd-html5-backend');
8
+ var lucideReact = require('lucide-react');
9
+ var reactSlot = require('@radix-ui/react-slot');
10
+ var classVarianceAuthority = require('class-variance-authority');
11
+ var clsx = require('clsx');
12
+ var tailwindMerge = require('tailwind-merge');
13
+ var jsxRuntime = require('react/jsx-runtime');
14
+ var LabelPrimitive = require('@radix-ui/react-label');
15
+ var SelectPrimitive = require('@radix-ui/react-select');
16
+ var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
17
+ var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
18
+ var TooltipPrimitive = require('@radix-ui/react-tooltip');
19
+ var pdfjsLib = require('pdfjs-dist');
20
+ var pdfLib = require('pdf-lib');
21
+
22
+ function _interopNamespace(e) {
23
+ if (e && e.__esModule) return e;
24
+ var n = Object.create(null);
25
+ if (e) {
26
+ Object.keys(e).forEach(function (k) {
27
+ if (k !== 'default') {
28
+ var d = Object.getOwnPropertyDescriptor(e, k);
29
+ Object.defineProperty(n, k, d.get ? d : {
30
+ enumerable: true,
31
+ get: function () { return e[k]; }
32
+ });
33
+ }
34
+ });
35
+ }
36
+ n.default = e;
37
+ return Object.freeze(n);
38
+ }
39
+
40
+ var React7__namespace = /*#__PURE__*/_interopNamespace(React7);
41
+ var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
42
+ var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
43
+ var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
44
+ var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMenuPrimitive);
45
+ var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
46
+ var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
47
+
48
+ // src/components/PageAssembler.tsx
49
+ function cn(...inputs) {
50
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
51
+ }
52
+ var buttonVariants = classVarianceAuthority.cva(
53
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
54
+ {
55
+ variants: {
56
+ variant: {
57
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
58
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
59
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
60
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
61
+ ghost: "hover:bg-accent hover:text-accent-foreground",
62
+ link: "text-primary underline-offset-4 hover:underline"
63
+ },
64
+ size: {
65
+ default: "h-10 px-4 py-2",
66
+ sm: "h-9 rounded-md px-3",
67
+ lg: "h-11 md:h-12 rounded-md px-8",
68
+ icon: "h-10 w-10"
69
+ }
70
+ },
71
+ defaultVariants: {
72
+ variant: "default",
73
+ size: "default"
74
+ }
75
+ }
76
+ );
77
+ var Button = React7__namespace.forwardRef(
78
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
79
+ const Comp = asChild ? reactSlot.Slot : "button";
80
+ return /* @__PURE__ */ jsxRuntime.jsx(
81
+ Comp,
82
+ {
83
+ className: cn(buttonVariants({ variant, size }), className),
84
+ ref,
85
+ ...props
86
+ }
87
+ );
88
+ }
89
+ );
90
+ Button.displayName = "Button";
91
+ var Card = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
92
+ "div",
93
+ {
94
+ ref,
95
+ className: cn(
96
+ "rounded-lg bg-card text-card-foreground shadow-sm",
97
+ className
98
+ ),
99
+ style: {
100
+ border: "1px solid hsl(var(--xpa-border))",
101
+ ...props.style || {}
102
+ },
103
+ ...props
104
+ }
105
+ ));
106
+ Card.displayName = "Card";
107
+ var CardHeader = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
108
+ "div",
109
+ {
110
+ ref,
111
+ className: cn("flex flex-col space-y-1.5 p-6", className),
112
+ ...props
113
+ }
114
+ ));
115
+ CardHeader.displayName = "CardHeader";
116
+ var CardTitle = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
117
+ "h3",
118
+ {
119
+ ref,
120
+ className: cn(
121
+ "text-2xl font-semibold leading-none tracking-tight",
122
+ className
123
+ ),
124
+ ...props
125
+ }
126
+ ));
127
+ CardTitle.displayName = "CardTitle";
128
+ var CardDescription = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
129
+ "p",
130
+ {
131
+ ref,
132
+ className: cn("text-sm text-muted-foreground", className),
133
+ ...props
134
+ }
135
+ ));
136
+ CardDescription.displayName = "CardDescription";
137
+ var CardContent = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
138
+ CardContent.displayName = "CardContent";
139
+ var CardFooter = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
140
+ "div",
141
+ {
142
+ ref,
143
+ className: cn("flex items-center p-6 pt-0", className),
144
+ ...props
145
+ }
146
+ ));
147
+ CardFooter.displayName = "CardFooter";
148
+ var Input = React7__namespace.forwardRef(
149
+ ({ className, type, ...props }, ref) => {
150
+ return /* @__PURE__ */ jsxRuntime.jsx(
151
+ "input",
152
+ {
153
+ type,
154
+ className: cn(
155
+ "flex h-10 w-full rounded-md border-2 border-input bg-background px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground transition-all duration-200 focus:outline-none focus:border-primary focus:ring-0 focus:shadow-[0_0_0_3px_rgba(0,153,205,0.15)] focus-visible:outline-none focus-visible:border-primary focus-visible:ring-0 focus-visible:shadow-[0_0_0_3px_rgba(0,153,205,0.15)] disabled:cursor-not-allowed disabled:opacity-50",
156
+ className
157
+ ),
158
+ ref,
159
+ ...props
160
+ }
161
+ );
162
+ }
163
+ );
164
+ Input.displayName = "Input";
165
+ var labelVariants = classVarianceAuthority.cva(
166
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
167
+ );
168
+ var Label = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
169
+ LabelPrimitive__namespace.Root,
170
+ {
171
+ ref,
172
+ className: cn(labelVariants(), className),
173
+ ...props
174
+ }
175
+ ));
176
+ Label.displayName = LabelPrimitive__namespace.Root.displayName;
177
+ var badgeVariants = classVarianceAuthority.cva(
178
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
179
+ {
180
+ variants: {
181
+ variant: {
182
+ default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
183
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
184
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
185
+ outline: "text-foreground"
186
+ }
187
+ },
188
+ defaultVariants: {
189
+ variant: "default"
190
+ }
191
+ }
192
+ );
193
+ function Badge({ className, variant, ...props }) {
194
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
195
+ }
196
+ var Select = SelectPrimitive__namespace.Root;
197
+ var SelectValue = SelectPrimitive__namespace.Value;
198
+ var SelectTrigger = React7__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
199
+ SelectPrimitive__namespace.Trigger,
200
+ {
201
+ ref,
202
+ className: cn(
203
+ "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
204
+ className
205
+ ),
206
+ ...props,
207
+ children: [
208
+ children,
209
+ /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 opacity-50" }) })
210
+ ]
211
+ }
212
+ ));
213
+ SelectTrigger.displayName = SelectPrimitive__namespace.Trigger.displayName;
214
+ var SelectScrollUpButton = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
215
+ SelectPrimitive__namespace.ScrollUpButton,
216
+ {
217
+ ref,
218
+ className: cn(
219
+ "flex cursor-default items-center justify-center py-1",
220
+ className
221
+ ),
222
+ ...props,
223
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4" })
224
+ }
225
+ ));
226
+ SelectScrollUpButton.displayName = SelectPrimitive__namespace.ScrollUpButton.displayName;
227
+ var SelectScrollDownButton = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
228
+ SelectPrimitive__namespace.ScrollDownButton,
229
+ {
230
+ ref,
231
+ className: cn(
232
+ "flex cursor-default items-center justify-center py-1",
233
+ className
234
+ ),
235
+ ...props,
236
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" })
237
+ }
238
+ ));
239
+ SelectScrollDownButton.displayName = SelectPrimitive__namespace.ScrollDownButton.displayName;
240
+ var SelectContent = React7__namespace.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
241
+ SelectPrimitive__namespace.Content,
242
+ {
243
+ ref,
244
+ className: cn(
245
+ "relative max-h-96 min-w-[12rem] overflow-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
246
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
247
+ className
248
+ ),
249
+ position,
250
+ style: {
251
+ zIndex: 99999,
252
+ backgroundColor: "#ffffff",
253
+ border: "1px solid #e2e8f0",
254
+ borderRadius: "0.5rem",
255
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
256
+ marginTop: "4px"
257
+ },
258
+ ...props,
259
+ children: [
260
+ /* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
261
+ /* @__PURE__ */ jsxRuntime.jsx(
262
+ SelectPrimitive__namespace.Viewport,
263
+ {
264
+ className: cn(
265
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
266
+ ),
267
+ style: { padding: "6px" },
268
+ children
269
+ }
270
+ ),
271
+ /* @__PURE__ */ jsxRuntime.jsx(SelectScrollDownButton, {})
272
+ ]
273
+ }
274
+ ) }));
275
+ SelectContent.displayName = SelectPrimitive__namespace.Content.displayName;
276
+ var SelectLabel = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
277
+ SelectPrimitive__namespace.Label,
278
+ {
279
+ ref,
280
+ className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className),
281
+ ...props
282
+ }
283
+ ));
284
+ SelectLabel.displayName = SelectPrimitive__namespace.Label.displayName;
285
+ var SelectItem = React7__namespace.forwardRef(({ className, children, ...props }, ref) => {
286
+ const [isHovered, setIsHovered] = React7__namespace.useState(false);
287
+ return /* @__PURE__ */ jsxRuntime.jsxs(
288
+ SelectPrimitive__namespace.Item,
289
+ {
290
+ ref,
291
+ className: cn(
292
+ "relative flex w-full cursor-pointer select-none items-center outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
293
+ className
294
+ ),
295
+ style: {
296
+ backgroundColor: isHovered ? "#f1f5f9" : "transparent",
297
+ color: "#1e293b",
298
+ padding: "8px 12px",
299
+ borderRadius: "6px",
300
+ fontSize: "14px",
301
+ marginBottom: "2px"
302
+ },
303
+ onMouseEnter: () => setIsHovered(true),
304
+ onMouseLeave: () => setIsHovered(false),
305
+ ...props,
306
+ children: [
307
+ /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children }),
308
+ /* @__PURE__ */ jsxRuntime.jsx(
309
+ SelectPrimitive__namespace.ItemIndicator,
310
+ {
311
+ style: {
312
+ marginLeft: "auto",
313
+ paddingLeft: "8px",
314
+ color: "#0099cd"
315
+ },
316
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" })
317
+ }
318
+ )
319
+ ]
320
+ }
321
+ );
322
+ });
323
+ SelectItem.displayName = SelectPrimitive__namespace.Item.displayName;
324
+ var SelectSeparator = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
325
+ SelectPrimitive__namespace.Separator,
326
+ {
327
+ ref,
328
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
329
+ ...props
330
+ }
331
+ ));
332
+ SelectSeparator.displayName = SelectPrimitive__namespace.Separator.displayName;
333
+ var AlertDialog = AlertDialogPrimitive__namespace.Root;
334
+ var AlertDialogPortal = AlertDialogPrimitive__namespace.Portal;
335
+ var AlertDialogOverlay = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
336
+ AlertDialogPrimitive__namespace.Overlay,
337
+ {
338
+ className: cn(
339
+ "fixed inset-0 z-[9998] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
340
+ className
341
+ ),
342
+ ...props,
343
+ ref
344
+ }
345
+ ));
346
+ AlertDialogOverlay.displayName = AlertDialogPrimitive__namespace.Overlay.displayName;
347
+ var AlertDialogContent = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { container: document.querySelector(".signiphi-page-assembly"), children: [
348
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogOverlay, {}),
349
+ /* @__PURE__ */ jsxRuntime.jsx(
350
+ AlertDialogPrimitive__namespace.Content,
351
+ {
352
+ ref,
353
+ className: cn(
354
+ "fixed left-[50%] top-[50%] z-[9999] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
355
+ className
356
+ ),
357
+ ...props
358
+ }
359
+ )
360
+ ] }));
361
+ AlertDialogContent.displayName = AlertDialogPrimitive__namespace.Content.displayName;
362
+ var AlertDialogHeader = ({
363
+ className,
364
+ ...props
365
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
366
+ "div",
367
+ {
368
+ className: cn(
369
+ "flex flex-col space-y-2 text-center sm:text-left",
370
+ className
371
+ ),
372
+ ...props
373
+ }
374
+ );
375
+ AlertDialogHeader.displayName = "AlertDialogHeader";
376
+ var AlertDialogFooter = ({
377
+ className,
378
+ ...props
379
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
380
+ "div",
381
+ {
382
+ className: cn(
383
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
384
+ className
385
+ ),
386
+ ...props
387
+ }
388
+ );
389
+ AlertDialogFooter.displayName = "AlertDialogFooter";
390
+ var AlertDialogTitle = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
391
+ AlertDialogPrimitive__namespace.Title,
392
+ {
393
+ ref,
394
+ className: cn("text-lg font-semibold", className),
395
+ ...props
396
+ }
397
+ ));
398
+ AlertDialogTitle.displayName = AlertDialogPrimitive__namespace.Title.displayName;
399
+ var AlertDialogDescription = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
400
+ AlertDialogPrimitive__namespace.Description,
401
+ {
402
+ ref,
403
+ className: cn("text-sm text-muted-foreground", className),
404
+ ...props
405
+ }
406
+ ));
407
+ AlertDialogDescription.displayName = AlertDialogPrimitive__namespace.Description.displayName;
408
+ var AlertDialogAction = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
409
+ AlertDialogPrimitive__namespace.Action,
410
+ {
411
+ ref,
412
+ className: cn(buttonVariants(), className),
413
+ ...props
414
+ }
415
+ ));
416
+ AlertDialogAction.displayName = AlertDialogPrimitive__namespace.Action.displayName;
417
+ var AlertDialogCancel = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
418
+ AlertDialogPrimitive__namespace.Cancel,
419
+ {
420
+ ref,
421
+ className: cn(
422
+ buttonVariants({ variant: "outline" }),
423
+ "mt-2 sm:mt-0",
424
+ className
425
+ ),
426
+ ...props
427
+ }
428
+ ));
429
+ AlertDialogCancel.displayName = AlertDialogPrimitive__namespace.Cancel.displayName;
430
+ var DropdownMenu = DropdownMenuPrimitive__namespace.Root;
431
+ var DropdownMenuTrigger = DropdownMenuPrimitive__namespace.Trigger;
432
+ var DropdownMenuSubTrigger = React7__namespace.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
433
+ DropdownMenuPrimitive__namespace.SubTrigger,
434
+ {
435
+ ref,
436
+ className: cn(
437
+ "flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
438
+ inset && "pl-8",
439
+ className
440
+ ),
441
+ ...props,
442
+ children: [
443
+ children,
444
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "ml-auto" })
445
+ ]
446
+ }
447
+ ));
448
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive__namespace.SubTrigger.displayName;
449
+ var DropdownMenuSubContent = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
450
+ DropdownMenuPrimitive__namespace.SubContent,
451
+ {
452
+ ref,
453
+ className: cn(
454
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
455
+ className
456
+ ),
457
+ ...props
458
+ }
459
+ ));
460
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive__namespace.SubContent.displayName;
461
+ var DropdownMenuContent = React7__namespace.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
462
+ DropdownMenuPrimitive__namespace.Content,
463
+ {
464
+ ref,
465
+ sideOffset,
466
+ className: cn(
467
+ "min-w-[12rem] overflow-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
468
+ className
469
+ ),
470
+ style: {
471
+ zIndex: 99999,
472
+ backgroundColor: "#ffffff",
473
+ border: "1px solid #e2e8f0",
474
+ borderRadius: "0.5rem",
475
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
476
+ padding: "6px"
477
+ },
478
+ ...props
479
+ }
480
+ ) }));
481
+ DropdownMenuContent.displayName = DropdownMenuPrimitive__namespace.Content.displayName;
482
+ var DropdownMenuItem = React7__namespace.forwardRef(({ className, inset, ...props }, ref) => {
483
+ const [isHovered, setIsHovered] = React7__namespace.useState(false);
484
+ return /* @__PURE__ */ jsxRuntime.jsx(
485
+ DropdownMenuPrimitive__namespace.Item,
486
+ {
487
+ ref,
488
+ className: cn(
489
+ "relative flex cursor-pointer select-none items-center gap-2 outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
490
+ inset && "pl-8",
491
+ className
492
+ ),
493
+ style: {
494
+ backgroundColor: isHovered ? "#f1f5f9" : "transparent",
495
+ color: "#1e293b",
496
+ padding: "8px 12px",
497
+ borderRadius: "6px",
498
+ fontSize: "14px",
499
+ marginBottom: "2px"
500
+ },
501
+ onMouseEnter: () => setIsHovered(true),
502
+ onMouseLeave: () => setIsHovered(false),
503
+ ...props
504
+ }
505
+ );
506
+ });
507
+ DropdownMenuItem.displayName = DropdownMenuPrimitive__namespace.Item.displayName;
508
+ var DropdownMenuCheckboxItem = React7__namespace.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
509
+ DropdownMenuPrimitive__namespace.CheckboxItem,
510
+ {
511
+ ref,
512
+ className: cn(
513
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
514
+ className
515
+ ),
516
+ checked,
517
+ ...props,
518
+ children: [
519
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }) }) }),
520
+ children
521
+ ]
522
+ }
523
+ ));
524
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive__namespace.CheckboxItem.displayName;
525
+ var DropdownMenuRadioItem = React7__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
526
+ DropdownMenuPrimitive__namespace.RadioItem,
527
+ {
528
+ ref,
529
+ className: cn(
530
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
531
+ className
532
+ ),
533
+ ...props,
534
+ children: [
535
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "h-2 w-2 fill-current" }) }) }),
536
+ children
537
+ ]
538
+ }
539
+ ));
540
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive__namespace.RadioItem.displayName;
541
+ var DropdownMenuLabel = React7__namespace.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
542
+ DropdownMenuPrimitive__namespace.Label,
543
+ {
544
+ ref,
545
+ className: cn(
546
+ "px-2 py-1.5 text-sm font-semibold",
547
+ inset && "pl-8",
548
+ className
549
+ ),
550
+ ...props
551
+ }
552
+ ));
553
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive__namespace.Label.displayName;
554
+ var DropdownMenuSeparator = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
555
+ DropdownMenuPrimitive__namespace.Separator,
556
+ {
557
+ ref,
558
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
559
+ ...props
560
+ }
561
+ ));
562
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive__namespace.Separator.displayName;
563
+ var TooltipProvider = TooltipPrimitive__namespace.Provider;
564
+ var Tooltip = TooltipPrimitive__namespace.Root;
565
+ var TooltipTrigger = TooltipPrimitive__namespace.Trigger;
566
+ var TooltipContent = React7__namespace.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
567
+ TooltipPrimitive__namespace.Content,
568
+ {
569
+ ref,
570
+ sideOffset,
571
+ className: cn(
572
+ "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
573
+ className
574
+ ),
575
+ ...props
576
+ }
577
+ ));
578
+ TooltipContent.displayName = TooltipPrimitive__namespace.Content.displayName;
579
+ if (typeof window !== "undefined") {
580
+ pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
581
+ }
582
+ async function pdfToImages(pdfBytes, options) {
583
+ try {
584
+ const header = new TextDecoder().decode(pdfBytes.slice(0, 10));
585
+ if (!header.startsWith("%PDF-")) {
586
+ console.error("Invalid PDF: Does not start with %PDF- header");
587
+ throw new Error("Invalid PDF format: Missing PDF header");
588
+ }
589
+ if (typeof window !== "undefined") {
590
+ pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
591
+ }
592
+ const loadingTask = pdfjsLib__namespace.getDocument({
593
+ data: pdfBytes,
594
+ verbosity: 0
595
+ });
596
+ const pdfDoc = await loadingTask.promise;
597
+ const pages = [];
598
+ let pdfLibDoc = null;
599
+ try {
600
+ pdfLibDoc = await pdfLib.PDFDocument.load(pdfBytes);
601
+ } catch {
602
+ }
603
+ for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) {
604
+ const page = await pdfDoc.getPage(pageNum);
605
+ const viewport = page.getViewport({ scale: 2 });
606
+ let pdfWidth = viewport.width / 2;
607
+ let pdfHeight = viewport.height / 2;
608
+ if (pdfLibDoc) {
609
+ try {
610
+ const pdfLibPage = pdfLibDoc.getPage(pageNum - 1);
611
+ const pdfLibWidth = pdfLibPage.getWidth();
612
+ const pdfLibHeight = pdfLibPage.getHeight();
613
+ pdfWidth = pdfLibWidth;
614
+ pdfHeight = pdfLibHeight;
615
+ } catch {
616
+ }
617
+ }
618
+ const canvas = document.createElement("canvas");
619
+ const context = canvas.getContext("2d");
620
+ canvas.height = viewport.height;
621
+ canvas.width = viewport.width;
622
+ const hideFormFields = options?.hideFormFields ?? false;
623
+ const renderContext = {
624
+ canvasContext: context,
625
+ viewport,
626
+ // Hide annotations/form fields when specified
627
+ renderInteractiveForms: !hideFormFields,
628
+ // Additional options to ensure form fields are hidden
629
+ ...hideFormFields && {
630
+ annotationMode: 0,
631
+ // Disable annotations
632
+ renderAnnotations: false,
633
+ renderForms: false
634
+ }
635
+ };
636
+ await page.render(renderContext).promise;
637
+ const imageUrl = canvas.toDataURL("image/png");
638
+ pages.push({
639
+ imageUrl,
640
+ width: pdfWidth,
641
+ height: pdfHeight
642
+ });
643
+ }
644
+ return pages;
645
+ } catch (error) {
646
+ console.error("Error converting PDF to images with PDF.js:", error);
647
+ throw error;
648
+ }
649
+ }
650
+ async function imageToPdf(imageFile) {
651
+ return new Promise((resolve, reject) => {
652
+ const img = new Image();
653
+ const canvas = document.createElement("canvas");
654
+ const ctx = canvas.getContext("2d");
655
+ img.onload = async () => {
656
+ try {
657
+ canvas.width = img.width;
658
+ canvas.height = img.height;
659
+ ctx.drawImage(img, 0, 0);
660
+ canvas.toBlob(
661
+ async (blob) => {
662
+ if (!blob) {
663
+ reject(new Error("Failed to convert image to blob"));
664
+ return;
665
+ }
666
+ const imageBytes = new Uint8Array(await blob.arrayBuffer());
667
+ const pdfDoc = await pdfLib.PDFDocument.create();
668
+ const embeddedImage = await pdfDoc.embedPng(imageBytes);
669
+ const { width, height } = embeddedImage.scale(1);
670
+ const maxWidth = 595;
671
+ const maxHeight = 842;
672
+ let pageWidth = width;
673
+ let pageHeight = height;
674
+ if (width > maxWidth || height > maxHeight) {
675
+ const scale = Math.min(maxWidth / width, maxHeight / height);
676
+ pageWidth = width * scale;
677
+ pageHeight = height * scale;
678
+ }
679
+ const page = pdfDoc.addPage([
680
+ Math.max(pageWidth, 100),
681
+ Math.max(pageHeight, 100)
682
+ ]);
683
+ const x = (page.getWidth() - pageWidth) / 2;
684
+ const y = (page.getHeight() - pageHeight) / 2;
685
+ page.drawImage(embeddedImage, {
686
+ x: Math.max(x, 0),
687
+ y: Math.max(y, 0),
688
+ width: pageWidth,
689
+ height: pageHeight
690
+ });
691
+ const pdfBytes = await pdfDoc.save();
692
+ resolve(pdfBytes);
693
+ },
694
+ "image/png",
695
+ 0.95
696
+ );
697
+ } catch (error) {
698
+ reject(error);
699
+ }
700
+ };
701
+ img.onerror = () => {
702
+ reject(new Error("Failed to load image"));
703
+ };
704
+ const objectUrl = URL.createObjectURL(imageFile);
705
+ img.src = objectUrl;
706
+ });
707
+ }
708
+ function createPdfBlobUrl(pdfBytes) {
709
+ const blob = new Blob([pdfBytes], {
710
+ type: "application/pdf"
711
+ });
712
+ return URL.createObjectURL(blob);
713
+ }
714
+ function downloadPdf(pdfBytes, filename) {
715
+ const blob = new Blob([pdfBytes], {
716
+ type: "application/pdf"
717
+ });
718
+ const url = URL.createObjectURL(blob);
719
+ const a = document.createElement("a");
720
+ a.href = url;
721
+ a.download = filename;
722
+ a.click();
723
+ URL.revokeObjectURL(url);
724
+ }
725
+ var isMultiSelectModifier = (event) => {
726
+ return event.ctrlKey || event.metaKey;
727
+ };
728
+ var isRangeSelectModifier = (event) => {
729
+ return event.shiftKey;
730
+ };
731
+ var handleContextMenu = (event) => {
732
+ if (event.ctrlKey && /Mac|iPod|iPhone|iPad/.test(navigator.userAgent)) {
733
+ event.preventDefault();
734
+ }
735
+ };
736
+ var getPageRange = (files, startPageId, endPageId) => {
737
+ const allPages = [];
738
+ files.forEach((file) => {
739
+ file.pages.forEach((page) => {
740
+ allPages.push({ id: page.id, fileId: file.id });
741
+ });
742
+ });
743
+ const startIndex = allPages.findIndex((p) => p.id === startPageId);
744
+ const endIndex = allPages.findIndex((p) => p.id === endPageId);
745
+ if (startIndex === -1 || endIndex === -1) return [];
746
+ const start = Math.min(startIndex, endIndex);
747
+ const end = Math.max(startIndex, endIndex);
748
+ return allPages.slice(start, end + 1).map((p) => p.id);
749
+ };
750
+ function assemblerReducer(state, action) {
751
+ switch (action.type) {
752
+ case "ADD_FILE": {
753
+ const existingFileById = state.files.find((f) => f.id === action.payload.id);
754
+ if (existingFileById) return state;
755
+ return {
756
+ ...state,
757
+ files: [...state.files, action.payload]
758
+ };
759
+ }
760
+ case "REMOVE_FILE":
761
+ return {
762
+ ...state,
763
+ files: state.files.filter((f) => f.id !== action.payload),
764
+ selection: state.selection.filter(
765
+ (pageId) => !state.files.find((f) => f.id === action.payload)?.pages.some((p) => p.id === pageId)
766
+ )
767
+ };
768
+ case "UPDATE_FILE":
769
+ return {
770
+ ...state,
771
+ files: state.files.map(
772
+ (f) => f.id === action.payload.fileId ? { ...f, ...action.payload.updates } : f
773
+ )
774
+ };
775
+ case "REORDER_PAGES":
776
+ return {
777
+ ...state,
778
+ files: state.files.map(
779
+ (f) => f.id === action.payload.fileId ? { ...f, pages: action.payload.newOrder } : f
780
+ )
781
+ };
782
+ case "REORDER_FILES":
783
+ return {
784
+ ...state,
785
+ files: action.payload.newOrder
786
+ };
787
+ case "MOVE_PAGES": {
788
+ const { pageIds, targetFileId } = action.payload;
789
+ const existingPageIds = state.files.flatMap((f) => f.pages.map((p) => p.id));
790
+ const pagesToActuallyMove = pageIds.filter((id) => existingPageIds.includes(id));
791
+ if (pagesToActuallyMove.length === 0) return state;
792
+ const pagesToMove = [];
793
+ for (const file of state.files) {
794
+ for (const page of file.pages) {
795
+ if (pagesToActuallyMove.includes(page.id)) {
796
+ pagesToMove.push(page);
797
+ }
798
+ }
799
+ }
800
+ const updatedFiles = state.files.map((file) => {
801
+ if (file.id === targetFileId) {
802
+ const existingPageIds2 = file.pages.map((p) => p.id);
803
+ const newPages = pagesToMove.filter((p) => !existingPageIds2.includes(p.id));
804
+ return {
805
+ ...file,
806
+ pages: [...file.pages, ...newPages]
807
+ };
808
+ } else {
809
+ return {
810
+ ...file,
811
+ pages: file.pages.filter((page) => !pagesToActuallyMove.includes(page.id))
812
+ };
813
+ }
814
+ });
815
+ return {
816
+ ...state,
817
+ files: updatedFiles,
818
+ selection: []
819
+ };
820
+ }
821
+ case "DELETE_PAGES": {
822
+ const pageIdsToDelete = action.payload;
823
+ const existingPageIds = state.files.flatMap((f) => f.pages.map((p) => p.id));
824
+ const pagesToActuallyDelete = pageIdsToDelete.filter((id) => existingPageIds.includes(id));
825
+ if (pagesToActuallyDelete.length === 0) return state;
826
+ const updatedFiles = state.files.map((file) => {
827
+ const remainingPages = file.pages.filter((page) => !pagesToActuallyDelete.includes(page.id));
828
+ return {
829
+ ...file,
830
+ pages: remainingPages
831
+ };
832
+ }).filter((file) => file.pages.length > 0);
833
+ return {
834
+ ...state,
835
+ files: updatedFiles,
836
+ selection: state.selection.filter((id) => !pagesToActuallyDelete.includes(id))
837
+ };
838
+ }
839
+ case "SET_SELECTION":
840
+ return {
841
+ ...state,
842
+ selection: action.payload
843
+ };
844
+ case "TOGGLE_PAGE_SELECTION": {
845
+ const { pageId } = action.payload;
846
+ const isSelected = state.selection.includes(pageId);
847
+ if (isSelected) {
848
+ return {
849
+ ...state,
850
+ selection: state.selection.filter((id) => id !== pageId),
851
+ lastSelectedPageId: pageId
852
+ };
853
+ } else {
854
+ return {
855
+ ...state,
856
+ selection: [...state.selection, pageId],
857
+ lastSelectedPageId: pageId
858
+ };
859
+ }
860
+ }
861
+ case "RANGE_SELECT_PAGES": {
862
+ const { pageId, files } = action.payload;
863
+ if (!state.lastSelectedPageId) {
864
+ return {
865
+ ...state,
866
+ selection: [pageId],
867
+ lastSelectedPageId: pageId
868
+ };
869
+ }
870
+ const rangePageIds = getPageRange(files, state.lastSelectedPageId, pageId);
871
+ const newSelection = [.../* @__PURE__ */ new Set([...state.selection, ...rangePageIds])];
872
+ return {
873
+ ...state,
874
+ selection: newSelection,
875
+ lastSelectedPageId: pageId
876
+ };
877
+ }
878
+ case "SINGLE_SELECT_PAGE": {
879
+ return {
880
+ ...state,
881
+ selection: [action.payload],
882
+ lastSelectedPageId: action.payload
883
+ };
884
+ }
885
+ case "CLEAR_SELECTION":
886
+ return {
887
+ ...state,
888
+ selection: [],
889
+ lastSelectedPageId: void 0
890
+ };
891
+ case "RENAME_FILE":
892
+ return {
893
+ ...state,
894
+ files: state.files.map(
895
+ (f) => f.id === action.payload.fileId ? { ...f, name: action.payload.name } : f
896
+ )
897
+ };
898
+ case "RESET":
899
+ return action.payload || { files: [], selection: [], lastSelectedPageId: void 0 };
900
+ default:
901
+ return state;
902
+ }
903
+ }
904
+ var DND_TYPES = {
905
+ PAGE: "page",
906
+ FILE: "file"
907
+ };
908
+ var DraggablePageThumbnail = ({
909
+ page,
910
+ fileId,
911
+ index,
912
+ isSelected,
913
+ onSingleSelect,
914
+ onToggleSelect,
915
+ onRangeSelect,
916
+ movePageInFile,
917
+ isDraggingPageRef
918
+ }) => {
919
+ const ref = React7.useRef(null);
920
+ const [{ isDragging }, drag] = reactDnd.useDrag({
921
+ type: DND_TYPES.PAGE,
922
+ item: () => {
923
+ if (isDraggingPageRef?.current !== void 0) {
924
+ isDraggingPageRef.current = true;
925
+ }
926
+ return { pageId: page.id, fileId, index };
927
+ },
928
+ collect: (monitor) => ({
929
+ isDragging: monitor.isDragging()
930
+ }),
931
+ end: () => {
932
+ if (isDraggingPageRef?.current !== void 0) {
933
+ isDraggingPageRef.current = false;
934
+ }
935
+ }
936
+ });
937
+ const [{ handlerId }, drop] = reactDnd.useDrop({
938
+ accept: DND_TYPES.PAGE,
939
+ collect(monitor) {
940
+ return {
941
+ handlerId: monitor.getHandlerId()
942
+ };
943
+ },
944
+ hover(item, monitor) {
945
+ if (!ref.current) return;
946
+ if (item.fileId !== fileId) return;
947
+ const dragIndex = item.index;
948
+ const hoverIndex = index;
949
+ if (dragIndex === hoverIndex) return;
950
+ const hoverBoundingRect = ref.current?.getBoundingClientRect();
951
+ const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
952
+ const clientOffset = monitor.getClientOffset();
953
+ const hoverClientY = clientOffset.y - hoverBoundingRect.top;
954
+ if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) return;
955
+ if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) return;
956
+ movePageInFile(dragIndex, hoverIndex);
957
+ item.index = hoverIndex;
958
+ }
959
+ });
960
+ React7.useEffect(() => {
961
+ drag(drop(ref));
962
+ }, [drag, drop]);
963
+ const handleClick = (e) => {
964
+ e.preventDefault();
965
+ handleContextMenu(e);
966
+ if (isRangeSelectModifier(e)) {
967
+ onRangeSelect(page.id);
968
+ } else if (isMultiSelectModifier(e)) {
969
+ onToggleSelect(page.id);
970
+ } else {
971
+ onSingleSelect(page.id);
972
+ }
973
+ };
974
+ return /* @__PURE__ */ jsxRuntime.jsxs(
975
+ "div",
976
+ {
977
+ ref,
978
+ "data-handler-id": handlerId,
979
+ className: cn(
980
+ "relative group cursor-pointer border-2 rounded-lg overflow-hidden bg-white transition-all",
981
+ isDragging && "opacity-50 scale-95",
982
+ isSelected ? "border-primary shadow-md" : "border-gray-200 hover:border-gray-300"
983
+ ),
984
+ onClick: handleClick,
985
+ children: [
986
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity bg-black/50 rounded p-1 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "h-3 w-3 text-white" }) }),
987
+ /* @__PURE__ */ jsxRuntime.jsx(
988
+ "div",
989
+ {
990
+ className: "absolute top-2 left-2 z-10",
991
+ onClick: (e) => e.stopPropagation(),
992
+ children: /* @__PURE__ */ jsxRuntime.jsx(
993
+ "input",
994
+ {
995
+ type: "checkbox",
996
+ checked: isSelected,
997
+ onChange: (e) => {
998
+ const nativeEvent = e.nativeEvent;
999
+ if (nativeEvent && "shiftKey" in nativeEvent && nativeEvent.shiftKey) {
1000
+ onRangeSelect(page.id);
1001
+ } else if (nativeEvent && ("ctrlKey" in nativeEvent && nativeEvent.ctrlKey || "metaKey" in nativeEvent && nativeEvent.metaKey)) {
1002
+ onToggleSelect(page.id);
1003
+ } else {
1004
+ onSingleSelect(page.id);
1005
+ }
1006
+ },
1007
+ onContextMenu: handleContextMenu,
1008
+ className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary focus:ring-2 bg-white/90 cursor-pointer"
1009
+ }
1010
+ )
1011
+ }
1012
+ ),
1013
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aspect-[3/4] relative", children: [
1014
+ /* @__PURE__ */ jsxRuntime.jsx(
1015
+ "img",
1016
+ {
1017
+ src: page.thumbUrl,
1018
+ alt: `Page ${index + 1}`,
1019
+ className: "w-full h-full object-cover"
1020
+ }
1021
+ ),
1022
+ /* @__PURE__ */ jsxRuntime.jsx(
1023
+ Badge,
1024
+ {
1025
+ variant: "secondary",
1026
+ className: "absolute bottom-1 right-1 text-xs px-1 py-0",
1027
+ children: index + 1
1028
+ }
1029
+ )
1030
+ ] })
1031
+ ]
1032
+ }
1033
+ );
1034
+ };
1035
+ var ReorderablePageGrid = ({
1036
+ file,
1037
+ selectedPageIds,
1038
+ onSingleSelectPage,
1039
+ onTogglePageSelect,
1040
+ onRangeSelectPage,
1041
+ onReorderPages,
1042
+ isDraggingPageRef
1043
+ }) => {
1044
+ const movePageInFile = React7.useCallback((dragIndex, hoverIndex) => {
1045
+ const newPages = [...file.pages];
1046
+ const draggedPage = newPages[dragIndex];
1047
+ newPages.splice(dragIndex, 1);
1048
+ newPages.splice(hoverIndex, 0, draggedPage);
1049
+ onReorderPages(file.id, newPages);
1050
+ }, [file.id, file.pages, onReorderPages]);
1051
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4", children: file.pages.map((page, index) => /* @__PURE__ */ jsxRuntime.jsx(
1052
+ DraggablePageThumbnail,
1053
+ {
1054
+ page,
1055
+ fileId: file.id,
1056
+ index,
1057
+ isSelected: selectedPageIds.includes(page.id),
1058
+ onSingleSelect: onSingleSelectPage,
1059
+ onToggleSelect: onTogglePageSelect,
1060
+ onRangeSelect: onRangeSelectPage,
1061
+ movePageInFile,
1062
+ isDraggingPageRef
1063
+ },
1064
+ page.id
1065
+ )) });
1066
+ };
1067
+ var FileDropZone = ({
1068
+ targetIndex,
1069
+ onReorderFiles,
1070
+ files
1071
+ }) => {
1072
+ const [{ isOver, canDrop }, drop] = reactDnd.useDrop({
1073
+ accept: DND_TYPES.FILE,
1074
+ drop: (item) => {
1075
+ const currentIndex = files.findIndex((f) => f.id === item.fileId);
1076
+ if (currentIndex === -1) return;
1077
+ let newIndex = targetIndex;
1078
+ if (currentIndex < targetIndex) {
1079
+ newIndex = targetIndex - 1;
1080
+ }
1081
+ if (currentIndex === newIndex) return;
1082
+ const newFiles = [...files];
1083
+ const [movedFile] = newFiles.splice(currentIndex, 1);
1084
+ newFiles.splice(newIndex, 0, movedFile);
1085
+ onReorderFiles(newFiles);
1086
+ },
1087
+ collect: (monitor) => ({
1088
+ isOver: monitor.isOver(),
1089
+ canDrop: monitor.canDrop()
1090
+ })
1091
+ });
1092
+ const isActive = isOver && canDrop;
1093
+ return /* @__PURE__ */ jsxRuntime.jsx(
1094
+ "div",
1095
+ {
1096
+ ref: drop,
1097
+ className: cn(
1098
+ "h-2 transition-all duration-200 mx-4",
1099
+ isActive ? "h-8 bg-primary/20 border-2 border-dashed border-primary rounded-lg" : ""
1100
+ ),
1101
+ children: isActive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full text-primary text-sm font-medium", children: "Drop here to reorder" })
1102
+ }
1103
+ );
1104
+ };
1105
+ var FileCard = ({
1106
+ file,
1107
+ selectedPageIds,
1108
+ onSingleSelectPage,
1109
+ onTogglePageSelect,
1110
+ onRangeSelectPage,
1111
+ onSelectAllInFile,
1112
+ onRemoveFile,
1113
+ onRenameFile,
1114
+ onReorderPages,
1115
+ isDraggingPageRef
1116
+ }) => {
1117
+ const [isRenaming, setIsRenaming] = React7.useState(false);
1118
+ const [newName, setNewName] = React7.useState(file.name);
1119
+ const fileSelectedPages = file.pages.filter((p) => selectedPageIds.includes(p.id));
1120
+ const allPagesSelected = file.pages.length > 0 && fileSelectedPages.length === file.pages.length;
1121
+ const [{ isDraggingFile }, dragFile] = reactDnd.useDrag({
1122
+ type: DND_TYPES.FILE,
1123
+ item: () => {
1124
+ if (isDraggingPageRef?.current !== void 0) {
1125
+ isDraggingPageRef.current = true;
1126
+ }
1127
+ return { fileId: file.id, file };
1128
+ },
1129
+ collect: (monitor) => ({
1130
+ isDraggingFile: monitor.isDragging()
1131
+ }),
1132
+ end: () => {
1133
+ if (isDraggingPageRef?.current !== void 0) {
1134
+ isDraggingPageRef.current = false;
1135
+ }
1136
+ }
1137
+ });
1138
+ const [, drop] = reactDnd.useDrop({
1139
+ accept: DND_TYPES.PAGE,
1140
+ drop: (_item) => {
1141
+ }
1142
+ });
1143
+ const handleRename = () => {
1144
+ if (newName.trim() && newName !== file.name) {
1145
+ onRenameFile(file.id, newName.trim());
1146
+ }
1147
+ setIsRenaming(false);
1148
+ };
1149
+ const combineRefs = React7.useCallback((el) => {
1150
+ drop(el);
1151
+ dragFile(el);
1152
+ }, [drop, dragFile]);
1153
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1154
+ Card,
1155
+ {
1156
+ className: cn(
1157
+ "mb-6 transition-all cursor-move",
1158
+ isDraggingFile ? "opacity-50 rotate-2 scale-105 shadow-2xl z-50" : "opacity-100"
1159
+ ),
1160
+ ref: combineRefs,
1161
+ children: [
1162
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1163
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1164
+ file.type === "pdf" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "h-5 w-5 text-red-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Image, { className: "h-5 w-5 text-blue-500" }),
1165
+ isRenaming ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1166
+ /* @__PURE__ */ jsxRuntime.jsx(
1167
+ Input,
1168
+ {
1169
+ value: newName,
1170
+ onChange: (e) => setNewName(e.target.value),
1171
+ onKeyDown: (e) => {
1172
+ if (e.key === "Enter") handleRename();
1173
+ if (e.key === "Escape") {
1174
+ setIsRenaming(false);
1175
+ setNewName(file.name);
1176
+ }
1177
+ },
1178
+ className: "h-8 text-sm",
1179
+ autoFocus: true
1180
+ }
1181
+ ),
1182
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: handleRename, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" }) }),
1183
+ /* @__PURE__ */ jsxRuntime.jsx(
1184
+ Button,
1185
+ {
1186
+ type: "button",
1187
+ size: "sm",
1188
+ variant: "ghost",
1189
+ onClick: () => {
1190
+ setIsRenaming(false);
1191
+ setNewName(file.name);
1192
+ },
1193
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" })
1194
+ }
1195
+ )
1196
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1197
+ /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-base", children: file.name }),
1198
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
1199
+ file.pages.length,
1200
+ " page",
1201
+ file.pages.length !== 1 ? "s" : ""
1202
+ ] })
1203
+ ] })
1204
+ ] }),
1205
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1206
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
1207
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
1208
+ Button,
1209
+ {
1210
+ type: "button",
1211
+ variant: "outline",
1212
+ size: "sm",
1213
+ onClick: () => onSelectAllInFile(file.id),
1214
+ disabled: file.pages.length === 0,
1215
+ children: [
1216
+ allPagesSelected && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3 mr-2" }),
1217
+ "Select All"
1218
+ ]
1219
+ }
1220
+ ) }),
1221
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: "Select all pages in this file" })
1222
+ ] }) }),
1223
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
1224
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "hover:bg-gray-100 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "h-4 w-4" }) }) }),
1225
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-52", children: [
1226
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onClick: () => setIsRenaming(true), children: [
1227
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-4 w-4 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
1228
+ "Rename File"
1229
+ ] }),
1230
+ /* @__PURE__ */ jsxRuntime.jsxs(
1231
+ DropdownMenuItem,
1232
+ {
1233
+ onClick: () => onRemoveFile(file.id),
1234
+ className: "text-red-600 hover:text-red-700 hover:bg-red-50 focus:text-red-700 focus:bg-red-50",
1235
+ children: [
1236
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4 mr-2" }),
1237
+ "Remove File"
1238
+ ]
1239
+ }
1240
+ )
1241
+ ] })
1242
+ ] })
1243
+ ] })
1244
+ ] }) }),
1245
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntime.jsx(
1246
+ ReorderablePageGrid,
1247
+ {
1248
+ file,
1249
+ selectedPageIds,
1250
+ onSingleSelectPage,
1251
+ onTogglePageSelect,
1252
+ onRangeSelectPage,
1253
+ onReorderPages,
1254
+ isDraggingPageRef
1255
+ }
1256
+ ) })
1257
+ ]
1258
+ }
1259
+ );
1260
+ };
1261
+ var BulkActionBar = ({
1262
+ selectedCount,
1263
+ files,
1264
+ onMovePages,
1265
+ onDeletePages,
1266
+ onClearSelection
1267
+ }) => {
1268
+ if (selectedCount === 0) return null;
1269
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-4 z-10 mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 shadow-lg border-primary/20 bg-blue-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between flex-wrap gap-4", children: [
1270
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 flex-wrap", children: [
1271
+ /* @__PURE__ */ jsxRuntime.jsxs(
1272
+ "span",
1273
+ {
1274
+ className: "inline-flex items-center text-sm font-medium text-white rounded-full",
1275
+ style: {
1276
+ backgroundColor: "#0099cd",
1277
+ padding: "6px 14px"
1278
+ },
1279
+ children: [
1280
+ selectedCount,
1281
+ " page",
1282
+ selectedCount !== 1 ? "s" : "",
1283
+ " selected"
1284
+ ]
1285
+ }
1286
+ ),
1287
+ files.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1288
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
1289
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "move-select", className: "text-sm font-medium text-gray-700", children: "Move to file:" }) }),
1290
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Move selected pages to another file" }) })
1291
+ ] }) }),
1292
+ /* @__PURE__ */ jsxRuntime.jsxs(Select, { onValueChange: onMovePages, children: [
1293
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: "move-select", className: "w-48 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Choose file..." }) }),
1294
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: files.map((file) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: file.id, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1295
+ file.type === "pdf" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Image, { className: "h-4 w-4" }),
1296
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: file.name })
1297
+ ] }) }, file.id)) })
1298
+ ] })
1299
+ ] })
1300
+ ] }),
1301
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1302
+ /* @__PURE__ */ jsxRuntime.jsxs(
1303
+ Button,
1304
+ {
1305
+ type: "button",
1306
+ variant: "destructive",
1307
+ size: "sm",
1308
+ onClick: onDeletePages,
1309
+ children: [
1310
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4 mr-2" }),
1311
+ "Delete Selected"
1312
+ ]
1313
+ }
1314
+ ),
1315
+ /* @__PURE__ */ jsxRuntime.jsx(
1316
+ Button,
1317
+ {
1318
+ type: "button",
1319
+ variant: "outline",
1320
+ size: "sm",
1321
+ onClick: onClearSelection,
1322
+ className: "bg-white",
1323
+ children: "Clear Selection"
1324
+ }
1325
+ )
1326
+ ] })
1327
+ ] }) }) });
1328
+ };
1329
+ var PageAssembler = React7.forwardRef(
1330
+ (props, ref) => {
1331
+ const {
1332
+ initialPdf,
1333
+ initialState,
1334
+ onChange,
1335
+ onValidityChange,
1336
+ limits,
1337
+ disableFileUpload = false,
1338
+ className
1339
+ } = props;
1340
+ const [state, dispatch] = React7.useReducer(
1341
+ assemblerReducer,
1342
+ initialState || {
1343
+ files: [],
1344
+ selection: [],
1345
+ lastSelectedPageId: void 0
1346
+ }
1347
+ );
1348
+ const [isLoading, setIsLoading] = React7.useState(false);
1349
+ const [processingStatus, setProcessingStatus] = React7.useState("");
1350
+ const [showDeleteConfirm, setShowDeleteConfirm] = React7.useState(false);
1351
+ const [showRemoveFileConfirm, setShowRemoveFileConfirm] = React7.useState(false);
1352
+ const [fileToRemove, setFileToRemove] = React7.useState(null);
1353
+ const fileInputRef = React7.useRef(null);
1354
+ const processedInitialPdfRef = React7.useRef(null);
1355
+ const isDraggingPage = React7.useRef(false);
1356
+ const onChangeRef = React7.useRef(onChange);
1357
+ const summary = React7.useMemo(() => ({
1358
+ totalFiles: state.files.length,
1359
+ totalPages: state.files.reduce((sum, file) => sum + file.pages.length, 0)
1360
+ }), [state.files]);
1361
+ const isValid = summary.totalPages > 0;
1362
+ React7.useEffect(() => {
1363
+ onChangeRef.current = onChange;
1364
+ }, [onChange]);
1365
+ const debouncedOnChange = React7.useMemo(
1366
+ () => debounce((newState) => {
1367
+ onChangeRef.current?.(newState);
1368
+ }, 200),
1369
+ []
1370
+ );
1371
+ React7.useEffect(() => {
1372
+ debouncedOnChange(state);
1373
+ }, [state, debouncedOnChange]);
1374
+ React7.useEffect(() => {
1375
+ onValidityChange?.(isValid);
1376
+ }, [isValid, onValidityChange]);
1377
+ const processInitialPdf = React7.useCallback(async (pdf) => {
1378
+ setIsLoading(true);
1379
+ setProcessingStatus("Processing initial PDF...");
1380
+ try {
1381
+ let pdfBytes;
1382
+ if (pdf instanceof Blob) {
1383
+ const arrayBuffer = await pdf.arrayBuffer();
1384
+ pdfBytes = new Uint8Array(arrayBuffer);
1385
+ } else if (pdf instanceof ArrayBuffer) {
1386
+ pdfBytes = new Uint8Array(pdf);
1387
+ } else {
1388
+ pdfBytes = new Uint8Array(pdf);
1389
+ }
1390
+ const defensiveCopy = new Uint8Array(pdfBytes);
1391
+ const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1392
+ if (pages.length === 0) {
1393
+ throw new Error("Failed to process PDF pages");
1394
+ }
1395
+ let originalBytes;
1396
+ let originalFile;
1397
+ try {
1398
+ new Uint8Array(pdfBytes.buffer || pdfBytes, 0, 1);
1399
+ originalBytes = new Uint8Array(pdfBytes);
1400
+ originalFile = new File([pdfBytes.buffer], "Initial Document.pdf", { type: "application/pdf" });
1401
+ } catch (error) {
1402
+ const errorMessage = error instanceof Error ? error.message : String(error);
1403
+ if (errorMessage.includes("detached") || errorMessage.includes("ArrayBuffer")) {
1404
+ throw new Error("Initial PDF data is no longer available. Please try refreshing the page.");
1405
+ }
1406
+ throw error;
1407
+ }
1408
+ const fileName = pdf instanceof File ? pdf.name : "Initial Document.pdf";
1409
+ const fileId = generateId();
1410
+ const file = {
1411
+ id: fileId,
1412
+ name: fileName,
1413
+ type: "pdf",
1414
+ originalFile,
1415
+ originalBytes,
1416
+ pages: pages.map((page, index) => ({
1417
+ id: generateId(),
1418
+ srcIndex: index,
1419
+ thumbUrl: page.imageUrl,
1420
+ width: page.width,
1421
+ height: page.height,
1422
+ mime: "application/pdf",
1423
+ originalFileId: fileId
1424
+ }))
1425
+ };
1426
+ dispatch({ type: "ADD_FILE", payload: file });
1427
+ } catch (error) {
1428
+ console.error("Error processing initial PDF:", error);
1429
+ } finally {
1430
+ setIsLoading(false);
1431
+ setProcessingStatus("");
1432
+ }
1433
+ }, []);
1434
+ React7.useEffect(() => {
1435
+ if (initialPdf && !initialState) {
1436
+ const pdfIdentifier = initialPdf instanceof Uint8Array ? `uint8array-${initialPdf.length}-${initialPdf[0]}-${initialPdf[initialPdf.length - 1]}` : `${initialPdf.constructor.name}-${initialPdf.size || initialPdf.byteLength}`;
1437
+ if (processedInitialPdfRef.current === pdfIdentifier) {
1438
+ return;
1439
+ }
1440
+ processedInitialPdfRef.current = pdfIdentifier;
1441
+ processInitialPdf(initialPdf);
1442
+ }
1443
+ }, [initialPdf, initialState, processInitialPdf]);
1444
+ React7.useEffect(() => {
1445
+ if (initialState) {
1446
+ dispatch({ type: "RESET", payload: initialState });
1447
+ }
1448
+ }, [initialState]);
1449
+ const processFiles = React7.useCallback(async (files) => {
1450
+ const fileArray = Array.from(files);
1451
+ const maxFileSize = (limits?.maxFileSizeMB || 10) * 1024 * 1024;
1452
+ setIsLoading(true);
1453
+ setProcessingStatus(`Processing ${fileArray.length} file${fileArray.length !== 1 ? "s" : ""}...`);
1454
+ for (const file of fileArray) {
1455
+ try {
1456
+ if (file.size > maxFileSize) {
1457
+ console.error(`File ${file.name} is too large`);
1458
+ continue;
1459
+ }
1460
+ const validTypes = ["application/pdf", "image/png", "image/jpeg", "image/jpg", "image/webp"];
1461
+ if (!validTypes.includes(file.type)) {
1462
+ console.error(`Unsupported file type: ${file.name}`);
1463
+ continue;
1464
+ }
1465
+ const fileInfo = {
1466
+ id: generateId(),
1467
+ name: file.name,
1468
+ type: file.type === "application/pdf" ? "pdf" : "image",
1469
+ originalFile: file,
1470
+ originalBytes: new Uint8Array(),
1471
+ pages: []
1472
+ };
1473
+ if (file.type === "application/pdf") {
1474
+ setProcessingStatus(`Processing PDF: ${file.name}`);
1475
+ const arrayBuffer = await file.arrayBuffer();
1476
+ const pdfBytes = new Uint8Array(arrayBuffer);
1477
+ fileInfo.originalBytes = new Uint8Array(pdfBytes);
1478
+ const defensiveCopy = new Uint8Array(pdfBytes);
1479
+ const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1480
+ fileInfo.pages = pages.map((page, index) => ({
1481
+ id: generateId(),
1482
+ srcIndex: index,
1483
+ thumbUrl: page.imageUrl,
1484
+ width: page.width,
1485
+ height: page.height,
1486
+ mime: file.type,
1487
+ originalFileId: fileInfo.id
1488
+ }));
1489
+ } else {
1490
+ setProcessingStatus(`Processing image: ${file.name}`);
1491
+ const arrayBuffer = await file.arrayBuffer();
1492
+ const imageBytes = new Uint8Array(arrayBuffer);
1493
+ fileInfo.originalBytes = new Uint8Array(imageBytes);
1494
+ const thumbUrl = URL.createObjectURL(file);
1495
+ const img = new Image();
1496
+ const dimensions = await new Promise((resolve) => {
1497
+ img.onload = () => resolve({ width: img.width, height: img.height });
1498
+ img.src = thumbUrl;
1499
+ });
1500
+ const maxWidth = 595;
1501
+ const maxHeight = 842;
1502
+ let pdfWidth = dimensions.width;
1503
+ let pdfHeight = dimensions.height;
1504
+ if (dimensions.width > maxWidth || dimensions.height > maxHeight) {
1505
+ const scaleX = maxWidth / dimensions.width;
1506
+ const scaleY = maxHeight / dimensions.height;
1507
+ const scale = Math.min(scaleX, scaleY);
1508
+ pdfWidth = dimensions.width * scale;
1509
+ pdfHeight = dimensions.height * scale;
1510
+ }
1511
+ fileInfo.pages = [{
1512
+ id: generateId(),
1513
+ srcIndex: 0,
1514
+ thumbUrl,
1515
+ width: Math.max(pdfWidth, 100),
1516
+ height: Math.max(pdfHeight, 100),
1517
+ mime: file.type,
1518
+ originalFileId: fileInfo.id
1519
+ }];
1520
+ }
1521
+ dispatch({ type: "ADD_FILE", payload: fileInfo });
1522
+ } catch (error) {
1523
+ console.error(`Error processing file ${file.name}:`, error);
1524
+ }
1525
+ }
1526
+ setIsLoading(false);
1527
+ setProcessingStatus("");
1528
+ }, [limits]);
1529
+ const handleFileUpload = React7.useCallback(() => {
1530
+ fileInputRef.current?.click();
1531
+ }, []);
1532
+ const handleFileChange = React7.useCallback((e) => {
1533
+ const files = e.target.files;
1534
+ if (files) {
1535
+ processFiles(files);
1536
+ }
1537
+ if (fileInputRef.current) {
1538
+ fileInputRef.current.value = "";
1539
+ }
1540
+ }, [processFiles]);
1541
+ const handleDrop = React7.useCallback((e) => {
1542
+ e.preventDefault();
1543
+ const files = e.dataTransfer.files;
1544
+ if (files && files.length > 0) {
1545
+ if (isDraggingPage.current) {
1546
+ return;
1547
+ }
1548
+ processFiles(files);
1549
+ }
1550
+ }, [processFiles]);
1551
+ const handleDragOver = React7.useCallback((e) => {
1552
+ e.preventDefault();
1553
+ }, []);
1554
+ const handleSingleSelectPage = React7.useCallback((pageId) => {
1555
+ dispatch({ type: "SINGLE_SELECT_PAGE", payload: pageId });
1556
+ }, []);
1557
+ const handleTogglePageSelect = React7.useCallback((pageId) => {
1558
+ dispatch({ type: "TOGGLE_PAGE_SELECTION", payload: { pageId, files: state.files } });
1559
+ }, [state.files]);
1560
+ const handleRangeSelectPage = React7.useCallback((pageId) => {
1561
+ dispatch({ type: "RANGE_SELECT_PAGES", payload: { pageId, files: state.files } });
1562
+ }, [state.files]);
1563
+ const handleSelectAllInFile = React7.useCallback((fileId) => {
1564
+ const file = state.files.find((f) => f.id === fileId);
1565
+ if (!file) return;
1566
+ const filePageIds = file.pages.map((p) => p.id);
1567
+ const allSelected = filePageIds.every((id) => state.selection.includes(id));
1568
+ if (allSelected) {
1569
+ dispatch({
1570
+ type: "SET_SELECTION",
1571
+ payload: state.selection.filter((id) => !filePageIds.includes(id))
1572
+ });
1573
+ } else {
1574
+ const newSelection = [.../* @__PURE__ */ new Set([...state.selection, ...filePageIds])];
1575
+ dispatch({ type: "SET_SELECTION", payload: newSelection });
1576
+ }
1577
+ }, [state.files, state.selection]);
1578
+ const handleMovePages = React7.useCallback((targetFileId) => {
1579
+ if (state.selection.length === 0) return;
1580
+ dispatch({ type: "MOVE_PAGES", payload: { pageIds: state.selection, targetFileId } });
1581
+ }, [state.selection]);
1582
+ const handleDeletePages = React7.useCallback(() => {
1583
+ setShowDeleteConfirm(true);
1584
+ }, []);
1585
+ const confirmDeletePages = React7.useCallback(() => {
1586
+ dispatch({ type: "DELETE_PAGES", payload: state.selection });
1587
+ setShowDeleteConfirm(false);
1588
+ }, [state.selection]);
1589
+ const handleRemoveFile = React7.useCallback((fileId) => {
1590
+ const file = state.files.find((f) => f.id === fileId);
1591
+ if (!file) return;
1592
+ if (file.pages.length > 0) {
1593
+ setFileToRemove({
1594
+ id: file.id,
1595
+ name: file.name,
1596
+ pageCount: file.pages.length
1597
+ });
1598
+ setShowRemoveFileConfirm(true);
1599
+ } else {
1600
+ dispatch({ type: "REMOVE_FILE", payload: fileId });
1601
+ }
1602
+ }, [state.files]);
1603
+ const confirmRemoveFile = React7.useCallback(() => {
1604
+ if (fileToRemove) {
1605
+ dispatch({ type: "REMOVE_FILE", payload: fileToRemove.id });
1606
+ setFileToRemove(null);
1607
+ }
1608
+ setShowRemoveFileConfirm(false);
1609
+ }, [fileToRemove]);
1610
+ const handleRenameFile = React7.useCallback((fileId, name) => {
1611
+ dispatch({ type: "RENAME_FILE", payload: { fileId, name } });
1612
+ }, []);
1613
+ const handleReorderFiles = React7.useCallback((newOrder) => {
1614
+ dispatch({ type: "REORDER_FILES", payload: { newOrder } });
1615
+ }, []);
1616
+ React7.useImperativeHandle(ref, () => ({
1617
+ assemble: async () => {
1618
+ setIsLoading(true);
1619
+ setProcessingStatus("Assembling PDF...");
1620
+ try {
1621
+ const { PDFDocument: PDFDocument2 } = await import('pdf-lib');
1622
+ const combinedDoc = await PDFDocument2.create();
1623
+ const loadedPdfs = /* @__PURE__ */ new Map();
1624
+ const fileMap = /* @__PURE__ */ new Map();
1625
+ for (const file of state.files) {
1626
+ fileMap.set(file.id, file);
1627
+ if (file.type === "pdf" && file.originalBytes) {
1628
+ try {
1629
+ const sourcePdf = await PDFDocument2.load(file.originalBytes);
1630
+ loadedPdfs.set(file.id, sourcePdf);
1631
+ } catch (error) {
1632
+ console.error(`Error loading PDF for file ${file.id}:`, error);
1633
+ }
1634
+ }
1635
+ }
1636
+ for (const file of state.files) {
1637
+ if (file.pages.length === 0) continue;
1638
+ for (const page of file.pages) {
1639
+ const originalFileId = page.originalFileId || file.id;
1640
+ const sourceFile = fileMap.get(originalFileId);
1641
+ if (!sourceFile) {
1642
+ console.warn(`Source file not found for page ${page.id}`);
1643
+ continue;
1644
+ }
1645
+ if (sourceFile.type === "pdf") {
1646
+ const sourcePdf = loadedPdfs.get(originalFileId);
1647
+ if (!sourcePdf) {
1648
+ console.warn(`Source PDF not loaded for page ${page.id}`);
1649
+ continue;
1650
+ }
1651
+ const sourcePageCount = sourcePdf.getPageCount();
1652
+ if (page.srcIndex >= 0 && page.srcIndex < sourcePageCount) {
1653
+ try {
1654
+ const copiedPages = await combinedDoc.copyPages(sourcePdf, [page.srcIndex]);
1655
+ copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
1656
+ } catch (copyError) {
1657
+ console.error(`Error copying page ${page.srcIndex}:`, copyError);
1658
+ throw new Error(`Failed to copy page: ${copyError instanceof Error ? copyError.message : String(copyError)}`);
1659
+ }
1660
+ }
1661
+ } else if (sourceFile.type === "image" && sourceFile.originalFile) {
1662
+ try {
1663
+ const imagePdfBytes = await imageToPdf(sourceFile.originalFile);
1664
+ const imagePdf = await PDFDocument2.load(imagePdfBytes);
1665
+ const copiedPages = await combinedDoc.copyPages(imagePdf, [0]);
1666
+ copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
1667
+ } catch (imageError) {
1668
+ console.error(`Error converting image page:`, imageError);
1669
+ throw new Error(`Failed to convert image: ${imageError instanceof Error ? imageError.message : String(imageError)}`);
1670
+ }
1671
+ }
1672
+ }
1673
+ }
1674
+ const pdfBytes = await combinedDoc.save();
1675
+ const blob = new Blob([pdfBytes.buffer], { type: "application/pdf" });
1676
+ return blob;
1677
+ } catch (error) {
1678
+ console.error("Error assembling PDF:", error);
1679
+ throw error;
1680
+ } finally {
1681
+ setIsLoading(false);
1682
+ setProcessingStatus("");
1683
+ }
1684
+ },
1685
+ getSummary: () => summary,
1686
+ isBusy: () => isLoading,
1687
+ getState: () => state
1688
+ }), [state, summary, isLoading]);
1689
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(reactDnd.DndProvider, { backend: reactDndHtml5Backend.HTML5Backend, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-6 pb-6", className), children: [
1690
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1691
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1692
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium", children: "Page Assembly" }),
1693
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Upload, arrange, and combine pages into a single PDF document" })
1694
+ ] }),
1695
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
1696
+ summary.totalPages > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-500", children: [
1697
+ summary.totalFiles,
1698
+ " file",
1699
+ summary.totalFiles !== 1 ? "s" : "",
1700
+ ", ",
1701
+ summary.totalPages,
1702
+ " page",
1703
+ summary.totalPages !== 1 ? "s" : ""
1704
+ ] }),
1705
+ !disableFileUpload && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1706
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", onClick: handleFileUpload, disabled: isLoading, children: [
1707
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "h-4 w-4 mr-2" }),
1708
+ "Add Files"
1709
+ ] }),
1710
+ /* @__PURE__ */ jsxRuntime.jsx(
1711
+ "input",
1712
+ {
1713
+ ref: fileInputRef,
1714
+ type: "file",
1715
+ multiple: true,
1716
+ accept: ".pdf,image/*",
1717
+ onChange: handleFileChange,
1718
+ className: "hidden"
1719
+ }
1720
+ )
1721
+ ] })
1722
+ ] })
1723
+ ] }),
1724
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1725
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-primary" }),
1726
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: processingStatus })
1727
+ ] }) }),
1728
+ /* @__PURE__ */ jsxRuntime.jsx(
1729
+ BulkActionBar,
1730
+ {
1731
+ selectedCount: state.selection.length,
1732
+ files: state.files,
1733
+ onMovePages: handleMovePages,
1734
+ onDeletePages: handleDeletePages,
1735
+ onClearSelection: () => dispatch({ type: "CLEAR_SELECTION" })
1736
+ }
1737
+ ),
1738
+ state.files.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
1739
+ "div",
1740
+ {
1741
+ onDrop: handleDrop,
1742
+ onDragOver: handleDragOver,
1743
+ children: [
1744
+ /* @__PURE__ */ jsxRuntime.jsx(
1745
+ FileDropZone,
1746
+ {
1747
+ targetIndex: 0,
1748
+ onReorderFiles: handleReorderFiles,
1749
+ files: state.files
1750
+ }
1751
+ ),
1752
+ state.files.map((file, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1753
+ /* @__PURE__ */ jsxRuntime.jsx(
1754
+ FileCard,
1755
+ {
1756
+ file,
1757
+ selectedPageIds: state.selection,
1758
+ onSingleSelectPage: handleSingleSelectPage,
1759
+ onTogglePageSelect: handleTogglePageSelect,
1760
+ onRangeSelectPage: handleRangeSelectPage,
1761
+ onSelectAllInFile: handleSelectAllInFile,
1762
+ onRemoveFile: handleRemoveFile,
1763
+ onRenameFile: handleRenameFile,
1764
+ onReorderPages: (fileId, newOrder) => dispatch({ type: "REORDER_PAGES", payload: { fileId, newOrder } }),
1765
+ isDraggingPageRef: isDraggingPage
1766
+ }
1767
+ ),
1768
+ /* @__PURE__ */ jsxRuntime.jsx(
1769
+ FileDropZone,
1770
+ {
1771
+ targetIndex: index + 1,
1772
+ onReorderFiles: handleReorderFiles,
1773
+ files: state.files
1774
+ }
1775
+ )
1776
+ ] }, file.id))
1777
+ ]
1778
+ }
1779
+ ) : !disableFileUpload && /* @__PURE__ */ jsxRuntime.jsx(
1780
+ Card,
1781
+ {
1782
+ className: "p-12 border-dashed border-2 border-gray-300 hover:border-gray-400 transition-colors cursor-pointer",
1783
+ onClick: handleFileUpload,
1784
+ onDrop: handleDrop,
1785
+ onDragOver: handleDragOver,
1786
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
1787
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: "h-12 w-12 mx-auto text-gray-400 mb-4" }),
1788
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium text-gray-900 mb-2", children: "No files added" }),
1789
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500 mb-4", children: "Upload PDF files and images to start building your document" }),
1790
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", variant: "outline", children: [
1791
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "h-4 w-4 mr-2" }),
1792
+ "Choose Files"
1793
+ ] })
1794
+ ] })
1795
+ }
1796
+ ),
1797
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { open: showDeleteConfirm, onOpenChange: setShowDeleteConfirm, children: /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { children: [
1798
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { children: [
1799
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogTitle, { children: "Delete Pages" }),
1800
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogDescription, { children: [
1801
+ "Are you sure you want to delete ",
1802
+ state.selection.length,
1803
+ " selected page",
1804
+ state.selection.length !== 1 ? "s" : "",
1805
+ "? This action cannot be undone."
1806
+ ] })
1807
+ ] }),
1808
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogFooter, { children: [
1809
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { children: "Cancel" }),
1810
+ /* @__PURE__ */ jsxRuntime.jsx(
1811
+ AlertDialogAction,
1812
+ {
1813
+ className: "bg-destructive text-white hover:bg-destructive/90",
1814
+ onClick: confirmDeletePages,
1815
+ children: "Delete"
1816
+ }
1817
+ )
1818
+ ] })
1819
+ ] }) }),
1820
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { open: showRemoveFileConfirm, onOpenChange: setShowRemoveFileConfirm, children: /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { children: [
1821
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { children: [
1822
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogTitle, { children: "Remove File" }),
1823
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogDescription, { children: [
1824
+ 'Are you sure you want to remove "',
1825
+ fileToRemove?.name,
1826
+ '" and all its ',
1827
+ fileToRemove?.pageCount,
1828
+ " page",
1829
+ fileToRemove?.pageCount !== 1 ? "s" : "",
1830
+ "? This action cannot be undone."
1831
+ ] })
1832
+ ] }),
1833
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogFooter, { children: [
1834
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { onClick: () => {
1835
+ setFileToRemove(null);
1836
+ setShowRemoveFileConfirm(false);
1837
+ }, children: "Cancel" }),
1838
+ /* @__PURE__ */ jsxRuntime.jsx(
1839
+ AlertDialogAction,
1840
+ {
1841
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
1842
+ onClick: confirmRemoveFile,
1843
+ children: "Remove File"
1844
+ }
1845
+ )
1846
+ ] })
1847
+ ] }) })
1848
+ ] }) }) });
1849
+ }
1850
+ );
1851
+ PageAssembler.displayName = "PageAssembler";
1852
+ function generateId() {
1853
+ return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1854
+ }
1855
+ function debounce(func, wait) {
1856
+ let timeout;
1857
+ return ((...args) => {
1858
+ clearTimeout(timeout);
1859
+ timeout = setTimeout(() => func(...args), wait);
1860
+ });
1861
+ }
1862
+ var PageAssembler_default = PageAssembler;
1863
+
1864
+ exports.Button = Button;
1865
+ exports.PageAssembler = PageAssembler;
1866
+ exports.createPdfBlobUrl = createPdfBlobUrl;
1867
+ exports.default = PageAssembler_default;
1868
+ exports.downloadPdf = downloadPdf;
1869
+ exports.imageToPdf = imageToPdf;
1870
+ exports.pdfToImages = pdfToImages;
1871
+ //# sourceMappingURL=index.js.map
1872
+ //# sourceMappingURL=index.js.map