@ptengine/design-components 0.3.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 (197) hide show
  1. package/README.md +309 -0
  2. package/components.json +21 -0
  3. package/dist/components/ui/accordion.d.ts +8 -0
  4. package/dist/components/ui/accordion.d.ts.map +1 -0
  5. package/dist/components/ui/alert-dialog.d.ts +21 -0
  6. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  7. package/dist/components/ui/alert.d.ts +9 -0
  8. package/dist/components/ui/alert.d.ts.map +1 -0
  9. package/dist/components/ui/aspect-ratio.d.ts +4 -0
  10. package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
  11. package/dist/components/ui/attachment.d.ts +26 -0
  12. package/dist/components/ui/attachment.d.ts.map +1 -0
  13. package/dist/components/ui/avatar.d.ts +10 -0
  14. package/dist/components/ui/avatar.d.ts.map +1 -0
  15. package/dist/components/ui/badge.d.ts +10 -0
  16. package/dist/components/ui/badge.d.ts.map +1 -0
  17. package/dist/components/ui/breadcrumb.d.ts +22 -0
  18. package/dist/components/ui/breadcrumb.d.ts.map +1 -0
  19. package/dist/components/ui/bubble.d.ts +19 -0
  20. package/dist/components/ui/bubble.d.ts.map +1 -0
  21. package/dist/components/ui/button-group.d.ts +13 -0
  22. package/dist/components/ui/button-group.d.ts.map +1 -0
  23. package/dist/components/ui/button.d.ts +13 -0
  24. package/dist/components/ui/button.d.ts.map +1 -0
  25. package/dist/components/ui/calendar.d.ts +9 -0
  26. package/dist/components/ui/calendar.d.ts.map +1 -0
  27. package/dist/components/ui/card.d.ts +9 -0
  28. package/dist/components/ui/card.d.ts.map +1 -0
  29. package/dist/components/ui/carousel.d.ts +23 -0
  30. package/dist/components/ui/carousel.d.ts.map +1 -0
  31. package/dist/components/ui/chart.d.ts +63 -0
  32. package/dist/components/ui/chart.d.ts.map +1 -0
  33. package/dist/components/ui/checkbox.d.ts +5 -0
  34. package/dist/components/ui/checkbox.d.ts.map +1 -0
  35. package/dist/components/ui/collapsible.d.ts +6 -0
  36. package/dist/components/ui/collapsible.d.ts.map +1 -0
  37. package/dist/components/ui/command.d.ts +81 -0
  38. package/dist/components/ui/command.d.ts.map +1 -0
  39. package/dist/components/ui/context-menu.d.ts +28 -0
  40. package/dist/components/ui/context-menu.d.ts.map +1 -0
  41. package/dist/components/ui/dialog.d.ts +22 -0
  42. package/dist/components/ui/dialog.d.ts.map +1 -0
  43. package/dist/components/ui/direction.d.ts +8 -0
  44. package/dist/components/ui/direction.d.ts.map +1 -0
  45. package/dist/components/ui/drawer.d.ts +23 -0
  46. package/dist/components/ui/drawer.d.ts.map +1 -0
  47. package/dist/components/ui/dropdown-menu.d.ts +28 -0
  48. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  49. package/dist/components/ui/empty.d.ts +13 -0
  50. package/dist/components/ui/empty.d.ts.map +1 -0
  51. package/dist/components/ui/field.d.ts +25 -0
  52. package/dist/components/ui/field.d.ts.map +1 -0
  53. package/dist/components/ui/hover-card.d.ts +7 -0
  54. package/dist/components/ui/hover-card.d.ts.map +1 -0
  55. package/dist/components/ui/input-group.d.ts +13 -0
  56. package/dist/components/ui/input-group.d.ts.map +1 -0
  57. package/dist/components/ui/input-otp.d.ts +35 -0
  58. package/dist/components/ui/input-otp.d.ts.map +1 -0
  59. package/dist/components/ui/input.d.ts +5 -0
  60. package/dist/components/ui/input.d.ts.map +1 -0
  61. package/dist/components/ui/item.d.ts +24 -0
  62. package/dist/components/ui/item.d.ts.map +1 -0
  63. package/dist/components/ui/kbd.d.ts +5 -0
  64. package/dist/components/ui/kbd.d.ts.map +1 -0
  65. package/dist/components/ui/label.d.ts +6 -0
  66. package/dist/components/ui/label.d.ts.map +1 -0
  67. package/dist/components/ui/marker.d.ts +13 -0
  68. package/dist/components/ui/marker.d.ts.map +1 -0
  69. package/dist/components/ui/menubar.d.ts +29 -0
  70. package/dist/components/ui/menubar.d.ts.map +1 -0
  71. package/dist/components/ui/message-scroller.d.ts +26 -0
  72. package/dist/components/ui/message-scroller.d.ts.map +1 -0
  73. package/dist/components/ui/message.d.ts +11 -0
  74. package/dist/components/ui/message.d.ts.map +1 -0
  75. package/dist/components/ui/native-select.d.ts +4 -0
  76. package/dist/components/ui/native-select.d.ts.map +1 -0
  77. package/dist/components/ui/navigation-menu.d.ts +13 -0
  78. package/dist/components/ui/navigation-menu.d.ts.map +1 -0
  79. package/dist/components/ui/pagination.d.ts +35 -0
  80. package/dist/components/ui/pagination.d.ts.map +1 -0
  81. package/dist/components/ui/popover.d.ts +8 -0
  82. package/dist/components/ui/popover.d.ts.map +1 -0
  83. package/dist/components/ui/progress.d.ts +5 -0
  84. package/dist/components/ui/progress.d.ts.map +1 -0
  85. package/dist/components/ui/radio-group.d.ts +6 -0
  86. package/dist/components/ui/radio-group.d.ts.map +1 -0
  87. package/dist/components/ui/resizable.d.ts +24 -0
  88. package/dist/components/ui/resizable.d.ts.map +1 -0
  89. package/dist/components/ui/scroll-area.d.ts +6 -0
  90. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  91. package/dist/components/ui/search-input.d.ts +23 -0
  92. package/dist/components/ui/search-input.d.ts.map +1 -0
  93. package/dist/components/ui/select.d.ts +14 -0
  94. package/dist/components/ui/select.d.ts.map +1 -0
  95. package/dist/components/ui/separator.d.ts +5 -0
  96. package/dist/components/ui/separator.d.ts.map +1 -0
  97. package/dist/components/ui/sheet.d.ts +28 -0
  98. package/dist/components/ui/sheet.d.ts.map +1 -0
  99. package/dist/components/ui/sidebar.d.ts +70 -0
  100. package/dist/components/ui/sidebar.d.ts.map +1 -0
  101. package/dist/components/ui/skeleton.d.ts +4 -0
  102. package/dist/components/ui/skeleton.d.ts.map +1 -0
  103. package/dist/components/ui/slider.d.ts +5 -0
  104. package/dist/components/ui/slider.d.ts.map +1 -0
  105. package/dist/components/ui/sonner.d.ts +6 -0
  106. package/dist/components/ui/sonner.d.ts.map +1 -0
  107. package/dist/components/ui/spinner.d.ts +7 -0
  108. package/dist/components/ui/spinner.d.ts.map +1 -0
  109. package/dist/components/ui/switch.d.ts +5 -0
  110. package/dist/components/ui/switch.d.ts.map +1 -0
  111. package/dist/components/ui/table.d.ts +11 -0
  112. package/dist/components/ui/table.d.ts.map +1 -0
  113. package/dist/components/ui/tabs.d.ts +13 -0
  114. package/dist/components/ui/tabs.d.ts.map +1 -0
  115. package/dist/components/ui/textarea.d.ts +5 -0
  116. package/dist/components/ui/textarea.d.ts.map +1 -0
  117. package/dist/components/ui/toggle-group.d.ts +13 -0
  118. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  119. package/dist/components/ui/toggle.d.ts +13 -0
  120. package/dist/components/ui/toggle.d.ts.map +1 -0
  121. package/dist/components/ui/tooltip.d.ts +8 -0
  122. package/dist/components/ui/tooltip.d.ts.map +1 -0
  123. package/dist/hooks/use-mobile.d.ts +2 -0
  124. package/dist/hooks/use-mobile.d.ts.map +1 -0
  125. package/dist/index.cjs +82 -0
  126. package/dist/index.d.ts +71 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +20969 -0
  129. package/dist/lib/utils.d.ts +4 -0
  130. package/dist/lib/utils.d.ts.map +1 -0
  131. package/llms.txt +173 -0
  132. package/package.json +125 -0
  133. package/src/components/ui/accordion.tsx +51 -0
  134. package/src/components/ui/alert-dialog.tsx +115 -0
  135. package/src/components/ui/alert.tsx +48 -0
  136. package/src/components/ui/aspect-ratio.tsx +5 -0
  137. package/src/components/ui/attachment.tsx +186 -0
  138. package/src/components/ui/avatar.tsx +57 -0
  139. package/src/components/ui/badge.tsx +40 -0
  140. package/src/components/ui/breadcrumb.tsx +101 -0
  141. package/src/components/ui/bubble.tsx +123 -0
  142. package/src/components/ui/button-group.tsx +74 -0
  143. package/src/components/ui/button.tsx +64 -0
  144. package/src/components/ui/calendar.tsx +63 -0
  145. package/src/components/ui/card.tsx +55 -0
  146. package/src/components/ui/carousel.tsx +252 -0
  147. package/src/components/ui/chart.tsx +323 -0
  148. package/src/components/ui/checkbox.tsx +26 -0
  149. package/src/components/ui/collapsible.tsx +9 -0
  150. package/src/components/ui/command.tsx +136 -0
  151. package/src/components/ui/context-menu.tsx +187 -0
  152. package/src/components/ui/dialog.tsx +103 -0
  153. package/src/components/ui/direction.tsx +15 -0
  154. package/src/components/ui/drawer.tsx +98 -0
  155. package/src/components/ui/dropdown-menu.tsx +186 -0
  156. package/src/components/ui/empty.tsx +75 -0
  157. package/src/components/ui/field.tsx +175 -0
  158. package/src/components/ui/hover-card.tsx +27 -0
  159. package/src/components/ui/input-group.tsx +80 -0
  160. package/src/components/ui/input-otp.tsx +67 -0
  161. package/src/components/ui/input.tsx +24 -0
  162. package/src/components/ui/item.tsx +118 -0
  163. package/src/components/ui/kbd.tsx +21 -0
  164. package/src/components/ui/label.tsx +19 -0
  165. package/src/components/ui/marker.tsx +67 -0
  166. package/src/components/ui/menubar.tsx +218 -0
  167. package/src/components/ui/message-scroller.tsx +206 -0
  168. package/src/components/ui/message.tsx +85 -0
  169. package/src/components/ui/native-select.tsx +29 -0
  170. package/src/components/ui/navigation-menu.tsx +120 -0
  171. package/src/components/ui/pagination.tsx +108 -0
  172. package/src/components/ui/popover.tsx +31 -0
  173. package/src/components/ui/progress.tsx +23 -0
  174. package/src/components/ui/radio-group.tsx +36 -0
  175. package/src/components/ui/resizable.tsx +40 -0
  176. package/src/components/ui/scroll-area.tsx +44 -0
  177. package/src/components/ui/search-input.tsx +97 -0
  178. package/src/components/ui/select.tsx +151 -0
  179. package/src/components/ui/separator.tsx +24 -0
  180. package/src/components/ui/sheet.tsx +124 -0
  181. package/src/components/ui/sidebar.tsx +704 -0
  182. package/src/components/ui/skeleton.tsx +9 -0
  183. package/src/components/ui/slider.tsx +41 -0
  184. package/src/components/ui/sonner.tsx +45 -0
  185. package/src/components/ui/spinner.tsx +21 -0
  186. package/src/components/ui/switch.tsx +27 -0
  187. package/src/components/ui/table.tsx +95 -0
  188. package/src/components/ui/tabs.tsx +119 -0
  189. package/src/components/ui/textarea.tsx +23 -0
  190. package/src/components/ui/toggle-group.tsx +55 -0
  191. package/src/components/ui/toggle.tsx +40 -0
  192. package/src/components/ui/tooltip.tsx +30 -0
  193. package/src/hooks/use-mobile.ts +19 -0
  194. package/src/index.ts +414 -0
  195. package/src/lib/utils.ts +7 -0
  196. package/src/styles/tokens.css +360 -0
  197. package/tailwind.preset.js +235 -0
@@ -0,0 +1,85 @@
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '../../lib/utils';
4
+
5
+ function MessageGroup({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
6
+ return (
7
+ <div
8
+ data-slot="message-group"
9
+ className={cn('flex min-w-0 flex-col gap-[8px]', className)}
10
+ {...props}
11
+ />
12
+ );
13
+ }
14
+
15
+ function Message({
16
+ className,
17
+ align = 'start',
18
+ ...props
19
+ }: React.HTMLAttributes<HTMLDivElement> & { align?: 'start' | 'end' }) {
20
+ return (
21
+ <div
22
+ data-slot="message"
23
+ data-align={align}
24
+ className={cn(
25
+ 'group/message relative flex w-full min-w-0 gap-[8px] text-[14px] leading-[20px] data-[align=end]:flex-row-reverse',
26
+ className
27
+ )}
28
+ {...props}
29
+ />
30
+ );
31
+ }
32
+
33
+ function MessageAvatar({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
34
+ return (
35
+ <div
36
+ data-slot="message-avatar"
37
+ className={cn(
38
+ 'flex w-fit min-w-[32px] shrink-0 items-center justify-center self-end overflow-hidden rounded-full bg-muted group-has-[[data-slot=message-footer]]/message:-translate-y-[32px]',
39
+ className
40
+ )}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+
46
+ function MessageContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
47
+ return (
48
+ <div
49
+ data-slot="message-content"
50
+ className={cn(
51
+ 'flex w-full min-w-0 flex-col gap-[10px] break-words group-data-[align=end]/message:[&>[data-slot]]:self-end',
52
+ className
53
+ )}
54
+ {...props}
55
+ />
56
+ );
57
+ }
58
+
59
+ function MessageHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
60
+ return (
61
+ <div
62
+ data-slot="message-header"
63
+ className={cn(
64
+ 'flex max-w-full min-w-0 items-center px-[12px] text-[13px] leading-[20px] font-medium text-muted-foreground group-has-[[data-variant=ghost]]/message:px-0',
65
+ className
66
+ )}
67
+ {...props}
68
+ />
69
+ );
70
+ }
71
+
72
+ function MessageFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
73
+ return (
74
+ <div
75
+ data-slot="message-footer"
76
+ className={cn(
77
+ 'flex max-w-full min-w-0 items-center px-[12px] text-[13px] leading-[20px] font-medium text-muted-foreground group-has-[[data-variant=ghost]]/message:px-0 group-data-[align=end]/message:justify-end',
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ );
83
+ }
84
+
85
+ export { MessageGroup, Message, MessageAvatar, MessageContent, MessageFooter, MessageHeader };
@@ -0,0 +1,29 @@
1
+ import * as React from 'react';
2
+ import { ChevronDown } from 'lucide-react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const NativeSelect = React.forwardRef<
7
+ HTMLSelectElement,
8
+ React.SelectHTMLAttributes<HTMLSelectElement>
9
+ >(({ className, children, ...props }, ref) => (
10
+ <div className="relative w-full">
11
+ <select
12
+ ref={ref}
13
+ className={cn(
14
+ 'h-[32px] w-full appearance-none rounded-[var(--pt-radius-md)] border border-input bg-transparent pl-[12px] pr-[32px] text-[13px] leading-[20px] text-foreground transition-colors enabled:hover:border-neutral focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:enabled:hover:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/30',
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ {children}
20
+ </select>
21
+ <ChevronDown
22
+ className="pointer-events-none absolute right-[10px] top-1/2 size-[16px] -translate-y-1/2 text-muted-foreground"
23
+ aria-hidden="true"
24
+ />
25
+ </div>
26
+ ));
27
+ NativeSelect.displayName = 'NativeSelect';
28
+
29
+ export { NativeSelect };
@@ -0,0 +1,120 @@
1
+ import * as React from 'react';
2
+ import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
3
+ import { cva } from 'class-variance-authority';
4
+ import { ChevronDown } from 'lucide-react';
5
+
6
+ import { cn } from '../../lib/utils';
7
+
8
+ const NavigationMenu = React.forwardRef<
9
+ React.ElementRef<typeof NavigationMenuPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
11
+ >(({ className, children, ...props }, ref) => (
12
+ <NavigationMenuPrimitive.Root
13
+ ref={ref}
14
+ className={cn('relative z-10 flex max-w-max flex-1 items-center justify-center', className)}
15
+ {...props}
16
+ >
17
+ {children}
18
+ <NavigationMenuViewport />
19
+ </NavigationMenuPrimitive.Root>
20
+ ));
21
+ NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
22
+
23
+ const NavigationMenuList = React.forwardRef<
24
+ React.ElementRef<typeof NavigationMenuPrimitive.List>,
25
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
26
+ >(({ className, ...props }, ref) => (
27
+ <NavigationMenuPrimitive.List
28
+ ref={ref}
29
+ className={cn('group flex flex-1 list-none items-center justify-center gap-[4px]', className)}
30
+ {...props}
31
+ />
32
+ ));
33
+ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
34
+
35
+ const NavigationMenuItem = NavigationMenuPrimitive.Item;
36
+
37
+ const navigationMenuTriggerStyle = cva(
38
+ 'state-layer group inline-flex h-[32px] w-max items-center justify-center rounded-[var(--pt-radius-md)] bg-background px-[16px] py-[8px] text-[14px] leading-[20px] font-medium text-foreground transition-colors focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=open]:bg-accent'
39
+ );
40
+
41
+ const NavigationMenuTrigger = React.forwardRef<
42
+ React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
43
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
44
+ >(({ className, children, ...props }, ref) => (
45
+ <NavigationMenuPrimitive.Trigger
46
+ ref={ref}
47
+ className={cn(navigationMenuTriggerStyle(), 'group', className)}
48
+ {...props}
49
+ >
50
+ {children}{' '}
51
+ <ChevronDown
52
+ className="relative top-[1px] ml-[4px] h-[12px] w-[12px] transition duration-300 group-data-[state=open]:rotate-180"
53
+ aria-hidden="true"
54
+ />
55
+ </NavigationMenuPrimitive.Trigger>
56
+ ));
57
+ NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
58
+
59
+ const NavigationMenuContent = React.forwardRef<
60
+ React.ElementRef<typeof NavigationMenuPrimitive.Content>,
61
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
62
+ >(({ className, ...props }, ref) => (
63
+ <NavigationMenuPrimitive.Content
64
+ ref={ref}
65
+ className={cn(
66
+ 'left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto',
67
+ className
68
+ )}
69
+ {...props}
70
+ />
71
+ ));
72
+ NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
73
+
74
+ const NavigationMenuLink = NavigationMenuPrimitive.Link;
75
+
76
+ const NavigationMenuViewport = React.forwardRef<
77
+ React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
78
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
79
+ >(({ className, ...props }, ref) => (
80
+ <div className={cn('absolute left-0 top-full flex justify-center')}>
81
+ <NavigationMenuPrimitive.Viewport
82
+ className={cn(
83
+ 'origin-top-center relative mt-[6px] h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-[var(--pt-radius-md)] border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]',
84
+ className
85
+ )}
86
+ ref={ref}
87
+ {...props}
88
+ />
89
+ </div>
90
+ ));
91
+ NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName;
92
+
93
+ const NavigationMenuIndicator = React.forwardRef<
94
+ React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
95
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
96
+ >(({ className, ...props }, ref) => (
97
+ <NavigationMenuPrimitive.Indicator
98
+ ref={ref}
99
+ className={cn(
100
+ 'top-full z-[1] flex h-[6px] items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in',
101
+ className
102
+ )}
103
+ {...props}
104
+ >
105
+ <div className="relative top-[60%] h-[8px] w-[8px] rotate-45 rounded-tl-[var(--pt-radius-sm)] bg-border" />
106
+ </NavigationMenuPrimitive.Indicator>
107
+ ));
108
+ NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName;
109
+
110
+ export {
111
+ navigationMenuTriggerStyle,
112
+ NavigationMenu,
113
+ NavigationMenuList,
114
+ NavigationMenuItem,
115
+ NavigationMenuContent,
116
+ NavigationMenuTrigger,
117
+ NavigationMenuLink,
118
+ NavigationMenuIndicator,
119
+ NavigationMenuViewport
120
+ };
@@ -0,0 +1,108 @@
1
+ import * as React from 'react';
2
+ import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+ import { type ButtonProps, buttonVariants } from './button';
6
+
7
+ const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
8
+ <nav
9
+ role="navigation"
10
+ aria-label="pagination"
11
+ className={cn('mx-auto flex w-full justify-center', className)}
12
+ {...props}
13
+ />
14
+ );
15
+ Pagination.displayName = 'Pagination';
16
+
17
+ const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'>>(
18
+ ({ className, ...props }, ref) => (
19
+ <ul ref={ref} className={cn('flex flex-row items-center gap-[4px]', className)} {...props} />
20
+ )
21
+ );
22
+ PaginationContent.displayName = 'PaginationContent';
23
+
24
+ const PaginationItem = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(
25
+ ({ ...props }, ref) => <li ref={ref} {...props} />
26
+ );
27
+ PaginationItem.displayName = 'PaginationItem';
28
+
29
+ type PaginationLinkProps = {
30
+ isActive?: boolean;
31
+ } & Pick<ButtonProps, 'size'> &
32
+ React.ComponentProps<'a'>;
33
+
34
+ const PaginationLink = ({ className, isActive, size = 'icon', ...props }: PaginationLinkProps) => (
35
+ <a
36
+ aria-current={isActive ? 'page' : undefined}
37
+ className={cn(
38
+ buttonVariants({
39
+ variant: isActive ? 'secondary' : 'ghost',
40
+ size
41
+ }),
42
+ className
43
+ )}
44
+ {...props}
45
+ />
46
+ );
47
+ PaginationLink.displayName = 'PaginationLink';
48
+
49
+ /* 库不做 i18n:可见文案与无障碍标签由消费方传入,默认英文(同 SearchInput 的 clearLabel) */
50
+ const PaginationPrevious = ({
51
+ className,
52
+ label = 'Previous',
53
+ ...props
54
+ }: React.ComponentProps<typeof PaginationLink> & { label?: string }) => (
55
+ <PaginationLink
56
+ aria-label={label}
57
+ size="default"
58
+ className={cn('gap-[4px] pl-[10px]', className)}
59
+ {...props}
60
+ >
61
+ <ChevronLeft className="h-[16px] w-[16px]" />
62
+ <span>{label}</span>
63
+ </PaginationLink>
64
+ );
65
+ PaginationPrevious.displayName = 'PaginationPrevious';
66
+
67
+ const PaginationNext = ({
68
+ className,
69
+ label = 'Next',
70
+ ...props
71
+ }: React.ComponentProps<typeof PaginationLink> & { label?: string }) => (
72
+ <PaginationLink
73
+ aria-label={label}
74
+ size="default"
75
+ className={cn('gap-[4px] pr-[10px]', className)}
76
+ {...props}
77
+ >
78
+ <span>{label}</span>
79
+ <ChevronRight className="h-[16px] w-[16px]" />
80
+ </PaginationLink>
81
+ );
82
+ PaginationNext.displayName = 'PaginationNext';
83
+
84
+ const PaginationEllipsis = ({
85
+ className,
86
+ label = 'More pages',
87
+ ...props
88
+ }: React.ComponentProps<'span'> & { label?: string }) => (
89
+ <span
90
+ aria-hidden
91
+ className={cn('flex h-[32px] w-[36px] items-center justify-center text-foreground', className)}
92
+ {...props}
93
+ >
94
+ <MoreHorizontal className="h-[16px] w-[16px]" />
95
+ <span className="sr-only">{label}</span>
96
+ </span>
97
+ );
98
+ PaginationEllipsis.displayName = 'PaginationEllipsis';
99
+
100
+ export {
101
+ Pagination,
102
+ PaginationContent,
103
+ PaginationLink,
104
+ PaginationItem,
105
+ PaginationPrevious,
106
+ PaginationNext,
107
+ PaginationEllipsis
108
+ };
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const Popover = PopoverPrimitive.Root;
7
+
8
+ const PopoverTrigger = PopoverPrimitive.Trigger;
9
+
10
+ const PopoverAnchor = PopoverPrimitive.Anchor;
11
+
12
+ const PopoverContent = React.forwardRef<
13
+ React.ElementRef<typeof PopoverPrimitive.Content>,
14
+ React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
15
+ >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
16
+ <PopoverPrimitive.Portal>
17
+ <PopoverPrimitive.Content
18
+ ref={ref}
19
+ align={align}
20
+ sideOffset={sideOffset}
21
+ className={cn(
22
+ 'z-[var(--pt-z-popup,50)] w-[288px] rounded-[var(--pt-radius-md)] border bg-popover p-[16px] text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
23
+ className
24
+ )}
25
+ {...props}
26
+ />
27
+ </PopoverPrimitive.Portal>
28
+ ));
29
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
30
+
31
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+ import * as ProgressPrimitive from '@radix-ui/react-progress';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const Progress = React.forwardRef<
7
+ React.ElementRef<typeof ProgressPrimitive.Root>,
8
+ React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
9
+ >(({ className, value, ...props }, ref) => (
10
+ <ProgressPrimitive.Root
11
+ ref={ref}
12
+ className={cn('relative h-[8px] w-full overflow-hidden rounded-full bg-secondary', className)}
13
+ {...props}
14
+ >
15
+ <ProgressPrimitive.Indicator
16
+ className="h-full w-full flex-1 bg-primary transition-all"
17
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
18
+ />
19
+ </ProgressPrimitive.Root>
20
+ ));
21
+ Progress.displayName = ProgressPrimitive.Root.displayName;
22
+
23
+ export { Progress };
@@ -0,0 +1,36 @@
1
+ import * as React from 'react';
2
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
3
+ import { Circle } from 'lucide-react';
4
+
5
+ import { cn } from '../../lib/utils';
6
+
7
+ const RadioGroup = React.forwardRef<
8
+ React.ElementRef<typeof RadioGroupPrimitive.Root>,
9
+ React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
10
+ >(({ className, ...props }, ref) => {
11
+ return <RadioGroupPrimitive.Root className={cn('grid gap-[8px]', className)} {...props} ref={ref} />;
12
+ });
13
+ RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
14
+
15
+ const RadioGroupItem = React.forwardRef<
16
+ React.ElementRef<typeof RadioGroupPrimitive.Item>,
17
+ React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
18
+ >(({ className, ...props }, ref) => {
19
+ return (
20
+ <RadioGroupPrimitive.Item
21
+ ref={ref}
22
+ className={cn(
23
+ 'aspect-square h-[16px] w-[16px] rounded-full border border-neutral text-primary transition-colors enabled:hover:border-strong data-[state=unchecked]:enabled:active:bg-press focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:border-weak disabled:bg-disable disabled:text-disabled enabled:data-[state=checked]:border-primary',
24
+ className
25
+ )}
26
+ {...props}
27
+ >
28
+ <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
29
+ <Circle className="h-[14px] w-[14px] fill-current" />
30
+ </RadioGroupPrimitive.Indicator>
31
+ </RadioGroupPrimitive.Item>
32
+ );
33
+ });
34
+ RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
35
+
36
+ export { RadioGroup, RadioGroupItem };
@@ -0,0 +1,40 @@
1
+ import { GripVertical } from 'lucide-react';
2
+ import * as ResizablePrimitive from 'react-resizable-panels';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const ResizablePanelGroup = ({
7
+ className,
8
+ ...props
9
+ }: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
10
+ <ResizablePrimitive.PanelGroup
11
+ className={cn('flex h-full w-full data-[panel-group-direction=vertical]:flex-col', className)}
12
+ {...props}
13
+ />
14
+ );
15
+
16
+ const ResizablePanel = ResizablePrimitive.Panel;
17
+
18
+ const ResizableHandle = ({
19
+ withHandle,
20
+ className,
21
+ ...props
22
+ }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
23
+ withHandle?: boolean;
24
+ }) => (
25
+ <ResizablePrimitive.PanelResizeHandle
26
+ className={cn(
27
+ 'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-[4px] after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-[4px] data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
28
+ className
29
+ )}
30
+ {...props}
31
+ >
32
+ {withHandle && (
33
+ <div className="z-10 flex h-[16px] w-[12px] items-center justify-center rounded-[var(--pt-radius-sm)] border bg-border">
34
+ <GripVertical className="h-[10px] w-[10px]" />
35
+ </div>
36
+ )}
37
+ </ResizablePrimitive.PanelResizeHandle>
38
+ );
39
+
40
+ export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const ScrollArea = React.forwardRef<
7
+ React.ElementRef<typeof ScrollAreaPrimitive.Root>,
8
+ React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
9
+ >(({ className, children, ...props }, ref) => (
10
+ <ScrollAreaPrimitive.Root
11
+ ref={ref}
12
+ className={cn('relative overflow-hidden', className)}
13
+ {...props}
14
+ >
15
+ <ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
16
+ {children}
17
+ </ScrollAreaPrimitive.Viewport>
18
+ <ScrollBar />
19
+ <ScrollAreaPrimitive.Corner />
20
+ </ScrollAreaPrimitive.Root>
21
+ ));
22
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
23
+
24
+ const ScrollBar = React.forwardRef<
25
+ React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
26
+ React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
27
+ >(({ className, orientation = 'vertical', ...props }, ref) => (
28
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
29
+ ref={ref}
30
+ orientation={orientation}
31
+ className={cn(
32
+ 'flex touch-none select-none transition-colors',
33
+ orientation === 'vertical' && 'h-full w-[10px] border-l border-l-transparent p-[1px]',
34
+ orientation === 'horizontal' && 'h-[10px] flex-col border-t border-t-transparent p-[1px]',
35
+ className
36
+ )}
37
+ {...props}
38
+ >
39
+ <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
40
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
41
+ ));
42
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
43
+
44
+ export { ScrollArea, ScrollBar };
@@ -0,0 +1,97 @@
1
+ import * as React from 'react';
2
+ import { Search, X } from 'lucide-react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from './input-group';
6
+
7
+ /* 三档:高 24/32/40 · 字 12/13/14 · 辅助图标 12/16/16 · 左右间距 8/10/12(带 icon 组件档) */
8
+ const SIZE_CLASSES = {
9
+ sm: 'h-[24px] px-[8px] rounded-[var(--pt-radius-sm)] [&_input]:text-[12px] [&_input]:leading-[16px]',
10
+ default: 'h-[32px] px-[10px]',
11
+ lg: 'h-[40px] px-[12px] [&_input]:text-[14px] [&_input]:leading-[20px]'
12
+ } as const;
13
+
14
+ /* 放大镜(寓意图标):16 / 16 / 20 */
15
+ const ICON_CLASSES = {
16
+ sm: '[&_svg]:size-[16px]',
17
+ default: '[&_svg]:size-[16px]',
18
+ lg: '[&_svg]:size-[20px]'
19
+ } as const;
20
+
21
+ /* 清空钮(按钮里的辅助图标):sm 12 · default 12 · lg 16;容器与按钮同值,避免跨元素层叠打架 */
22
+ const CLEAR_ADDON_CLASSES = {
23
+ sm: '[&_svg]:size-[12px]',
24
+ default: '[&_svg]:size-[12px]',
25
+ lg: '[&_svg]:size-[16px]'
26
+ } as const;
27
+
28
+ const CLEAR_BUTTON_CLASSES = {
29
+ sm: 'size-[20px] p-0 [&_svg]:size-[12px]',
30
+ default: 'size-[24px] p-0 [&_svg]:size-[12px]',
31
+ lg: 'size-[24px] p-0 [&_svg]:size-[16px]'
32
+ } as const;
33
+
34
+ export interface SearchInputProps
35
+ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type' | 'size'> {
36
+ /** 尺寸:sm 24px(行内)· default 32px(常规)· lg 36px(页面级主搜索) */
37
+ size?: keyof typeof SIZE_CLASSES;
38
+ /** 受控值 */
39
+ value: string;
40
+ /** 值变化回调(输入 / 点清空 / Esc 清空统一经由这里) */
41
+ onValueChange: (value: string) => void;
42
+ /** 清空(点 ✕ 或 Esc)后的附加回调,如重置分页 */
43
+ onClear?: () => void;
44
+ /** 清空钮的无障碍标签(库不做 i18n,消费方传译文) */
45
+ clearLabel?: string;
46
+ /** 容器 className(只用于宽度等布局) */
47
+ className?: string;
48
+ }
49
+
50
+ const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
51
+ (
52
+ { value, onValueChange, onClear, clearLabel = 'Clear', size = 'default', className, onKeyDown, disabled, ...props },
53
+ ref
54
+ ) => {
55
+ const clear = () => {
56
+ onValueChange('');
57
+ onClear?.();
58
+ };
59
+
60
+ return (
61
+ <InputGroup className={cn(SIZE_CLASSES[size], className)}>
62
+ <InputGroupAddon align="inline-start" className={ICON_CLASSES[size]}>
63
+ <Search />
64
+ </InputGroupAddon>
65
+ <InputGroupInput
66
+ ref={ref}
67
+ role="searchbox"
68
+ value={value}
69
+ disabled={disabled}
70
+ onChange={e => onValueChange(e.target.value)}
71
+ onKeyDown={e => {
72
+ if (e.key === 'Escape' && value) {
73
+ e.stopPropagation();
74
+ clear();
75
+ }
76
+ onKeyDown?.(e);
77
+ }}
78
+ {...props}
79
+ />
80
+ {value && !disabled && (
81
+ <InputGroupAddon align="inline-end" className={CLEAR_ADDON_CLASSES[size]}>
82
+ <InputGroupButton
83
+ aria-label={clearLabel}
84
+ className={CLEAR_BUTTON_CLASSES[size]}
85
+ onClick={clear}
86
+ >
87
+ <X />
88
+ </InputGroupButton>
89
+ </InputGroupAddon>
90
+ )}
91
+ </InputGroup>
92
+ );
93
+ }
94
+ );
95
+ SearchInput.displayName = 'SearchInput';
96
+
97
+ export { SearchInput };