@open-mercato/ui 0.6.4-develop.4199.1.86677441c2 → 0.6.4-develop.4210.1.d412061cfe
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.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +14 -0
- package/dist/backend/DataTable.js +28 -62
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
- package/dist/backend/detail/AttachmentMetadataDialog.js.map +2 -2
- package/dist/primitives/activity-feed.js +196 -0
- package/dist/primitives/activity-feed.js.map +7 -0
- package/dist/primitives/avatar.js +140 -14
- package/dist/primitives/avatar.js.map +3 -3
- package/dist/primitives/badge.js +94 -5
- package/dist/primitives/badge.js.map +2 -2
- package/dist/primitives/button-group.js +52 -0
- package/dist/primitives/button-group.js.map +7 -0
- package/dist/primitives/color-picker.js +520 -0
- package/dist/primitives/color-picker.js.map +7 -0
- package/dist/primitives/command-menu.js +355 -0
- package/dist/primitives/command-menu.js.map +7 -0
- package/dist/primitives/dialog.js +210 -35
- package/dist/primitives/dialog.js.map +2 -2
- package/dist/primitives/drawer.js +219 -0
- package/dist/primitives/drawer.js.map +7 -0
- package/dist/primitives/notification-feed.js +213 -0
- package/dist/primitives/notification-feed.js.map +7 -0
- package/dist/primitives/notification.js +23 -2
- package/dist/primitives/notification.js.map +2 -2
- package/dist/primitives/pagination.js +245 -0
- package/dist/primitives/pagination.js.map +7 -0
- package/dist/primitives/progress.js +178 -5
- package/dist/primitives/progress.js.map +2 -2
- package/dist/primitives/rating.js +174 -0
- package/dist/primitives/rating.js.map +7 -0
- package/dist/primitives/scroll-area.js +82 -0
- package/dist/primitives/scroll-area.js.map +7 -0
- package/dist/primitives/segmented-control.js +101 -0
- package/dist/primitives/segmented-control.js.map +7 -0
- package/dist/primitives/separator.js +103 -4
- package/dist/primitives/separator.js.map +2 -2
- package/dist/primitives/slider.js +115 -0
- package/dist/primitives/slider.js.map +7 -0
- package/dist/primitives/step-indicator.js +187 -0
- package/dist/primitives/step-indicator.js.map +7 -0
- package/dist/primitives/table.js +102 -10
- package/dist/primitives/table.js.map +2 -2
- package/dist/primitives/tabs.js +122 -14
- package/dist/primitives/tabs.js.map +2 -2
- package/dist/primitives/time-picker.js +9 -11
- package/dist/primitives/time-picker.js.map +2 -2
- package/package.json +8 -4
- package/src/backend/DataTable.tsx +43 -60
- package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
- package/src/primitives/__tests__/activity-feed.test.tsx +216 -0
- package/src/primitives/__tests__/avatar.test.tsx +131 -0
- package/src/primitives/__tests__/badge.test.tsx +189 -0
- package/src/primitives/__tests__/button-group.test.tsx +117 -0
- package/src/primitives/__tests__/color-picker.test.tsx +589 -0
- package/src/primitives/__tests__/command-menu.test.tsx +231 -0
- package/src/primitives/__tests__/dialog.test.tsx +290 -0
- package/src/primitives/__tests__/drawer.test.tsx +264 -0
- package/src/primitives/__tests__/notification-feed.test.tsx +303 -0
- package/src/primitives/__tests__/notification.test.tsx +102 -2
- package/src/primitives/__tests__/pagination.test.tsx +268 -0
- package/src/primitives/__tests__/progress.test.tsx +222 -0
- package/src/primitives/__tests__/rating.test.tsx +164 -0
- package/src/primitives/__tests__/scroll-area.test.tsx +109 -0
- package/src/primitives/__tests__/segmented-control.test.tsx +129 -0
- package/src/primitives/__tests__/separator.test.tsx +143 -0
- package/src/primitives/__tests__/slider.test.tsx +86 -0
- package/src/primitives/__tests__/step-indicator.test.tsx +205 -0
- package/src/primitives/__tests__/table.test.tsx +199 -0
- package/src/primitives/__tests__/tabs.test.tsx +139 -0
- package/src/primitives/activity-feed.tsx +326 -0
- package/src/primitives/avatar.tsx +225 -22
- package/src/primitives/badge.tsx +141 -6
- package/src/primitives/button-group.tsx +100 -0
- package/src/primitives/color-picker.tsx +693 -0
- package/src/primitives/command-menu.tsx +503 -0
- package/src/primitives/dialog.tsx +315 -51
- package/src/primitives/drawer.tsx +338 -0
- package/src/primitives/notification-feed.tsx +358 -0
- package/src/primitives/notification.tsx +42 -2
- package/src/primitives/pagination.tsx +376 -0
- package/src/primitives/progress.tsx +267 -6
- package/src/primitives/rating.tsx +245 -0
- package/src/primitives/scroll-area.tsx +169 -0
- package/src/primitives/segmented-control.tsx +162 -0
- package/src/primitives/separator.tsx +163 -3
- package/src/primitives/slider.tsx +160 -0
- package/src/primitives/step-indicator.tsx +287 -0
- package/src/primitives/table.tsx +142 -11
- package/src/primitives/tabs.tsx +174 -12
- package/src/primitives/time-picker.tsx +9 -11
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/primitives/avatar.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nconst avatarVariants = cva(\n 'inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full font-semibold select-none',\n {\n variants: {\n size: {\n xs: 'size-5 text-xs',\n sm: 'size-7 text-xs',\n md: 'size-9 text-sm',\n lg: 'size-12 text-base',\n xl: 'size-16 text-xl',\n },\n variant: {\n default: 'bg-primary/10 text-primary',\n monochrome: 'bg-muted text-muted-foreground',\n },\n },\n defaultVariants: {\n size: 'md',\n variant: 'default',\n },\n },\n)\n\nfunction computeInitials(label: string): string {\n const trimmed = label.trim()\n if (!trimmed.length) return '?'\n const parts = trimmed.split(/\\s+/).filter(Boolean)\n if (parts.length === 1) {\n return parts[0].slice(0, 2).toUpperCase()\n }\n const first = parts[0][0] ?? ''\n const last = parts[parts.length - 1][0] ?? ''\n return (first + last).toUpperCase()\n}\n\nexport type AvatarProps = {\n label: string\n src?: string | null\n icon?: React.ReactNode\n ariaLabel?: string\n} & VariantProps<typeof avatarVariants> &\n Omit<React.HTMLAttributes<HTMLDivElement>, 'role' | 'aria-label'>\n\nexport const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(\n ({ className, label, src, icon, size, variant, ariaLabel, ...rest }, ref) => {\n const initials = React.useMemo(() => computeInitials(label), [label])\n return (\n <div\n ref={ref}\n role=\"img\"\n aria-label={ariaLabel ?? label}\n className={cn(avatarVariants({ size, variant }), className)}\n {...rest}\n >\n {src ? (\n <img src={src} alt=\"\" className=\"size-full object-cover\" aria-hidden=\"true\" />\n ) : icon ? (\n <span aria-hidden=\"true\" className=\"flex items-center justify-center [&>svg]:size-[55%]\">\n {icon}\n </span>\n ) : (\n <span aria-hidden=\"true\">{initials}</span>\n )}\n </div>\n )\n },\n)\n\nAvatar.displayName = 'Avatar'\n\nexport { avatarVariants }\n\nexport type AvatarStackProps = {\n children: React.ReactNode\n max?: number\n size?: VariantProps<typeof avatarVariants>['size']\n className?: string\n}\n\nexport function AvatarStack({ children, max = 4, size = 'md', className }: AvatarStackProps) {\n const items = React.Children.toArray(children)\n const visible = items.slice(0, max)\n const overflow = items.length - max\n\n return (\n <div className={cn('flex items-center [&>*:not(:first-child)]:-ml-2 [&>*]:ring-2 [&>*]:ring-background', className)}>\n {visible}\n {overflow > 0 && (\n <Avatar label={`+${overflow}`} size={size} variant=\"monochrome\" className=\"-ml-2\" />\n )}\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\n\n/**\n * User / entity avatar with auto-generated initials, optional photo,\n * optional icon override, optional **status indicator** (online/away/\n * busy/away dot per Figma `Bottom Status [1.1]`), optional **badge**\n * slot for top-right affordances (verified check, premium icon, X to\n * remove \u2014 per Figma `Top Status [1.1]`), and optional outer **ring**\n * (accent / status-colored).\n *\n * Phase B.4 rewrite per Figma `Avatars` page (`210:4129`):\n * - `Avatar [1.1]` (`245:18786`)\n * - `Bottom Status [1.1]` (`245:18721`) \u2014 5 dot tones\n * - `Top Status [1.1]` (`245:18697`) \u2014 6 icon-badge variants\n * - `Avatar Group [1.1]` (`581:6198`) + `Compact Avatar Group [1.1]`\n * (`2906:14962`) \u2014 see `AvatarStack`.\n *\n * Backward compatibility (5 import sites \u2014 customers linking\n * adapters + LinkEntityDialog + ds-v5 demo): existing\n * `<Avatar src label size variant icon />` API stays callable\n * verbatim. New optional props (`status`, `statusPosition`, `ring`,\n * `badge`, `badgeClassName`) are additive.\n */\n\nconst avatarVariants = cva(\n 'inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full font-semibold select-none',\n {\n variants: {\n size: {\n xs: 'size-5 text-xs',\n sm: 'size-7 text-xs',\n md: 'size-9 text-sm',\n lg: 'size-12 text-base',\n xl: 'size-16 text-xl',\n },\n variant: {\n default: 'bg-primary/10 text-primary',\n monochrome: 'bg-muted text-muted-foreground',\n },\n },\n defaultVariants: {\n size: 'md',\n variant: 'default',\n },\n },\n)\n\nfunction computeInitials(label: string): string {\n const trimmed = label.trim()\n if (!trimmed.length) return '?'\n const parts = trimmed.split(/\\s+/).filter(Boolean)\n if (parts.length === 1) {\n return parts[0].slice(0, 2).toUpperCase()\n }\n const first = parts[0][0] ?? ''\n const last = parts[parts.length - 1][0] ?? ''\n return (first + last).toUpperCase()\n}\n\n// Status tone \u2192 background color class. Surface stays opaque + ringed\n// by the page background (`ring-background`) so the badge reads as\n// an overlay on top of the avatar circle.\nexport type AvatarStatus =\n | 'online'\n | 'offline'\n | 'busy'\n | 'away'\n | 'success'\n | 'warning'\n | 'error'\n | 'info'\n\nconst AVATAR_STATUS_BG: Record<AvatarStatus, string> = {\n online: 'bg-status-success-icon',\n offline: 'bg-muted-foreground',\n busy: 'bg-status-error-icon',\n away: 'bg-status-warning-icon',\n success: 'bg-status-success-icon',\n warning: 'bg-status-warning-icon',\n error: 'bg-status-error-icon',\n info: 'bg-status-info-icon',\n}\n\n// Status dot size per avatar size \u2014 slightly less than 1/3 of the\n// avatar diameter so the dot reads but doesn't overpower.\nconst AVATAR_STATUS_SIZE: Record<NonNullable<VariantProps<typeof avatarVariants>['size']>, string> = {\n xs: 'size-1.5',\n sm: 'size-2',\n md: 'size-2.5',\n lg: 'size-3',\n xl: 'size-4',\n}\n\n// Outer ring tones (story-style highlight, selected, status outline).\nexport type AvatarRingTone = 'accent' | 'success' | 'warning' | 'error' | 'muted'\n\nconst AVATAR_RING_CLASS: Record<AvatarRingTone, string> = {\n accent: 'ring-2 ring-accent-indigo ring-offset-2 ring-offset-background',\n success: 'ring-2 ring-status-success-icon ring-offset-2 ring-offset-background',\n warning: 'ring-2 ring-status-warning-icon ring-offset-2 ring-offset-background',\n error: 'ring-2 ring-status-error-icon ring-offset-2 ring-offset-background',\n muted: 'ring-2 ring-input ring-offset-2 ring-offset-background',\n}\n\nexport type AvatarProps = {\n label: string\n src?: string | null\n icon?: React.ReactNode\n ariaLabel?: string\n /** Bottom-right (default) or top-right status dot. */\n status?: AvatarStatus\n /** Where the status dot sits. @default 'bottom-right' */\n statusPosition?: 'bottom-right' | 'top-right'\n /** Outer ring affordance \u2014 pass `true` for accent (alias for\n * `'accent'`) or a specific tone. */\n ring?: boolean | AvatarRingTone\n /** Custom top-right badge slot \u2014 overrides `status` when both are\n * set with `statusPosition='top-right'`. Use for verified check\n * icons, premium markers, \"X to remove\" affordances per Figma\n * `Top Status [1.1]`. The badge content is rendered inside a\n * `rounded-full ring-2 ring-background` shell sized relative to\n * the avatar \u2014 pass a simple icon (`<Check className=\"size-3\" />`)\n * for the cleanest look. */\n badge?: React.ReactNode\n /** Override the badge wrapper className (size, bg, etc.). */\n badgeClassName?: string\n} & VariantProps<typeof avatarVariants> &\n Omit<React.HTMLAttributes<HTMLDivElement>, 'role' | 'aria-label'>\n\ntype AvatarCircleProps = Omit<\n AvatarProps,\n 'status' | 'statusPosition' | 'ring' | 'badge' | 'badgeClassName'\n> & {\n className?: string\n}\n\n// Inner div (the actual avatar circle). Implemented as forwardRef so\n// the outer Avatar wrapper can forward refs through to the rendered\n// `<div role=\"img\">` regardless of whether it lives directly inside\n// Avatar or inside the decorated `<span data-slot=\"avatar-root\">`\n// wrapper.\nconst AvatarCircle = React.forwardRef<HTMLDivElement, AvatarCircleProps>(function AvatarCircle(\n { className, label, src, icon, size, variant, ariaLabel, ...rest },\n ref,\n) {\n const initials = React.useMemo(() => computeInitials(label), [label])\n return (\n <div\n ref={ref}\n role=\"img\"\n aria-label={ariaLabel ?? label}\n data-slot=\"avatar\"\n className={cn(avatarVariants({ size, variant }), className)}\n {...rest}\n >\n {src ? (\n <img src={src} alt=\"\" className=\"size-full object-cover\" aria-hidden=\"true\" />\n ) : icon ? (\n <span aria-hidden=\"true\" className=\"flex items-center justify-center [&>svg]:size-[55%]\">\n {icon}\n </span>\n ) : (\n <span aria-hidden=\"true\">{initials}</span>\n )}\n </div>\n )\n})\n\nexport const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>((props, ref) => {\n const {\n className,\n label,\n src,\n icon,\n size = 'md',\n variant,\n ariaLabel,\n status,\n statusPosition = 'bottom-right',\n ring,\n badge,\n badgeClassName,\n ...rest\n } = props\n\n const resolvedRingTone: AvatarRingTone | null = ring === true ? 'accent' : ring || null\n const showStatus = status !== undefined\n const showBadge =\n badge !== undefined && (statusPosition === 'top-right' || !showStatus)\n const showTopStatus = showStatus && statusPosition === 'top-right' && !showBadge\n const showBottomStatus = showStatus && statusPosition === 'bottom-right' && badge === undefined\n\n // Plain avatar (no overlay decorations) \u2014 preserve the original\n // single-element output for backward compat.\n if (!showStatus && !showBadge && !resolvedRingTone) {\n return (\n <AvatarCircle\n ref={ref as React.Ref<HTMLDivElement>}\n className={className}\n label={label}\n src={src}\n icon={icon}\n size={size}\n variant={variant}\n ariaLabel={ariaLabel}\n {...rest}\n />\n )\n }\n\n const ringClass = resolvedRingTone ? AVATAR_RING_CLASS[resolvedRingTone] : ''\n const statusSize = AVATAR_STATUS_SIZE[size ?? 'md']\n const statusPositionClass =\n statusPosition === 'top-right'\n ? '-right-0 -top-0 translate-x-1/4 -translate-y-1/4'\n : '-right-0 -bottom-0 translate-x-1/4 translate-y-1/4'\n const badgePositionClass = '-right-0 -top-0 translate-x-1/4 -translate-y-1/4'\n\n return (\n <span\n data-slot=\"avatar-root\"\n className={cn('relative inline-flex shrink-0 rounded-full', ringClass)}\n >\n <AvatarCircle\n ref={ref as React.Ref<HTMLDivElement>}\n className={className}\n label={label}\n src={src}\n icon={icon}\n size={size}\n variant={variant}\n ariaLabel={ariaLabel}\n {...rest}\n />\n {showBottomStatus || showTopStatus ? (\n <span\n data-slot=\"avatar-status\"\n data-status={status}\n data-position={statusPosition}\n aria-hidden=\"true\"\n className={cn(\n 'absolute inline-block rounded-full ring-2 ring-background',\n statusSize,\n AVATAR_STATUS_BG[status as AvatarStatus],\n statusPositionClass,\n )}\n />\n ) : null}\n {showBadge ? (\n <span\n data-slot=\"avatar-badge\"\n aria-hidden=\"true\"\n className={cn(\n 'absolute inline-flex items-center justify-center rounded-full ring-2 ring-background bg-background text-foreground',\n // Default size ~40% of avatar; consumer overrides via badgeClassName.\n size === 'xs' || size === 'sm' ? 'size-3.5' : size === 'md' ? 'size-4' : size === 'lg' ? 'size-5' : 'size-6',\n badgePositionClass,\n badgeClassName,\n )}\n >\n {badge}\n </span>\n ) : null}\n </span>\n )\n})\n\nAvatar.displayName = 'Avatar'\n\nexport { avatarVariants }\n\nexport type AvatarStackProps = {\n children: React.ReactNode\n max?: number\n size?: VariantProps<typeof avatarVariants>['size']\n className?: string\n}\n\nexport function AvatarStack({ children, max = 4, size = 'md', className }: AvatarStackProps) {\n const items = React.Children.toArray(children)\n const visible = items.slice(0, max)\n const overflow = items.length - max\n\n return (\n <div\n data-slot=\"avatar-stack\"\n className={cn('flex items-center [&>*:not(:first-child)]:-ml-2 [&>*]:ring-2 [&>*]:ring-background', className)}\n >\n {visible}\n {overflow > 0 && (\n <Avatar label={`+${overflow}`} size={size} variant=\"monochrome\" className=\"-ml-2\" />\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["AvatarCircle"]
|
|
7
7
|
}
|
package/dist/primitives/badge.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
3
|
import * as React from "react";
|
|
4
|
+
import { X } from "lucide-react";
|
|
3
5
|
import { cva } from "class-variance-authority";
|
|
4
6
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
5
7
|
const badgeVariants = cva(
|
|
6
|
-
"inline-flex items-center rounded-full border
|
|
8
|
+
"inline-flex items-center gap-1 rounded-full border font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
7
9
|
{
|
|
8
10
|
variants: {
|
|
9
11
|
variant: {
|
|
10
12
|
default: "border-transparent bg-primary text-primary-foreground shadow",
|
|
11
13
|
secondary: "border-transparent bg-secondary text-secondary-foreground",
|
|
14
|
+
// Kept verbatim from the base contract — BC guarantee in spec
|
|
15
|
+
// 2026-05-13-ds-foundation-v5.md mandates existing variants must
|
|
16
|
+
// render byte-identically. For the soft error-toned look, use
|
|
17
|
+
// the new `error` variant below.
|
|
12
18
|
destructive: "border-transparent bg-destructive text-destructive-foreground shadow",
|
|
13
19
|
outline: "text-foreground",
|
|
14
20
|
muted: "border-transparent bg-muted text-muted-foreground",
|
|
@@ -16,15 +22,98 @@ const badgeVariants = cva(
|
|
|
16
22
|
warning: "border-status-warning-border bg-status-warning-bg text-status-warning-text",
|
|
17
23
|
info: "border-status-info-border bg-status-info-bg text-status-info-text",
|
|
18
24
|
neutral: "border-status-neutral-border bg-status-neutral-bg text-status-neutral-text",
|
|
19
|
-
error: "border-status-error-border bg-status-error-bg text-status-error-text"
|
|
25
|
+
error: "border-status-error-border bg-status-error-bg text-status-error-text",
|
|
26
|
+
// Phase B.8 addition — brand-violet tinted pill for custom
|
|
27
|
+
// views / renewal tags. Mirrors `Tag` brand variant.
|
|
28
|
+
brand: "border-brand-violet/30 bg-brand-violet/10 text-brand-violet"
|
|
29
|
+
},
|
|
30
|
+
size: {
|
|
31
|
+
sm: "px-2 py-0.5 text-[10px]",
|
|
32
|
+
default: "px-2.5 py-0.5 text-xs",
|
|
33
|
+
lg: "px-3 py-1 text-sm"
|
|
20
34
|
}
|
|
21
35
|
},
|
|
22
36
|
defaultVariants: {
|
|
23
|
-
variant: "default"
|
|
37
|
+
variant: "default",
|
|
38
|
+
size: "default"
|
|
24
39
|
}
|
|
25
40
|
}
|
|
26
41
|
);
|
|
27
|
-
const
|
|
42
|
+
const BADGE_DOT_TONE = {
|
|
43
|
+
default: "bg-primary-foreground",
|
|
44
|
+
secondary: "bg-secondary-foreground",
|
|
45
|
+
destructive: "bg-status-error-icon",
|
|
46
|
+
outline: "bg-foreground",
|
|
47
|
+
muted: "bg-muted-foreground",
|
|
48
|
+
success: "bg-status-success-icon",
|
|
49
|
+
warning: "bg-status-warning-icon",
|
|
50
|
+
info: "bg-status-info-icon",
|
|
51
|
+
neutral: "bg-muted-foreground",
|
|
52
|
+
error: "bg-status-error-icon",
|
|
53
|
+
brand: "bg-brand-violet"
|
|
54
|
+
};
|
|
55
|
+
const BADGE_DOT_SIZE = {
|
|
56
|
+
sm: "size-1.5",
|
|
57
|
+
default: "size-1.5",
|
|
58
|
+
lg: "size-2"
|
|
59
|
+
};
|
|
60
|
+
const Badge = React.forwardRef(
|
|
61
|
+
({
|
|
62
|
+
className,
|
|
63
|
+
variant,
|
|
64
|
+
size,
|
|
65
|
+
dot = false,
|
|
66
|
+
removable = false,
|
|
67
|
+
onRemove,
|
|
68
|
+
removeAriaLabel = "Remove",
|
|
69
|
+
children,
|
|
70
|
+
...props
|
|
71
|
+
}, ref) => {
|
|
72
|
+
const resolvedVariant = variant ?? "default";
|
|
73
|
+
const resolvedSize = size ?? "default";
|
|
74
|
+
return /* @__PURE__ */ jsxs(
|
|
75
|
+
"div",
|
|
76
|
+
{
|
|
77
|
+
ref,
|
|
78
|
+
"data-slot": "badge",
|
|
79
|
+
"data-variant": resolvedVariant,
|
|
80
|
+
"data-size": resolvedSize,
|
|
81
|
+
className: cn(badgeVariants({ variant, size }), className),
|
|
82
|
+
...props,
|
|
83
|
+
children: [
|
|
84
|
+
dot ? /* @__PURE__ */ jsx(
|
|
85
|
+
"span",
|
|
86
|
+
{
|
|
87
|
+
"data-slot": "badge-dot",
|
|
88
|
+
"aria-hidden": "true",
|
|
89
|
+
className: cn(
|
|
90
|
+
"inline-block shrink-0 rounded-full",
|
|
91
|
+
BADGE_DOT_SIZE[resolvedSize],
|
|
92
|
+
BADGE_DOT_TONE[resolvedVariant]
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
) : null,
|
|
96
|
+
children,
|
|
97
|
+
removable ? /* @__PURE__ */ jsx(
|
|
98
|
+
"button",
|
|
99
|
+
{
|
|
100
|
+
type: "button",
|
|
101
|
+
"data-slot": "badge-remove",
|
|
102
|
+
"aria-label": removeAriaLabel,
|
|
103
|
+
onClick: onRemove,
|
|
104
|
+
className: cn(
|
|
105
|
+
"-mr-0.5 ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full outline-none transition-opacity",
|
|
106
|
+
"opacity-70 hover:opacity-100 focus-visible:opacity-100",
|
|
107
|
+
resolvedSize === "lg" ? "size-4" : "size-3.5"
|
|
108
|
+
),
|
|
109
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: resolvedSize === "lg" ? "size-3" : "size-2.5" })
|
|
110
|
+
}
|
|
111
|
+
) : null
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
);
|
|
28
117
|
Badge.displayName = "Badge";
|
|
29
118
|
export {
|
|
30
119
|
Badge,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/primitives/badge.tsx"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { X } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\n\n/**\n * Status / category pill primitive. Phase B.8 rewrite per Figma\n * `Badge` page (`119:2863`) \u2014 `Badge [1.1]` (`118:2324`, color + size\n * matrix) and `Status Badge [1.1]` (`171:5100`, semantic-colored\n * status pills).\n *\n * Backward compatibility (83 import sites \u2014 biggest cascade in v5):\n * - The complete `variant` union (`default | secondary | destructive\n * | outline | muted | success | warning | info | neutral | error`)\n * stays callable verbatim.\n * - Every existing import-site renders identically \u2014 no padding\n * bump, no font-weight delta, no color change.\n * - `className` passthrough works for every variant.\n *\n * New (additive):\n * - `size: 'sm' | 'default' | 'lg'` \u2014 text-xs / text-xs / text-sm\n * typography ladder with matching px/py padding.\n * - `dot: boolean` \u2014 leading 6px dot in the variant's accent color\n * (status-style \"\u25CF Active\" pattern per Figma).\n * - `removable: boolean` + `onRemove` \u2014 trailing X icon-button for\n * tag-style dismissible badges.\n * - `brand` variant \u2014 brand-violet/10 tint per `Tag` brand variant\n * (kept distinct from generic info / neutral \u2014 used for renewal\n * tags, custom views).\n */\n\nconst badgeVariants = cva(\n 'inline-flex items-center gap-1 rounded-full border font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n {\n variants: {\n variant: {\n default: 'border-transparent bg-primary text-primary-foreground shadow',\n secondary: 'border-transparent bg-secondary text-secondary-foreground',\n // Kept verbatim from the base contract \u2014 BC guarantee in spec\n // 2026-05-13-ds-foundation-v5.md mandates existing variants must\n // render byte-identically. For the soft error-toned look, use\n // the new `error` variant below.\n destructive: 'border-transparent bg-destructive text-destructive-foreground shadow',\n outline: 'text-foreground',\n muted: 'border-transparent bg-muted text-muted-foreground',\n success: 'border-status-success-border bg-status-success-bg text-status-success-text',\n warning: 'border-status-warning-border bg-status-warning-bg text-status-warning-text',\n info: 'border-status-info-border bg-status-info-bg text-status-info-text',\n neutral: 'border-status-neutral-border bg-status-neutral-bg text-status-neutral-text',\n error: 'border-status-error-border bg-status-error-bg text-status-error-text',\n // Phase B.8 addition \u2014 brand-violet tinted pill for custom\n // views / renewal tags. Mirrors `Tag` brand variant.\n brand: 'border-brand-violet/30 bg-brand-violet/10 text-brand-violet',\n },\n size: {\n sm: 'px-2 py-0.5 text-[10px]',\n default: 'px-2.5 py-0.5 text-xs',\n lg: 'px-3 py-1 text-sm',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\n// Leading-dot tone per variant. Uses the icon-color end of the status\n// token palette so the dot reads against the soft tinted background.\nconst BADGE_DOT_TONE: Record<NonNullable<VariantProps<typeof badgeVariants>['variant']>, string> = {\n default: 'bg-primary-foreground',\n secondary: 'bg-secondary-foreground',\n destructive: 'bg-status-error-icon',\n outline: 'bg-foreground',\n muted: 'bg-muted-foreground',\n success: 'bg-status-success-icon',\n warning: 'bg-status-warning-icon',\n info: 'bg-status-info-icon',\n neutral: 'bg-muted-foreground',\n error: 'bg-status-error-icon',\n brand: 'bg-brand-violet',\n}\n\n// Leading-dot size per badge size.\nconst BADGE_DOT_SIZE: Record<NonNullable<VariantProps<typeof badgeVariants>['size']>, string> = {\n sm: 'size-1.5',\n default: 'size-1.5',\n lg: 'size-2',\n}\n\nexport type BadgeVariant = NonNullable<VariantProps<typeof badgeVariants>['variant']>\nexport type BadgeSize = NonNullable<VariantProps<typeof badgeVariants>['size']>\n\nexport type BadgeProps = React.HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof badgeVariants> & {\n /** Leading status dot in the variant's accent tone. */\n dot?: boolean\n /** Trailing X icon-button for tag-style dismissible badges.\n * Renders only when `removable` is true. */\n removable?: boolean\n /** Click handler for the remove button. Required when `removable`\n * is true. */\n onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void\n /** Accessible label for the remove button. Default `'Remove'`. */\n removeAriaLabel?: string\n }\n\nexport const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(\n (\n {\n className,\n variant,\n size,\n dot = false,\n removable = false,\n onRemove,\n removeAriaLabel = 'Remove',\n children,\n ...props\n },\n ref,\n ) => {\n const resolvedVariant = (variant ?? 'default') as BadgeVariant\n const resolvedSize = (size ?? 'default') as BadgeSize\n return (\n <div\n ref={ref}\n data-slot=\"badge\"\n data-variant={resolvedVariant}\n data-size={resolvedSize}\n className={cn(badgeVariants({ variant, size }), className)}\n {...props}\n >\n {dot ? (\n <span\n data-slot=\"badge-dot\"\n aria-hidden=\"true\"\n className={cn(\n 'inline-block shrink-0 rounded-full',\n BADGE_DOT_SIZE[resolvedSize],\n BADGE_DOT_TONE[resolvedVariant],\n )}\n />\n ) : null}\n {children}\n {removable ? (\n <button\n type=\"button\"\n data-slot=\"badge-remove\"\n aria-label={removeAriaLabel}\n onClick={onRemove}\n className={cn(\n '-mr-0.5 ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full outline-none transition-opacity',\n 'opacity-70 hover:opacity-100 focus-visible:opacity-100',\n resolvedSize === 'lg' ? 'size-4' : 'size-3.5',\n )}\n >\n <X aria-hidden=\"true\" className={resolvedSize === 'lg' ? 'size-3' : 'size-2.5'} />\n </button>\n ) : null}\n </div>\n )\n },\n)\n\nBadge.displayName = 'Badge'\n\nexport { badgeVariants }\n"],
|
|
5
|
+
"mappings": ";AAgIM,SASI,KATJ;AA9HN,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,WAA8B;AAEvC,SAAS,UAAU;AA4BnB,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,QAKX,aAAa;AAAA,QACb,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,MAAM;AAAA,QACN,SAAS;AAAA,QACT,OAAO;AAAA;AAAA;AAAA,QAGP,OAAO;AAAA,MACT;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,MACN;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAIA,MAAM,iBAA6F;AAAA,EACjG,SAAS;AAAA,EACT,WAAW;AAAA,EACX,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AACT;AAGA,MAAM,iBAA0F;AAAA,EAC9F,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,IAAI;AACN;AAmBO,MAAM,QAAQ,MAAM;AAAA,EACzB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,YAAY;AAAA,IACZ;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,kBAAmB,WAAW;AACpC,UAAM,eAAgB,QAAQ;AAC9B,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,aAAU;AAAA,QACV,gBAAc;AAAA,QACd,aAAW;AAAA,QACX,WAAW,GAAG,cAAc,EAAE,SAAS,KAAK,CAAC,GAAG,SAAS;AAAA,QACxD,GAAG;AAAA,QAEH;AAAA,gBACC;AAAA,YAAC;AAAA;AAAA,cACC,aAAU;AAAA,cACV,eAAY;AAAA,cACZ,WAAW;AAAA,gBACT;AAAA,gBACA,eAAe,YAAY;AAAA,gBAC3B,eAAe,eAAe;AAAA,cAChC;AAAA;AAAA,UACF,IACE;AAAA,UACH;AAAA,UACA,YACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,aAAU;AAAA,cACV,cAAY;AAAA,cACZ,SAAS;AAAA,cACT,WAAW;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA,iBAAiB,OAAO,WAAW;AAAA,cACrC;AAAA,cAEA,8BAAC,KAAE,eAAY,QAAO,WAAW,iBAAiB,OAAO,WAAW,YAAY;AAAA;AAAA,UAClF,IACE;AAAA;AAAA;AAAA,IACN;AAAA,EAEJ;AACF;AAEA,MAAM,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
|
+
const buttonGroupVariants = cva(
|
|
7
|
+
// Outer chrome: rounded shell + border + clipped corners + shared shadow.
|
|
8
|
+
// Descendant rules collapse children into segments:
|
|
9
|
+
// * strip own corners / shadow / outer border on every child
|
|
10
|
+
// * raise focus-visible above neighbours so the focus ring is not clipped
|
|
11
|
+
// * separator: border-r (horizontal) or border-b (vertical) on every
|
|
12
|
+
// child except the last one
|
|
13
|
+
"inline-flex w-fit border border-input bg-background shadow-xs overflow-hidden [&>*]:rounded-none [&>*]:shadow-none [&>*]:border-0 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 disabled:opacity-50",
|
|
14
|
+
{
|
|
15
|
+
variants: {
|
|
16
|
+
orientation: {
|
|
17
|
+
horizontal: "flex-row [&>*:not(:last-child)]:border-r [&>*:not(:last-child)]:border-input",
|
|
18
|
+
vertical: "flex-col [&>*:not(:last-child)]:border-b [&>*:not(:last-child)]:border-input"
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
// Figma `2X-Small (24)` → cornerRadius 6 → DS `rounded-sm` (6px).
|
|
22
|
+
"2xs": "rounded-sm",
|
|
23
|
+
// Figma `X-Small (32)` → cornerRadius 8 → DS `rounded-md` (8px).
|
|
24
|
+
sm: "rounded-md",
|
|
25
|
+
// Figma `Small (36)` → cornerRadius 8 → DS `rounded-md` (8px).
|
|
26
|
+
default: "rounded-md"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
orientation: "horizontal",
|
|
31
|
+
size: "default"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
const ButtonGroup = React.forwardRef(
|
|
36
|
+
({ className, orientation, size, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
37
|
+
"div",
|
|
38
|
+
{
|
|
39
|
+
ref,
|
|
40
|
+
"data-slot": "button-group",
|
|
41
|
+
role: "group",
|
|
42
|
+
className: cn(buttonGroupVariants({ orientation, size }), className),
|
|
43
|
+
...props
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
);
|
|
47
|
+
ButtonGroup.displayName = "ButtonGroup";
|
|
48
|
+
export {
|
|
49
|
+
ButtonGroup,
|
|
50
|
+
buttonGroupVariants
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=button-group.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/primitives/button-group.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\n\n/**\n * Joined / connected button group per Figma `Button Group [1.1]`\n * (component set id `199961:1616` in DS Open Mercato). Renders an outer\n * rounded border with N children that touch each other to share an\n * internal separator line. Use for related actions on the same row\n * (Save / Save & New / overflow ellipsis) or compact view-mode toggles.\n *\n * `ButtonGroup` is for *related actions* (each does something different).\n * For mutually-exclusive selection states (only one selected at a time)\n * use `SegmentedControl` instead.\n *\n * The wrapper takes a `size` (2xs / sm / default) that controls the outer\n * radius per Figma \u2014 `2xs` = `rounded-sm` (Figma 2X-Small 24, radius 6),\n * `sm` and `default` = `rounded-md` (Figma X-Small 32 + Small 36, radius 8).\n * Same-row sizing convention from `packages/ui/AGENTS.md` still applies:\n * every child Button / IconButton inside the group MUST share the same\n * `size` prop as the group itself.\n *\n * Visual joining is handled at the wrapper level via descendant CSS\n * selectors \u2014 children render normally, the wrapper strips their own\n * corners, shadow, and outer borders, and adds an internal separator\n * (`border-r` / `border-b`) between siblings. This way no `cloneElement`\n * is required and any element that accepts a `className` (Button,\n * IconButton, LinkButton, asChild wrappers, etc.) can be a group member.\n *\n * ```tsx\n * <ButtonGroup>\n * <Button>Save</Button>\n * <Button>Save & New</Button>\n * <IconButton aria-label=\"More\"><MoreHorizontal /></IconButton>\n * </ButtonGroup>\n *\n * <ButtonGroup orientation=\"vertical\" size=\"sm\">\n * <Button variant=\"outline\">Up</Button>\n * <Button variant=\"outline\">Down</Button>\n * </ButtonGroup>\n * ```\n */\nconst buttonGroupVariants = cva(\n // Outer chrome: rounded shell + border + clipped corners + shared shadow.\n // Descendant rules collapse children into segments:\n // * strip own corners / shadow / outer border on every child\n // * raise focus-visible above neighbours so the focus ring is not clipped\n // * separator: border-r (horizontal) or border-b (vertical) on every\n // child except the last one\n 'inline-flex w-fit border border-input bg-background shadow-xs overflow-hidden ' +\n \"[&>*]:rounded-none [&>*]:shadow-none [&>*]:border-0 \" +\n \"[&>*]:focus-visible:relative [&>*]:focus-visible:z-10 \" +\n 'disabled:opacity-50',\n {\n variants: {\n orientation: {\n horizontal:\n 'flex-row [&>*:not(:last-child)]:border-r [&>*:not(:last-child)]:border-input',\n vertical:\n 'flex-col [&>*:not(:last-child)]:border-b [&>*:not(:last-child)]:border-input',\n },\n size: {\n // Figma `2X-Small (24)` \u2192 cornerRadius 6 \u2192 DS `rounded-sm` (6px).\n '2xs': 'rounded-sm',\n // Figma `X-Small (32)` \u2192 cornerRadius 8 \u2192 DS `rounded-md` (8px).\n sm: 'rounded-md',\n // Figma `Small (36)` \u2192 cornerRadius 8 \u2192 DS `rounded-md` (8px).\n default: 'rounded-md',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n size: 'default',\n },\n },\n)\n\nexport type ButtonGroupProps = React.HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof buttonGroupVariants> & {\n /** Forwarded to the wrapper's `aria-label` for screen-reader context. */\n 'aria-label'?: string\n }\n\nexport const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(\n ({ className, orientation, size, ...props }, ref) => (\n <div\n ref={ref}\n data-slot=\"button-group\"\n role=\"group\"\n className={cn(buttonGroupVariants({ orientation, size }), className)}\n {...props}\n />\n ),\n)\nButtonGroup.displayName = 'ButtonGroup'\n\nexport { buttonGroupVariants }\n"],
|
|
5
|
+
"mappings": ";AAwFI;AAtFJ,YAAY,WAAW;AACvB,SAAS,WAA8B;AAEvC,SAAS,UAAU;AAwCnB,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO1B;AAAA,EAIA;AAAA,IACE,UAAU;AAAA,MACR,aAAa;AAAA,QACX,YACE;AAAA,QACF,UACE;AAAA,MACJ;AAAA,MACA,MAAM;AAAA;AAAA,QAEJ,OAAO;AAAA;AAAA,QAEP,IAAI;AAAA;AAAA,QAEJ,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,aAAa;AAAA,MACb,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAQO,MAAM,cAAc,MAAM;AAAA,EAC/B,CAAC,EAAE,WAAW,aAAa,MAAM,GAAG,MAAM,GAAG,QAC3C;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aAAU;AAAA,MACV,MAAK;AAAA,MACL,WAAW,GAAG,oBAAoB,EAAE,aAAa,KAAK,CAAC,GAAG,SAAS;AAAA,MAClE,GAAG;AAAA;AAAA,EACN;AAEJ;AACA,YAAY,cAAc;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|