tembro 4.2.1 → 6.0.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 (177) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/components/charts/progress-circle.d.ts +12 -3
  3. package/dist/components/data-table/data-table.d.ts +2 -2
  4. package/dist/components/feedback/index.d.ts +0 -2
  5. package/dist/components/layout/section.d.ts +1 -8
  6. package/dist/components/patterns/index.d.ts +0 -8
  7. package/dist/components/patterns/public.d.ts +0 -8
  8. package/dist/components/ui/hover-card/index.cjs +1 -0
  9. package/dist/components/ui/hover-card/index.d.ts +11 -0
  10. package/dist/components/ui/hover-card/index.js +1 -0
  11. package/dist/components/ui/menubar/index.cjs +1 -0
  12. package/dist/components/ui/menubar/index.d.ts +42 -0
  13. package/dist/components/ui/menubar/index.js +1 -0
  14. package/dist/components/ui/navigation-menu/index.cjs +1 -0
  15. package/dist/components/ui/navigation-menu/index.d.ts +20 -0
  16. package/dist/components/ui/navigation-menu/index.js +1 -0
  17. package/dist/components/ui/number-field/index.cjs +1 -0
  18. package/dist/components/ui/number-field/index.d.ts +18 -0
  19. package/dist/components/ui/number-field/index.js +1 -0
  20. package/dist/components/ui/toggle-group/index.cjs +1 -0
  21. package/dist/components/ui/toggle-group/index.d.ts +13 -0
  22. package/dist/components/ui/toggle-group/index.js +1 -0
  23. package/dist/components/ui/toolbar/index.cjs +1 -0
  24. package/dist/components/ui/toolbar/index.d.ts +14 -0
  25. package/dist/components/ui/toolbar/index.js +1 -0
  26. package/dist/index.d.ts +7 -0
  27. package/dist/src/components/charts/progress-circle.cjs +1 -1
  28. package/dist/src/components/charts/progress-circle.js +57 -3
  29. package/dist/src/components/data-table/data-table.cjs +1 -1
  30. package/dist/src/components/data-table/data-table.js +102 -100
  31. package/dist/src/components/feedback/index.cjs +1 -1
  32. package/dist/src/components/feedback/index.js +2 -4
  33. package/dist/src/components/layout/index.cjs +1 -1
  34. package/dist/src/components/layout/index.js +3 -3
  35. package/dist/src/components/layout/public.cjs +1 -1
  36. package/dist/src/components/layout/public.js +3 -3
  37. package/dist/src/components/layout/section.cjs +1 -1
  38. package/dist/src/components/layout/section.js +2 -26
  39. package/dist/src/components/patterns/index.cjs +1 -1
  40. package/dist/src/components/patterns/index.js +2 -10
  41. package/dist/src/components/patterns/public.cjs +1 -1
  42. package/dist/src/components/patterns/public.js +2 -10
  43. package/dist/src/components/ui/hover-card/index.cjs +1 -0
  44. package/dist/src/components/ui/hover-card/index.js +50 -0
  45. package/dist/src/components/ui/menubar/index.cjs +1 -0
  46. package/dist/src/components/ui/menubar/index.js +132 -0
  47. package/dist/src/components/ui/navigation-menu/index.cjs +1 -0
  48. package/dist/src/components/ui/navigation-menu/index.js +73 -0
  49. package/dist/src/components/ui/number-field/index.cjs +1 -0
  50. package/dist/src/components/ui/number-field/index.js +73 -0
  51. package/dist/src/components/ui/toggle-group/index.cjs +1 -0
  52. package/dist/src/components/ui/toggle-group/index.js +32 -0
  53. package/dist/src/components/ui/toolbar/index.cjs +1 -0
  54. package/dist/src/components/ui/toolbar/index.js +50 -0
  55. package/dist/src/index.cjs +1 -1
  56. package/dist/src/index.js +92 -95
  57. package/dist/src/public-component-surface.cjs +1 -1
  58. package/dist/src/public-component-surface.js +31 -42
  59. package/package.json +1 -1
  60. package/packages/cli/dist/index.cjs +112 -112
  61. package/packages/cli/vendor/src/components/charts/progress-circle.tsx +78 -3
  62. package/packages/cli/vendor/src/components/data-table/data-table.tsx +4 -4
  63. package/packages/cli/vendor/src/components/feedback/index.ts +0 -2
  64. package/packages/cli/vendor/src/components/layout/section.tsx +1 -28
  65. package/packages/cli/vendor/src/components/patterns/index.ts +0 -8
  66. package/packages/cli/vendor/src/components/patterns/public.ts +0 -8
  67. package/packages/cli/vendor/src/components/ui/hover-card/index.tsx +72 -0
  68. package/packages/cli/vendor/src/components/ui/menubar/index.tsx +140 -0
  69. package/packages/cli/vendor/src/components/ui/navigation-menu/index.tsx +100 -0
  70. package/packages/cli/vendor/src/components/ui/number-field/index.tsx +89 -0
  71. package/packages/cli/vendor/src/components/ui/toggle-group/index.tsx +72 -0
  72. package/packages/cli/vendor/src/components/ui/toolbar/index.tsx +67 -0
  73. package/packages/cli/vendor/src/index.ts +12 -5
  74. package/packages/cli/vendor/src/public-component-surface.ts +7 -10
  75. package/packages/cli/vendor/templates/showcase/src/showcase/data/registry.ts +14 -12
  76. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +2 -2
  77. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +1 -1
  78. package/packages/cli/vendor/templates/showcase/src/showcase/sections/ComponentLivePreview.tsx +2 -2
  79. package/packages/cli/vendor/templates/showcase/src/showcase/sections/FormsSection.tsx +2 -2
  80. package/packages/cli/vendor/templates/styles/globals.css +5 -5
  81. package/registry.json +2630 -233
  82. package/dist/components/charts/progress-ring.cjs +0 -1
  83. package/dist/components/charts/progress-ring.d.ts +0 -13
  84. package/dist/components/charts/progress-ring.js +0 -1
  85. package/dist/components/feedback/loading-state.cjs +0 -1
  86. package/dist/components/feedback/loading-state.d.ts +0 -9
  87. package/dist/components/feedback/loading-state.js +0 -1
  88. package/dist/components/feedback/page-state.cjs +0 -1
  89. package/dist/components/feedback/page-state.d.ts +0 -18
  90. package/dist/components/feedback/page-state.js +0 -1
  91. package/dist/components/layout/page-container.cjs +0 -1
  92. package/dist/components/layout/page-container.d.ts +0 -7
  93. package/dist/components/layout/page-container.js +0 -1
  94. package/dist/components/layout/page-header.cjs +0 -1
  95. package/dist/components/layout/page-header.d.ts +0 -23
  96. package/dist/components/layout/page-header.js +0 -1
  97. package/dist/components/layout/section-header.cjs +0 -1
  98. package/dist/components/layout/section-header.d.ts +0 -14
  99. package/dist/components/layout/section-header.js +0 -1
  100. package/dist/components/layout/sidebar-nav.cjs +0 -1
  101. package/dist/components/layout/sidebar-nav.d.ts +0 -37
  102. package/dist/components/layout/sidebar-nav.js +0 -1
  103. package/dist/components/layout/sticky-footer-bar.cjs +0 -1
  104. package/dist/components/layout/sticky-footer-bar.d.ts +0 -7
  105. package/dist/components/layout/sticky-footer-bar.js +0 -1
  106. package/dist/components/patterns/bulk-action-bar.cjs +0 -1
  107. package/dist/components/patterns/bulk-action-bar.d.ts +0 -10
  108. package/dist/components/patterns/bulk-action-bar.js +0 -1
  109. package/dist/components/patterns/data-view.cjs +0 -1
  110. package/dist/components/patterns/data-view.d.ts +0 -17
  111. package/dist/components/patterns/data-view.js +0 -1
  112. package/dist/components/patterns/detail-layout.cjs +0 -1
  113. package/dist/components/patterns/detail-layout.d.ts +0 -16
  114. package/dist/components/patterns/detail-layout.js +0 -1
  115. package/dist/components/patterns/form-builder.cjs +0 -1
  116. package/dist/components/patterns/form-builder.d.ts +0 -110
  117. package/dist/components/patterns/form-builder.js +0 -1
  118. package/dist/components/patterns/page-toolbar.cjs +0 -1
  119. package/dist/components/patterns/page-toolbar.d.ts +0 -11
  120. package/dist/components/patterns/page-toolbar.js +0 -1
  121. package/dist/components/patterns/resource-detail-page.cjs +0 -1
  122. package/dist/components/patterns/resource-detail-page.d.ts +0 -39
  123. package/dist/components/patterns/resource-detail-page.js +0 -1
  124. package/dist/components/patterns/resource-page.cjs +0 -1
  125. package/dist/components/patterns/resource-page.d.ts +0 -30
  126. package/dist/components/patterns/resource-page.js +0 -1
  127. package/dist/components/patterns/settings-page.cjs +0 -1
  128. package/dist/components/patterns/settings-page.d.ts +0 -21
  129. package/dist/components/patterns/settings-page.js +0 -1
  130. package/dist/src/components/charts/progress-ring.cjs +0 -1
  131. package/dist/src/components/charts/progress-ring.js +0 -57
  132. package/dist/src/components/feedback/loading-state.cjs +0 -1
  133. package/dist/src/components/feedback/loading-state.js +0 -15
  134. package/dist/src/components/feedback/page-state.cjs +0 -1
  135. package/dist/src/components/feedback/page-state.js +0 -28
  136. package/dist/src/components/layout/page-container.cjs +0 -1
  137. package/dist/src/components/layout/page-container.js +0 -21
  138. package/dist/src/components/layout/page-header.cjs +0 -1
  139. package/dist/src/components/layout/page-header.js +0 -92
  140. package/dist/src/components/layout/section-header.cjs +0 -1
  141. package/dist/src/components/layout/section-header.js +0 -44
  142. package/dist/src/components/layout/sidebar-nav.cjs +0 -1
  143. package/dist/src/components/layout/sidebar-nav.js +0 -220
  144. package/dist/src/components/layout/sticky-footer-bar.cjs +0 -1
  145. package/dist/src/components/layout/sticky-footer-bar.js +0 -20
  146. package/dist/src/components/patterns/bulk-action-bar.cjs +0 -1
  147. package/dist/src/components/patterns/bulk-action-bar.js +0 -34
  148. package/dist/src/components/patterns/data-view.cjs +0 -1
  149. package/dist/src/components/patterns/data-view.js +0 -47
  150. package/dist/src/components/patterns/detail-layout.cjs +0 -1
  151. package/dist/src/components/patterns/detail-layout.js +0 -65
  152. package/dist/src/components/patterns/form-builder.cjs +0 -1
  153. package/dist/src/components/patterns/form-builder.js +0 -263
  154. package/dist/src/components/patterns/page-toolbar.cjs +0 -1
  155. package/dist/src/components/patterns/page-toolbar.js +0 -41
  156. package/dist/src/components/patterns/resource-detail-page.cjs +0 -1
  157. package/dist/src/components/patterns/resource-detail-page.js +0 -100
  158. package/dist/src/components/patterns/resource-page.cjs +0 -1
  159. package/dist/src/components/patterns/resource-page.js +0 -88
  160. package/dist/src/components/patterns/settings-page.cjs +0 -1
  161. package/dist/src/components/patterns/settings-page.js +0 -64
  162. package/packages/cli/vendor/src/components/charts/progress-ring.tsx +0 -56
  163. package/packages/cli/vendor/src/components/feedback/loading-state.tsx +0 -15
  164. package/packages/cli/vendor/src/components/feedback/page-state.tsx +0 -29
  165. package/packages/cli/vendor/src/components/layout/page-container.tsx +0 -30
  166. package/packages/cli/vendor/src/components/layout/page-header.tsx +0 -104
  167. package/packages/cli/vendor/src/components/layout/section-header.tsx +0 -56
  168. package/packages/cli/vendor/src/components/layout/sidebar-nav.tsx +0 -377
  169. package/packages/cli/vendor/src/components/layout/sticky-footer-bar.tsx +0 -23
  170. package/packages/cli/vendor/src/components/patterns/bulk-action-bar.tsx +0 -53
  171. package/packages/cli/vendor/src/components/patterns/data-view.tsx +0 -64
  172. package/packages/cli/vendor/src/components/patterns/detail-layout.tsx +0 -75
  173. package/packages/cli/vendor/src/components/patterns/form-builder.tsx +0 -472
  174. package/packages/cli/vendor/src/components/patterns/page-toolbar.tsx +0 -61
  175. package/packages/cli/vendor/src/components/patterns/resource-detail-page.tsx +0 -164
  176. package/packages/cli/vendor/src/components/patterns/resource-page.tsx +0 -149
  177. package/packages/cli/vendor/src/components/patterns/settings-page.tsx +0 -84
@@ -1,29 +0,0 @@
1
- import * as React from "react"
2
-
3
- import { StateView, type StateViewProps, type StateViewStatus } from "./state-view"
4
- import { cn } from "@/lib/utils"
5
-
6
- export type PageStateTone = Extract<StateViewStatus, "empty" | "loading" | "error" | "success" | "info">
7
- export type PageStateProps = Omit<StateViewProps, "status" | "size" | "variant" | "tone" | "actions" | "slot"> & {
8
- tone?: PageStateTone
9
- action?: React.ReactNode
10
- extra?: React.ReactNode
11
- compact?: boolean
12
- }
13
-
14
- /** @deprecated Use StateView. */
15
- function PageState({ tone = "empty", action, extra, compact = false, className, ...props }: PageStateProps) {
16
- return <StateView status={tone} size={compact ? "compact" : "page"} actions={<>{action}{extra}</>} slot="page-state" className={className} {...props} />
17
- }
18
-
19
- export type InlineStateProps = Omit<PageStateProps, "compact"> & {
20
- retryLabel?: React.ReactNode
21
- onRetry?: () => void
22
- }
23
-
24
- /** @deprecated Use StateView with variant="inline". */
25
- function InlineState({ tone = "empty", action, className, ...props }: InlineStateProps) {
26
- return <StateView variant="inline" size="compact" actions={action} slot="inline-state" className={cn("min-h-0", className)} {...props} status={tone} />
27
- }
28
-
29
- export { InlineState, PageState }
@@ -1,30 +0,0 @@
1
- import * as React from "react"
2
-
3
- import { cn } from "@/lib/utils"
4
-
5
- export type PageContainerSize = "default" | "sm" | "md" | "lg" | "xl" | "full"
6
-
7
- export type PageContainerProps = React.ComponentProps<"div"> & {
8
- size?: PageContainerSize
9
- }
10
-
11
- const sizeClassName: Record<PageContainerSize, string> = {
12
- sm: "max-w-3xl",
13
- md: "max-w-5xl",
14
- lg: "max-w-6xl",
15
- xl: "max-w-7xl",
16
- default: "max-w-7xl",
17
- full: "max-w-none",
18
- }
19
-
20
- function PageContainer({ className, size = "default", ...props }: PageContainerProps) {
21
- return (
22
- <div
23
- data-slot="page-container"
24
- className={cn("mx-auto flex w-full flex-col gap-4", sizeClassName[size], className)}
25
- {...props}
26
- />
27
- )
28
- }
29
-
30
- export { PageContainer }
@@ -1,104 +0,0 @@
1
- import * as React from "react"
2
- import { cva, type VariantProps } from "class-variance-authority"
3
-
4
- import { cn } from "@/lib/utils"
5
-
6
- const pageHeaderVariants = cva("flex flex-col border transition-[background-color,border-color,box-shadow]", {
7
- variants: {
8
- variant: {
9
- default: "border-border/75 bg-card/96 shadow-sm ring-1 ring-foreground/5",
10
- elevated: "border-border/70 bg-card shadow-[0_1px_2px_rgba(15,23,42,0.06),0_18px_45px_rgba(15,23,42,0.08)] ring-1 ring-foreground/5",
11
- outline: "border-border bg-transparent shadow-none",
12
- ghost: "border-transparent bg-transparent shadow-none",
13
- soft: "border-transparent bg-muted/45 shadow-none",
14
- },
15
- size: {
16
- sm: "gap-3 rounded-[var(--radius-2xl)] p-4",
17
- default: "gap-4 rounded-[var(--radius-3xl)] p-5",
18
- lg: "gap-5 rounded-[calc(var(--radius-3xl)*1.1)] p-6",
19
- },
20
- tone: {
21
- neutral: "",
22
- info: "border-blue-500/20 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),oklch(0.94_0.03_235)_28%),var(--card))]",
23
- success: "border-emerald-500/20 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),oklch(0.94_0.04_155)_30%),var(--card))]",
24
- warning: "border-amber-500/24 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),oklch(0.94_0.05_85)_30%),var(--card))]",
25
- danger: "border-destructive/24 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),var(--destructive)_8%),var(--card))]",
26
- },
27
- },
28
- defaultVariants: {
29
- variant: "default",
30
- size: "default",
31
- tone: "neutral",
32
- },
33
- })
34
-
35
- export type PageHeaderProps = React.ComponentProps<"div"> &
36
- VariantProps<typeof pageHeaderVariants> & {
37
- title?: React.ReactNode
38
- description?: React.ReactNode
39
- eyebrow?: React.ReactNode
40
- breadcrumbs?: React.ReactNode
41
- actions?: React.ReactNode
42
- meta?: React.ReactNode
43
- leading?: React.ReactNode
44
- footer?: React.ReactNode
45
- sticky?: boolean
46
- titleClassName?: string
47
- descriptionClassName?: string
48
- actionsClassName?: string
49
- }
50
-
51
- function PageHeader({
52
- className,
53
- variant,
54
- size,
55
- tone,
56
- title,
57
- description,
58
- eyebrow,
59
- breadcrumbs,
60
- actions,
61
- meta,
62
- leading,
63
- footer,
64
- sticky = false,
65
- titleClassName,
66
- descriptionClassName,
67
- actionsClassName,
68
- children,
69
- ...props
70
- }: PageHeaderProps) {
71
- return (
72
- <div
73
- data-slot="page-header"
74
- data-sticky={sticky || undefined}
75
- className={cn(
76
- pageHeaderVariants({ variant, size, tone }),
77
- sticky && "sticky top-0 z-30 bg-background/92 backdrop-blur supports-[backdrop-filter]:bg-background/78",
78
- className
79
- )}
80
- {...props}
81
- >
82
- {breadcrumbs && <div className="text-sm text-muted-foreground/95">{breadcrumbs}</div>}
83
-
84
- <div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
85
- <div className="flex min-w-0 gap-4">
86
- {leading ? <div className="shrink-0">{leading}</div> : null}
87
- <div className="min-w-0 space-y-2">
88
- {eyebrow && <div className="text-[11px] font-semibold uppercase tracking-[0.24em] text-muted-foreground">{eyebrow}</div>}
89
- {title && <h1 className={cn("truncate text-3xl font-semibold tracking-[-0.03em] text-foreground", size === "sm" && "text-2xl", size === "lg" && "text-4xl", titleClassName)}>{title}</h1>}
90
- {description && <p className={cn("max-w-3xl text-sm leading-7 text-muted-foreground", descriptionClassName)}>{description}</p>}
91
- {meta && <div className="pt-1 text-sm text-muted-foreground">{meta}</div>}
92
- </div>
93
- </div>
94
-
95
- {actions && <div className={cn("flex shrink-0 flex-wrap items-center gap-2.5", actionsClassName)}>{actions}</div>}
96
- </div>
97
-
98
- {children}
99
- {footer && <div data-slot="page-header-footer" className="border-t border-border/70 pt-4">{footer}</div>}
100
- </div>
101
- )
102
- }
103
-
104
- export { PageHeader, pageHeaderVariants }
@@ -1,56 +0,0 @@
1
- import * as React from "react"
2
-
3
- import { cn } from "@/lib/utils"
4
-
5
- export type SectionHeaderProps = React.ComponentProps<"div"> & {
6
- eyebrow?: React.ReactNode
7
- title?: React.ReactNode
8
- description?: React.ReactNode
9
- actions?: React.ReactNode
10
- meta?: React.ReactNode
11
- align?: "start" | "center"
12
- size?: "sm" | "default" | "lg"
13
- titleClassName?: string
14
- descriptionClassName?: string
15
- }
16
-
17
- const titleSizeClassName = {
18
- sm: "text-xl",
19
- default: "text-2xl",
20
- lg: "text-3xl",
21
- }
22
-
23
- function SectionHeader({
24
- className,
25
- eyebrow,
26
- title,
27
- description,
28
- actions,
29
- meta,
30
- align = "start",
31
- size = "default",
32
- titleClassName,
33
- descriptionClassName,
34
- children,
35
- ...props
36
- }: SectionHeaderProps) {
37
- return (
38
- <div
39
- data-slot="section-header"
40
- data-align={align}
41
- className={cn("flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between", align === "center" && "text-center sm:flex-col sm:items-center", className)}
42
- {...props}
43
- >
44
- <div className={cn("min-w-0 space-y-2", align === "center" && "mx-auto max-w-2xl")}>
45
- {eyebrow ? <p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">{eyebrow}</p> : null}
46
- {title ? <h2 className={cn("font-semibold tracking-[-0.03em] text-foreground", titleSizeClassName[size], titleClassName)}>{title}</h2> : null}
47
- {description ? <p className={cn("max-w-3xl text-sm leading-7 text-muted-foreground", descriptionClassName)}>{description}</p> : null}
48
- {meta ? <div className="text-sm text-muted-foreground">{meta}</div> : null}
49
- {children}
50
- </div>
51
- {actions ? <div className="flex shrink-0 flex-wrap items-center gap-2.5">{actions}</div> : null}
52
- </div>
53
- )
54
- }
55
-
56
- export { SectionHeader }
@@ -1,377 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
-
5
- import { Badge } from "@/components/ui/badge"
6
- import { Tooltip } from "@/components/ui/tooltip"
7
- import { cn } from "@/lib/utils"
8
- import { ControllableDetails } from "./controllable-details"
9
-
10
- export type SidebarNavItem = {
11
- key: string
12
- label: React.ReactNode
13
- icon?: React.ReactNode
14
- badge?: React.ReactNode
15
- href?: string
16
- items?: SidebarNavItem[]
17
- active?: boolean
18
- current?: React.AriaAttributes["aria-current"]
19
- disabled?: boolean
20
- hidden?: boolean
21
- sectionLabel?: React.ReactNode
22
- defaultExpanded?: boolean
23
- expanded?: boolean
24
- onExpandedChange?: (expanded: boolean) => void
25
- tooltip?: React.ReactNode
26
- onSelect?: () => void
27
- }
28
-
29
- export type SidebarNavProps = React.ComponentProps<"nav"> & {
30
- items: SidebarNavItem[]
31
- collapsed?: boolean
32
- scrollable?: boolean
33
- tooltipOnCollapsed?: boolean
34
- showSectionLabels?: boolean
35
- itemSize?: "sm" | "md" | "lg"
36
- activeIndicator?: "none" | "bar" | "pill"
37
- itemClassName?: string
38
- activeItemClassName?: string
39
- renderItem?: (item: SidebarNavItem, element: React.ReactNode) => React.ReactNode
40
- renderLink?: (props: React.ComponentProps<"a"> & { item: SidebarNavItem; [key: `data-${string}`]: string | boolean | undefined }) => React.ReactNode
41
- }
42
-
43
- function hasVisibleChildren(item: SidebarNavItem) {
44
- return item.items?.some((child) => !child.hidden) ?? false
45
- }
46
-
47
- function isActiveItem(item: SidebarNavItem): boolean {
48
- if (item.active) return true
49
- return item.items?.some((child) => isActiveItem(child)) ?? false
50
- }
51
-
52
- function SidebarLeaf({
53
- item,
54
- collapsed,
55
- depth,
56
- itemSize,
57
- activeIndicator,
58
- itemClassName,
59
- activeItemClassName,
60
- renderLink,
61
- }: {
62
- item: SidebarNavItem
63
- collapsed: boolean
64
- depth: number
65
- itemSize: NonNullable<SidebarNavProps["itemSize"]>
66
- activeIndicator: NonNullable<SidebarNavProps["activeIndicator"]>
67
- itemClassName?: string
68
- activeItemClassName?: string
69
- renderLink?: SidebarNavProps["renderLink"]
70
- }) {
71
- const currentValue: React.AriaAttributes["aria-current"] = item.current ?? (item.active ? "page" : undefined)
72
- const content = (
73
- <>
74
- {item.icon && <span className="shrink-0 [&_svg]:size-4">{item.icon}</span>}
75
- {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
76
- {!collapsed && item.badge && (
77
- <Badge variant="secondary" className="ml-auto h-5 shrink-0 px-1.5">
78
- {item.badge}
79
- </Badge>
80
- )}
81
- </>
82
- )
83
-
84
- const commonClassName = cn(
85
- "group flex items-center gap-2 border border-transparent text-sm font-medium transition-[background-color,border-color,color,box-shadow] data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
86
- collapsed && "justify-center px-0",
87
- depth > 0 && !collapsed && "pl-3",
88
- itemClassName,
89
- item.active && activeItemClassName
90
- )
91
-
92
- const wrapCollapsed = (node: React.ReactNode) =>
93
- collapsed ? (
94
- <Tooltip content={item.tooltip ?? item.label} side="right">
95
- <span className="block">{node}</span>
96
- </Tooltip>
97
- ) : (
98
- node
99
- )
100
-
101
- const internal = item.href && item.href.startsWith("/")
102
-
103
- if (internal) {
104
- if (renderLink) {
105
- return wrapCollapsed(
106
- renderLink({
107
- item,
108
- href: item.href,
109
- "data-slot": "sidebar-nav-item",
110
- "data-depth": String(depth),
111
- "data-active": item.active || undefined,
112
- "data-disabled": item.disabled || undefined,
113
- "data-size": itemSize,
114
- "data-active-indicator": activeIndicator,
115
- "aria-current": currentValue,
116
- className: commonClassName,
117
- onClick: (event) => {
118
- if (item.disabled) {
119
- event.preventDefault()
120
- return
121
- }
122
- item.onSelect?.()
123
- },
124
- children: content,
125
- })
126
- )
127
- }
128
-
129
- return wrapCollapsed(
130
- <a
131
- href={item.href}
132
- data-slot="sidebar-nav-item"
133
- data-depth={depth}
134
- data-active={item.active || undefined}
135
- data-disabled={item.disabled || undefined}
136
- data-size={itemSize}
137
- data-active-indicator={activeIndicator}
138
- aria-current={currentValue}
139
- className={commonClassName}
140
- onClick={(event) => {
141
- if (item.disabled) {
142
- event.preventDefault()
143
- return
144
- }
145
- item.onSelect?.()
146
- }}
147
- >
148
- {content}
149
- </a>
150
- )
151
- }
152
-
153
- if (item.href) {
154
- return wrapCollapsed(
155
- <button
156
- type="button"
157
- data-slot="sidebar-nav-item"
158
- data-depth={depth}
159
- data-active={item.active || undefined}
160
- data-disabled={item.disabled || undefined}
161
- data-size={itemSize}
162
- data-active-indicator={activeIndicator}
163
- aria-current={currentValue}
164
- className={cn("w-full text-left", commonClassName)}
165
- onClick={() => {
166
- if (item.disabled) return
167
- const href = item.href
168
- if (!href) return
169
- item.onSelect?.()
170
- if (href.startsWith("http")) {
171
- window.open(href, "_blank", "noopener,noreferrer")
172
- return
173
- }
174
- window.location.assign(href)
175
- }}
176
- >
177
- {content}
178
- </button>
179
- )
180
- }
181
-
182
- return wrapCollapsed(
183
- <button
184
- type="button"
185
- data-slot="sidebar-nav-item"
186
- data-depth={depth}
187
- data-active={item.active || undefined}
188
- data-disabled={item.disabled || undefined}
189
- data-size={itemSize}
190
- data-active-indicator={activeIndicator}
191
- aria-current={currentValue}
192
- disabled={item.disabled}
193
- className={cn("w-full text-left", commonClassName)}
194
- onClick={item.onSelect}
195
- >
196
- {content}
197
- </button>
198
- )
199
- }
200
-
201
- function SidebarTree({
202
- items,
203
- collapsed,
204
- depth,
205
- showSectionLabels,
206
- itemSize,
207
- activeIndicator,
208
- itemClassName,
209
- activeItemClassName,
210
- renderItem,
211
- renderLink,
212
- }: {
213
- items: SidebarNavItem[]
214
- collapsed: boolean
215
- depth: number
216
- showSectionLabels: boolean
217
- itemSize: NonNullable<SidebarNavProps["itemSize"]>
218
- activeIndicator: NonNullable<SidebarNavProps["activeIndicator"]>
219
- itemClassName?: string
220
- activeItemClassName?: string
221
- renderItem?: SidebarNavProps["renderItem"]
222
- renderLink?: SidebarNavProps["renderLink"]
223
- }) {
224
- return items.map((item) => {
225
- if (item.hidden) return null
226
-
227
- const showSectionLabel = showSectionLabels && !collapsed && depth === 0 && item.sectionLabel
228
- const hasChildren = hasVisibleChildren(item)
229
-
230
- if (!hasChildren) {
231
- const element = (
232
- <SidebarLeaf
233
- item={item}
234
- collapsed={collapsed}
235
- depth={depth}
236
- itemSize={itemSize}
237
- activeIndicator={activeIndicator}
238
- itemClassName={itemClassName}
239
- activeItemClassName={activeItemClassName}
240
- renderLink={renderLink}
241
- />
242
- )
243
-
244
- return (
245
- <React.Fragment key={item.key}>
246
- {showSectionLabel ? (
247
- <div
248
- data-slot="sidebar-nav-group-label"
249
- className="px-2 pb-1 pt-3 text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground first:pt-0"
250
- >
251
- {item.sectionLabel}
252
- </div>
253
- ) : null}
254
- {renderItem ? renderItem(item, element) : element}
255
- </React.Fragment>
256
- )
257
- }
258
-
259
- const isExpanded = item.defaultExpanded ?? isActiveItem(item)
260
- const trigger = (
261
- <summary
262
- data-slot="sidebar-nav-group-trigger"
263
- className={cn(
264
- "flex min-h-9 list-none items-center gap-2 rounded-xl border border-transparent px-2.5 text-sm font-medium text-[color:var(--aui-page-muted-strong,var(--muted-foreground))] transition-[background-color,border-color,color,box-shadow] hover:border-[color:var(--aui-divider)] hover:bg-[color:var(--aui-page-bg-alt)] hover:text-[color:var(--aui-page-foreground)]",
265
- collapsed ? "justify-center px-0" : "px-2"
266
- )}
267
- >
268
- {item.icon ? (
269
- collapsed ? (
270
- <Tooltip content={item.tooltip ?? item.label} side="right">
271
- <span className="shrink-0 [&_svg]:size-4">{item.icon}</span>
272
- </Tooltip>
273
- ) : (
274
- <span className="shrink-0 [&_svg]:size-4">{item.icon}</span>
275
- )
276
- ) : null}
277
- {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
278
- {!collapsed && item.badge ? (
279
- <Badge variant="secondary" className="h-5 shrink-0 px-1.5">
280
- {item.badge}
281
- </Badge>
282
- ) : null}
283
- {!collapsed && (
284
- <span
285
- data-slot="sidebar-nav-group-chevron"
286
- className="ml-auto text-xs text-muted-foreground transition-transform group-open/sidebar-nav-details:rotate-90"
287
- >
288
-
289
- </span>
290
- )}
291
- </summary>
292
- )
293
-
294
- const groupElement = (
295
- <div data-slot="sidebar-nav-group" data-depth={depth}>
296
- {showSectionLabel ? (
297
- <div
298
- data-slot="sidebar-nav-group-label"
299
- className="px-2 pb-1 pt-3 text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground first:pt-0"
300
- >
301
- {item.sectionLabel}
302
- </div>
303
- ) : null}
304
- <ControllableDetails
305
- data-slot="sidebar-nav-group-details"
306
- open={item.expanded}
307
- defaultOpen={isExpanded}
308
- className="group/sidebar-nav-details"
309
- onOpenChange={item.onExpandedChange}
310
- >
311
- {trigger}
312
- <div
313
- data-slot="sidebar-nav-group-content"
314
- className={cn("mt-1 grid gap-1", !collapsed && "ml-3 border-l border-border/55 pl-2")}
315
- >
316
- <SidebarTree
317
- items={item.items ?? []}
318
- collapsed={collapsed}
319
- depth={depth + 1}
320
- showSectionLabels={showSectionLabels}
321
- itemSize={itemSize}
322
- activeIndicator={activeIndicator}
323
- itemClassName={itemClassName}
324
- activeItemClassName={activeItemClassName}
325
- renderItem={renderItem}
326
- renderLink={renderLink}
327
- />
328
- </div>
329
- </ControllableDetails>
330
- </div>
331
- )
332
-
333
- return renderItem ? <React.Fragment key={item.key}>{renderItem(item, groupElement)}</React.Fragment> : <React.Fragment key={item.key}>{groupElement}</React.Fragment>
334
- })
335
- }
336
-
337
- function SidebarNav({
338
- className,
339
- items,
340
- collapsed = false,
341
- scrollable = true,
342
- showSectionLabels = true,
343
- itemSize = "md",
344
- activeIndicator = "bar",
345
- itemClassName,
346
- activeItemClassName,
347
- renderItem,
348
- renderLink,
349
- ...props
350
- }: SidebarNavProps) {
351
- const visibleItems = items.filter((item) => !item.hidden)
352
-
353
- return (
354
- <nav
355
- aria-label="Primary navigation"
356
- data-slot="sidebar-nav"
357
- data-collapsed={collapsed || undefined}
358
- className={cn("grid min-h-0 gap-1", scrollable ? "overflow-y-auto overscroll-contain" : null, className)}
359
- {...props}
360
- >
361
- <SidebarTree
362
- items={visibleItems}
363
- collapsed={collapsed}
364
- depth={0}
365
- showSectionLabels={showSectionLabels}
366
- itemSize={itemSize}
367
- activeIndicator={activeIndicator}
368
- itemClassName={itemClassName}
369
- activeItemClassName={activeItemClassName}
370
- renderItem={renderItem}
371
- renderLink={renderLink}
372
- />
373
- </nav>
374
- )
375
- }
376
-
377
- export { SidebarNav }
@@ -1,23 +0,0 @@
1
- import * as React from "react"
2
-
3
- import { cn } from "@/lib/utils"
4
-
5
- export type StickyFooterBarProps = React.ComponentProps<"div"> & {
6
- start?: React.ReactNode
7
- end?: React.ReactNode
8
- }
9
-
10
- function StickyFooterBar({ start, end, className, children, ...props }: StickyFooterBarProps) {
11
- return (
12
- <div
13
- data-slot="sticky-footer-bar"
14
- className={cn("sticky bottom-0 z-30 flex flex-wrap items-center justify-between gap-3 border-t bg-background px-4 py-3 shadow-lg", className)}
15
- {...props}
16
- >
17
- <div className="min-w-0 flex-1">{start ?? children}</div>
18
- {end && <div className="flex shrink-0 items-center gap-2">{end}</div>}
19
- </div>
20
- )
21
- }
22
-
23
- export { StickyFooterBar }
@@ -1,53 +0,0 @@
1
- import * as React from "react"
2
- import { XIcon } from "lucide-react"
3
-
4
- import { Button } from "@/components/ui/button"
5
- import { cn } from "@/lib/utils"
6
-
7
- export type BulkActionBarProps = React.ComponentProps<"div"> & {
8
- selectedCount: number
9
- selectedLabel?: (count: number) => React.ReactNode
10
- actions?: React.ReactNode
11
- clearLabel?: React.ReactNode
12
- onClear?: () => void
13
- }
14
-
15
- function BulkActionBar({
16
- className,
17
- selectedCount,
18
- selectedLabel = (count) => `${count} selected`,
19
- actions,
20
- clearLabel = "Clear",
21
- onClear,
22
- children,
23
- ...props
24
- }: BulkActionBarProps) {
25
- if (selectedCount <= 0) return null
26
-
27
- return (
28
- <div
29
- data-slot="bulk-action-bar"
30
- className={cn(
31
- "flex flex-col gap-3 rounded-xl border bg-card p-3 shadow-sm sm:flex-row sm:items-center sm:justify-between",
32
- className
33
- )}
34
- {...props}
35
- >
36
- <div data-slot="bulk-action-bar-count" className="text-sm font-medium">
37
- {selectedLabel(selectedCount)}
38
- </div>
39
- <div data-slot="bulk-action-bar-actions" className="flex flex-wrap items-center gap-2">
40
- {children}
41
- {actions}
42
- {onClear && (
43
- <Button type="button" variant="ghost" size="sm" onClick={onClear}>
44
- <XIcon data-icon="inline-start" />
45
- {clearLabel}
46
- </Button>
47
- )}
48
- </div>
49
- </div>
50
- )
51
- }
52
-
53
- export { BulkActionBar }