@open-mercato/ui 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd

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 (246) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +204 -121
  3. package/dist/backend/AppShell.js +25 -28
  4. package/dist/backend/AppShell.js.map +2 -2
  5. package/dist/backend/ContextHelp.js +1 -1
  6. package/dist/backend/ContextHelp.js.map +1 -1
  7. package/dist/backend/CrudForm.js +12 -15
  8. package/dist/backend/CrudForm.js.map +2 -2
  9. package/dist/backend/DataTable.js +9 -10
  10. package/dist/backend/DataTable.js.map +2 -2
  11. package/dist/backend/FilterBar.js +6 -8
  12. package/dist/backend/FilterBar.js.map +2 -2
  13. package/dist/backend/FilterOverlay.js +10 -10
  14. package/dist/backend/FilterOverlay.js.map +2 -2
  15. package/dist/backend/FlashMessages.js +1 -1
  16. package/dist/backend/FlashMessages.js.map +2 -2
  17. package/dist/backend/JsonBuilder.js +6 -6
  18. package/dist/backend/JsonBuilder.js.map +1 -1
  19. package/dist/backend/NextStepCallout.js +1 -1
  20. package/dist/backend/NextStepCallout.js.map +1 -1
  21. package/dist/backend/PerspectiveSidebar.js +2 -2
  22. package/dist/backend/PerspectiveSidebar.js.map +2 -2
  23. package/dist/backend/ProfileDropdown.js +1 -1
  24. package/dist/backend/ProfileDropdown.js.map +1 -1
  25. package/dist/backend/RowActions.js +1 -1
  26. package/dist/backend/RowActions.js.map +1 -1
  27. package/dist/backend/UserMenu.js +2 -2
  28. package/dist/backend/UserMenu.js.map +1 -1
  29. package/dist/backend/WebhookSetupGuide.js +11 -11
  30. package/dist/backend/WebhookSetupGuide.js.map +2 -2
  31. package/dist/backend/charts/KpiCard.js +3 -3
  32. package/dist/backend/charts/KpiCard.js.map +1 -1
  33. package/dist/backend/columns/ColumnChooserPanel.js +1 -1
  34. package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
  35. package/dist/backend/custom-fields/FieldDefinitionsEditor.js +3 -3
  36. package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +2 -2
  37. package/dist/backend/dashboard/DashboardScreen.js +1 -1
  38. package/dist/backend/dashboard/DashboardScreen.js.map +1 -1
  39. package/dist/backend/date-range/DateRangeSelect.js +1 -1
  40. package/dist/backend/date-range/DateRangeSelect.js.map +1 -1
  41. package/dist/backend/date-range/InlineDateRangeSelect.js +1 -1
  42. package/dist/backend/date-range/InlineDateRangeSelect.js.map +1 -1
  43. package/dist/backend/detail/AccessDeniedMessage.js +1 -1
  44. package/dist/backend/detail/AccessDeniedMessage.js.map +1 -1
  45. package/dist/backend/detail/ActivitiesSection.js +5 -5
  46. package/dist/backend/detail/ActivitiesSection.js.map +1 -1
  47. package/dist/backend/detail/AddressEditor.js +3 -3
  48. package/dist/backend/detail/AddressEditor.js.map +2 -2
  49. package/dist/backend/detail/AddressTiles.js +3 -3
  50. package/dist/backend/detail/AddressTiles.js.map +2 -2
  51. package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
  52. package/dist/backend/detail/AttachmentMetadataDialog.js.map +1 -1
  53. package/dist/backend/detail/CustomDataSection.js +1 -1
  54. package/dist/backend/detail/CustomDataSection.js.map +1 -1
  55. package/dist/backend/detail/InlineEditors.js +5 -5
  56. package/dist/backend/detail/InlineEditors.js.map +1 -1
  57. package/dist/backend/detail/NotesSection.js +6 -6
  58. package/dist/backend/detail/NotesSection.js.map +1 -1
  59. package/dist/backend/detail/TagsSection.js +1 -1
  60. package/dist/backend/detail/TagsSection.js.map +1 -1
  61. package/dist/backend/devtools/UmesDevToolsPanel.js +6 -6
  62. package/dist/backend/devtools/UmesDevToolsPanel.js.map +2 -2
  63. package/dist/backend/devtools/components/ConflictWarnings.js +3 -3
  64. package/dist/backend/devtools/components/ConflictWarnings.js.map +2 -2
  65. package/dist/backend/devtools/components/EnricherTiming.js +2 -2
  66. package/dist/backend/devtools/components/EnricherTiming.js.map +2 -2
  67. package/dist/backend/devtools/components/EventFlow.js +5 -5
  68. package/dist/backend/devtools/components/EventFlow.js.map +2 -2
  69. package/dist/backend/devtools/components/ExtensionPointList.js +3 -3
  70. package/dist/backend/devtools/components/ExtensionPointList.js.map +2 -2
  71. package/dist/backend/devtools/components/InterceptorActivity.js +6 -6
  72. package/dist/backend/devtools/components/InterceptorActivity.js.map +2 -2
  73. package/dist/backend/forms/ActionsDropdown.js +1 -1
  74. package/dist/backend/forms/ActionsDropdown.js.map +1 -1
  75. package/dist/backend/forms/FormActionButtons.js +2 -3
  76. package/dist/backend/forms/FormActionButtons.js.map +2 -2
  77. package/dist/backend/indexes/PartialIndexBanner.js +8 -8
  78. package/dist/backend/indexes/PartialIndexBanner.js.map +2 -2
  79. package/dist/backend/inputs/ComboboxInput.js +1 -1
  80. package/dist/backend/inputs/ComboboxInput.js.map +2 -2
  81. package/dist/backend/inputs/DatePicker.js +3 -3
  82. package/dist/backend/inputs/DatePicker.js.map +1 -1
  83. package/dist/backend/inputs/DateTimePicker.js +3 -3
  84. package/dist/backend/inputs/DateTimePicker.js.map +1 -1
  85. package/dist/backend/inputs/EventSelect.js +1 -1
  86. package/dist/backend/inputs/EventSelect.js.map +2 -2
  87. package/dist/backend/inputs/LookupSelect.js +1 -1
  88. package/dist/backend/inputs/LookupSelect.js.map +1 -1
  89. package/dist/backend/inputs/SwitchableMarkdownInput.js +1 -1
  90. package/dist/backend/inputs/SwitchableMarkdownInput.js.map +1 -1
  91. package/dist/backend/inputs/TagsInput.js +2 -2
  92. package/dist/backend/inputs/TagsInput.js.map +2 -2
  93. package/dist/backend/inputs/TimeInput.js +1 -1
  94. package/dist/backend/inputs/TimeInput.js.map +1 -1
  95. package/dist/backend/inputs/TimePicker.js +3 -3
  96. package/dist/backend/inputs/TimePicker.js.map +1 -1
  97. package/dist/backend/messages/MessageObjectDetail.js +1 -1
  98. package/dist/backend/messages/MessageObjectDetail.js.map +1 -1
  99. package/dist/backend/messages/MessageObjectPreview.js +1 -1
  100. package/dist/backend/messages/MessageObjectPreview.js.map +1 -1
  101. package/dist/backend/messages/message-compose-form-groups.js +3 -3
  102. package/dist/backend/messages/message-compose-form-groups.js.map +1 -1
  103. package/dist/backend/notifications/NotificationCountBadge.js +1 -1
  104. package/dist/backend/notifications/NotificationCountBadge.js.map +2 -2
  105. package/dist/backend/notifications/NotificationPanel.js +3 -3
  106. package/dist/backend/notifications/NotificationPanel.js.map +1 -1
  107. package/dist/backend/progress/ProgressTopBar.js +4 -4
  108. package/dist/backend/progress/ProgressTopBar.js.map +2 -2
  109. package/dist/backend/schedule/ScheduleAgenda.js +1 -1
  110. package/dist/backend/schedule/ScheduleAgenda.js.map +2 -2
  111. package/dist/backend/schedule/ScheduleCalendar.js +1 -1
  112. package/dist/backend/schedule/ScheduleCalendar.js.map +1 -1
  113. package/dist/backend/schedule/ScheduleGrid.js +1 -1
  114. package/dist/backend/schedule/ScheduleGrid.js.map +2 -2
  115. package/dist/backend/version-history/VersionHistoryPanel.js +4 -4
  116. package/dist/backend/version-history/VersionHistoryPanel.js.map +2 -2
  117. package/dist/frontend/AuthFooter.js +1 -1
  118. package/dist/frontend/AuthFooter.js.map +1 -1
  119. package/dist/frontend/LanguageSwitcher.js +1 -1
  120. package/dist/frontend/LanguageSwitcher.js.map +1 -1
  121. package/dist/frontend/Layout.js +2 -2
  122. package/dist/frontend/Layout.js.map +1 -1
  123. package/dist/index.js +5 -0
  124. package/dist/index.js.map +2 -2
  125. package/dist/portal/PortalShell.js +15 -15
  126. package/dist/portal/PortalShell.js.map +2 -2
  127. package/dist/portal/components/PortalCard.js +2 -2
  128. package/dist/portal/components/PortalCard.js.map +2 -2
  129. package/dist/portal/components/PortalNotificationPanel.js +18 -18
  130. package/dist/portal/components/PortalNotificationPanel.js.map +2 -2
  131. package/dist/portal/components/PortalPageHeader.js +1 -1
  132. package/dist/portal/components/PortalPageHeader.js.map +2 -2
  133. package/dist/primitives/avatar.js +11 -1
  134. package/dist/primitives/avatar.js.map +2 -2
  135. package/dist/primitives/badge.js +1 -1
  136. package/dist/primitives/badge.js.map +1 -1
  137. package/dist/primitives/button.js +9 -5
  138. package/dist/primitives/button.js.map +2 -2
  139. package/dist/primitives/calendar.js +1 -1
  140. package/dist/primitives/calendar.js.map +1 -1
  141. package/dist/primitives/checkbox-field.js +63 -0
  142. package/dist/primitives/checkbox-field.js.map +7 -0
  143. package/dist/primitives/checkbox.js +31 -17
  144. package/dist/primitives/checkbox.js.map +2 -2
  145. package/dist/primitives/dialog.js +4 -4
  146. package/dist/primitives/dialog.js.map +1 -1
  147. package/dist/primitives/fancy-button.js +72 -0
  148. package/dist/primitives/fancy-button.js.map +7 -0
  149. package/dist/primitives/icon-button.js +20 -4
  150. package/dist/primitives/icon-button.js.map +2 -2
  151. package/dist/primitives/kbd.js +27 -0
  152. package/dist/primitives/kbd.js.map +7 -0
  153. package/dist/primitives/link-button.js +56 -0
  154. package/dist/primitives/link-button.js.map +7 -0
  155. package/dist/primitives/popover.js +1 -1
  156. package/dist/primitives/popover.js.map +1 -1
  157. package/dist/primitives/social-button.js +61 -0
  158. package/dist/primitives/social-button.js.map +7 -0
  159. package/dist/primitives/tabs.js +1 -1
  160. package/dist/primitives/tabs.js.map +1 -1
  161. package/dist/primitives/tag.js +45 -0
  162. package/dist/primitives/tag.js.map +7 -0
  163. package/dist/primitives/tooltip.js +1 -1
  164. package/dist/primitives/tooltip.js.map +1 -1
  165. package/package.json +3 -3
  166. package/src/backend/AppShell.tsx +25 -28
  167. package/src/backend/ContextHelp.tsx +1 -1
  168. package/src/backend/CrudForm.tsx +12 -15
  169. package/src/backend/DataTable.tsx +9 -10
  170. package/src/backend/FilterBar.tsx +6 -5
  171. package/src/backend/FilterOverlay.tsx +10 -10
  172. package/src/backend/FlashMessages.tsx +1 -1
  173. package/src/backend/JsonBuilder.tsx +6 -6
  174. package/src/backend/NextStepCallout.tsx +1 -1
  175. package/src/backend/PerspectiveSidebar.tsx +2 -2
  176. package/src/backend/ProfileDropdown.tsx +1 -1
  177. package/src/backend/RowActions.tsx +1 -1
  178. package/src/backend/UserMenu.tsx +2 -2
  179. package/src/backend/WebhookSetupGuide.tsx +11 -11
  180. package/src/backend/charts/KpiCard.tsx +3 -3
  181. package/src/backend/columns/ColumnChooserPanel.tsx +1 -1
  182. package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +3 -3
  183. package/src/backend/dashboard/DashboardScreen.tsx +1 -1
  184. package/src/backend/date-range/DateRangeSelect.tsx +1 -1
  185. package/src/backend/date-range/InlineDateRangeSelect.tsx +1 -1
  186. package/src/backend/detail/AccessDeniedMessage.tsx +1 -1
  187. package/src/backend/detail/ActivitiesSection.tsx +5 -5
  188. package/src/backend/detail/AddressEditor.tsx +3 -3
  189. package/src/backend/detail/AddressTiles.tsx +3 -3
  190. package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
  191. package/src/backend/detail/CustomDataSection.tsx +1 -1
  192. package/src/backend/detail/InlineEditors.tsx +5 -5
  193. package/src/backend/detail/NotesSection.tsx +6 -6
  194. package/src/backend/detail/TagsSection.tsx +1 -1
  195. package/src/backend/devtools/UmesDevToolsPanel.tsx +6 -6
  196. package/src/backend/devtools/components/ConflictWarnings.tsx +4 -4
  197. package/src/backend/devtools/components/EnricherTiming.tsx +2 -2
  198. package/src/backend/devtools/components/EventFlow.tsx +5 -5
  199. package/src/backend/devtools/components/ExtensionPointList.tsx +3 -3
  200. package/src/backend/devtools/components/InterceptorActivity.tsx +6 -6
  201. package/src/backend/forms/ActionsDropdown.tsx +1 -1
  202. package/src/backend/forms/FormActionButtons.tsx +4 -5
  203. package/src/backend/indexes/PartialIndexBanner.tsx +8 -8
  204. package/src/backend/inputs/ComboboxInput.tsx +1 -1
  205. package/src/backend/inputs/DatePicker.tsx +3 -3
  206. package/src/backend/inputs/DateTimePicker.tsx +3 -3
  207. package/src/backend/inputs/EventSelect.tsx +1 -1
  208. package/src/backend/inputs/LookupSelect.tsx +1 -1
  209. package/src/backend/inputs/SwitchableMarkdownInput.tsx +1 -1
  210. package/src/backend/inputs/TagsInput.tsx +2 -2
  211. package/src/backend/inputs/TimeInput.tsx +1 -1
  212. package/src/backend/inputs/TimePicker.tsx +3 -3
  213. package/src/backend/messages/MessageObjectDetail.tsx +1 -1
  214. package/src/backend/messages/MessageObjectPreview.tsx +1 -1
  215. package/src/backend/messages/message-compose-form-groups.tsx +3 -3
  216. package/src/backend/notifications/NotificationCountBadge.tsx +1 -1
  217. package/src/backend/notifications/NotificationPanel.tsx +3 -3
  218. package/src/backend/progress/ProgressTopBar.tsx +4 -4
  219. package/src/backend/schedule/ScheduleAgenda.tsx +1 -1
  220. package/src/backend/schedule/ScheduleCalendar.tsx +1 -1
  221. package/src/backend/schedule/ScheduleGrid.tsx +1 -1
  222. package/src/backend/version-history/VersionHistoryPanel.tsx +4 -4
  223. package/src/frontend/AuthFooter.tsx +1 -1
  224. package/src/frontend/LanguageSwitcher.tsx +1 -1
  225. package/src/frontend/Layout.tsx +2 -2
  226. package/src/index.ts +6 -1
  227. package/src/portal/PortalShell.tsx +15 -15
  228. package/src/portal/components/PortalCard.tsx +2 -2
  229. package/src/portal/components/PortalNotificationPanel.tsx +18 -18
  230. package/src/portal/components/PortalPageHeader.tsx +1 -1
  231. package/src/primitives/avatar.tsx +22 -0
  232. package/src/primitives/badge.tsx +1 -1
  233. package/src/primitives/button.tsx +12 -5
  234. package/src/primitives/calendar.tsx +1 -1
  235. package/src/primitives/checkbox-field.tsx +85 -0
  236. package/src/primitives/checkbox.tsx +44 -18
  237. package/src/primitives/dialog.tsx +4 -4
  238. package/src/primitives/fancy-button.tsx +89 -0
  239. package/src/primitives/icon-button.tsx +19 -2
  240. package/src/primitives/kbd.tsx +38 -0
  241. package/src/primitives/link-button.tsx +55 -0
  242. package/src/primitives/popover.tsx +1 -1
  243. package/src/primitives/social-button.tsx +80 -0
  244. package/src/primitives/tabs.tsx +1 -1
  245. package/src/primitives/tag.tsx +66 -0
  246. package/src/primitives/tooltip.tsx +1 -1
@@ -73,3 +73,25 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
73
73
  Avatar.displayName = 'Avatar'
74
74
 
75
75
  export { avatarVariants }
76
+
77
+ export type AvatarStackProps = {
78
+ children: React.ReactNode
79
+ max?: number
80
+ size?: VariantProps<typeof avatarVariants>['size']
81
+ className?: string
82
+ }
83
+
84
+ export function AvatarStack({ children, max = 4, size = 'md', className }: AvatarStackProps) {
85
+ const items = React.Children.toArray(children)
86
+ const visible = items.slice(0, max)
87
+ const overflow = items.length - max
88
+
89
+ return (
90
+ <div className={cn('flex items-center [&>*:not(:first-child)]:-ml-2 [&>*]:ring-2 [&>*]:ring-background', className)}>
91
+ {visible}
92
+ {overflow > 0 && (
93
+ <Avatar label={`+${overflow}`} size={size} variant="monochrome" className="-ml-2" />
94
+ )}
95
+ </div>
96
+ )
97
+ }
@@ -3,7 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
3
3
  import { cn } from '@open-mercato/shared/lib/utils'
4
4
 
5
5
  const badgeVariants = cva(
6
- 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
6
+ 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
7
7
  {
8
8
  variants: {
9
9
  variant: {
@@ -4,13 +4,19 @@ import { cva, type VariantProps } from 'class-variance-authority'
4
4
  import { cn } from '@open-mercato/shared/lib/utils'
5
5
 
6
6
  const buttonVariants = cva(
7
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
7
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none disabled:[background-image:none] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:outline-none focus-visible:shadow-focus aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
- default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
11
+ default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary-hover',
12
12
  destructive:
13
- 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
13
+ 'bg-destructive text-white shadow-xs hover:bg-destructive/90 aria-invalid:ring-destructive dark:aria-invalid:ring-destructive dark:bg-destructive/10',
14
+ 'destructive-outline':
15
+ 'border border-destructive/30 bg-background text-destructive shadow-xs hover:bg-destructive/10 dark:border-destructive/40 dark:hover:bg-destructive/15',
16
+ 'destructive-soft':
17
+ 'bg-destructive/10 text-destructive hover:bg-destructive/15 dark:bg-destructive/15 dark:hover:bg-destructive/20',
18
+ 'destructive-ghost':
19
+ 'text-destructive hover:bg-destructive/10 dark:hover:bg-destructive/15',
14
20
  outline:
15
21
  'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
16
22
  secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
@@ -20,8 +26,9 @@ const buttonVariants = cva(
20
26
  },
21
27
  size: {
22
28
  default: 'h-9 px-4 py-2 has-[>svg]:px-3',
23
- sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
24
- lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
29
+ sm: 'h-8 gap-1.5 px-3 has-[>svg]:px-2.5',
30
+ lg: 'h-10 px-6 has-[>svg]:px-4',
31
+ '2xs': 'h-7 gap-1 px-2 py-0.5 has-[>svg]:px-1.5 text-xs',
25
32
  icon: 'size-9',
26
33
  },
27
34
  },
@@ -35,7 +35,7 @@ export function Calendar({ className, classNames, showOutsideDays = true, ...pro
35
35
  ),
36
36
  month_grid: 'w-full border-collapse space-y-1',
37
37
  weekdays: 'flex',
38
- weekday: 'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
38
+ weekday: 'text-muted-foreground rounded-md w-9 font-normal text-xs',
39
39
  weeks: 'w-full border-collapse space-y-1',
40
40
  week: 'flex w-full mt-2',
41
41
  day: 'h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
@@ -0,0 +1,85 @@
1
+ import * as React from "react"
2
+ import { cn } from "@open-mercato/shared/lib/utils"
3
+ import { Checkbox, type CheckboxProps } from "./checkbox"
4
+
5
+ export type CheckboxFieldProps = Omit<CheckboxProps, "id"> & {
6
+ id?: string
7
+ label: React.ReactNode
8
+ sublabel?: React.ReactNode
9
+ description?: React.ReactNode
10
+ badge?: React.ReactNode
11
+ link?: React.ReactNode
12
+ /** When true, renders the checkbox on the right of the label content. */
13
+ flip?: boolean
14
+ /** Additional className for the outer wrapper. */
15
+ containerClassName?: string
16
+ /** Additional className for the right-side content stack. */
17
+ contentClassName?: string
18
+ }
19
+
20
+ export const CheckboxField = React.forwardRef<
21
+ React.ElementRef<typeof Checkbox>,
22
+ CheckboxFieldProps
23
+ >(({
24
+ id: idProp,
25
+ label,
26
+ sublabel,
27
+ description,
28
+ badge,
29
+ link,
30
+ flip = false,
31
+ containerClassName,
32
+ contentClassName,
33
+ size = "md",
34
+ className,
35
+ disabled,
36
+ ...checkboxProps
37
+ }, ref) => {
38
+ const reactId = React.useId()
39
+ const id = idProp ?? `checkbox-field-${reactId}`
40
+
41
+ const checkbox = (
42
+ <Checkbox
43
+ ref={ref}
44
+ id={id}
45
+ size={size}
46
+ disabled={disabled}
47
+ className={cn("mt-0.5", className)}
48
+ {...checkboxProps}
49
+ />
50
+ )
51
+
52
+ const content = (
53
+ <div className={cn("flex flex-1 min-w-0 flex-col gap-2.5", contentClassName)}>
54
+ <div className="flex flex-col gap-1">
55
+ <div className="flex flex-wrap items-center gap-1">
56
+ <label
57
+ htmlFor={id}
58
+ className={cn(
59
+ "text-sm font-medium leading-5 text-foreground select-none",
60
+ disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer"
61
+ )}
62
+ >
63
+ {label}
64
+ </label>
65
+ {sublabel ? (
66
+ <span className="text-xs leading-4 text-muted-foreground select-none">{sublabel}</span>
67
+ ) : null}
68
+ {badge ? <span className="inline-flex shrink-0">{badge}</span> : null}
69
+ </div>
70
+ {description ? (
71
+ <p className="text-xs leading-4 text-muted-foreground">{description}</p>
72
+ ) : null}
73
+ </div>
74
+ {link ? <div className="flex">{link}</div> : null}
75
+ </div>
76
+ )
77
+
78
+ return (
79
+ <div className={cn("flex items-start gap-2", flip && "flex-row-reverse", containerClassName)}>
80
+ {flip ? content : checkbox}
81
+ {flip ? checkbox : content}
82
+ </div>
83
+ )
84
+ })
85
+ CheckboxField.displayName = "CheckboxField"
@@ -1,28 +1,54 @@
1
1
  import * as React from "react"
2
2
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
3
- import { Check } from "lucide-react"
3
+ import { Check, Minus } from "lucide-react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
4
5
 
5
6
  import { cn } from "@open-mercato/shared/lib/utils"
6
7
 
8
+ const checkboxVariants = cva(
9
+ "peer shrink-0 rounded-[4px] border border-input bg-background shadow-xs ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-indigo/40 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-accent-indigo data-[state=checked]:text-accent-indigo-foreground data-[state=checked]:border-accent-indigo data-[state=indeterminate]:bg-accent-indigo data-[state=indeterminate]:text-accent-indigo-foreground data-[state=indeterminate]:border-accent-indigo hover:border-accent-indigo/60 transition-colors",
10
+ {
11
+ variants: {
12
+ size: {
13
+ sm: "size-4",
14
+ md: "size-5",
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ size: "sm",
19
+ },
20
+ }
21
+ )
22
+
23
+ const indicatorIconBySize = {
24
+ sm: "size-3.5",
25
+ md: "size-4",
26
+ } as const
27
+
28
+ export type CheckboxProps = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> &
29
+ VariantProps<typeof checkboxVariants>
30
+
7
31
  const Checkbox = React.forwardRef<
8
32
  React.ElementRef<typeof CheckboxPrimitive.Root>,
9
- React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
10
- >(({ className, ...props }, ref) => (
11
- <CheckboxPrimitive.Root
12
- ref={ref}
13
- className={cn(
14
- "peer size-4 shrink-0 rounded-sm border border-input bg-background shadow-xs ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary",
15
- className
16
- )}
17
- {...props}
18
- >
19
- <CheckboxPrimitive.Indicator
20
- className={cn("flex items-center justify-center text-current")}
33
+ CheckboxProps
34
+ >(({ className, size, ...props }, ref) => {
35
+ const iconClass = indicatorIconBySize[size ?? "sm"]
36
+ return (
37
+ <CheckboxPrimitive.Root
38
+ ref={ref}
39
+ className={cn(checkboxVariants({ size, className }))}
40
+ {...props}
21
41
  >
22
- <Check className="size-3.5" />
23
- </CheckboxPrimitive.Indicator>
24
- </CheckboxPrimitive.Root>
25
- ))
42
+ <CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}>
43
+ {props.checked === "indeterminate" ? (
44
+ <Minus className={iconClass} aria-hidden="true" />
45
+ ) : (
46
+ <Check className={iconClass} aria-hidden="true" />
47
+ )}
48
+ </CheckboxPrimitive.Indicator>
49
+ </CheckboxPrimitive.Root>
50
+ )
51
+ })
26
52
  Checkbox.displayName = CheckboxPrimitive.Root.displayName
27
53
 
28
- export { Checkbox }
54
+ export { Checkbox, checkboxVariants }
@@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
21
21
  <DialogPrimitive.Overlay
22
22
  ref={ref}
23
23
  className={cn(
24
- 'fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-opacity data-[state=open]:animate-in data-[state=closed]:animate-out',
24
+ 'fixed inset-0 z-modal bg-black/50 backdrop-blur-sm transition-opacity data-[state=open]:animate-in data-[state=closed]:animate-out',
25
25
  className
26
26
  )}
27
27
  {...props}
@@ -53,16 +53,16 @@ const DialogContent = React.forwardRef<
53
53
  ref={ref}
54
54
  data-dialog-content=""
55
55
  className={cn(
56
- 'fixed inset-x-0 bottom-0 z-50 flex min-h-[50vh] max-h-[70vh] w-full translate-x-0 translate-y-0 flex-col gap-4 overflow-y-auto rounded-t-2xl border-t bg-card p-6 shadow-lg',
56
+ 'fixed inset-x-0 bottom-0 z-modal flex min-h-[50vh] max-h-[70vh] w-full translate-x-0 translate-y-0 flex-col gap-4 overflow-y-auto rounded-t-2xl border-t bg-card p-6 shadow-lg',
57
57
  'sm:inset-auto sm:left-1/2 sm:top-1/2 sm:min-h-0 sm:h-auto sm:w-full sm:max-w-lg sm:max-h-[90vh] sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-xl sm:border',
58
- 'focus:outline-none data-[state=open]:animate-in data-[state=closed]:animate-out',
58
+ 'focus-visible:outline-none data-[state=open]:animate-in data-[state=closed]:animate-out',
59
59
  className,
60
60
  )}
61
61
  {...props}
62
62
  >
63
63
  <DialogClose
64
64
  data-dialog-close=""
65
- className="absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
65
+ className="absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
66
66
  aria-label={t('ui.dialog.close.ariaLabel', 'Close')}
67
67
  >
68
68
  <X className="h-4 w-4" />
@@ -0,0 +1,89 @@
1
+ import * as React from 'react'
2
+ import { Slot } from '@radix-ui/react-slot'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import { cn } from '@open-mercato/shared/lib/utils'
5
+
6
+ export type FancyButtonType = 'neutral' | 'basic' | 'primary' | 'destructive'
7
+
8
+ const sheenGradient =
9
+ 'linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0) 100%)'
10
+
11
+ const fancyTypeStyles: Record<
12
+ FancyButtonType,
13
+ { className: string; style: React.CSSProperties }
14
+ > = {
15
+ neutral: {
16
+ className:
17
+ 'border border-white/[0.12] text-white shadow-[0px_1px_2px_0px_rgba(27,28,29,0.48),0px_0px_0px_1px_#242628] hover:brightness-110',
18
+ style: {
19
+ backgroundImage: `${sheenGradient}, linear-gradient(90deg, #171717 0%, #171717 100%)`,
20
+ },
21
+ },
22
+ basic: {
23
+ className:
24
+ 'bg-background text-muted-foreground shadow-[0px_1px_3px_0px_rgba(14,18,27,0.12),0px_0px_0px_1px_var(--border,#ebebeb)] hover:bg-accent',
25
+ style: {},
26
+ },
27
+ primary: {
28
+ className: 'text-foreground hover:brightness-105',
29
+ style: {
30
+ backgroundImage:
31
+ 'linear-gradient(161.7deg, var(--brand-lime, #B4F372) 0%, #EEFB63 35.36%, var(--brand-violet, #BC9AFF) 70.72%)',
32
+ },
33
+ },
34
+ destructive: {
35
+ className:
36
+ 'border border-white/[0.12] text-white shadow-[0px_1px_2px_0px_rgba(14,18,27,0.24),0px_0px_0px_1px_var(--destructive,#dc2626)] hover:brightness-110',
37
+ style: {
38
+ backgroundImage: `${sheenGradient}, linear-gradient(90deg, var(--destructive, #dc2626) 0%, var(--destructive, #dc2626) 100%)`,
39
+ },
40
+ },
41
+ }
42
+
43
+ const fancyButtonVariants = cva(
44
+ "inline-flex items-center justify-center gap-1 whitespace-nowrap font-medium cursor-pointer transition-all overflow-hidden disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none disabled:[background-image:none] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-5 [&_svg]:shrink-0 outline-none focus-visible:outline-none focus-visible:shadow-focus",
45
+ {
46
+ variants: {
47
+ size: {
48
+ default: 'h-10 px-3 text-sm rounded-md',
49
+ sm: 'h-9 px-2 text-sm rounded-md',
50
+ xs: 'h-8 px-2 text-xs rounded-md',
51
+ },
52
+ },
53
+ defaultVariants: {
54
+ size: 'default',
55
+ },
56
+ }
57
+ )
58
+
59
+ export type FancyButtonProps = Omit<React.ComponentProps<'button'>, 'type'> &
60
+ VariantProps<typeof fancyButtonVariants> & {
61
+ asChild?: boolean
62
+ intent?: FancyButtonType
63
+ htmlType?: 'button' | 'submit' | 'reset'
64
+ }
65
+
66
+ export function FancyButton({
67
+ className,
68
+ size,
69
+ intent = 'neutral',
70
+ htmlType = 'button',
71
+ asChild = false,
72
+ style,
73
+ ...props
74
+ }: FancyButtonProps) {
75
+ const Comp = asChild ? Slot : 'button'
76
+ const { className: typeClassName, style: typeStyle } = fancyTypeStyles[intent]
77
+ return (
78
+ <Comp
79
+ data-slot="fancy-button"
80
+ data-fancy-intent={intent}
81
+ type={asChild ? undefined : htmlType}
82
+ className={cn(fancyButtonVariants({ size, className }), typeClassName)}
83
+ style={{ ...typeStyle, ...style }}
84
+ {...props}
85
+ />
86
+ )
87
+ }
88
+
89
+ export { fancyButtonVariants }
@@ -4,13 +4,17 @@ import { cva, type VariantProps } from 'class-variance-authority'
4
4
  import { cn } from '@open-mercato/shared/lib/utils'
5
5
 
6
6
  const iconButtonVariants = cva(
7
- "inline-flex items-center justify-center rounded-md cursor-pointer transition-all outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
7
+ "inline-flex items-center justify-center cursor-pointer transition-all outline-none disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:outline-none focus-visible:shadow-focus aria-pressed:bg-primary aria-pressed:text-primary-foreground aria-pressed:hover:bg-primary-hover",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
11
  outline:
12
12
  'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
13
13
  ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
14
+ white:
15
+ 'bg-background text-muted-foreground shadow-xs hover:bg-accent hover:text-accent-foreground',
16
+ modifiable:
17
+ 'bg-transparent text-current hover:bg-foreground/10',
14
18
  },
15
19
  size: {
16
20
  xs: 'size-6',
@@ -18,10 +22,15 @@ const iconButtonVariants = cva(
18
22
  default: 'size-8',
19
23
  lg: 'size-9',
20
24
  },
25
+ fullRadius: {
26
+ true: 'rounded-full',
27
+ false: 'rounded-md',
28
+ },
21
29
  },
22
30
  defaultVariants: {
23
31
  variant: 'outline',
24
32
  size: 'default',
33
+ fullRadius: false,
25
34
  },
26
35
  }
27
36
  )
@@ -30,12 +39,20 @@ export function IconButton({
30
39
  className,
31
40
  variant,
32
41
  size,
42
+ fullRadius,
33
43
  asChild = false,
34
44
  ...props
35
45
  }: React.ComponentProps<'button'> &
36
46
  VariantProps<typeof iconButtonVariants> & { asChild?: boolean }) {
37
47
  const Comp = asChild ? Slot : 'button'
38
- return <Comp data-slot="icon-button" type={asChild ? undefined : 'button'} className={cn(iconButtonVariants({ variant, size, className }))} {...props} />
48
+ return (
49
+ <Comp
50
+ data-slot="icon-button"
51
+ type={asChild ? undefined : 'button'}
52
+ className={cn(iconButtonVariants({ variant, size, fullRadius, className }))}
53
+ {...props}
54
+ />
55
+ )
39
56
  }
40
57
 
41
58
  export { iconButtonVariants }
@@ -0,0 +1,38 @@
1
+ import * as React from 'react'
2
+ import { cn } from '@open-mercato/shared/lib/utils'
3
+
4
+ export type KbdProps = React.HTMLAttributes<HTMLElement>
5
+
6
+ export function Kbd({ children, className, ...props }: KbdProps) {
7
+ return (
8
+ <kbd
9
+ className={cn(
10
+ 'inline-flex items-center rounded-sm border border-border bg-muted px-1.5 py-0.5 font-mono text-xs text-muted-foreground shadow-xs',
11
+ className,
12
+ )}
13
+ {...props}
14
+ >
15
+ {children}
16
+ </kbd>
17
+ )
18
+ }
19
+
20
+ export type KbdShortcutProps = {
21
+ keys: string[]
22
+ className?: string
23
+ }
24
+
25
+ export function KbdShortcut({ keys, className }: KbdShortcutProps) {
26
+ return (
27
+ <span className={cn('inline-flex items-center gap-1', className)}>
28
+ {keys.map((key, i) => (
29
+ <React.Fragment key={i}>
30
+ <Kbd>{key}</Kbd>
31
+ {i < keys.length - 1 && (
32
+ <span className="text-xs text-muted-foreground">+</span>
33
+ )}
34
+ </React.Fragment>
35
+ ))}
36
+ </span>
37
+ )
38
+ }
@@ -0,0 +1,55 @@
1
+ import * as React from 'react'
2
+ import { Slot } from '@radix-ui/react-slot'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import { cn } from '@open-mercato/shared/lib/utils'
5
+
6
+ const linkButtonVariants = cva(
7
+ 'inline-flex items-center justify-center gap-1 cursor-pointer font-medium transition-colors outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 focus-visible:underline',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ gray: 'text-muted-foreground hover:text-foreground',
12
+ black: 'text-foreground hover:text-foreground/80',
13
+ primary: 'text-primary hover:text-primary-hover',
14
+ error: 'text-destructive hover:text-destructive/80',
15
+ modifiable: 'text-current hover:opacity-80',
16
+ },
17
+ size: {
18
+ sm: 'text-xs leading-4 [&_svg:not([class*=size-])]:size-3',
19
+ default: 'text-sm leading-5 [&_svg:not([class*=size-])]:size-4',
20
+ },
21
+ underline: {
22
+ always: 'underline underline-offset-4',
23
+ hover: 'underline-offset-4 hover:underline',
24
+ none: '',
25
+ },
26
+ },
27
+ defaultVariants: {
28
+ variant: 'primary',
29
+ size: 'default',
30
+ underline: 'hover',
31
+ },
32
+ }
33
+ )
34
+
35
+ export function LinkButton({
36
+ className,
37
+ variant,
38
+ size,
39
+ underline,
40
+ asChild = false,
41
+ ...props
42
+ }: React.ComponentProps<'button'> &
43
+ VariantProps<typeof linkButtonVariants> & { asChild?: boolean }) {
44
+ const Comp = asChild ? Slot : 'button'
45
+ return (
46
+ <Comp
47
+ data-slot="link-button"
48
+ type={asChild ? undefined : 'button'}
49
+ className={cn(linkButtonVariants({ variant, size, underline, className }))}
50
+ {...props}
51
+ />
52
+ )
53
+ }
54
+
55
+ export { linkButtonVariants }
@@ -22,7 +22,7 @@ export const PopoverContent = React.forwardRef<
22
22
  align={align}
23
23
  sideOffset={sideOffset}
24
24
  className={cn(
25
- 'z-50 min-w-[280px] rounded-md border bg-popover p-0 text-popover-foreground shadow-md outline-none',
25
+ 'z-dropdown min-w-[280px] rounded-md border bg-popover p-0 text-popover-foreground shadow-md outline-none',
26
26
  'data-[state=open]:animate-in data-[state=closed]:animate-out',
27
27
  'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
28
28
  'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
@@ -0,0 +1,80 @@
1
+ import * as React from 'react'
2
+ import { Slot } from '@radix-ui/react-slot'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import { cn } from '@open-mercato/shared/lib/utils'
5
+
6
+ export type SocialBrand =
7
+ | 'apple'
8
+ | 'github'
9
+ | 'x'
10
+ | 'google'
11
+ | 'facebook'
12
+ | 'dropbox'
13
+ | 'linkedin'
14
+
15
+ const baseClasses =
16
+ "inline-flex h-10 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-5 [&_svg]:shrink-0 outline-none focus-visible:outline-none focus-visible:shadow-focus"
17
+
18
+ const filledByBrand: Record<SocialBrand, string> = {
19
+ apple: 'bg-brand-apple text-white hover:bg-brand-apple/90',
20
+ github: 'bg-brand-github text-white hover:bg-brand-github/90',
21
+ x: 'bg-brand-x text-white hover:bg-brand-x/90',
22
+ google: 'bg-background text-foreground border border-brand-google-stroke hover:bg-accent',
23
+ facebook: 'bg-brand-facebook text-white hover:bg-brand-facebook/90',
24
+ dropbox: 'bg-brand-dropbox text-white hover:bg-brand-dropbox/90',
25
+ linkedin: 'bg-brand-linkedin text-white hover:bg-brand-linkedin/90',
26
+ }
27
+
28
+ const strokeByBrand: Record<SocialBrand, string> = {
29
+ apple: 'bg-background text-brand-apple border border-brand-apple/30 hover:bg-brand-apple/5',
30
+ github: 'bg-background text-brand-github border border-brand-github/30 hover:bg-brand-github/5',
31
+ x: 'bg-background text-brand-x border border-brand-x/30 hover:bg-brand-x/5',
32
+ google: 'bg-background text-foreground border border-brand-google-stroke hover:bg-accent',
33
+ facebook: 'bg-background text-brand-facebook border border-brand-facebook/40 hover:bg-brand-facebook/5',
34
+ dropbox: 'bg-background text-brand-dropbox border border-brand-dropbox/40 hover:bg-brand-dropbox/5',
35
+ linkedin: 'bg-background text-brand-linkedin border border-brand-linkedin/40 hover:bg-brand-linkedin/5',
36
+ }
37
+
38
+ const socialButtonVariants = cva(baseClasses, {
39
+ variants: {
40
+ iconOnly: {
41
+ true: 'w-10 px-0',
42
+ false: 'px-4',
43
+ },
44
+ },
45
+ defaultVariants: {
46
+ iconOnly: false,
47
+ },
48
+ })
49
+
50
+ export type SocialButtonProps = React.ComponentProps<'button'> &
51
+ VariantProps<typeof socialButtonVariants> & {
52
+ asChild?: boolean
53
+ brand: SocialBrand
54
+ /** Visual treatment of the button. Renamed from `style` to avoid shadowing the native HTML/React `style` (CSSProperties) attribute. */
55
+ appearance?: 'filled' | 'stroke'
56
+ }
57
+
58
+ export function SocialButton({
59
+ className,
60
+ brand,
61
+ appearance = 'filled',
62
+ iconOnly,
63
+ asChild = false,
64
+ ...props
65
+ }: SocialButtonProps) {
66
+ const Comp = asChild ? Slot : 'button'
67
+ const brandClasses = appearance === 'stroke' ? strokeByBrand[brand] : filledByBrand[brand]
68
+ return (
69
+ <Comp
70
+ data-slot="social-button"
71
+ data-brand={brand}
72
+ data-appearance={appearance}
73
+ type={asChild ? undefined : 'button'}
74
+ className={cn(socialButtonVariants({ iconOnly, className }), brandClasses)}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ export { socialButtonVariants }
@@ -103,7 +103,7 @@ export function TabsTrigger({ value, children, className, disabled }: TabsTrigge
103
103
  className={cn(
104
104
  isSelected
105
105
  ? 'bg-background text-foreground shadow'
106
- : 'hover:bg-background/50 hover:text-foreground',
106
+ : 'hover:bg-background/80 hover:text-foreground',
107
107
  className,
108
108
  )}
109
109
  >