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