tembro 4.0.1 → 4.1.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 (61) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/components/display/chat.cjs +1 -0
  3. package/dist/components/display/chat.d.ts +94 -0
  4. package/dist/components/display/chat.js +1 -0
  5. package/dist/components/display/index.d.ts +1 -0
  6. package/dist/components/display/kanban.d.ts +33 -1
  7. package/dist/components/layout/sidebar.d.ts +24 -2
  8. package/dist/components/modern/rich-text-editor.d.ts +13 -1
  9. package/dist/components/theme-provider.d.ts +19 -6
  10. package/dist/components/ui/badge/index.d.ts +8 -2
  11. package/dist/src/components/display/activity-feed.cjs +1 -1
  12. package/dist/src/components/display/activity-feed.js +4 -1
  13. package/dist/src/components/display/chat.cjs +1 -0
  14. package/dist/src/components/display/chat.js +372 -0
  15. package/dist/src/components/display/index.cjs +1 -1
  16. package/dist/src/components/display/index.js +17 -16
  17. package/dist/src/components/display/kanban.cjs +1 -1
  18. package/dist/src/components/display/kanban.js +321 -176
  19. package/dist/src/components/display/timeline.cjs +1 -1
  20. package/dist/src/components/display/timeline.js +5 -5
  21. package/dist/src/components/inputs/tag-input.cjs +1 -1
  22. package/dist/src/components/inputs/tag-input.js +6 -2
  23. package/dist/src/components/layout/index.cjs +1 -1
  24. package/dist/src/components/layout/index.js +4 -4
  25. package/dist/src/components/layout/public.cjs +1 -1
  26. package/dist/src/components/layout/public.js +4 -4
  27. package/dist/src/components/layout/sidebar.cjs +1 -1
  28. package/dist/src/components/layout/sidebar.js +326 -228
  29. package/dist/src/components/modern/rich-text-editor.cjs +1 -1
  30. package/dist/src/components/modern/rich-text-editor.js +216 -89
  31. package/dist/src/components/theme-provider.cjs +1 -1
  32. package/dist/src/components/theme-provider.js +58 -36
  33. package/dist/src/components/ui/badge/index.cjs +1 -1
  34. package/dist/src/components/ui/badge/index.js +59 -47
  35. package/dist/src/components/ui/input/clearable.cjs +1 -1
  36. package/dist/src/components/ui/input/clearable.js +5 -2
  37. package/dist/src/components/ui/input/primitive.cjs +1 -1
  38. package/dist/src/components/ui/input/primitive.js +1 -1
  39. package/dist/src/index.cjs +1 -1
  40. package/dist/src/index.js +87 -86
  41. package/dist/src/public-component-surface.cjs +1 -1
  42. package/dist/src/public-component-surface.js +5 -0
  43. package/package.json +1 -1
  44. package/packages/cli/dist/index.cjs +3 -3
  45. package/packages/cli/vendor/src/components/display/activity-feed.tsx +1 -1
  46. package/packages/cli/vendor/src/components/display/chat.tsx +237 -0
  47. package/packages/cli/vendor/src/components/display/index.ts +1 -0
  48. package/packages/cli/vendor/src/components/display/kanban.tsx +219 -72
  49. package/packages/cli/vendor/src/components/display/timeline.tsx +10 -10
  50. package/packages/cli/vendor/src/components/inputs/tag-input.tsx +3 -2
  51. package/packages/cli/vendor/src/components/layout/sidebar.tsx +212 -51
  52. package/packages/cli/vendor/src/components/modern/rich-text-editor.tsx +115 -32
  53. package/packages/cli/vendor/src/components/theme-provider.tsx +82 -36
  54. package/packages/cli/vendor/src/components/ui/badge/index.tsx +29 -8
  55. package/packages/cli/vendor/src/components/ui/input/clearable.tsx +2 -2
  56. package/packages/cli/vendor/src/components/ui/input/primitive.tsx +1 -1
  57. package/packages/cli/vendor/src/public-component-surface.ts +1 -0
  58. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +2 -2
  59. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +1 -1
  60. package/packages/cli/vendor/templates/styles/globals.css +91 -10
  61. package/registry.json +3 -1
@@ -1,9 +1,10 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from "react"
4
- import { ChevronRightIcon, MenuIcon, XIcon } from "lucide-react"
4
+ import { ChevronRightIcon, MenuIcon, SearchIcon, XIcon } from "lucide-react"
5
5
 
6
6
  import { useIsMobile } from "@/hooks/use-is-mobile"
7
+ import { Input } from "@/components/ui/input"
7
8
  import { Tooltip } from "@/components/ui/tooltip"
8
9
  import { cn } from "@/lib/utils"
9
10
  import { ControllableDetails } from "./controllable-details"
@@ -24,9 +25,22 @@ export type SidebarItem = {
24
25
  expanded?: boolean
25
26
  onExpandedChange?: (expanded: boolean) => void
26
27
  current?: React.AriaAttributes["aria-current"]
27
- tooltip?: React.ReactNode
28
- onSelect?: () => void
29
- }
28
+ tooltip?: React.ReactNode
29
+ onSelect?: () => void
30
+ keywords?: string[]
31
+ action?: React.ReactNode
32
+ actionLabel?: string
33
+ onAction?: () => void
34
+ }
35
+
36
+ export type SidebarSearch = {
37
+ value?: string
38
+ defaultValue?: string
39
+ placeholder?: string
40
+ label?: string
41
+ onValueChange?: (value: string) => void
42
+ empty?: React.ReactNode
43
+ }
30
44
 
31
45
  export type SidebarFooterAccount = {
32
46
  label: React.ReactNode
@@ -41,7 +55,12 @@ export type SidebarProps = React.ComponentProps<"aside"> & {
41
55
  header?: React.ReactNode
42
56
  footer?: React.ReactNode
43
57
  items?: SidebarItem[]
44
- collapsed?: boolean
58
+ collapsed?: boolean
59
+ defaultCollapsed?: boolean
60
+ onCollapsedChange?: (collapsed: boolean) => void
61
+ variant?: "sidebar" | "floating" | "inset"
62
+ side?: "left" | "right"
63
+ collapsible?: "icon" | "offcanvas" | "none"
45
64
  width?: React.CSSProperties["width"]
46
65
  collapsedWidth?: React.CSSProperties["width"]
47
66
  mobileWidth?: React.CSSProperties["width"]
@@ -55,6 +74,10 @@ export type SidebarProps = React.ComponentProps<"aside"> & {
55
74
  itemSize?: "sm" | "md" | "lg"
56
75
  activeIndicator?: "none" | "bar" | "pill"
57
76
  navigationLabel?: string
77
+ search?: SidebarSearch | React.ReactNode
78
+ hideScrollbar?: boolean
79
+ keyboardShortcut?: string | false
80
+ persistKey?: string
58
81
  responsive?: boolean
59
82
  mobileBreakpoint?: number
60
83
  mobileOpen?: boolean
@@ -154,7 +177,8 @@ function SidebarLeafItem({
154
177
  renderLink?: SidebarProps["renderLink"]
155
178
  }) {
156
179
  const currentValue: React.AriaAttributes["aria-current"] = item.current ?? (item.active ? "page" : undefined)
157
- const commonProps = {
180
+ const commonProps = {
181
+ "aria-label": collapsed && typeof item.label === "string" ? item.label : undefined,
158
182
  "aria-current": currentValue,
159
183
  "aria-disabled": item.disabled || undefined,
160
184
  "data-slot": "sidebar-item" as const,
@@ -164,7 +188,7 @@ function SidebarLeafItem({
164
188
  "data-size": itemSize,
165
189
  "data-active-indicator": activeIndicator,
166
190
  className: cn(
167
- "flex items-center gap-2 border border-transparent font-medium outline-none transition-[background-color,border-color,color,box-shadow] data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
191
+ "flex min-w-0 flex-1 items-center gap-2 border border-transparent text-left font-medium outline-none transition-[background-color,border-color,color,box-shadow] data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
168
192
  getSidebarInteractiveClassName({ active: item.active, disabled: item.disabled }),
169
193
  getSidebarItemLayoutClassName({ collapsed, depth, itemSize, activeIndicator })
170
194
  ),
@@ -178,19 +202,41 @@ function SidebarLeafItem({
178
202
  </>
179
203
  )
180
204
 
181
- const wrapCollapsedContent = (node: React.ReactNode) =>
205
+ const wrapCollapsedContent = (node: React.ReactNode) =>
182
206
  collapsed ? (
183
207
  <Tooltip content={item.tooltip ?? item.label} side="right">
184
208
  <span className="block">{node}</span>
185
209
  </Tooltip>
186
210
  ) : (
187
- node
188
- )
211
+ node
212
+ )
213
+
214
+ const wrapItemAction = (node: React.ReactNode) => {
215
+ if (collapsed || !item.action) return node
216
+ return (
217
+ <div data-slot="sidebar-item-row" className="group/sidebar-item-row flex min-w-0 items-center gap-1">
218
+ {node}
219
+ <button
220
+ type="button"
221
+ data-slot="sidebar-item-action"
222
+ aria-label={item.actionLabel ?? `Actions for ${String(item.label)}`}
223
+ className="grid size-8 shrink-0 place-items-center rounded-md p-0 leading-none text-muted-foreground opacity-0 outline-none transition hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-sidebar-ring group-hover/sidebar-item-row:opacity-100"
224
+ onClick={(event) => {
225
+ event.preventDefault()
226
+ event.stopPropagation()
227
+ item.onAction?.()
228
+ }}
229
+ >
230
+ {item.action}
231
+ </button>
232
+ </div>
233
+ )
234
+ }
189
235
 
190
236
  if (item.href?.startsWith("/")) {
191
237
  if (renderLink) {
192
- return wrapCollapsedContent(
193
- <>
238
+ return wrapCollapsedContent(wrapItemAction(
239
+ <>
194
240
  {renderLink({
195
241
  item,
196
242
  href: item.href,
@@ -204,12 +250,12 @@ function SidebarLeafItem({
204
250
  },
205
251
  children: content,
206
252
  })}
207
- </>
208
- )
253
+ </>
254
+ ))
209
255
  }
210
256
 
211
- return wrapCollapsedContent(
212
- <a
257
+ return wrapCollapsedContent(wrapItemAction(
258
+ <a
213
259
  href={item.href}
214
260
  {...commonProps}
215
261
  onClick={(event) => {
@@ -221,13 +267,13 @@ function SidebarLeafItem({
221
267
  }}
222
268
  >
223
269
  {content}
224
- </a>
225
- )
270
+ </a>
271
+ ))
226
272
  }
227
273
 
228
274
  if (item.href) {
229
- return wrapCollapsedContent(
230
- <button
275
+ return wrapCollapsedContent(wrapItemAction(
276
+ <button
231
277
  type="button"
232
278
  {...commonProps}
233
279
  className={cn(commonProps.className, "w-full")}
@@ -244,12 +290,12 @@ function SidebarLeafItem({
244
290
  }}
245
291
  >
246
292
  {content}
247
- </button>
248
- )
293
+ </button>
294
+ ))
249
295
  }
250
296
 
251
- return wrapCollapsedContent(
252
- <button
297
+ return wrapCollapsedContent(wrapItemAction(
298
+ <button
253
299
  type="button"
254
300
  disabled={item.disabled}
255
301
  {...commonProps}
@@ -259,8 +305,8 @@ function SidebarLeafItem({
259
305
  }}
260
306
  >
261
307
  {content}
262
- </button>
263
- )
308
+ </button>
309
+ ))
264
310
  }
265
311
 
266
312
  function SidebarTree({
@@ -333,12 +379,13 @@ function SidebarTree({
333
379
  onOpenChange={item.onExpandedChange}
334
380
  >
335
381
  <summary
382
+ aria-label={collapsed && typeof item.label === "string" ? item.label : undefined}
336
383
  data-slot="sidebar-group-trigger"
337
384
  data-size={itemSize}
338
385
  data-active={active || undefined}
339
386
  data-active-indicator={activeIndicator}
340
387
  className={cn(
341
- "flex list-none items-center gap-2 border border-transparent font-medium outline-none transition-[background-color,border-color,color,box-shadow]",
388
+ "flex list-none items-center gap-2 border border-transparent text-left font-medium outline-none transition-[background-color,border-color,color,box-shadow]",
342
389
  getSidebarInteractiveClassName({ active }),
343
390
  getSidebarItemLayoutClassName({ collapsed, depth, itemSize, activeIndicator })
344
391
  )}
@@ -379,6 +426,22 @@ function SidebarTree({
379
426
  })
380
427
  }
381
428
 
429
+ function filterSidebarItems(items: SidebarItem[], query: string): SidebarItem[] {
430
+ const normalized = query.trim().toLocaleLowerCase()
431
+ if (!normalized) return items
432
+
433
+ return items.flatMap((item) => {
434
+ const children = item.items ? filterSidebarItems(item.items, normalized) : []
435
+ const label = typeof item.label === "string" ? item.label : ""
436
+ const haystack = [label, item.sectionLabel, ...(item.keywords ?? [])]
437
+ .filter((value): value is string => typeof value === "string")
438
+ .join(" ")
439
+ .toLocaleLowerCase()
440
+ if (!haystack.includes(normalized) && children.length === 0) return []
441
+ return [{ ...item, items: children.length ? children : item.items, defaultExpanded: children.length ? true : item.defaultExpanded }]
442
+ })
443
+ }
444
+
382
445
  function SidebarActionButton({
383
446
  item,
384
447
  collapsed,
@@ -481,7 +544,7 @@ function SidebarFooterAccount({
481
544
  )
482
545
  }
483
546
 
484
- function SidebarSurface({
547
+ function SidebarSurface({
485
548
  className,
486
549
  style,
487
550
  header,
@@ -501,6 +564,11 @@ function SidebarSurface({
501
564
  itemSize = "md",
502
565
  activeIndicator = "bar",
503
566
  navigationLabel = "Primary navigation",
567
+ search,
568
+ hideScrollbar = true,
569
+ variant = "sidebar",
570
+ side = "left",
571
+ collapsible = "icon",
504
572
  onItemSelect,
505
573
  renderItem,
506
574
  renderLink,
@@ -515,8 +583,11 @@ function SidebarSurface({
515
583
  }: Omit<SidebarProps, "responsive" | "mobileBreakpoint" | "mobileOpen" | "defaultMobileOpen" | "onMobileOpenChange" | "mobileToggleLabel" | "mobileToggleIcon" | "showMobileToggle" | "mobileToggleClassName" | "mobilePanelClassName" | "mobileOverlayClassName" | "renderMobileToggle"> & {
516
584
  mobile?: boolean
517
585
  onRequestClose?: () => void
518
- }) {
519
- const visibleItems = items.filter((item) => !item.hidden)
586
+ }) {
587
+ const searchConfig = search && !React.isValidElement(search) && typeof search === "object" ? search as SidebarSearch : undefined
588
+ const [internalSearch, setInternalSearch] = React.useState(searchConfig?.defaultValue ?? "")
589
+ const searchValue = searchConfig?.value ?? internalSearch
590
+ const visibleItems = filterSidebarItems(items.filter((item) => !item.hidden), searchValue)
520
591
  const visibleRailItems = railItems.filter((item) => !item.hidden)
521
592
  const visibleSecondaryActions = secondaryActions.filter((item) => !item.hidden)
522
593
 
@@ -528,14 +599,25 @@ function SidebarSurface({
528
599
  const showMobileHeader = mobile && (mobileTitle || mobileDescription || onRequestClose)
529
600
 
530
601
  return (
531
- <aside
602
+ <aside
532
603
  data-slot="sidebar"
533
- data-collapsed={collapsed || undefined}
534
- data-mobile={mobile || undefined}
535
- className={cn("group/sidebar flex h-full min-h-0 flex-col overflow-hidden", className)}
536
- style={{
537
- width: collapsed ? collapsedWidth : width,
538
- minWidth: collapsed ? collapsedWidth : width,
604
+ data-collapsed={collapsed || undefined}
605
+ data-mobile={mobile || undefined}
606
+ data-variant={variant}
607
+ data-side={side}
608
+ data-collapsible={collapsible}
609
+ className={cn(
610
+ "peer group/sidebar flex h-full min-h-0 flex-col overflow-hidden bg-sidebar text-sidebar-foreground transition-[width,min-width,transform,border-radius,box-shadow] duration-200",
611
+ side === "right" && "border-l border-r-0",
612
+ !mobile && variant === "floating" && "m-2 h-[calc(100%-1rem)] rounded-xl border shadow-lg",
613
+ !mobile && variant === "inset" && "m-2 h-[calc(100%-1rem)] rounded-lg border bg-sidebar/92 shadow-sm",
614
+ mobile && "m-0 h-full rounded-none border-y-0",
615
+ collapsible === "offcanvas" && collapsed && (side === "left" ? "-translate-x-full" : "translate-x-full"),
616
+ className
617
+ )}
618
+ style={{
619
+ width: collapsed ? (collapsible === "icon" ? collapsedWidth : collapsible === "offcanvas" ? 0 : width) : width,
620
+ minWidth: collapsed ? (collapsible === "icon" ? collapsedWidth : collapsible === "offcanvas" ? 0 : width) : width,
539
621
  ...style,
540
622
  }}
541
623
  {...props}
@@ -569,12 +651,34 @@ function SidebarSurface({
569
651
  ) : null}
570
652
  </div>
571
653
  </div>
572
- )}
573
-
654
+ )}
655
+
656
+ {search && !collapsed ? (
657
+ <div data-slot="sidebar-search" className="shrink-0 px-2 pt-2">
658
+ {React.isValidElement(search) ? search : (
659
+ <Input
660
+ kind="search"
661
+ value={searchValue}
662
+ onValueChange={(nextValue) => {
663
+ if (searchConfig?.value === undefined) setInternalSearch(nextValue)
664
+ searchConfig?.onValueChange?.(nextValue)
665
+ }}
666
+ placeholder={searchConfig?.placeholder ?? "Search navigation..."}
667
+ searchIcon={<SearchIcon />}
668
+ aria-label={searchConfig?.label ?? "Search navigation"}
669
+ className="h-9 bg-sidebar-accent/45"
670
+ />
671
+ )}
672
+ </div>
673
+ ) : null}
674
+
574
675
  <nav
575
676
  data-slot="sidebar-nav"
576
677
  aria-label={navigationLabel}
577
- className="flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto overscroll-contain p-2"
678
+ className={cn(
679
+ "flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto overscroll-contain p-2 [scrollbar-gutter:stable]",
680
+ hideScrollbar && "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
681
+ )}
578
682
  >
579
683
  {children ??
580
684
  visibleItems.map((item) => {
@@ -591,7 +695,7 @@ function SidebarSurface({
591
695
  </Tooltip>
592
696
  )
593
697
  })}
594
- {!children && !renderItem && (
698
+ {!children && !renderItem && (
595
699
  <SidebarTree
596
700
  items={visibleItems}
597
701
  collapsed={collapsed}
@@ -602,7 +706,12 @@ function SidebarSurface({
602
706
  onItemSelect={handleSelect}
603
707
  renderLink={renderLink}
604
708
  />
605
- )}
709
+ )}
710
+ {!children && visibleItems.length === 0 ? (
711
+ <div data-slot="sidebar-search-empty" className="grid min-h-24 place-items-center px-4 text-center text-xs text-muted-foreground">
712
+ {searchConfig?.empty ?? "No navigation items found."}
713
+ </div>
714
+ ) : null}
606
715
  </nav>
607
716
 
608
717
  {(footerAccount || footerSecondary || footer || visibleSecondaryActions.length > 0 || (collapsed && (collapsedRail || visibleRailItems.length > 0))) && (
@@ -670,8 +779,13 @@ function Sidebar({
670
779
  className,
671
780
  header,
672
781
  footer,
673
- items = [],
782
+ items = [],
674
783
  collapsed: collapsedProp,
784
+ defaultCollapsed = false,
785
+ onCollapsedChange,
786
+ variant = "sidebar",
787
+ side = "left",
788
+ collapsible = "icon",
675
789
  width = DEFAULT_SIDEBAR_WIDTH,
676
790
  collapsedWidth = DEFAULT_COLLAPSED_SIDEBAR_WIDTH,
677
791
  mobileWidth = DEFAULT_MOBILE_SIDEBAR_WIDTH,
@@ -685,6 +799,10 @@ function Sidebar({
685
799
  itemSize = "md",
686
800
  activeIndicator = "bar",
687
801
  navigationLabel = "Primary navigation",
802
+ search,
803
+ hideScrollbar = true,
804
+ keyboardShortcut = "b",
805
+ persistKey,
688
806
  responsive = true,
689
807
  mobileBreakpoint = DEFAULT_SIDEBAR_BREAKPOINT,
690
808
  mobileOpen: mobileOpenProp,
@@ -708,11 +826,38 @@ function Sidebar({
708
826
  ...props
709
827
  }: SidebarProps) {
710
828
  const sidebarContext = useSidebar(true)
711
- const collapsed = collapsedProp ?? sidebarContext?.collapsed ?? false
829
+ const [internalCollapsed, setInternalCollapsed] = React.useState(defaultCollapsed)
830
+ const collapsed = collapsible === "none" ? false : collapsedProp ?? sidebarContext?.collapsed ?? internalCollapsed
712
831
  const matchesMobileBreakpoint = useIsMobile(mobileBreakpoint)
713
832
  const isMobile = responsive && matchesMobileBreakpoint
714
833
  const [uncontrolledMobileOpen, setUncontrolledMobileOpen] = React.useState(defaultMobileOpen)
715
834
  const mobileOpen = mobileOpenProp ?? sidebarContext?.mobileOpen ?? uncontrolledMobileOpen
835
+
836
+ const setCollapsed = React.useCallback((nextCollapsed: boolean) => {
837
+ if (collapsible === "none") return
838
+ if (collapsedProp === undefined && sidebarContext) sidebarContext.setCollapsed(nextCollapsed)
839
+ else if (collapsedProp === undefined) setInternalCollapsed(nextCollapsed)
840
+ onCollapsedChange?.(nextCollapsed)
841
+ if (persistKey) window.localStorage.setItem(persistKey, String(nextCollapsed))
842
+ }, [collapsedProp, collapsible, onCollapsedChange, persistKey, sidebarContext])
843
+
844
+ React.useEffect(() => {
845
+ if (!persistKey || collapsedProp !== undefined) return
846
+ const stored = window.localStorage.getItem(persistKey)
847
+ if (stored === "true" || stored === "false") setCollapsed(stored === "true")
848
+ }, [collapsedProp, persistKey, setCollapsed])
849
+
850
+ React.useEffect(() => {
851
+ if (!keyboardShortcut || collapsible === "none") return
852
+ const handleShortcut = (event: KeyboardEvent) => {
853
+ if ((event.metaKey || event.ctrlKey) && event.key.toLocaleLowerCase() === keyboardShortcut.toLocaleLowerCase()) {
854
+ event.preventDefault()
855
+ setCollapsed(!collapsed)
856
+ }
857
+ }
858
+ window.addEventListener("keydown", handleShortcut)
859
+ return () => window.removeEventListener("keydown", handleShortcut)
860
+ }, [collapsed, collapsible, keyboardShortcut, setCollapsed])
716
861
 
717
862
  const setMobileOpen = React.useCallback((nextOpen: boolean) => {
718
863
  if (mobileOpenProp == null && sidebarContext) {
@@ -766,6 +911,11 @@ function Sidebar({
766
911
  itemSize,
767
912
  activeIndicator,
768
913
  navigationLabel,
914
+ search,
915
+ hideScrollbar,
916
+ variant,
917
+ side,
918
+ collapsible,
769
919
  mobileCloseLabel,
770
920
  closeOnSelect,
771
921
  onItemSelect,
@@ -833,21 +983,32 @@ function Sidebar({
833
983
  role="dialog"
834
984
  aria-modal="true"
835
985
  aria-label={typeof mobileTitle === "string" ? mobileTitle : "Navigation"}
836
- className={cn(
837
- "fixed inset-y-0 left-0 z-50 max-w-[22rem] border-r border-[color:var(--aui-divider,var(--border))] bg-[color:var(--aui-page-bg,var(--background))] shadow-2xl transition-transform duration-200 ease-out",
838
- mobileOpen ? "translate-x-0" : "-translate-x-full",
986
+ className={cn(
987
+ "fixed inset-y-0 z-50 max-w-[22rem] border-[color:var(--aui-divider,var(--border))] bg-[color:var(--aui-page-bg,var(--background))] shadow-2xl transition-transform duration-200 ease-out",
988
+ side === "left" ? "left-0 border-r" : "right-0 border-l",
989
+ mobileOpen ? "translate-x-0" : side === "left" ? "-translate-x-full" : "translate-x-full",
839
990
  mobilePanelClassName,
840
991
  className
841
992
  )}
842
993
  style={{
843
994
  width: mobileWidth,
844
995
  minWidth: mobileWidth,
845
- translate: mobileOpen ? "0 0" : "-100% 0",
996
+ translate: mobileOpen ? "0 0" : side === "left" ? "-100% 0" : "100% 0",
846
997
  }}
847
998
  />
848
999
  </div>
849
1000
  </>
850
1001
  )
851
- }
852
-
853
- export { Sidebar }
1002
+ }
1003
+
1004
+ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
1005
+ return (
1006
+ <main
1007
+ data-slot="sidebar-inset"
1008
+ className={cn("relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:border md:peer-data-[variant=inset]:shadow-sm", className)}
1009
+ {...props}
1010
+ />
1011
+ )
1012
+ }
1013
+
1014
+ export { Sidebar, SidebarInset }