@classic-homes/theme-react 0.1.50 → 0.1.52

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.mjs CHANGED
@@ -110,21 +110,91 @@ var Input = React3.forwardRef(
110
110
  );
111
111
  Input.displayName = "Input";
112
112
 
113
- // src/components/Label.tsx
113
+ // src/components/PasswordInput.tsx
114
114
  import * as React4 from "react";
115
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
116
+ var EyeIcon = () => /* @__PURE__ */ jsxs(
117
+ "svg",
118
+ {
119
+ width: 18,
120
+ height: 18,
121
+ viewBox: "0 0 24 24",
122
+ fill: "none",
123
+ stroke: "currentColor",
124
+ strokeWidth: 2,
125
+ strokeLinecap: "round",
126
+ strokeLinejoin: "round",
127
+ children: [
128
+ /* @__PURE__ */ jsx4("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
129
+ /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "3" })
130
+ ]
131
+ }
132
+ );
133
+ var EyeOffIcon = () => /* @__PURE__ */ jsx4(
134
+ "svg",
135
+ {
136
+ width: 18,
137
+ height: 18,
138
+ viewBox: "0 0 24 24",
139
+ fill: "none",
140
+ stroke: "currentColor",
141
+ strokeWidth: 2,
142
+ strokeLinecap: "round",
143
+ strokeLinejoin: "round",
144
+ children: /* @__PURE__ */ jsx4("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24M1 1l22 22" })
145
+ }
146
+ );
147
+ var PasswordInput = React4.forwardRef(
148
+ ({ className, disabled, showLabel = "Show password", hideLabel = "Hide password", ...props }, ref) => {
149
+ const [showPassword, setShowPassword] = React4.useState(false);
150
+ const toggleVisibility = () => {
151
+ setShowPassword((prev) => !prev);
152
+ };
153
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
154
+ /* @__PURE__ */ jsx4(
155
+ "input",
156
+ {
157
+ type: showPassword ? "text" : "password",
158
+ className: cn(
159
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 pr-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
160
+ className
161
+ ),
162
+ disabled,
163
+ ref,
164
+ ...props
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsx4(
168
+ "button",
169
+ {
170
+ type: "button",
171
+ className: "absolute right-0 top-0 h-10 w-10 flex items-center justify-center text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-r-md disabled:pointer-events-none disabled:opacity-50",
172
+ onClick: toggleVisibility,
173
+ disabled,
174
+ "aria-label": showPassword ? hideLabel : showLabel,
175
+ children: showPassword ? /* @__PURE__ */ jsx4(EyeOffIcon, {}) : /* @__PURE__ */ jsx4(EyeIcon, {})
176
+ }
177
+ )
178
+ ] });
179
+ }
180
+ );
181
+ PasswordInput.displayName = "PasswordInput";
182
+
183
+ // src/components/Label.tsx
184
+ import * as React5 from "react";
115
185
  import * as LabelPrimitive from "@radix-ui/react-label";
116
186
  import { cva as cva2 } from "class-variance-authority";
117
- import { jsx as jsx4 } from "react/jsx-runtime";
187
+ import { jsx as jsx5 } from "react/jsx-runtime";
118
188
  var labelVariants = cva2(
119
189
  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
120
190
  );
121
- var Label = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props }));
191
+ var Label = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props }));
122
192
  Label.displayName = LabelPrimitive.Root.displayName;
123
193
 
124
194
  // src/components/Badge.tsx
125
- import * as React5 from "react";
195
+ import * as React6 from "react";
126
196
  import { cva as cva3 } from "class-variance-authority";
127
- import { jsx as jsx5 } from "react/jsx-runtime";
197
+ import { jsx as jsx6 } from "react/jsx-runtime";
128
198
  var badgeVariants = cva3(
129
199
  "inline-flex items-center rounded-full border border-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",
130
200
  {
@@ -141,9 +211,9 @@ var badgeVariants = cva3(
141
211
  }
142
212
  }
143
213
  );
144
- var Badge = React5.forwardRef(
214
+ var Badge = React6.forwardRef(
145
215
  ({ className, variant, ...props }, ref) => {
146
- return /* @__PURE__ */ jsx5(
216
+ return /* @__PURE__ */ jsx6(
147
217
  "div",
148
218
  {
149
219
  ref,
@@ -157,10 +227,10 @@ var Badge = React5.forwardRef(
157
227
  Badge.displayName = "Badge";
158
228
 
159
229
  // src/components/Separator.tsx
160
- import * as React6 from "react";
230
+ import * as React7 from "react";
161
231
  import * as SeparatorPrimitive from "@radix-ui/react-separator";
162
- import { jsx as jsx6 } from "react/jsx-runtime";
163
- var Separator = React6.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx6(
232
+ import { jsx as jsx7 } from "react/jsx-runtime";
233
+ var Separator = React7.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx7(
164
234
  SeparatorPrimitive.Root,
165
235
  {
166
236
  ref,
@@ -177,12 +247,14 @@ var Separator = React6.forwardRef(({ className, orientation = "horizontal", deco
177
247
  Separator.displayName = SeparatorPrimitive.Root.displayName;
178
248
 
179
249
  // src/components/Switch.tsx
180
- import * as React7 from "react";
250
+ import * as React8 from "react";
181
251
  import * as SwitchPrimitives from "@radix-ui/react-switch";
182
- import { jsx as jsx7 } from "react/jsx-runtime";
183
- var Switch = React7.forwardRef(
184
- ({ className, size = "default", ...props }, ref) => /* @__PURE__ */ jsx7(
185
- SwitchPrimitives.Root,
252
+ import { jsx as jsx8 } from "react/jsx-runtime";
253
+ var SwitchRoot = SwitchPrimitives.Root;
254
+ var SwitchThumb = SwitchPrimitives.Thumb;
255
+ var Switch = React8.forwardRef(
256
+ ({ className, size = "default", ...props }, ref) => /* @__PURE__ */ jsx8(
257
+ SwitchRoot,
186
258
  {
187
259
  className: cn(
188
260
  "peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
@@ -190,10 +262,10 @@ var Switch = React7.forwardRef(
190
262
  size === "sm" && "h-5 w-9",
191
263
  className
192
264
  ),
193
- ...props,
194
265
  ref,
195
- children: /* @__PURE__ */ jsx7(
196
- SwitchPrimitives.Thumb,
266
+ ...props,
267
+ children: /* @__PURE__ */ jsx8(
268
+ SwitchThumb,
197
269
  {
198
270
  className: cn(
199
271
  "pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform",
@@ -208,10 +280,10 @@ var Switch = React7.forwardRef(
208
280
  Switch.displayName = SwitchPrimitives.Root.displayName;
209
281
 
210
282
  // src/components/Avatar.tsx
211
- import * as React8 from "react";
283
+ import * as React9 from "react";
212
284
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
213
- import { jsx as jsx8 } from "react/jsx-runtime";
214
- var Avatar = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
285
+ import { jsx as jsx9 } from "react/jsx-runtime";
286
+ var Avatar = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
215
287
  AvatarPrimitive.Root,
216
288
  {
217
289
  ref,
@@ -220,7 +292,7 @@ var Avatar = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
220
292
  }
221
293
  ));
222
294
  Avatar.displayName = AvatarPrimitive.Root.displayName;
223
- var AvatarImage = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
295
+ var AvatarImage = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
224
296
  AvatarPrimitive.Image,
225
297
  {
226
298
  ref,
@@ -229,7 +301,7 @@ var AvatarImage = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
229
301
  }
230
302
  ));
231
303
  AvatarImage.displayName = AvatarPrimitive.Image.displayName;
232
- var AvatarFallback = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
304
+ var AvatarFallback = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
233
305
  AvatarPrimitive.Fallback,
234
306
  {
235
307
  ref,
@@ -243,15 +315,19 @@ var AvatarFallback = React8.forwardRef(({ className, ...props }, ref) => /* @__P
243
315
  AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
244
316
 
245
317
  // src/components/Dialog.tsx
246
- import * as React9 from "react";
318
+ import * as React10 from "react";
247
319
  import * as DialogPrimitive from "@radix-ui/react-dialog";
248
- import { jsx as jsx9, jsxs } from "react/jsx-runtime";
320
+ import { jsx as jsx10, jsxs as jsxs2 } from "react/jsx-runtime";
321
+ var PrimitiveOverlay = DialogPrimitive.Overlay;
322
+ var PrimitiveContent = DialogPrimitive.Content;
323
+ var PrimitiveTitle = DialogPrimitive.Title;
324
+ var PrimitiveDescription = DialogPrimitive.Description;
249
325
  var Dialog = DialogPrimitive.Root;
250
326
  var DialogTrigger = DialogPrimitive.Trigger;
251
327
  var DialogPortal = DialogPrimitive.Portal;
252
328
  var DialogClose = DialogPrimitive.Close;
253
- var DialogOverlay = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
254
- DialogPrimitive.Overlay,
329
+ var DialogOverlay = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
330
+ PrimitiveOverlay,
255
331
  {
256
332
  ref,
257
333
  className: cn(
@@ -262,10 +338,10 @@ var DialogOverlay = React9.forwardRef(({ className, ...props }, ref) => /* @__PU
262
338
  }
263
339
  ));
264
340
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
265
- var DialogContent = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
266
- /* @__PURE__ */ jsx9(DialogOverlay, {}),
267
- /* @__PURE__ */ jsx9(
268
- DialogPrimitive.Content,
341
+ var DialogContent = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs2(DialogPortal, { children: [
342
+ /* @__PURE__ */ jsx10(DialogOverlay, {}),
343
+ /* @__PURE__ */ jsx10(
344
+ PrimitiveContent,
269
345
  {
270
346
  ref,
271
347
  className: cn(
@@ -278,9 +354,9 @@ var DialogContent = React9.forwardRef(({ className, children, ...props }, ref) =
278
354
  )
279
355
  ] }));
280
356
  DialogContent.displayName = DialogPrimitive.Content.displayName;
281
- var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx9("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
357
+ var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx10("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
282
358
  DialogHeader.displayName = "DialogHeader";
283
- var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx9(
359
+ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx10(
284
360
  "div",
285
361
  {
286
362
  className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
@@ -288,8 +364,8 @@ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx9(
288
364
  }
289
365
  );
290
366
  DialogFooter.displayName = "DialogFooter";
291
- var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
292
- DialogPrimitive.Title,
367
+ var DialogTitle = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
368
+ PrimitiveTitle,
293
369
  {
294
370
  ref,
295
371
  className: cn("text-lg font-semibold leading-none tracking-tight", className),
@@ -297,8 +373,8 @@ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE
297
373
  }
298
374
  ));
299
375
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
300
- var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
301
- DialogPrimitive.Description,
376
+ var DialogDescription = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
377
+ PrimitiveDescription,
302
378
  {
303
379
  ref,
304
380
  className: cn("text-sm text-muted-foreground", className),
@@ -308,9 +384,9 @@ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @
308
384
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
309
385
 
310
386
  // src/components/PageHeader.tsx
311
- import * as React10 from "react";
387
+ import * as React11 from "react";
312
388
  import { cva as cva4 } from "class-variance-authority";
313
- import { jsx as jsx10, jsxs as jsxs2 } from "react/jsx-runtime";
389
+ import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
314
390
  var pageHeaderContainerVariants = cva4("", {
315
391
  variants: {
316
392
  variant: {
@@ -359,22 +435,916 @@ var pageHeaderActionsVariants = cva4("flex gap-4", {
359
435
  variant: "default"
360
436
  }
361
437
  });
362
- var PageHeader = React10.forwardRef(
363
- ({ className, variant, title, subtitle, actions, ...props }, ref) => /* @__PURE__ */ jsxs2(
438
+ var PageHeader = React11.forwardRef(
439
+ ({ className, variant, title, subtitle, actions, ...props }, ref) => /* @__PURE__ */ jsxs3(
364
440
  "header",
365
441
  {
366
442
  ref,
367
443
  className: cn(pageHeaderContainerVariants({ variant }), className),
368
444
  ...props,
369
445
  children: [
370
- /* @__PURE__ */ jsx10("h1", { className: pageHeaderTitleVariants({ variant }), children: title }),
371
- subtitle && /* @__PURE__ */ jsx10("p", { className: pageHeaderSubtitleVariants({ variant }), children: subtitle }),
372
- actions && /* @__PURE__ */ jsx10("div", { className: pageHeaderActionsVariants({ variant }), children: actions })
446
+ /* @__PURE__ */ jsx11("h1", { className: pageHeaderTitleVariants({ variant }), children: title }),
447
+ subtitle && /* @__PURE__ */ jsx11("p", { className: pageHeaderSubtitleVariants({ variant }), children: subtitle }),
448
+ actions && /* @__PURE__ */ jsx11("div", { className: pageHeaderActionsVariants({ variant }), children: actions })
373
449
  ]
374
450
  }
375
451
  )
376
452
  );
377
453
  PageHeader.displayName = "PageHeader";
454
+
455
+ // src/components/DataPanel.tsx
456
+ import * as React12 from "react";
457
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
458
+ import {
459
+ DEFAULT_PANEL_STATE,
460
+ DEFAULT_CONSTRAINTS,
461
+ loadPanelState,
462
+ savePanelState,
463
+ getPointerPosition,
464
+ calculateDragPosition,
465
+ calculateResize,
466
+ getResizeCursor,
467
+ getPinnedResizeHandle,
468
+ constrainSize,
469
+ constrainPosition,
470
+ constrainPinnedWidth,
471
+ constrainPinnedHeight,
472
+ detectEdgeSnap,
473
+ getPinnedPositionStyles,
474
+ getDetachedPositionStyles,
475
+ getInitialDetachedPosition,
476
+ isHorizontalEdge,
477
+ calculateDetachDistance,
478
+ calculatePullOffset,
479
+ calculateDetachedPositionFromPinned,
480
+ getPinnedPullTransform
481
+ } from "@classic-homes/data-panel-core";
482
+ import { Fragment, jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
483
+ var DropdownTrigger = DropdownMenuPrimitive.Trigger;
484
+ var DropdownContent = DropdownMenuPrimitive.Content;
485
+ var DropdownLabel = DropdownMenuPrimitive.Label;
486
+ var DropdownItem = DropdownMenuPrimitive.Item;
487
+ var DropdownSeparator = DropdownMenuPrimitive.Separator;
488
+ function useDataPanel(options = {}) {
489
+ const {
490
+ persistKey,
491
+ initialMode = DEFAULT_PANEL_STATE.mode,
492
+ initialEdge = DEFAULT_PANEL_STATE.edge,
493
+ initialExpanded = DEFAULT_PANEL_STATE.isExpanded,
494
+ constraints = {}
495
+ } = options;
496
+ const resolvedConstraints = { ...DEFAULT_CONSTRAINTS, ...constraints };
497
+ const [persistedState] = React12.useState(() => {
498
+ if (persistKey && typeof window !== "undefined") {
499
+ return loadPanelState(persistKey);
500
+ }
501
+ return null;
502
+ });
503
+ const [mode, setMode] = React12.useState(persistedState?.mode ?? initialMode);
504
+ const [edge, setEdge] = React12.useState(persistedState?.edge ?? initialEdge);
505
+ const [isExpanded, setIsExpanded] = React12.useState(
506
+ persistedState?.isExpanded ?? initialExpanded
507
+ );
508
+ const [detachedPosition, setDetachedPosition] = React12.useState(
509
+ persistedState?.detachedPosition ?? DEFAULT_PANEL_STATE.detachedPosition
510
+ );
511
+ const [detachedSize, setDetachedSize] = React12.useState(
512
+ persistedState?.detachedSize ?? DEFAULT_PANEL_STATE.detachedSize
513
+ );
514
+ const [pinnedSize, setPinnedSize] = React12.useState(
515
+ persistedState?.pinnedSize ?? DEFAULT_PANEL_STATE.pinnedSize
516
+ );
517
+ const saveTimeoutRef = React12.useRef(null);
518
+ const debouncedSave = React12.useCallback(() => {
519
+ if (!persistKey) return;
520
+ if (saveTimeoutRef.current) {
521
+ clearTimeout(saveTimeoutRef.current);
522
+ }
523
+ saveTimeoutRef.current = setTimeout(() => {
524
+ savePanelState(persistKey, {
525
+ mode,
526
+ variant: "full",
527
+ edge,
528
+ isExpanded,
529
+ detachedPosition,
530
+ detachedSize,
531
+ pinnedSize,
532
+ cardSnapIndex: 0
533
+ });
534
+ }, 300);
535
+ }, [persistKey, mode, edge, isExpanded, detachedPosition, detachedSize, pinnedSize]);
536
+ const handleSetMode = React12.useCallback(
537
+ (newMode) => {
538
+ setMode(newMode);
539
+ if (newMode === "detached" && typeof window !== "undefined" && detachedPosition.x === DEFAULT_PANEL_STATE.detachedPosition.x && detachedPosition.y === DEFAULT_PANEL_STATE.detachedPosition.y) {
540
+ setDetachedPosition(
541
+ getInitialDetachedPosition(detachedSize, window.innerWidth, window.innerHeight)
542
+ );
543
+ }
544
+ },
545
+ [detachedPosition, detachedSize]
546
+ );
547
+ const handleSetDetachedPosition = React12.useCallback(
548
+ (position) => {
549
+ if (typeof window === "undefined") {
550
+ setDetachedPosition(position);
551
+ return;
552
+ }
553
+ setDetachedPosition(
554
+ constrainPosition(position, detachedSize, window.innerWidth, window.innerHeight)
555
+ );
556
+ },
557
+ [detachedSize]
558
+ );
559
+ const handleSetDetachedSize = React12.useCallback(
560
+ (size) => {
561
+ setDetachedSize(constrainSize(size, resolvedConstraints));
562
+ },
563
+ [resolvedConstraints]
564
+ );
565
+ const handleSetPinnedSize = React12.useCallback(
566
+ (size) => {
567
+ if (typeof window === "undefined") {
568
+ setPinnedSize(size);
569
+ return;
570
+ }
571
+ if (isHorizontalEdge(edge)) {
572
+ setPinnedSize(constrainPinnedWidth(size, resolvedConstraints, window.innerWidth));
573
+ } else {
574
+ setPinnedSize(constrainPinnedHeight(size, resolvedConstraints, window.innerHeight));
575
+ }
576
+ },
577
+ [edge, resolvedConstraints]
578
+ );
579
+ React12.useEffect(() => {
580
+ debouncedSave();
581
+ }, [debouncedSave]);
582
+ return {
583
+ mode,
584
+ setMode: handleSetMode,
585
+ edge,
586
+ setEdge,
587
+ isExpanded,
588
+ setIsExpanded,
589
+ detachedPosition,
590
+ setDetachedPosition: handleSetDetachedPosition,
591
+ detachedSize,
592
+ setDetachedSize: handleSetDetachedSize,
593
+ pinnedSize,
594
+ setPinnedSize: handleSetPinnedSize
595
+ };
596
+ }
597
+ var ChevronUpIcon = () => /* @__PURE__ */ jsx12(
598
+ "svg",
599
+ {
600
+ xmlns: "http://www.w3.org/2000/svg",
601
+ width: "16",
602
+ height: "16",
603
+ viewBox: "0 0 24 24",
604
+ fill: "none",
605
+ stroke: "currentColor",
606
+ strokeWidth: "2",
607
+ strokeLinecap: "round",
608
+ strokeLinejoin: "round",
609
+ children: /* @__PURE__ */ jsx12("path", { d: "m18 15-6-6-6 6" })
610
+ }
611
+ );
612
+ var MoreVerticalIcon = () => /* @__PURE__ */ jsxs4(
613
+ "svg",
614
+ {
615
+ xmlns: "http://www.w3.org/2000/svg",
616
+ width: "16",
617
+ height: "16",
618
+ viewBox: "0 0 24 24",
619
+ fill: "none",
620
+ stroke: "currentColor",
621
+ strokeWidth: "2",
622
+ strokeLinecap: "round",
623
+ strokeLinejoin: "round",
624
+ children: [
625
+ /* @__PURE__ */ jsx12("circle", { cx: "12", cy: "12", r: "1" }),
626
+ /* @__PURE__ */ jsx12("circle", { cx: "12", cy: "5", r: "1" }),
627
+ /* @__PURE__ */ jsx12("circle", { cx: "12", cy: "19", r: "1" })
628
+ ]
629
+ }
630
+ );
631
+ var CloseIcon = () => /* @__PURE__ */ jsxs4(
632
+ "svg",
633
+ {
634
+ xmlns: "http://www.w3.org/2000/svg",
635
+ width: "16",
636
+ height: "16",
637
+ viewBox: "0 0 24 24",
638
+ fill: "none",
639
+ stroke: "currentColor",
640
+ strokeWidth: "2",
641
+ strokeLinecap: "round",
642
+ strokeLinejoin: "round",
643
+ children: [
644
+ /* @__PURE__ */ jsx12("path", { d: "M18 6 6 18" }),
645
+ /* @__PURE__ */ jsx12("path", { d: "m6 6 12 12" })
646
+ ]
647
+ }
648
+ );
649
+ var edgeLabels = {
650
+ left: "Pin to left",
651
+ right: "Pin to right",
652
+ top: "Pin to top",
653
+ bottom: "Pin to bottom"
654
+ };
655
+ var DataPanelHeader = React12.forwardRef(
656
+ ({
657
+ title,
658
+ subtitle,
659
+ mode,
660
+ edge,
661
+ isExpanded,
662
+ onModeChange,
663
+ onEdgeChange,
664
+ onExpandedChange,
665
+ onClose,
666
+ disableClose = false,
667
+ disableModeSwitch = false,
668
+ headerContent,
669
+ headerActions,
670
+ className,
671
+ draggable = false
672
+ }, ref) => {
673
+ return /* @__PURE__ */ jsxs4(
674
+ "div",
675
+ {
676
+ ref,
677
+ className: cn(
678
+ "flex items-center justify-between gap-2 border-b border-border bg-muted/30 px-4 py-3",
679
+ draggable && "cursor-grab active:cursor-grabbing",
680
+ className
681
+ ),
682
+ "data-panel-header": true,
683
+ children: [
684
+ /* @__PURE__ */ jsx12("div", { className: "flex flex-col min-w-0 flex-1", children: headerContent ? headerContent : /* @__PURE__ */ jsxs4(Fragment, { children: [
685
+ title && /* @__PURE__ */ jsx12("h3", { className: "text-sm font-semibold leading-none truncate", children: title }),
686
+ subtitle && /* @__PURE__ */ jsx12("p", { className: "text-xs text-muted-foreground mt-1 truncate", children: subtitle })
687
+ ] }) }),
688
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1 shrink-0", children: [
689
+ headerActions,
690
+ /* @__PURE__ */ jsx12(
691
+ "button",
692
+ {
693
+ type: "button",
694
+ className: "flex h-8 w-8 items-center justify-center rounded-md bg-transparent text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
695
+ onClick: () => onExpandedChange?.(!isExpanded),
696
+ "aria-label": isExpanded ? "Collapse panel" : "Expand panel",
697
+ "aria-expanded": isExpanded,
698
+ children: /* @__PURE__ */ jsx12("span", { className: cn("transition-transform", !isExpanded && "rotate-180"), children: /* @__PURE__ */ jsx12(ChevronUpIcon, {}) })
699
+ }
700
+ ),
701
+ !disableModeSwitch && /* @__PURE__ */ jsxs4(DropdownMenuPrimitive.Root, { children: [
702
+ /* @__PURE__ */ jsx12(DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsx12(
703
+ "button",
704
+ {
705
+ type: "button",
706
+ className: "flex h-8 w-8 items-center justify-center rounded-md bg-transparent text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
707
+ "aria-label": "Panel options",
708
+ children: /* @__PURE__ */ jsx12(MoreVerticalIcon, {})
709
+ }
710
+ ) }),
711
+ /* @__PURE__ */ jsx12(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsxs4(
712
+ DropdownContent,
713
+ {
714
+ className: "z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95",
715
+ sideOffset: 4,
716
+ align: "end",
717
+ children: [
718
+ /* @__PURE__ */ jsx12(DropdownLabel, { className: "px-2 py-1.5 text-sm font-semibold", children: "Panel Position" }),
719
+ ["left", "right", "top", "bottom"].map((e) => /* @__PURE__ */ jsxs4(
720
+ DropdownItem,
721
+ {
722
+ className: "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
723
+ onSelect: () => {
724
+ onModeChange?.("pinned");
725
+ onEdgeChange?.(e);
726
+ },
727
+ children: [
728
+ edgeLabels[e],
729
+ mode === "pinned" && edge === e && /* @__PURE__ */ jsx12("span", { className: "ml-auto text-xs", children: "\u2713" })
730
+ ]
731
+ },
732
+ e
733
+ )),
734
+ /* @__PURE__ */ jsx12(DropdownSeparator, { className: "-mx-1 my-1 h-px bg-muted" }),
735
+ /* @__PURE__ */ jsxs4(
736
+ DropdownItem,
737
+ {
738
+ className: "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground",
739
+ onSelect: () => onModeChange?.("detached"),
740
+ children: [
741
+ "Detach",
742
+ mode === "detached" && /* @__PURE__ */ jsx12("span", { className: "ml-auto text-xs", children: "\u2713" })
743
+ ]
744
+ }
745
+ )
746
+ ]
747
+ }
748
+ ) })
749
+ ] }),
750
+ !disableClose && /* @__PURE__ */ jsx12(
751
+ "button",
752
+ {
753
+ type: "button",
754
+ className: "flex h-8 w-8 items-center justify-center rounded-md bg-transparent text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
755
+ onClick: onClose,
756
+ "aria-label": "Close panel",
757
+ children: /* @__PURE__ */ jsx12(CloseIcon, {})
758
+ }
759
+ )
760
+ ] })
761
+ ]
762
+ }
763
+ );
764
+ }
765
+ );
766
+ DataPanelHeader.displayName = "DataPanelHeader";
767
+ var DataPanelContent = React12.forwardRef(
768
+ ({ children, className }, ref) => {
769
+ return /* @__PURE__ */ jsx12("div", { ref, className: cn("flex-1 overflow-auto p-4", className), children });
770
+ }
771
+ );
772
+ DataPanelContent.displayName = "DataPanelContent";
773
+ var DataPanelFooter = React12.forwardRef(
774
+ ({ actions = [], footerContent, footerActions, className }, ref) => {
775
+ if (!footerContent && actions.length === 0 && !footerActions) {
776
+ return null;
777
+ }
778
+ const mapVariant = (variant) => {
779
+ if (variant === "primary") return "default";
780
+ return variant ?? "default";
781
+ };
782
+ return /* @__PURE__ */ jsx12(
783
+ "div",
784
+ {
785
+ ref,
786
+ className: cn(
787
+ "flex items-center justify-end gap-2 border-t border-border bg-muted/30 px-4 py-3",
788
+ className
789
+ ),
790
+ children: footerContent ? footerContent : /* @__PURE__ */ jsxs4(Fragment, { children: [
791
+ footerActions,
792
+ actions.map((action, index) => /* @__PURE__ */ jsx12(
793
+ Button,
794
+ {
795
+ variant: mapVariant(action.variant),
796
+ size: "sm",
797
+ disabled: action.disabled,
798
+ onClick: action.onClick,
799
+ children: action.label
800
+ },
801
+ index
802
+ ))
803
+ ] })
804
+ }
805
+ );
806
+ }
807
+ );
808
+ DataPanelFooter.displayName = "DataPanelFooter";
809
+ var DataPanelTab = React12.forwardRef(
810
+ ({ title = "Panel", edge, onClick, className }, ref) => {
811
+ const positionClasses = {
812
+ left: "left-0 top-1/2 -translate-y-1/2 rounded-r-md border-l-0",
813
+ right: "right-0 top-1/2 -translate-y-1/2 rounded-l-md border-r-0",
814
+ top: "top-0 left-1/2 -translate-x-1/2 rounded-b-md border-t-0",
815
+ bottom: "bottom-0 left-1/2 -translate-x-1/2 rounded-t-md border-b-0"
816
+ }[edge];
817
+ const isVertical = edge === "left" || edge === "right";
818
+ const iconRotation = {
819
+ left: "rotate-90",
820
+ right: "-rotate-90",
821
+ top: "rotate-180",
822
+ bottom: ""
823
+ }[edge];
824
+ return /* @__PURE__ */ jsxs4(
825
+ "button",
826
+ {
827
+ ref,
828
+ type: "button",
829
+ className: cn(
830
+ "fixed z-40 flex items-center justify-center gap-2 border border-border bg-background px-3 py-2 text-sm font-medium shadow-md transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
831
+ positionClasses,
832
+ isVertical && "[writing-mode:vertical-rl]",
833
+ className
834
+ ),
835
+ onClick,
836
+ "aria-label": `Expand ${title} panel`,
837
+ children: [
838
+ /* @__PURE__ */ jsx12("span", { className: cn("shrink-0", iconRotation), children: /* @__PURE__ */ jsx12(ChevronUpIcon, {}) }),
839
+ /* @__PURE__ */ jsx12("span", { className: cn(isVertical && "rotate-180"), children: title })
840
+ ]
841
+ }
842
+ );
843
+ }
844
+ );
845
+ DataPanelTab.displayName = "DataPanelTab";
846
+ var DataPanel = React12.forwardRef(
847
+ ({
848
+ open: controlledOpen,
849
+ onOpenChange,
850
+ mode: controlledMode,
851
+ onModeChange,
852
+ edge: controlledEdge,
853
+ onEdgeChange,
854
+ expanded: controlledExpanded,
855
+ onExpandedChange,
856
+ title,
857
+ subtitle,
858
+ children,
859
+ actions = [],
860
+ constraints = {},
861
+ disableClose = false,
862
+ disableResize = false,
863
+ disableDrag = false,
864
+ disableModeSwitch = false,
865
+ persistKey,
866
+ snapThreshold = 20,
867
+ detachThreshold = 40,
868
+ headerContent,
869
+ headerActions,
870
+ footerContent,
871
+ footerActions,
872
+ className
873
+ }, ref) => {
874
+ const resolvedConstraints = { ...DEFAULT_CONSTRAINTS, ...constraints };
875
+ const [internalOpen, setInternalOpen] = React12.useState(true);
876
+ const [internalMode, setInternalMode] = React12.useState(DEFAULT_PANEL_STATE.mode);
877
+ const [internalEdge, setInternalEdge] = React12.useState(DEFAULT_PANEL_STATE.edge);
878
+ const [internalExpanded, setInternalExpanded] = React12.useState(
879
+ DEFAULT_PANEL_STATE.isExpanded
880
+ );
881
+ const [detachedPosition, setDetachedPosition] = React12.useState(
882
+ DEFAULT_PANEL_STATE.detachedPosition
883
+ );
884
+ const [detachedSize, setDetachedSize] = React12.useState(DEFAULT_PANEL_STATE.detachedSize);
885
+ const [pinnedSize, setPinnedSize] = React12.useState(DEFAULT_PANEL_STATE.pinnedSize);
886
+ const [isDragging, setIsDragging] = React12.useState(false);
887
+ const [isResizing, setIsResizing] = React12.useState(false);
888
+ const [snapPreview, setSnapPreview] = React12.useState(null);
889
+ const [isPinnedDragging, setIsPinnedDragging] = React12.useState(false);
890
+ const [pullOffset, setPullOffset] = React12.useState(0);
891
+ const dragStateRef = React12.useRef({
892
+ startPosition: { x: 0, y: 0 },
893
+ startPanelPosition: { x: 0, y: 0 }
894
+ });
895
+ const pinnedDragStateRef = React12.useRef({
896
+ startPosition: { x: 0, y: 0 },
897
+ hasDetached: false
898
+ });
899
+ const resizeStateRef = React12.useRef({
900
+ handle: null,
901
+ startPosition: { x: 0, y: 0 },
902
+ startSize: { width: 0, height: 0 },
903
+ startPanelPosition: { x: 0, y: 0 }
904
+ });
905
+ const open = controlledOpen ?? internalOpen;
906
+ const mode = controlledMode ?? internalMode;
907
+ const edge = controlledEdge ?? internalEdge;
908
+ const isExpanded = controlledExpanded ?? internalExpanded;
909
+ const saveTimeoutRef = React12.useRef(null);
910
+ const debouncedSave = React12.useCallback(() => {
911
+ if (!persistKey) return;
912
+ if (saveTimeoutRef.current) {
913
+ clearTimeout(saveTimeoutRef.current);
914
+ }
915
+ saveTimeoutRef.current = setTimeout(() => {
916
+ savePanelState(persistKey, {
917
+ mode: internalMode,
918
+ variant: "full",
919
+ edge: internalEdge,
920
+ isExpanded: internalExpanded,
921
+ detachedPosition,
922
+ detachedSize,
923
+ pinnedSize,
924
+ cardSnapIndex: 0
925
+ });
926
+ }, 300);
927
+ }, [
928
+ persistKey,
929
+ internalMode,
930
+ internalEdge,
931
+ internalExpanded,
932
+ detachedPosition,
933
+ detachedSize,
934
+ pinnedSize
935
+ ]);
936
+ React12.useEffect(() => {
937
+ if (!persistKey) return;
938
+ const persisted = loadPanelState(persistKey);
939
+ if (persisted) {
940
+ if (controlledMode === void 0 && persisted.mode) setInternalMode(persisted.mode);
941
+ if (controlledEdge === void 0 && persisted.edge) setInternalEdge(persisted.edge);
942
+ if (controlledExpanded === void 0 && persisted.isExpanded !== void 0)
943
+ setInternalExpanded(persisted.isExpanded);
944
+ if (persisted.detachedPosition) setDetachedPosition(persisted.detachedPosition);
945
+ if (persisted.detachedSize) setDetachedSize(persisted.detachedSize);
946
+ if (persisted.pinnedSize) setPinnedSize(persisted.pinnedSize);
947
+ }
948
+ }, [persistKey, controlledMode, controlledEdge, controlledExpanded]);
949
+ React12.useEffect(() => {
950
+ if (mode === "detached" && detachedPosition.x === DEFAULT_PANEL_STATE.detachedPosition.x && detachedPosition.y === DEFAULT_PANEL_STATE.detachedPosition.y) {
951
+ setDetachedPosition(
952
+ getInitialDetachedPosition(detachedSize, window.innerWidth, window.innerHeight)
953
+ );
954
+ }
955
+ }, [mode, detachedPosition, detachedSize]);
956
+ const handleOpenChange = (newOpen) => {
957
+ if (controlledOpen === void 0) {
958
+ setInternalOpen(newOpen);
959
+ }
960
+ onOpenChange?.(newOpen);
961
+ };
962
+ const handleModeChange = (newMode) => {
963
+ if (controlledMode === void 0) {
964
+ setInternalMode(newMode);
965
+ }
966
+ onModeChange?.(newMode);
967
+ debouncedSave();
968
+ };
969
+ const handleEdgeChange = (newEdge) => {
970
+ if (controlledEdge === void 0) {
971
+ setInternalEdge(newEdge);
972
+ }
973
+ onEdgeChange?.(newEdge);
974
+ debouncedSave();
975
+ };
976
+ const handleExpandedChange = (newExpanded) => {
977
+ if (controlledExpanded === void 0) {
978
+ setInternalExpanded(newExpanded);
979
+ }
980
+ onExpandedChange?.(newExpanded);
981
+ debouncedSave();
982
+ };
983
+ const handleDragStart = (e) => {
984
+ if (disableDrag) return;
985
+ const target = e.target;
986
+ if (!target.closest("[data-panel-header]")) return;
987
+ const pos = getPointerPosition(e.nativeEvent);
988
+ if (mode === "detached") {
989
+ setIsDragging(true);
990
+ dragStateRef.current = {
991
+ startPosition: pos,
992
+ startPanelPosition: { ...detachedPosition }
993
+ };
994
+ document.body.style.cursor = "grabbing";
995
+ document.body.style.userSelect = "none";
996
+ } else if (mode === "pinned" && detachThreshold > 0) {
997
+ setIsPinnedDragging(true);
998
+ pinnedDragStateRef.current = {
999
+ startPosition: pos,
1000
+ hasDetached: false
1001
+ };
1002
+ setPullOffset(0);
1003
+ document.body.style.cursor = "grab";
1004
+ document.body.style.userSelect = "none";
1005
+ }
1006
+ };
1007
+ const handleDragMove = React12.useCallback(
1008
+ (e) => {
1009
+ if (!isDragging) return;
1010
+ const currentPos = getPointerPosition(e);
1011
+ const newPosition = calculateDragPosition(
1012
+ {
1013
+ isDragging: true,
1014
+ startPosition: dragStateRef.current.startPosition,
1015
+ startPanelPosition: dragStateRef.current.startPanelPosition,
1016
+ currentPosition: currentPos
1017
+ },
1018
+ currentPos
1019
+ );
1020
+ const snap = detectEdgeSnap(
1021
+ newPosition,
1022
+ detachedSize,
1023
+ window.innerWidth,
1024
+ window.innerHeight,
1025
+ snapThreshold
1026
+ );
1027
+ setSnapPreview(snap.shouldSnap ? snap.edge : null);
1028
+ setDetachedPosition(
1029
+ constrainPosition(newPosition, detachedSize, window.innerWidth, window.innerHeight)
1030
+ );
1031
+ },
1032
+ [isDragging, detachedSize, snapThreshold]
1033
+ );
1034
+ const handleDragEnd = React12.useCallback(() => {
1035
+ if (!isDragging) return;
1036
+ setIsDragging(false);
1037
+ document.body.style.cursor = "";
1038
+ document.body.style.userSelect = "";
1039
+ if (snapPreview) {
1040
+ handleModeChange("pinned");
1041
+ handleEdgeChange(snapPreview);
1042
+ setSnapPreview(null);
1043
+ } else {
1044
+ debouncedSave();
1045
+ }
1046
+ }, [isDragging, snapPreview, handleModeChange, handleEdgeChange, debouncedSave]);
1047
+ const handlePinnedDragMove = React12.useCallback(
1048
+ (e) => {
1049
+ if (!isPinnedDragging) return;
1050
+ const currentPos = getPointerPosition(e);
1051
+ const distance = calculateDetachDistance(
1052
+ pinnedDragStateRef.current.startPosition,
1053
+ currentPos,
1054
+ edge
1055
+ );
1056
+ if (distance >= detachThreshold && !pinnedDragStateRef.current.hasDetached) {
1057
+ pinnedDragStateRef.current.hasDetached = true;
1058
+ setIsPinnedDragging(false);
1059
+ setPullOffset(0);
1060
+ const newPosition = calculateDetachedPositionFromPinned(
1061
+ currentPos,
1062
+ pinnedSize,
1063
+ detachedSize,
1064
+ edge,
1065
+ window.innerWidth,
1066
+ window.innerHeight
1067
+ );
1068
+ setDetachedPosition(newPosition);
1069
+ handleModeChange("detached");
1070
+ setIsDragging(true);
1071
+ dragStateRef.current = {
1072
+ startPosition: currentPos,
1073
+ startPanelPosition: newPosition
1074
+ };
1075
+ document.body.style.cursor = "grabbing";
1076
+ } else if (!pinnedDragStateRef.current.hasDetached) {
1077
+ const pull = calculatePullOffset(distance, detachThreshold);
1078
+ setPullOffset(pull);
1079
+ }
1080
+ },
1081
+ [isPinnedDragging, edge, detachThreshold, pinnedSize, detachedSize, handleModeChange]
1082
+ );
1083
+ const handlePinnedDragEnd = React12.useCallback(() => {
1084
+ if (!isPinnedDragging) return;
1085
+ setIsPinnedDragging(false);
1086
+ setPullOffset(0);
1087
+ document.body.style.cursor = "";
1088
+ document.body.style.userSelect = "";
1089
+ }, [isPinnedDragging]);
1090
+ const handleResizeStart = (e, handle) => {
1091
+ if (disableResize) return;
1092
+ e.preventDefault();
1093
+ e.stopPropagation();
1094
+ setIsResizing(true);
1095
+ const pos = getPointerPosition(e.nativeEvent);
1096
+ resizeStateRef.current = {
1097
+ handle,
1098
+ startPosition: pos,
1099
+ startSize: mode === "detached" ? { ...detachedSize } : { width: pinnedSize, height: pinnedSize },
1100
+ startPanelPosition: { ...detachedPosition }
1101
+ };
1102
+ document.body.style.cursor = getResizeCursor(handle);
1103
+ document.body.style.userSelect = "none";
1104
+ };
1105
+ const handleResizeMove = React12.useCallback(
1106
+ (e) => {
1107
+ if (!isResizing || !resizeStateRef.current.handle) return;
1108
+ const currentPos = getPointerPosition(e);
1109
+ const { handle, startPosition, startSize, startPanelPosition } = resizeStateRef.current;
1110
+ if (mode === "detached") {
1111
+ const result = calculateResize(
1112
+ {
1113
+ isResizing: true,
1114
+ handle,
1115
+ startPosition,
1116
+ startSize,
1117
+ startPanelPosition
1118
+ },
1119
+ currentPos
1120
+ );
1121
+ const constrainedSize = constrainSize(result.size, resolvedConstraints);
1122
+ const constrainedPosition = constrainPosition(
1123
+ result.position,
1124
+ constrainedSize,
1125
+ window.innerWidth,
1126
+ window.innerHeight
1127
+ );
1128
+ setDetachedSize(constrainedSize);
1129
+ setDetachedPosition(constrainedPosition);
1130
+ } else {
1131
+ const delta = isHorizontalEdge(edge) ? currentPos.x - startPosition.x : currentPos.y - startPosition.y;
1132
+ const direction = edge === "left" || edge === "top" ? 1 : -1;
1133
+ const newSize = startSize.width + delta * direction;
1134
+ if (isHorizontalEdge(edge)) {
1135
+ setPinnedSize(constrainPinnedWidth(newSize, resolvedConstraints, window.innerWidth));
1136
+ } else {
1137
+ setPinnedSize(constrainPinnedHeight(newSize, resolvedConstraints, window.innerHeight));
1138
+ }
1139
+ }
1140
+ },
1141
+ [isResizing, mode, edge, resolvedConstraints]
1142
+ );
1143
+ const handleResizeEnd = React12.useCallback(() => {
1144
+ if (!isResizing) return;
1145
+ setIsResizing(false);
1146
+ resizeStateRef.current.handle = null;
1147
+ document.body.style.cursor = "";
1148
+ document.body.style.userSelect = "";
1149
+ debouncedSave();
1150
+ }, [isResizing, debouncedSave]);
1151
+ React12.useEffect(() => {
1152
+ if (isDragging) {
1153
+ window.addEventListener("pointermove", handleDragMove);
1154
+ window.addEventListener("pointerup", handleDragEnd);
1155
+ return () => {
1156
+ window.removeEventListener("pointermove", handleDragMove);
1157
+ window.removeEventListener("pointerup", handleDragEnd);
1158
+ };
1159
+ }
1160
+ }, [isDragging, handleDragMove, handleDragEnd]);
1161
+ React12.useEffect(() => {
1162
+ if (isPinnedDragging) {
1163
+ window.addEventListener("pointermove", handlePinnedDragMove);
1164
+ window.addEventListener("pointerup", handlePinnedDragEnd);
1165
+ return () => {
1166
+ window.removeEventListener("pointermove", handlePinnedDragMove);
1167
+ window.removeEventListener("pointerup", handlePinnedDragEnd);
1168
+ };
1169
+ }
1170
+ }, [isPinnedDragging, handlePinnedDragMove, handlePinnedDragEnd]);
1171
+ React12.useEffect(() => {
1172
+ if (isResizing) {
1173
+ window.addEventListener("pointermove", handleResizeMove);
1174
+ window.addEventListener("pointerup", handleResizeEnd);
1175
+ return () => {
1176
+ window.removeEventListener("pointermove", handleResizeMove);
1177
+ window.removeEventListener("pointerup", handleResizeEnd);
1178
+ };
1179
+ }
1180
+ }, [isResizing, handleResizeMove, handleResizeEnd]);
1181
+ const panelStyles = React12.useMemo(() => {
1182
+ if (mode === "pinned") {
1183
+ const baseStyles = getPinnedPositionStyles(edge, pinnedSize);
1184
+ if (pullOffset > 0) {
1185
+ const transform = getPinnedPullTransform(pullOffset, edge);
1186
+ return { ...baseStyles, transform };
1187
+ }
1188
+ return baseStyles;
1189
+ }
1190
+ return getDetachedPositionStyles(detachedPosition, detachedSize);
1191
+ }, [mode, edge, pinnedSize, detachedPosition, detachedSize, pullOffset]);
1192
+ const pinnedClasses = {
1193
+ left: "left-0 top-0 bottom-0 border-r",
1194
+ right: "right-0 top-0 bottom-0 border-l",
1195
+ top: "top-0 left-0 right-0 border-b",
1196
+ bottom: "bottom-0 left-0 right-0 border-t"
1197
+ }[edge];
1198
+ const animationClass = mode === "pinned" ? {
1199
+ left: "animate-slide-right",
1200
+ right: "animate-slide-left",
1201
+ top: "animate-slide-down",
1202
+ bottom: "animate-slide-up"
1203
+ }[edge] : "animate-scale-in";
1204
+ if (!open) return null;
1205
+ if (!isExpanded && mode === "pinned") {
1206
+ return /* @__PURE__ */ jsx12(DataPanelTab, { title, edge, onClick: () => handleExpandedChange(true) });
1207
+ }
1208
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
1209
+ snapPreview && /* @__PURE__ */ jsx12(
1210
+ "div",
1211
+ {
1212
+ className: cn(
1213
+ "fixed z-40 bg-primary/20 border-2 border-primary border-dashed transition-all",
1214
+ snapPreview === "left" && "left-0 top-0 bottom-0 w-80",
1215
+ snapPreview === "right" && "right-0 top-0 bottom-0 w-80",
1216
+ snapPreview === "top" && "top-0 left-0 right-0 h-64",
1217
+ snapPreview === "bottom" && "bottom-0 left-0 right-0 h-64"
1218
+ )
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ jsxs4(
1222
+ "div",
1223
+ {
1224
+ ref,
1225
+ className: cn(
1226
+ "fixed z-50 flex flex-col bg-background border border-border shadow-lg overflow-hidden",
1227
+ mode === "pinned" && pinnedClasses,
1228
+ mode === "detached" && "rounded-lg",
1229
+ isPinnedDragging && pullOffset > 0 && "shadow-2xl",
1230
+ animationClass,
1231
+ className
1232
+ ),
1233
+ style: panelStyles,
1234
+ role: mode === "detached" ? "dialog" : void 0,
1235
+ "aria-modal": mode === "detached" ? "true" : void 0,
1236
+ "aria-labelledby": title ? "data-panel-title" : void 0,
1237
+ onPointerDown: handleDragStart,
1238
+ children: [
1239
+ /* @__PURE__ */ jsx12(
1240
+ DataPanelHeader,
1241
+ {
1242
+ title,
1243
+ subtitle,
1244
+ mode,
1245
+ edge,
1246
+ isExpanded,
1247
+ onModeChange: handleModeChange,
1248
+ onEdgeChange: handleEdgeChange,
1249
+ onExpandedChange: handleExpandedChange,
1250
+ onClose: () => handleOpenChange(false),
1251
+ disableClose,
1252
+ disableModeSwitch,
1253
+ headerContent,
1254
+ headerActions,
1255
+ draggable: !disableDrag && (mode === "detached" || mode === "pinned" && detachThreshold > 0)
1256
+ }
1257
+ ),
1258
+ /* @__PURE__ */ jsx12(DataPanelContent, { children }),
1259
+ /* @__PURE__ */ jsx12(
1260
+ DataPanelFooter,
1261
+ {
1262
+ actions,
1263
+ footerContent,
1264
+ footerActions
1265
+ }
1266
+ ),
1267
+ !disableResize && /* @__PURE__ */ jsx12(Fragment, { children: mode === "detached" ? /* @__PURE__ */ jsxs4(Fragment, { children: [
1268
+ /* @__PURE__ */ jsx12(
1269
+ "div",
1270
+ {
1271
+ className: "resize-handle resize-handle--horizontal resize-handle--top",
1272
+ onPointerDown: (e) => handleResizeStart(e, "top")
1273
+ }
1274
+ ),
1275
+ /* @__PURE__ */ jsx12(
1276
+ "div",
1277
+ {
1278
+ className: "resize-handle resize-handle--horizontal resize-handle--bottom",
1279
+ onPointerDown: (e) => handleResizeStart(e, "bottom")
1280
+ }
1281
+ ),
1282
+ /* @__PURE__ */ jsx12(
1283
+ "div",
1284
+ {
1285
+ className: "resize-handle resize-handle--vertical resize-handle--left",
1286
+ onPointerDown: (e) => handleResizeStart(e, "left")
1287
+ }
1288
+ ),
1289
+ /* @__PURE__ */ jsx12(
1290
+ "div",
1291
+ {
1292
+ className: "resize-handle resize-handle--vertical resize-handle--right",
1293
+ onPointerDown: (e) => handleResizeStart(e, "right")
1294
+ }
1295
+ ),
1296
+ /* @__PURE__ */ jsx12(
1297
+ "div",
1298
+ {
1299
+ className: "resize-handle resize-handle--corner resize-handle--top-left",
1300
+ style: { "--handle-radius": "6px" },
1301
+ onPointerDown: (e) => handleResizeStart(e, "top-left")
1302
+ }
1303
+ ),
1304
+ /* @__PURE__ */ jsx12(
1305
+ "div",
1306
+ {
1307
+ className: "resize-handle resize-handle--corner resize-handle--top-right",
1308
+ style: { "--handle-radius": "6px" },
1309
+ onPointerDown: (e) => handleResizeStart(e, "top-right")
1310
+ }
1311
+ ),
1312
+ /* @__PURE__ */ jsx12(
1313
+ "div",
1314
+ {
1315
+ className: "resize-handle resize-handle--corner resize-handle--bottom-left",
1316
+ style: { "--handle-radius": "6px" },
1317
+ onPointerDown: (e) => handleResizeStart(e, "bottom-left")
1318
+ }
1319
+ ),
1320
+ /* @__PURE__ */ jsx12(
1321
+ "div",
1322
+ {
1323
+ className: "resize-handle resize-handle--corner resize-handle--bottom-right",
1324
+ style: { "--handle-radius": "6px" },
1325
+ onPointerDown: (e) => handleResizeStart(e, "bottom-right")
1326
+ }
1327
+ )
1328
+ ] }) : /* @__PURE__ */ jsx12(
1329
+ "div",
1330
+ {
1331
+ className: cn(
1332
+ "resize-handle",
1333
+ edge === "left" && "resize-handle--vertical resize-handle--right",
1334
+ edge === "right" && "resize-handle--vertical resize-handle--left",
1335
+ edge === "top" && "resize-handle--horizontal resize-handle--bottom",
1336
+ edge === "bottom" && "resize-handle--horizontal resize-handle--top"
1337
+ ),
1338
+ onPointerDown: (e) => handleResizeStart(e, getPinnedResizeHandle(edge))
1339
+ }
1340
+ ) })
1341
+ ]
1342
+ }
1343
+ )
1344
+ ] });
1345
+ }
1346
+ );
1347
+ DataPanel.displayName = "DataPanel";
378
1348
  export {
379
1349
  Avatar,
380
1350
  AvatarFallback,
@@ -387,6 +1357,11 @@ export {
387
1357
  CardFooter,
388
1358
  CardHeader,
389
1359
  CardTitle,
1360
+ DataPanel,
1361
+ DataPanelContent,
1362
+ DataPanelFooter,
1363
+ DataPanelHeader,
1364
+ DataPanelTab,
390
1365
  Dialog,
391
1366
  DialogClose,
392
1367
  DialogContent,
@@ -400,6 +1375,7 @@ export {
400
1375
  Input,
401
1376
  Label,
402
1377
  PageHeader,
1378
+ PasswordInput,
403
1379
  Separator,
404
1380
  Switch,
405
1381
  badgeVariants,
@@ -408,5 +1384,6 @@ export {
408
1384
  pageHeaderActionsVariants,
409
1385
  pageHeaderContainerVariants,
410
1386
  pageHeaderSubtitleVariants,
411
- pageHeaderTitleVariants
1387
+ pageHeaderTitleVariants,
1388
+ useDataPanel
412
1389
  };