@exegia/corpora-ui 0.17.0 → 0.18.0

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.
Files changed (112) hide show
  1. package/dist-lib/components/blocks/nav/sidebar-block.d.ts +1 -1
  2. package/dist-lib/components/blocks/scaffold/__tests__/scaffold.test.d.ts +1 -0
  3. package/dist-lib/components/blocks/scaffold/constants.d.ts +20 -0
  4. package/dist-lib/components/blocks/scaffold/index.d.ts +25 -0
  5. package/dist-lib/components/blocks/scaffold/panel-close-button.d.ts +4 -0
  6. package/dist-lib/components/blocks/scaffold/panel-menu-button.d.ts +7 -0
  7. package/dist-lib/components/blocks/scaffold/scaffold-actions.d.ts +9 -0
  8. package/dist-lib/components/blocks/scaffold/scaffold-canvas.d.ts +7 -0
  9. package/dist-lib/components/blocks/scaffold/scaffold-context.d.ts +5 -0
  10. package/dist-lib/components/blocks/scaffold/scaffold-inspector.d.ts +9 -0
  11. package/dist-lib/components/blocks/scaffold/scaffold-main.d.ts +8 -0
  12. package/dist-lib/components/blocks/scaffold/scaffold-panel.d.ts +10 -0
  13. package/dist-lib/components/blocks/scaffold/scaffold-root.d.ts +8 -0
  14. package/dist-lib/components/blocks/scaffold/scaffold-sidebar.d.ts +7 -0
  15. package/dist-lib/components/blocks/scaffold/scaffold-sub-panel.d.ts +3 -0
  16. package/dist-lib/components/blocks/scaffold/type.d.ts +133 -0
  17. package/dist-lib/components/blocks/scaffold/use-scaffold.d.ts +8 -0
  18. package/dist-lib/components/blocks/scaffold/utils.d.ts +15 -0
  19. package/dist-lib/components/blocks/shell/animated-panel-inset.d.ts +2 -0
  20. package/dist-lib/components/blocks/shell/animated-panel-provider.d.ts +2 -0
  21. package/dist-lib/components/blocks/shell/animated-panel-trigger.d.ts +2 -0
  22. package/dist-lib/components/blocks/shell/animated-panel.d.ts +2 -0
  23. package/dist-lib/components/blocks/shell/animated-sidebar-content.d.ts +2 -0
  24. package/dist-lib/components/blocks/shell/animated-sidebar-footer.d.ts +2 -0
  25. package/dist-lib/components/blocks/shell/animated-sidebar-group-content.d.ts +2 -0
  26. package/dist-lib/components/blocks/shell/animated-sidebar-group-label.d.ts +2 -0
  27. package/dist-lib/components/blocks/shell/animated-sidebar-group.d.ts +2 -0
  28. package/dist-lib/components/blocks/shell/animated-sidebar-header.d.ts +2 -0
  29. package/dist-lib/components/blocks/shell/animated-sidebar-menu-button.d.ts +3 -0
  30. package/dist-lib/components/blocks/shell/animated-sidebar-menu-item.d.ts +2 -0
  31. package/dist-lib/components/blocks/shell/animated-sidebar-menu-sub-button.d.ts +3 -0
  32. package/dist-lib/components/blocks/shell/animated-sidebar-menu-sub-item.d.ts +2 -0
  33. package/dist-lib/components/blocks/shell/animated-sidebar-menu-sub.d.ts +2 -0
  34. package/dist-lib/components/blocks/shell/animated-sidebar-menu.d.ts +2 -0
  35. package/dist-lib/components/blocks/shell/index.d.ts +16 -0
  36. package/dist-lib/components/blocks/shell/type.d.ts +90 -4
  37. package/dist-lib/components/blocks/shell/utils.d.ts +37 -0
  38. package/dist-lib/components/motion/index.d.ts +1 -0
  39. package/dist-lib/components/motion/overflow-actions.d.ts +35 -0
  40. package/dist-lib/components/ui/button-group.d.ts +11 -0
  41. package/dist-lib/components/ui/glasscn/glass-button-group.d.ts +5 -0
  42. package/dist-lib/components/ui/glasscn/glass-container.d.ts +7 -0
  43. package/dist-lib/components/ui/glasscn/glass-separator.d.ts +5 -0
  44. package/dist-lib/components/ui/group.d.ts +17 -0
  45. package/dist-lib/components/ui/separator.d.ts +2 -3
  46. package/dist-lib/components/ui/sheet.d.ts +14 -0
  47. package/dist-lib/components/ui/tooltip.d.ts +6 -0
  48. package/dist-lib/index.d.ts +2 -1
  49. package/dist-lib/index.js +1592 -1084
  50. package/dist-lib/index.js.map +1 -1
  51. package/dist-lib/lib/ease.d.ts +3 -0
  52. package/dist-lib/lib/hooks/use-hover-capable.d.ts +6 -0
  53. package/package.json +2 -1
  54. package/src/components/beste/piece/browser-frame.tsx +2 -2
  55. package/src/components/blocks/nav/sidebar-block.tsx +5 -5
  56. package/src/components/blocks/nav/sidebar-nav-row.tsx +4 -5
  57. package/src/components/blocks/scaffold/__tests__/scaffold.test.tsx +203 -0
  58. package/src/components/blocks/scaffold/constants.ts +28 -0
  59. package/src/components/blocks/scaffold/index.ts +38 -0
  60. package/src/components/blocks/scaffold/panel-close-button.tsx +36 -0
  61. package/src/components/blocks/scaffold/panel-menu-button.tsx +240 -0
  62. package/src/components/blocks/scaffold/scaffold-actions.tsx +97 -0
  63. package/src/components/blocks/scaffold/scaffold-canvas.tsx +29 -0
  64. package/src/components/blocks/scaffold/scaffold-context.ts +18 -0
  65. package/src/components/blocks/scaffold/scaffold-inspector.tsx +57 -0
  66. package/src/components/blocks/scaffold/scaffold-main.tsx +28 -0
  67. package/src/components/blocks/scaffold/scaffold-panel.tsx +98 -0
  68. package/src/components/blocks/scaffold/scaffold-root.tsx +68 -0
  69. package/src/components/blocks/scaffold/scaffold-sidebar.tsx +31 -0
  70. package/src/components/blocks/scaffold/scaffold-sub-panel.tsx +51 -0
  71. package/src/components/blocks/scaffold/type.ts +171 -0
  72. package/src/components/blocks/scaffold/use-scaffold.ts +48 -0
  73. package/src/components/blocks/scaffold/utils.ts +30 -0
  74. package/src/components/blocks/shell/animated-panel-inset.tsx +23 -0
  75. package/src/components/blocks/shell/animated-panel-provider.tsx +155 -0
  76. package/src/components/blocks/shell/animated-panel-trigger.tsx +42 -0
  77. package/src/components/blocks/shell/animated-panel.tsx +135 -0
  78. package/src/components/blocks/shell/animated-sidebar-content.tsx +19 -0
  79. package/src/components/blocks/shell/animated-sidebar-footer.tsx +19 -0
  80. package/src/components/blocks/shell/animated-sidebar-group-content.tsx +16 -0
  81. package/src/components/blocks/shell/animated-sidebar-group-label.tsx +29 -0
  82. package/src/components/blocks/shell/animated-sidebar-group.tsx +16 -0
  83. package/src/components/blocks/shell/animated-sidebar-header.tsx +16 -0
  84. package/src/components/blocks/shell/animated-sidebar-menu-button.tsx +151 -0
  85. package/src/components/blocks/shell/animated-sidebar-menu-item.tsx +20 -0
  86. package/src/components/blocks/shell/animated-sidebar-menu-sub-button.tsx +85 -0
  87. package/src/components/blocks/shell/animated-sidebar-menu-sub-item.tsx +19 -0
  88. package/src/components/blocks/shell/animated-sidebar-menu-sub.tsx +44 -0
  89. package/src/components/blocks/shell/animated-sidebar-menu.tsx +26 -0
  90. package/src/components/blocks/shell/index.ts +18 -0
  91. package/src/components/blocks/shell/shell-layout.tsx +28 -36
  92. package/src/components/blocks/shell/type.ts +112 -6
  93. package/src/components/blocks/shell/use-shell-panels.ts +1 -1
  94. package/src/components/blocks/shell/utils.ts +142 -1
  95. package/src/components/docs/demo-controls.tsx +1 -1
  96. package/src/components/motion/index.ts +0 -0
  97. package/src/components/motion/overflow-actions.tsx +376 -0
  98. package/src/components/ui/button-group.tsx +88 -0
  99. package/src/components/ui/glasscn/glass-button-group.tsx +48 -0
  100. package/src/components/ui/glasscn/glass-container.tsx +125 -0
  101. package/src/components/ui/glasscn/glass-separator.tsx +39 -0
  102. package/src/components/ui/glasscn/liquid-glass.tsx +250 -210
  103. package/src/components/ui/group.tsx +92 -0
  104. package/src/components/ui/separator.tsx +11 -11
  105. package/src/components/ui/sheet.tsx +135 -0
  106. package/src/components/ui/tooltip.tsx +66 -0
  107. package/src/index.css +1 -1
  108. package/src/index.ts +13 -1
  109. package/src/lib/ease.ts +26 -0
  110. package/src/lib/hooks/use-hover-capable.ts +23 -0
  111. package/dist-lib/components/motion/animated-sidebar.d.ts +0 -106
  112. package/src/components/motion/animated-sidebar.tsx +0 -1171
@@ -0,0 +1,151 @@
1
+ import type * as React from "react"
2
+ import { ChevronRight } from "lucide-react"
3
+ import { motion } from "motion/react"
4
+ import { SPRING_LAYOUT, SPRING_PRESS } from "@/lib/ease"
5
+ import { cn } from "@/lib/utils"
6
+ import type { AnimatedSidebarMenuButtonProps } from "./type"
7
+ import {
8
+ LABEL_ENTER_TRANSITION,
9
+ LABEL_EXIT_TRANSITION,
10
+ REDUCED_TRANSITION,
11
+ useAnimatedSidebar,
12
+ useAnimatedSidebarPanel,
13
+ } from "./utils"
14
+
15
+ export function AnimatedSidebarMenuButton({
16
+ children,
17
+ icon,
18
+ badge,
19
+ href,
20
+ isActive = false,
21
+ ariaExpanded,
22
+ disabled = false,
23
+ closeOnSelect,
24
+ target,
25
+ rel,
26
+ onSelect,
27
+ className,
28
+ }: AnimatedSidebarMenuButtonProps) {
29
+ const context = useAnimatedSidebar()
30
+ const panel = useAnimatedSidebarPanel()
31
+ const textLabel = typeof children === "string" ? children : undefined
32
+
33
+ const select = (
34
+ event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
35
+ ) => {
36
+ if (disabled) {
37
+ event.preventDefault()
38
+ return
39
+ }
40
+ onSelect?.()
41
+ const shouldCloseOnSelect = closeOnSelect ?? ariaExpanded === undefined
42
+ if (context.isMobile && shouldCloseOnSelect) {
43
+ context.setOpenMobile(false, panel.side)
44
+ }
45
+ }
46
+
47
+ const content = (
48
+ <>
49
+ {isActive ? (
50
+ <motion.span
51
+ layoutId={context.layoutId}
52
+ transition={context.reduce ? { duration: 0 } : SPRING_LAYOUT}
53
+ className="absolute inset-0 rounded-xl bg-muted"
54
+ />
55
+ ) : null}
56
+ {icon ? (
57
+ <span
58
+ aria-hidden="true"
59
+ className="relative z-10 grid size-5 shrink-0 place-items-center"
60
+ >
61
+ {icon}
62
+ </span>
63
+ ) : null}
64
+ <motion.span
65
+ initial={false}
66
+ animate={{
67
+ opacity: panel.collapsed ? 0 : 1,
68
+ x: panel.collapsed ? -4 : 0,
69
+ }}
70
+ transition={
71
+ context.reduce
72
+ ? REDUCED_TRANSITION
73
+ : panel.collapsed
74
+ ? LABEL_EXIT_TRANSITION
75
+ : LABEL_ENTER_TRANSITION
76
+ }
77
+ aria-hidden={panel.collapsed}
78
+ className={cn(
79
+ "relative z-10 min-w-0 flex-1 truncate",
80
+ panel.collapsed && "pointer-events-none"
81
+ )}
82
+ >
83
+ {children}
84
+ </motion.span>
85
+ {badge && !panel.collapsed ? (
86
+ <span className="relative z-10 shrink-0 text-xs text-muted-foreground">
87
+ {badge}
88
+ </span>
89
+ ) : null}
90
+ {ariaExpanded !== undefined ? (
91
+ <motion.span
92
+ aria-hidden="true"
93
+ initial={false}
94
+ animate={{
95
+ opacity: panel.collapsed ? 0 : 1,
96
+ rotate: ariaExpanded ? 90 : 0,
97
+ x: panel.collapsed ? 4 : 0,
98
+ }}
99
+ transition={context.reduce ? { duration: 0 } : SPRING_LAYOUT}
100
+ className="relative z-10 grid size-4 shrink-0 place-items-center text-muted-foreground"
101
+ >
102
+ <ChevronRight className="size-3.5" />
103
+ </motion.span>
104
+ ) : null}
105
+ </>
106
+ )
107
+
108
+ const interactiveClassName = cn(
109
+ "relative flex min-h-9 w-full min-w-0 items-center gap-2.5 overflow-hidden rounded-xl px-3 text-left text-sm font-medium outline-none",
110
+ "text-muted-foreground transition-colors hover:text-foreground",
111
+ "focus-visible:bg-muted/70 focus-visible:ring-2 focus-visible:ring-ring",
112
+ isActive && "text-foreground",
113
+ disabled && "cursor-not-allowed opacity-40",
114
+ className
115
+ )
116
+
117
+ return href ? (
118
+ <motion.a
119
+ href={href}
120
+ target={target}
121
+ rel={rel ?? (target === "_blank" ? "noreferrer noopener" : undefined)}
122
+ aria-current={isActive ? "page" : undefined}
123
+ aria-expanded={ariaExpanded}
124
+ aria-disabled={disabled || undefined}
125
+ aria-label={panel.collapsed ? textLabel : undefined}
126
+ title={panel.collapsed ? textLabel : undefined}
127
+ tabIndex={disabled ? -1 : undefined}
128
+ onClick={select}
129
+ whileTap={context.reduce || disabled ? undefined : { scale: 0.98 }}
130
+ transition={SPRING_PRESS}
131
+ className={interactiveClassName}
132
+ >
133
+ {content}
134
+ </motion.a>
135
+ ) : (
136
+ <motion.button
137
+ type="button"
138
+ disabled={disabled}
139
+ aria-current={isActive ? "page" : undefined}
140
+ aria-expanded={ariaExpanded}
141
+ aria-label={panel.collapsed ? textLabel : undefined}
142
+ title={panel.collapsed ? textLabel : undefined}
143
+ onClick={select}
144
+ whileTap={context.reduce || disabled ? undefined : { scale: 0.98 }}
145
+ transition={SPRING_PRESS}
146
+ className={interactiveClassName}
147
+ >
148
+ {content}
149
+ </motion.button>
150
+ )
151
+ }
@@ -0,0 +1,20 @@
1
+ import { forwardRef } from "react"
2
+ import { motion, type HTMLMotionProps } from "motion/react"
3
+ import { SPRING_LAYOUT } from "@/lib/ease"
4
+ import { cn } from "@/lib/utils"
5
+
6
+ export const AnimatedSidebarMenuItem = forwardRef<
7
+ HTMLLIElement,
8
+ HTMLMotionProps<"li">
9
+ >(function AnimatedSidebarMenuItem({ className, ...props }, forwardedRef) {
10
+ return (
11
+ <motion.li
12
+ {...props}
13
+ ref={forwardedRef}
14
+ layout="position"
15
+ transition={SPRING_LAYOUT}
16
+ data-slot="sidebar-menu-item"
17
+ className={cn("relative", className)}
18
+ />
19
+ )
20
+ })
@@ -0,0 +1,85 @@
1
+ import type * as React from "react"
2
+ import { motion } from "motion/react"
3
+ import { SPRING_PRESS } from "@/lib/ease"
4
+ import { cn } from "@/lib/utils"
5
+ import type { AnimatedSidebarMenuSubButtonProps } from "./type"
6
+ import { useAnimatedSidebar, useAnimatedSidebarPanel } from "./utils"
7
+
8
+ export function AnimatedSidebarMenuSubButton({
9
+ children,
10
+ icon,
11
+ href,
12
+ isActive = false,
13
+ disabled = false,
14
+ closeOnSelect = true,
15
+ target,
16
+ rel,
17
+ onSelect,
18
+ className,
19
+ }: AnimatedSidebarMenuSubButtonProps) {
20
+ const context = useAnimatedSidebar()
21
+ const panel = useAnimatedSidebarPanel()
22
+
23
+ const select = (
24
+ event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
25
+ ) => {
26
+ if (disabled) {
27
+ event.preventDefault()
28
+ return
29
+ }
30
+ onSelect?.()
31
+ if (context.isMobile && closeOnSelect) {
32
+ context.setOpenMobile(false, panel.side)
33
+ }
34
+ }
35
+
36
+ const content = (
37
+ <>
38
+ <span
39
+ aria-hidden="true"
40
+ className="grid size-4 shrink-0 place-items-center"
41
+ >
42
+ {icon ?? <span className="size-1 rounded-full bg-current" />}
43
+ </span>
44
+ <span className="min-w-0 flex-1 truncate">{children}</span>
45
+ </>
46
+ )
47
+
48
+ const interactiveClassName = cn(
49
+ "flex min-h-8 w-full min-w-0 items-center gap-2 rounded-lg px-2 text-left text-xs outline-none",
50
+ "text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground",
51
+ "focus-visible:bg-muted/70 focus-visible:ring-2 focus-visible:ring-ring",
52
+ isActive && "bg-muted/70 text-foreground",
53
+ disabled && "cursor-not-allowed opacity-40",
54
+ className
55
+ )
56
+
57
+ return href ? (
58
+ <motion.a
59
+ href={href}
60
+ target={target}
61
+ rel={rel ?? (target === "_blank" ? "noreferrer noopener" : undefined)}
62
+ aria-current={isActive ? "page" : undefined}
63
+ aria-disabled={disabled || undefined}
64
+ tabIndex={disabled ? -1 : undefined}
65
+ onClick={select}
66
+ whileTap={context.reduce || disabled ? undefined : { scale: 0.98 }}
67
+ transition={SPRING_PRESS}
68
+ className={interactiveClassName}
69
+ >
70
+ {content}
71
+ </motion.a>
72
+ ) : (
73
+ <motion.button
74
+ type="button"
75
+ disabled={disabled}
76
+ aria-current={isActive ? "page" : undefined}
77
+ onClick={select}
78
+ whileTap={context.reduce || disabled ? undefined : { scale: 0.98 }}
79
+ transition={SPRING_PRESS}
80
+ className={interactiveClassName}
81
+ >
82
+ {content}
83
+ </motion.button>
84
+ )
85
+ }
@@ -0,0 +1,19 @@
1
+ import { forwardRef } from "react"
2
+ import { motion, type HTMLMotionProps } from "motion/react"
3
+ import { cn } from "@/lib/utils"
4
+ import { SUBMENU_ITEM_VARIANTS } from "./utils"
5
+
6
+ export const AnimatedSidebarMenuSubItem = forwardRef<
7
+ HTMLLIElement,
8
+ HTMLMotionProps<"li">
9
+ >(function AnimatedSidebarMenuSubItem({ className, ...props }, forwardedRef) {
10
+ return (
11
+ <motion.li
12
+ {...props}
13
+ ref={forwardedRef}
14
+ variants={SUBMENU_ITEM_VARIANTS}
15
+ data-slot="sidebar-menu-sub-item"
16
+ className={cn("relative min-w-0", className)}
17
+ />
18
+ )
19
+ })
@@ -0,0 +1,44 @@
1
+ import { forwardRef } from "react"
2
+ import { AnimatePresence, motion } from "motion/react"
3
+ import { cn } from "@/lib/utils"
4
+ import type { AnimatedSidebarMenuSubProps } from "./type"
5
+ import {
6
+ SUBMENU_VARIANTS,
7
+ useAnimatedSidebar,
8
+ useAnimatedSidebarPanel,
9
+ } from "./utils"
10
+
11
+ export const AnimatedSidebarMenuSub = forwardRef<
12
+ HTMLUListElement,
13
+ AnimatedSidebarMenuSubProps
14
+ >(function AnimatedSidebarMenuSub(
15
+ { open, children, className, ...props },
16
+ forwardedRef
17
+ ) {
18
+ const context = useAnimatedSidebar()
19
+ const panel = useAnimatedSidebarPanel()
20
+
21
+ return (
22
+ <AnimatePresence initial={false} mode="popLayout">
23
+ {open && !panel.collapsed ? (
24
+ <motion.ul
25
+ {...props}
26
+ ref={forwardedRef}
27
+ key="sidebar-submenu"
28
+ variants={context.reduce ? undefined : SUBMENU_VARIANTS}
29
+ initial={context.reduce ? false : "closed"}
30
+ animate={context.reduce ? { opacity: 1 } : "open"}
31
+ exit={context.reduce ? { opacity: 0 } : "closed"}
32
+ transition={context.reduce ? { duration: 0.12 } : undefined}
33
+ data-slot="sidebar-menu-sub"
34
+ className={cn(
35
+ "relative mt-1 ml-5 flex min-w-0 flex-col gap-0.5 border-l border-border pl-3",
36
+ className
37
+ )}
38
+ >
39
+ {children}
40
+ </motion.ul>
41
+ ) : null}
42
+ </AnimatePresence>
43
+ )
44
+ })
@@ -0,0 +1,26 @@
1
+ import { forwardRef, type HTMLAttributes, type Ref } from "react"
2
+ import { SharedLayoutBg } from "@/components/motion/shared-layout-bg"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ export const AnimatedSidebarMenu = forwardRef<
6
+ HTMLUListElement,
7
+ HTMLAttributes<HTMLUListElement>
8
+ >(function AnimatedSidebarMenu(
9
+ { children, className, ...props },
10
+ forwardedRef
11
+ ) {
12
+ return (
13
+ <SharedLayoutBg
14
+ {...props}
15
+ ref={forwardedRef as Ref<HTMLElement>}
16
+ as="ul"
17
+ inset={0}
18
+ pillClassName="rounded-xl bg-muted/70"
19
+ pillContainerClassName="inset-y-auto top-0 h-9"
20
+ data-slot="sidebar-menu"
21
+ className={cn("flex w-full min-w-0 list-none flex-col gap-0.5", className)}
22
+ >
23
+ {children}
24
+ </SharedLayoutBg>
25
+ )
26
+ })
@@ -4,4 +4,22 @@ export type * from "./type"
4
4
  export * from "./use-shell-panels"
5
5
  export * from "./utils"
6
6
 
7
+ export * from "./animated-panel"
8
+ export * from "./animated-panel-inset"
9
+ export * from "./animated-panel-provider"
10
+ export * from "./animated-panel-trigger"
11
+
12
+ export * from "./animated-sidebar-header"
13
+ export * from "./animated-sidebar-content"
14
+ export * from "./animated-sidebar-footer"
15
+ export * from "./animated-sidebar-group"
16
+ export * from "./animated-sidebar-group-label"
17
+ export * from "./animated-sidebar-group-content"
18
+ export * from "./animated-sidebar-menu"
19
+ export * from "./animated-sidebar-menu-item"
20
+ export * from "./animated-sidebar-menu-sub"
21
+ export * from "./animated-sidebar-menu-sub-item"
22
+ export * from "./animated-sidebar-menu-sub-button"
23
+ export * from "./animated-sidebar-menu-button"
24
+
7
25
  export { ShellLayout as default }
@@ -4,15 +4,15 @@ import { MotionIcon } from "motion-icons-react"
4
4
  import * as React from "react"
5
5
 
6
6
  import {
7
- AnimatedSidebar,
8
- AnimatedSidebarInset,
9
- AnimatedSidebarProvider,
10
- AnimatedSidebarTrigger,
11
- } from "@/components/motion/animated-sidebar"
7
+ AnimatedPanel
8
+ } from "./animated-panel.tsx"
12
9
  import { cn } from "@/lib/utils"
13
10
  import type { ShellLayoutProps, ShellPanelControlProps } from "./type"
14
11
  import { TITLE_BAR_HEIGHT } from "./utils"
15
12
  import type { ClassNameValue } from "tailwind-merge"
13
+ import { AnimatedPanelProvider } from "./animated-panel-provider.tsx"
14
+ import { AnimatedPanelTrigger } from "./animated-panel-trigger.tsx"
15
+ import { AnimatedPanelInset } from "./animated-panel-inset.tsx"
16
16
 
17
17
  export function ShellLayout({
18
18
  children,
@@ -41,56 +41,56 @@ export function ShellLayout({
41
41
 
42
42
 
43
43
  return (
44
- <AnimatedSidebarProvider
44
+ <AnimatedPanelProvider
45
45
  {...panelControlProps}
46
46
  defaultOpen={initialOpen}
47
- className={cn(
48
- "relative block-full pr-2",
49
- className,
50
- background
51
- )}
47
+ className={cn("relative h-full min-h-0 pb-2", className, background)}
52
48
  style={{
53
49
  paddingTop: variant === "desktop" ? TITLE_BAR_HEIGHT : 0,
54
50
  }}
55
51
  >
56
- <AnimatedSidebar
52
+ <AnimatedPanel
57
53
  ariaLabel="Primary navigation"
58
54
  collapsible="icon"
59
55
  role="navigation"
60
56
  variant="inset"
61
57
  >
62
58
  {panels?.left?.component}
63
- </AnimatedSidebar>
59
+ </AnimatedPanel>
64
60
 
65
- <AnimatedSidebarInset className="min-w-24">
66
- <header className="flex h-12 items-center justify-between gap-2 px-2">
61
+ <AnimatedPanelInset className="min-w-24">
62
+ <header className="flex h-12 items-center justify-between gap-2 border-b px-2">
67
63
  <div className="flex min-w-0 items-center gap-2">
68
- <AnimatedSidebarTrigger>
64
+ <AnimatedPanelTrigger>
69
65
  {panels?.left?.trigger ?? (
70
66
  <MotionIcon name="PanelLeft" size={24} animation="press" />
71
67
  )}
72
- </AnimatedSidebarTrigger>
68
+ </AnimatedPanelTrigger>
73
69
  </div>
74
70
  {header && <div className="flex flex-1 items-center">{header}</div>}
75
71
  <div className="flex shrink-0 items-center gap-2">
76
- <AnimatedSidebarTrigger aria-label="Toggle panel" side="right">
72
+ <AnimatedPanelTrigger aria-label="Toggle panel" side="right">
77
73
  {panels?.right?.trigger ?? (
78
- <MotionIcon className="opacity-70" name="PanelRight" size={24} />
74
+ <MotionIcon
75
+ className="opacity-70"
76
+ name="PanelRight"
77
+ size={24}
78
+ />
79
79
  )}
80
- </AnimatedSidebarTrigger>
80
+ </AnimatedPanelTrigger>
81
81
  </div>
82
82
  </header>
83
- <div className="min-h-24 flex-1 overflow-auto">
84
- {children ?? <ShellLayoutPlaceholder />}
85
- </div>
86
- </AnimatedSidebarInset>
83
+ <div className="min-h-24 flex-1 overflow-auto">{children}</div>
84
+ </AnimatedPanelInset>
87
85
 
88
- <AnimatedSidebar
86
+ <AnimatedPanel
89
87
  ariaLabel={panels?.right?.name ?? "Secondary panel"}
90
88
  // Below md the panel is portal led over the page, so it carries the
91
89
  // surface itself; the desktop rail keeps it on the inner panel.
92
90
  className={cn(
93
- "max-md:border-l max-md:border-neutral-200 max-md:bg-white dark:max-md:border-neutral-700 dark:max-md:bg-card"
91
+ "mr-2 bg-neutral-50 dark:border-neutral-800 dark:bg-neutral-900",
92
+ "outline-offset-0.5 border-t-3 border-white outline-neutral-100 dark:inset-ring-black",
93
+ "rounded-lg shadow-md shadow-neutral-200 dark:shadow-neutral-950"
94
94
  )}
95
95
  collapsible="offcanvas"
96
96
  role="complementary"
@@ -98,15 +98,7 @@ export function ShellLayout({
98
98
  variant="inset"
99
99
  >
100
100
  {panels?.right?.component}
101
- </AnimatedSidebar>
102
- </AnimatedSidebarProvider>
103
- )
104
- }
105
-
106
- function ShellLayoutPlaceholder() {
107
- return (
108
- <div className="flex flex-col flex-1 p-4">
109
- <div className="h-96 border border-border bg-muted-foreground/10 rounded-lg" />
110
- </div>
101
+ </AnimatedPanel>
102
+ </AnimatedPanelProvider>
111
103
  )
112
104
  }
@@ -1,9 +1,11 @@
1
1
  import type { ReactNode } from "react"
2
2
 
3
- import type {
4
- AnimatedSidebarProviderProps,
5
- SidebarSide,
6
- } from "@/components/motion/animated-sidebar"
3
+ import {
4
+ type ButtonHTMLAttributes,
5
+ type CSSProperties,
6
+ type HTMLAttributes,
7
+ } from "react"
8
+ import type { HTMLMotionProps } from "motion/react"
7
9
 
8
10
  export interface ShellAction {
9
11
  id: string
@@ -47,7 +49,7 @@ export type TPanelMap<Side extends TPanelSide = TPanelSide> = Partial<
47
49
  >
48
50
 
49
51
  /** The open/close surface of the shell's panels, lifted straight from
50
- * AnimatedSidebarProvider — every prop is keyed by side, there are no
52
+ * AnimatedPanelProvider — every prop is keyed by side, there are no
51
53
  * explicit per-side props. `useShellPanels` produces the controlled subset
52
54
  * of these as `providerProps`. */
53
55
  export type ShellPanelControlProps = Pick<
@@ -82,7 +84,7 @@ export interface ShellPanelControls {
82
84
  /** Desktop-only convenience — the in-shell triggers already pick the
83
85
  * mobile state themselves when the viewport is narrow. */
84
86
  toggle: (side: SidebarSide) => void
85
- /** Spread onto ShellLayout (or AnimatedSidebarProvider directly). */
87
+ /** Spread onto ShellLayout (or AnimatedPanelProvider directly). */
86
88
  providerProps: ShellPanelControlProps
87
89
  }
88
90
 
@@ -95,3 +97,107 @@ export interface ShellLayoutProps extends ShellPanelControlProps {
95
97
  className?: string
96
98
  variant?: "web" | "desktop"
97
99
  }
100
+
101
+
102
+ export type SidebarSide = "left" | "right"
103
+ /** Open flags keyed by the side. Sides left out stay uncontrolled / at their
104
+ * default — there is no per-side prop, the record IS the API. */
105
+ export type SidebarOpenState = Partial<Record<SidebarSide, boolean>>
106
+ export type SidebarVariant = "sidebar" | "floating" | "inset"
107
+ export type SidebarCollapsible = "offcanvas" | "icon" | "none"
108
+
109
+ export interface AnimatedSidebarContextValue {
110
+ isMobile: boolean
111
+ layoutId: string
112
+ /** Desktop open state, keyed by side. */
113
+ open: Record<SidebarSide, boolean>
114
+ /** Mobile overlay open state, keyed by side. */
115
+ openMobile: Record<SidebarSide, boolean>
116
+ reduce: boolean
117
+ setOpen: (open: boolean, side: SidebarSide) => void
118
+ setOpenMobile: (open: boolean, side: SidebarSide) => void
119
+ /** Mobile-aware: toggles the overlay below md, the docked panel above. */
120
+ toggleSidebar: (side: SidebarSide) => void
121
+ triggerRefs: Record<SidebarSide, React.RefObject<HTMLButtonElement | null>>
122
+ }
123
+
124
+ export interface AnimatedSidebarProviderProps extends HTMLAttributes<HTMLDivElement> {
125
+ /** Controlled desktop open state, keyed by the side. A side left undefined
126
+ * stays uncontrolled. */
127
+ open?: SidebarOpenState
128
+ /** Initial desktop open state, merged over `{ left: true, right: false }`. */
129
+ defaultOpen?: SidebarOpenState
130
+ onOpenChange?: (open: boolean, side: SidebarSide) => void
131
+ /** Controlled mobile overlay state, keyed by side. */
132
+ openMobile?: SidebarOpenState
133
+ /** Initial mobile overlay state — every side starts closed. */
134
+ defaultOpenMobile?: SidebarOpenState
135
+ onOpenMobileChange?: (open: boolean, side: SidebarSide) => void
136
+ style?: SidebarProviderStyle
137
+ }
138
+
139
+ export type SidebarProviderStyle = CSSProperties & {
140
+ "--sidebar-width"?: string
141
+ "--sidebar-width-icon"?: string
142
+ "--sidebar-width-mobile"?: string
143
+ }
144
+
145
+ export type AnimatedSidebarInsetProps = HTMLMotionProps<"main">
146
+
147
+ export interface AnimatedSidebarTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
148
+ side?: SidebarSide
149
+ }
150
+
151
+ export interface AnimatedSidebarPanelContextValue {
152
+ collapsed: boolean
153
+ collapsible: SidebarCollapsible
154
+ side: SidebarSide
155
+ }
156
+
157
+ export interface AnimatedSidebarProps extends Omit<
158
+ HTMLMotionProps<"aside">,
159
+ "children"
160
+ > {
161
+ children?: ReactNode
162
+ side?: SidebarSide
163
+ variant?: SidebarVariant
164
+ collapsible?: SidebarCollapsible
165
+ ariaLabel?: string
166
+ panelClassName?: string
167
+ }
168
+
169
+ export interface AnimatedSidebarMenuSubProps extends Omit<
170
+ HTMLMotionProps<"ul">,
171
+ "children"
172
+ > {
173
+ open: boolean
174
+ children?: ReactNode
175
+ }
176
+
177
+ export interface AnimatedSidebarMenuSubButtonProps {
178
+ children: ReactNode
179
+ icon?: ReactNode
180
+ href?: string
181
+ isActive?: boolean
182
+ disabled?: boolean
183
+ closeOnSelect?: boolean
184
+ target?: "_blank" | "_self" | "_parent" | "_top"
185
+ rel?: string
186
+ onSelect?: () => void
187
+ className?: string
188
+ }
189
+
190
+ export interface AnimatedSidebarMenuButtonProps {
191
+ children: ReactNode
192
+ icon?: ReactNode
193
+ badge?: ReactNode
194
+ href?: string
195
+ isActive?: boolean
196
+ ariaExpanded?: boolean
197
+ disabled?: boolean
198
+ closeOnSelect?: boolean
199
+ target?: "_blank" | "_self" | "_parent" | "_top"
200
+ rel?: string
201
+ onSelect?: () => void
202
+ className?: string
203
+ }
@@ -2,10 +2,10 @@
2
2
 
3
3
  import { useCallback, useMemo, useState } from "react"
4
4
 
5
- import type { SidebarSide } from "@/components/motion/animated-sidebar"
6
5
  import type {
7
6
  ShellPanelControlProps,
8
7
  ShellPanelControls,
8
+ SidebarSide,
9
9
  UseShellPanelsOptions,
10
10
  } from "./type"
11
11