@open-mercato/ui 0.6.8-develop.7082.1.f2a845b020 → 0.6.8-develop.7088.1.3873d81f42
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/dist/primitives/alert.js +1 -1
- package/dist/primitives/alert.js.map +2 -2
- package/package.json +3 -3
- package/src/ai/parts/__tests__/ConfirmationCard.test.tsx +2 -0
- package/src/primitives/__tests__/alert.test.tsx +41 -1
- package/src/primitives/__tests__/notification.test.tsx +1 -1
- package/src/primitives/alert.tsx +5 -2
package/dist/primitives/alert.js
CHANGED
|
@@ -193,7 +193,7 @@ const AlertTitle = React.forwardRef(
|
|
|
193
193
|
);
|
|
194
194
|
AlertTitle.displayName = "AlertTitle";
|
|
195
195
|
const AlertDescription = React.forwardRef(
|
|
196
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsx("
|
|
196
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("text-sm leading-5", className), ...props })
|
|
197
197
|
);
|
|
198
198
|
AlertDescription.displayName = "AlertDescription";
|
|
199
199
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/primitives/alert.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertCircle, CheckCircle2, Info, Rocket, X, AlertTriangle } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nexport type AlertStatus = 'error' | 'warning' | 'success' | 'information' | 'feature'\nexport type AlertStyle = 'filled' | 'light' | 'lighter' | 'stroke'\nexport type AlertSize = 'xs' | 'sm' | 'default'\n\n/**\n * Legacy `variant` values from the pre-Figma-`169:2358` API. Kept for BC \u2014\n * mapped to `status` inside the Alert component so existing call sites do\n * not need migration. The Figma `light` look (`#fecaca` saturated tint\n * for error \u2192 `state/{x}/light` token family) is heavier than the\n * pre-Figma look; legacy call sites that want the softer pre-Figma\n * appearance should switch explicitly to `style=\"lighter\"`.\n */\ntype LegacyVariant = 'default' | 'destructive' | 'success' | 'warning' | 'info'\n\nconst legacyVariantToStatus: Record<LegacyVariant, AlertStatus> = {\n default: 'information',\n destructive: 'error',\n success: 'success',\n warning: 'warning',\n info: 'information',\n}\n\nconst alertVariants = cva(\n 'relative flex w-full gap-2 transition-colors',\n {\n variants: {\n status: {\n error: '',\n warning: '',\n success: '',\n information: '',\n feature: '',\n },\n style: {\n filled: '',\n light: '',\n lighter: '',\n stroke: '',\n },\n size: {\n // Figma X-Small: px-[8px] py-[6px], radius-8, Paragraph/X Small (12/16)\n xs: 'min-h-8 items-center rounded-lg px-2 py-1.5 text-xs leading-4 tracking-tight',\n // Figma Small: px-[10px] py-[8px], radius-8, Paragraph/Small (14/20)\n sm: 'min-h-9 items-center rounded-lg px-2.5 py-2 text-sm leading-5 tracking-tight',\n // Figma Large: px-[12px] py-[10px], radius-12, Paragraph/Small (14/20) multi-line\n default: 'items-start rounded-xl px-3 py-2.5 text-sm leading-5 tracking-tight',\n },\n },\n compoundVariants: [\n // === filled (Figma: bg = state/{x}/base, text = static-white) ===\n { status: 'error', style: 'filled', className: 'border border-transparent bg-status-error-icon text-white' },\n { status: 'warning', style: 'filled', className: 'border border-transparent bg-status-warning-icon text-white' },\n { status: 'success', style: 'filled', className: 'border border-transparent bg-status-success-icon text-white' },\n { status: 'information', style: 'filled', className: 'border border-transparent bg-status-info-icon text-white' },\n { status: 'feature', style: 'filled', className: 'border border-transparent bg-status-neutral-icon text-white' },\n // === light (Figma: bg = state/{x}/light, text = text/strong-950 = #171717 black) ===\n { status: 'error', style: 'light', className: 'border border-transparent bg-status-error-border text-foreground' },\n { status: 'warning', style: 'light', className: 'border border-transparent bg-status-warning-border text-foreground' },\n { status: 'success', style: 'light', className: 'border border-transparent bg-status-success-border text-foreground' },\n { status: 'information', style: 'light', className: 'border border-transparent bg-status-info-border text-foreground' },\n { status: 'feature', style: 'light', className: 'border border-transparent bg-status-neutral-border text-foreground' },\n // === lighter (Figma: bg = state/{x}/lighter, text = text/strong-950 = #171717 black) ===\n { status: 'error', style: 'lighter', className: 'border border-transparent bg-status-error-bg text-foreground' },\n { status: 'warning', style: 'lighter', className: 'border border-transparent bg-status-warning-bg text-foreground' },\n { status: 'success', style: 'lighter', className: 'border border-transparent bg-status-success-bg text-foreground' },\n { status: 'information', style: 'lighter', className: 'border border-transparent bg-status-info-bg text-foreground' },\n { status: 'feature', style: 'lighter', className: 'border border-transparent bg-status-neutral-bg text-foreground' },\n // === stroke (Figma: bg = white, border = stroke/soft-200, text = strong-950, shadow = regular-shadow/medium) ===\n { style: 'stroke', className: 'border border-border bg-background text-foreground shadow-lg' },\n ],\n defaultVariants: {\n status: 'information',\n style: 'light',\n size: 'sm',\n },\n },\n)\n\n// Dismiss button (X) color per Figma: text/strong-950 (#171717 black) at\n// `opacity-40` for light/lighter/stroke \u2014 matches the Figma `close-line`\n// icon which is the dark icon-strong-950 fill rendered at 40% alpha\n// (visually \u2248 #5c5c5c gray). White at full opacity for filled so it\n// stays legible over the saturated bg.\nconst alertDismissVariants = cva(\n 'shrink-0 rounded-md p-0.5 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40',\n {\n variants: {\n style: {\n filled: 'text-white opacity-90 hover:opacity-100',\n light: 'text-foreground opacity-40 hover:opacity-100',\n lighter: 'text-foreground opacity-40 hover:opacity-100',\n stroke: 'text-foreground opacity-40 hover:opacity-100',\n },\n },\n defaultVariants: { style: 'light' },\n },\n)\n\nconst alertIconBadgeVariants = cva(\n 'inline-flex shrink-0 items-center justify-center rounded-full text-white',\n {\n variants: {\n status: {\n error: 'bg-status-error-icon',\n warning: 'bg-status-warning-icon',\n success: 'bg-status-success-icon',\n information: 'bg-status-info-icon',\n feature: 'bg-status-neutral-icon',\n },\n size: {\n xs: 'size-4 [&>svg]:size-2.5',\n sm: 'size-5 [&>svg]:size-3',\n default: 'size-6 [&>svg]:size-3.5',\n },\n },\n defaultVariants: { status: 'information', size: 'sm' },\n },\n)\n\nconst defaultStatusIcons: Record<AlertStatus, React.ComponentType<{ className?: string; 'aria-hidden'?: 'true' }>> = {\n error: AlertCircle,\n warning: AlertTriangle,\n success: CheckCircle2,\n information: Info,\n feature: Rocket,\n}\n\nexport type AlertProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'role' | 'style'> &\n Omit<VariantProps<typeof alertVariants>, 'status' | 'style' | 'size'> & {\n status?: AlertStatus\n style?: AlertStyle\n size?: AlertSize\n /** Show the leading icon. Default `true`. */\n showIcon?: boolean\n /** Override the default per-status Lucide icon. */\n icon?: React.ReactNode\n /** Render a trailing close (X) button. Pair with `onDismiss`. */\n dismissible?: boolean\n onDismiss?: () => void\n dismissAriaLabel?: string\n /** Inline action slot (link buttons) rendered to the right of the body. */\n action?: React.ReactNode\n /**\n * @deprecated Use `status` + `style` instead. Kept for BC. Maps the\n * legacy single-prop variants onto `status` and picks up the new\n * `light` + `sm` defaults.\n */\n variant?: LegacyVariant\n }\n\nconst Alert = React.forwardRef<HTMLDivElement, AlertProps>(\n (\n {\n className,\n status,\n style,\n size,\n showIcon = true,\n icon,\n dismissible = false,\n onDismiss,\n dismissAriaLabel = 'Dismiss',\n action,\n variant,\n children,\n ...props\n },\n ref,\n ) => {\n const resolvedStatus: AlertStatus = status ?? (variant ? legacyVariantToStatus[variant] : 'information')\n const resolvedStyle: AlertStyle = style ?? 'light'\n const resolvedSize: AlertSize = size ?? 'sm'\n const IconComponent = defaultStatusIcons[resolvedStatus]\n const rawIcon = icon ?? <IconComponent aria-hidden=\"true\" />\n\n let iconSlot: React.ReactNode = null\n if (showIcon) {\n if (resolvedStyle === 'filled') {\n // Filled: plain icon over saturated bg \u2014 no badge wrap, inherit text-white.\n iconSlot = (\n <span\n className={cn(\n 'inline-flex shrink-0 items-center justify-center',\n resolvedSize === 'default' ? '[&>svg]:size-5' : '[&>svg]:size-4',\n )}\n data-slot=\"alert-icon\"\n >\n {rawIcon}\n </span>\n )\n } else {\n // light / lighter / stroke: badge wrap with status color bg + white icon.\n iconSlot = (\n <span\n className={alertIconBadgeVariants({ status: resolvedStatus, size: resolvedSize })}\n data-slot=\"alert-icon-badge\"\n data-status={resolvedStatus}\n >\n {rawIcon}\n </span>\n )\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(\n alertVariants({ status: resolvedStatus, style: resolvedStyle, size: resolvedSize }),\n className,\n )}\n data-slot=\"alert\"\n data-status={resolvedStatus}\n data-style={resolvedStyle}\n {...props}\n >\n {iconSlot}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {action ? <div className=\"shrink-0\">{action}</div> : null}\n {dismissible ? (\n <button\n type=\"button\"\n onClick={onDismiss}\n aria-label={dismissAriaLabel}\n className={alertDismissVariants({ style: resolvedStyle })}\n data-slot=\"alert-dismiss\"\n >\n <X aria-hidden=\"true\" className=\"size-4\" />\n </button>\n ) : null}\n </div>\n )\n },\n)\nAlert.displayName = 'Alert'\n\n// Figma \"Label/Small\": Inter Medium 14 / 20.\nconst AlertTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h5 ref={ref} className={cn('mb-1 text-sm font-medium leading-5', className)} {...props} />\n ),\n)\nAlertTitle.displayName = 'AlertTitle'\n\n// Figma \"Paragraph/Small\": Inter Regular 14 / 20.\nconst AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(\n ({ className, ...props }, ref) => (\n <p ref={ref} className={cn('text-sm leading-5', className)} {...props} />\n ),\n)\nAlertDescription.displayName = 'AlertDescription'\n\nexport { Alert, AlertDescription, AlertTitle, alertVariants, alertIconBadgeVariants }\n"],
|
|
5
|
-
"mappings": ";AAqL4B,cAgCtB,YAhCsB;AAnL5B,YAAY,WAAW;AACvB,SAAS,aAAa,cAAc,MAAM,QAAQ,GAAG,qBAAqB;AAC1E,SAAS,WAA8B;AAEvC,SAAS,UAAU;AAgBnB,MAAM,wBAA4D;AAAA,EAChE,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AACR;AAEA,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA;AAAA,QAEJ,IAAI;AAAA;AAAA,QAEJ,IAAI;AAAA;AAAA,QAEJ,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB,EAAE,QAAQ,SAAe,OAAO,UAAU,WAAW,4DAA4D;AAAA,MACjH,EAAE,QAAQ,WAAe,OAAO,UAAU,WAAW,8DAA8D;AAAA,MACnH,EAAE,QAAQ,WAAe,OAAO,UAAU,WAAW,8DAA8D;AAAA,MACnH,EAAE,QAAQ,eAAe,OAAO,UAAU,WAAW,2DAA2D;AAAA,MAChH,EAAE,QAAQ,WAAe,OAAO,UAAU,WAAW,8DAA8D;AAAA;AAAA,MAEnH,EAAE,QAAQ,SAAe,OAAO,SAAS,WAAW,mEAAmE;AAAA,MACvH,EAAE,QAAQ,WAAe,OAAO,SAAS,WAAW,qEAAqE;AAAA,MACzH,EAAE,QAAQ,WAAe,OAAO,SAAS,WAAW,qEAAqE;AAAA,MACzH,EAAE,QAAQ,eAAe,OAAO,SAAS,WAAW,kEAAkE;AAAA,MACtH,EAAE,QAAQ,WAAe,OAAO,SAAS,WAAW,qEAAqE;AAAA;AAAA,MAEzH,EAAE,QAAQ,SAAe,OAAO,WAAW,WAAW,+DAA+D;AAAA,MACrH,EAAE,QAAQ,WAAe,OAAO,WAAW,WAAW,iEAAiE;AAAA,MACvH,EAAE,QAAQ,WAAe,OAAO,WAAW,WAAW,iEAAiE;AAAA,MACvH,EAAE,QAAQ,eAAe,OAAO,WAAW,WAAW,8DAA8D;AAAA,MACpH,EAAE,QAAQ,WAAe,OAAO,WAAW,WAAW,iEAAiE;AAAA;AAAA,MAEvH,EAAE,OAAO,UAAU,WAAW,+DAA+D;AAAA,IAC/F;AAAA,IACA,iBAAiB;AAAA,MACf,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAOA,MAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,iBAAiB,EAAE,OAAO,QAAQ;AAAA,EACpC;AACF;AAEA,MAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,iBAAiB,EAAE,QAAQ,eAAe,MAAM,KAAK;AAAA,EACvD;AACF;AAEA,MAAM,qBAA+G;AAAA,EACnH,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AACX;AAyBA,MAAM,QAAQ,MAAM;AAAA,EAClB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,mBAAmB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,iBAA8B,WAAW,UAAU,sBAAsB,OAAO,IAAI;AAC1F,UAAM,gBAA4B,SAAS;AAC3C,UAAM,eAA0B,QAAQ;AACxC,UAAM,gBAAgB,mBAAmB,cAAc;AACvD,UAAM,UAAU,QAAQ,oBAAC,iBAAc,eAAY,QAAO;AAE1D,QAAI,WAA4B;AAChC,QAAI,UAAU;AACZ,UAAI,kBAAkB,UAAU;AAE9B,mBACE;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,iBAAiB,YAAY,mBAAmB;AAAA,YAClD;AAAA,YACA,aAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,MAEJ,OAAO;AAEL,mBACE;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,uBAAuB,EAAE,QAAQ,gBAAgB,MAAM,aAAa,CAAC;AAAA,YAChF,aAAU;AAAA,YACV,eAAa;AAAA,YAEZ;AAAA;AAAA,QACH;AAAA,MAEJ;AAAA,IACF;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,WAAW;AAAA,UACT,cAAc,EAAE,QAAQ,gBAAgB,OAAO,eAAe,MAAM,aAAa,CAAC;AAAA,UAClF;AAAA,QACF;AAAA,QACA,aAAU;AAAA,QACV,eAAa;AAAA,QACb,cAAY;AAAA,QACX,GAAG;AAAA,QAEH;AAAA;AAAA,UACD,oBAAC,SAAI,WAAU,kBAAkB,UAAS;AAAA,UACzC,SAAS,oBAAC,SAAI,WAAU,YAAY,kBAAO,IAAS;AAAA,UACpD,cACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,cAAY;AAAA,cACZ,WAAW,qBAAqB,EAAE,OAAO,cAAc,CAAC;AAAA,cACxD,aAAU;AAAA,cAEV,8BAAC,KAAE,eAAY,QAAO,WAAU,UAAS;AAAA;AAAA,UAC3C,IACE;AAAA;AAAA;AAAA,IACN;AAAA,EAEJ;AACF;AACA,MAAM,cAAc;AAGpB,MAAM,aAAa,MAAM;AAAA,EACvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,oBAAC,QAAG,KAAU,WAAW,GAAG,sCAAsC,SAAS,GAAI,GAAG,OAAO;AAE7F;AACA,WAAW,cAAc;
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertCircle, CheckCircle2, Info, Rocket, X, AlertTriangle } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nexport type AlertStatus = 'error' | 'warning' | 'success' | 'information' | 'feature'\nexport type AlertStyle = 'filled' | 'light' | 'lighter' | 'stroke'\nexport type AlertSize = 'xs' | 'sm' | 'default'\n\n/**\n * Legacy `variant` values from the pre-Figma-`169:2358` API. Kept for BC \u2014\n * mapped to `status` inside the Alert component so existing call sites do\n * not need migration. The Figma `light` look (`#fecaca` saturated tint\n * for error \u2192 `state/{x}/light` token family) is heavier than the\n * pre-Figma look; legacy call sites that want the softer pre-Figma\n * appearance should switch explicitly to `style=\"lighter\"`.\n */\ntype LegacyVariant = 'default' | 'destructive' | 'success' | 'warning' | 'info'\n\nconst legacyVariantToStatus: Record<LegacyVariant, AlertStatus> = {\n default: 'information',\n destructive: 'error',\n success: 'success',\n warning: 'warning',\n info: 'information',\n}\n\nconst alertVariants = cva(\n 'relative flex w-full gap-2 transition-colors',\n {\n variants: {\n status: {\n error: '',\n warning: '',\n success: '',\n information: '',\n feature: '',\n },\n style: {\n filled: '',\n light: '',\n lighter: '',\n stroke: '',\n },\n size: {\n // Figma X-Small: px-[8px] py-[6px], radius-8, Paragraph/X Small (12/16)\n xs: 'min-h-8 items-center rounded-lg px-2 py-1.5 text-xs leading-4 tracking-tight',\n // Figma Small: px-[10px] py-[8px], radius-8, Paragraph/Small (14/20)\n sm: 'min-h-9 items-center rounded-lg px-2.5 py-2 text-sm leading-5 tracking-tight',\n // Figma Large: px-[12px] py-[10px], radius-12, Paragraph/Small (14/20) multi-line\n default: 'items-start rounded-xl px-3 py-2.5 text-sm leading-5 tracking-tight',\n },\n },\n compoundVariants: [\n // === filled (Figma: bg = state/{x}/base, text = static-white) ===\n { status: 'error', style: 'filled', className: 'border border-transparent bg-status-error-icon text-white' },\n { status: 'warning', style: 'filled', className: 'border border-transparent bg-status-warning-icon text-white' },\n { status: 'success', style: 'filled', className: 'border border-transparent bg-status-success-icon text-white' },\n { status: 'information', style: 'filled', className: 'border border-transparent bg-status-info-icon text-white' },\n { status: 'feature', style: 'filled', className: 'border border-transparent bg-status-neutral-icon text-white' },\n // === light (Figma: bg = state/{x}/light, text = text/strong-950 = #171717 black) ===\n { status: 'error', style: 'light', className: 'border border-transparent bg-status-error-border text-foreground' },\n { status: 'warning', style: 'light', className: 'border border-transparent bg-status-warning-border text-foreground' },\n { status: 'success', style: 'light', className: 'border border-transparent bg-status-success-border text-foreground' },\n { status: 'information', style: 'light', className: 'border border-transparent bg-status-info-border text-foreground' },\n { status: 'feature', style: 'light', className: 'border border-transparent bg-status-neutral-border text-foreground' },\n // === lighter (Figma: bg = state/{x}/lighter, text = text/strong-950 = #171717 black) ===\n { status: 'error', style: 'lighter', className: 'border border-transparent bg-status-error-bg text-foreground' },\n { status: 'warning', style: 'lighter', className: 'border border-transparent bg-status-warning-bg text-foreground' },\n { status: 'success', style: 'lighter', className: 'border border-transparent bg-status-success-bg text-foreground' },\n { status: 'information', style: 'lighter', className: 'border border-transparent bg-status-info-bg text-foreground' },\n { status: 'feature', style: 'lighter', className: 'border border-transparent bg-status-neutral-bg text-foreground' },\n // === stroke (Figma: bg = white, border = stroke/soft-200, text = strong-950, shadow = regular-shadow/medium) ===\n { style: 'stroke', className: 'border border-border bg-background text-foreground shadow-lg' },\n ],\n defaultVariants: {\n status: 'information',\n style: 'light',\n size: 'sm',\n },\n },\n)\n\n// Dismiss button (X) color per Figma: text/strong-950 (#171717 black) at\n// `opacity-40` for light/lighter/stroke \u2014 matches the Figma `close-line`\n// icon which is the dark icon-strong-950 fill rendered at 40% alpha\n// (visually \u2248 #5c5c5c gray). White at full opacity for filled so it\n// stays legible over the saturated bg.\nconst alertDismissVariants = cva(\n 'shrink-0 rounded-md p-0.5 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40',\n {\n variants: {\n style: {\n filled: 'text-white opacity-90 hover:opacity-100',\n light: 'text-foreground opacity-40 hover:opacity-100',\n lighter: 'text-foreground opacity-40 hover:opacity-100',\n stroke: 'text-foreground opacity-40 hover:opacity-100',\n },\n },\n defaultVariants: { style: 'light' },\n },\n)\n\nconst alertIconBadgeVariants = cva(\n 'inline-flex shrink-0 items-center justify-center rounded-full text-white',\n {\n variants: {\n status: {\n error: 'bg-status-error-icon',\n warning: 'bg-status-warning-icon',\n success: 'bg-status-success-icon',\n information: 'bg-status-info-icon',\n feature: 'bg-status-neutral-icon',\n },\n size: {\n xs: 'size-4 [&>svg]:size-2.5',\n sm: 'size-5 [&>svg]:size-3',\n default: 'size-6 [&>svg]:size-3.5',\n },\n },\n defaultVariants: { status: 'information', size: 'sm' },\n },\n)\n\nconst defaultStatusIcons: Record<AlertStatus, React.ComponentType<{ className?: string; 'aria-hidden'?: 'true' }>> = {\n error: AlertCircle,\n warning: AlertTriangle,\n success: CheckCircle2,\n information: Info,\n feature: Rocket,\n}\n\nexport type AlertProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'role' | 'style'> &\n Omit<VariantProps<typeof alertVariants>, 'status' | 'style' | 'size'> & {\n status?: AlertStatus\n style?: AlertStyle\n size?: AlertSize\n /** Show the leading icon. Default `true`. */\n showIcon?: boolean\n /** Override the default per-status Lucide icon. */\n icon?: React.ReactNode\n /** Render a trailing close (X) button. Pair with `onDismiss`. */\n dismissible?: boolean\n onDismiss?: () => void\n dismissAriaLabel?: string\n /** Inline action slot (link buttons) rendered to the right of the body. */\n action?: React.ReactNode\n /**\n * @deprecated Use `status` + `style` instead. Kept for BC. Maps the\n * legacy single-prop variants onto `status` and picks up the new\n * `light` + `sm` defaults.\n */\n variant?: LegacyVariant\n }\n\nconst Alert = React.forwardRef<HTMLDivElement, AlertProps>(\n (\n {\n className,\n status,\n style,\n size,\n showIcon = true,\n icon,\n dismissible = false,\n onDismiss,\n dismissAriaLabel = 'Dismiss',\n action,\n variant,\n children,\n ...props\n },\n ref,\n ) => {\n const resolvedStatus: AlertStatus = status ?? (variant ? legacyVariantToStatus[variant] : 'information')\n const resolvedStyle: AlertStyle = style ?? 'light'\n const resolvedSize: AlertSize = size ?? 'sm'\n const IconComponent = defaultStatusIcons[resolvedStatus]\n const rawIcon = icon ?? <IconComponent aria-hidden=\"true\" />\n\n let iconSlot: React.ReactNode = null\n if (showIcon) {\n if (resolvedStyle === 'filled') {\n // Filled: plain icon over saturated bg \u2014 no badge wrap, inherit text-white.\n iconSlot = (\n <span\n className={cn(\n 'inline-flex shrink-0 items-center justify-center',\n resolvedSize === 'default' ? '[&>svg]:size-5' : '[&>svg]:size-4',\n )}\n data-slot=\"alert-icon\"\n >\n {rawIcon}\n </span>\n )\n } else {\n // light / lighter / stroke: badge wrap with status color bg + white icon.\n iconSlot = (\n <span\n className={alertIconBadgeVariants({ status: resolvedStatus, size: resolvedSize })}\n data-slot=\"alert-icon-badge\"\n data-status={resolvedStatus}\n >\n {rawIcon}\n </span>\n )\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(\n alertVariants({ status: resolvedStatus, style: resolvedStyle, size: resolvedSize }),\n className,\n )}\n data-slot=\"alert\"\n data-status={resolvedStatus}\n data-style={resolvedStyle}\n {...props}\n >\n {iconSlot}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {action ? <div className=\"shrink-0\">{action}</div> : null}\n {dismissible ? (\n <button\n type=\"button\"\n onClick={onDismiss}\n aria-label={dismissAriaLabel}\n className={alertDismissVariants({ style: resolvedStyle })}\n data-slot=\"alert-dismiss\"\n >\n <X aria-hidden=\"true\" className=\"size-4\" />\n </button>\n ) : null}\n </div>\n )\n },\n)\nAlert.displayName = 'Alert'\n\n// Figma \"Label/Small\": Inter Medium 14 / 20.\nconst AlertTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h5 ref={ref} className={cn('mb-1 text-sm font-medium leading-5', className)} {...props} />\n ),\n)\nAlertTitle.displayName = 'AlertTitle'\n\n// Figma \"Paragraph/Small\": Inter Regular 14 / 20.\n// Renders a <div>, not a <p>: callers routinely nest paragraphs, lists and other\n// block elements inside the description, which is invalid inside <p> and makes\n// React fail hydration with \"In HTML, <p> cannot be a descendant of <p>\".\nconst AlertDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn('text-sm leading-5', className)} {...props} />\n ),\n)\nAlertDescription.displayName = 'AlertDescription'\n\nexport { Alert, AlertDescription, AlertTitle, alertVariants, alertIconBadgeVariants }\n"],
|
|
5
|
+
"mappings": ";AAqL4B,cAgCtB,YAhCsB;AAnL5B,YAAY,WAAW;AACvB,SAAS,aAAa,cAAc,MAAM,QAAQ,GAAG,qBAAqB;AAC1E,SAAS,WAA8B;AAEvC,SAAS,UAAU;AAgBnB,MAAM,wBAA4D;AAAA,EAChE,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AACR;AAEA,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA;AAAA,QAEJ,IAAI;AAAA;AAAA,QAEJ,IAAI;AAAA;AAAA,QAEJ,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB,EAAE,QAAQ,SAAe,OAAO,UAAU,WAAW,4DAA4D;AAAA,MACjH,EAAE,QAAQ,WAAe,OAAO,UAAU,WAAW,8DAA8D;AAAA,MACnH,EAAE,QAAQ,WAAe,OAAO,UAAU,WAAW,8DAA8D;AAAA,MACnH,EAAE,QAAQ,eAAe,OAAO,UAAU,WAAW,2DAA2D;AAAA,MAChH,EAAE,QAAQ,WAAe,OAAO,UAAU,WAAW,8DAA8D;AAAA;AAAA,MAEnH,EAAE,QAAQ,SAAe,OAAO,SAAS,WAAW,mEAAmE;AAAA,MACvH,EAAE,QAAQ,WAAe,OAAO,SAAS,WAAW,qEAAqE;AAAA,MACzH,EAAE,QAAQ,WAAe,OAAO,SAAS,WAAW,qEAAqE;AAAA,MACzH,EAAE,QAAQ,eAAe,OAAO,SAAS,WAAW,kEAAkE;AAAA,MACtH,EAAE,QAAQ,WAAe,OAAO,SAAS,WAAW,qEAAqE;AAAA;AAAA,MAEzH,EAAE,QAAQ,SAAe,OAAO,WAAW,WAAW,+DAA+D;AAAA,MACrH,EAAE,QAAQ,WAAe,OAAO,WAAW,WAAW,iEAAiE;AAAA,MACvH,EAAE,QAAQ,WAAe,OAAO,WAAW,WAAW,iEAAiE;AAAA,MACvH,EAAE,QAAQ,eAAe,OAAO,WAAW,WAAW,8DAA8D;AAAA,MACpH,EAAE,QAAQ,WAAe,OAAO,WAAW,WAAW,iEAAiE;AAAA;AAAA,MAEvH,EAAE,OAAO,UAAU,WAAW,+DAA+D;AAAA,IAC/F;AAAA,IACA,iBAAiB;AAAA,MACf,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAOA,MAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,iBAAiB,EAAE,OAAO,QAAQ;AAAA,EACpC;AACF;AAEA,MAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,iBAAiB,EAAE,QAAQ,eAAe,MAAM,KAAK;AAAA,EACvD;AACF;AAEA,MAAM,qBAA+G;AAAA,EACnH,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AACX;AAyBA,MAAM,QAAQ,MAAM;AAAA,EAClB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,mBAAmB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,iBAA8B,WAAW,UAAU,sBAAsB,OAAO,IAAI;AAC1F,UAAM,gBAA4B,SAAS;AAC3C,UAAM,eAA0B,QAAQ;AACxC,UAAM,gBAAgB,mBAAmB,cAAc;AACvD,UAAM,UAAU,QAAQ,oBAAC,iBAAc,eAAY,QAAO;AAE1D,QAAI,WAA4B;AAChC,QAAI,UAAU;AACZ,UAAI,kBAAkB,UAAU;AAE9B,mBACE;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,iBAAiB,YAAY,mBAAmB;AAAA,YAClD;AAAA,YACA,aAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,MAEJ,OAAO;AAEL,mBACE;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,uBAAuB,EAAE,QAAQ,gBAAgB,MAAM,aAAa,CAAC;AAAA,YAChF,aAAU;AAAA,YACV,eAAa;AAAA,YAEZ;AAAA;AAAA,QACH;AAAA,MAEJ;AAAA,IACF;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,WAAW;AAAA,UACT,cAAc,EAAE,QAAQ,gBAAgB,OAAO,eAAe,MAAM,aAAa,CAAC;AAAA,UAClF;AAAA,QACF;AAAA,QACA,aAAU;AAAA,QACV,eAAa;AAAA,QACb,cAAY;AAAA,QACX,GAAG;AAAA,QAEH;AAAA;AAAA,UACD,oBAAC,SAAI,WAAU,kBAAkB,UAAS;AAAA,UACzC,SAAS,oBAAC,SAAI,WAAU,YAAY,kBAAO,IAAS;AAAA,UACpD,cACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,cAAY;AAAA,cACZ,WAAW,qBAAqB,EAAE,OAAO,cAAc,CAAC;AAAA,cACxD,aAAU;AAAA,cAEV,8BAAC,KAAE,eAAY,QAAO,WAAU,UAAS;AAAA;AAAA,UAC3C,IACE;AAAA;AAAA;AAAA,IACN;AAAA,EAEJ;AACF;AACA,MAAM,cAAc;AAGpB,MAAM,aAAa,MAAM;AAAA,EACvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,oBAAC,QAAG,KAAU,WAAW,GAAG,sCAAsC,SAAS,GAAI,GAAG,OAAO;AAE7F;AACA,WAAW,cAAc;AAMzB,MAAM,mBAAmB,MAAM;AAAA,EAC7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,oBAAC,SAAI,KAAU,WAAW,GAAG,qBAAqB,SAAS,GAAI,GAAG,OAAO;AAE7E;AACA,iBAAiB,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/ui",
|
|
3
|
-
"version": "0.6.8-develop.
|
|
3
|
+
"version": "0.6.8-develop.7088.1.3873d81f42",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -155,14 +155,14 @@
|
|
|
155
155
|
"remark-gfm": "^4.0.1"
|
|
156
156
|
},
|
|
157
157
|
"peerDependencies": {
|
|
158
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
158
|
+
"@open-mercato/shared": "0.6.8-develop.7088.1.3873d81f42",
|
|
159
159
|
"react": ">=18.0.0",
|
|
160
160
|
"react-dom": ">=18.0.0",
|
|
161
161
|
"react-is": ">=18.0.0"
|
|
162
162
|
},
|
|
163
163
|
"devDependencies": {
|
|
164
164
|
"@figma/code-connect": "^1.3.4",
|
|
165
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
165
|
+
"@open-mercato/shared": "0.6.8-develop.7088.1.3873d81f42",
|
|
166
166
|
"@testing-library/dom": "^10.4.1",
|
|
167
167
|
"@testing-library/jest-dom": "^7.0.0",
|
|
168
168
|
"@testing-library/react": "^16.3.1",
|
|
@@ -133,6 +133,8 @@ describe('ConfirmationCard', () => {
|
|
|
133
133
|
expect(
|
|
134
134
|
document.querySelectorAll('[data-ai-confirmation-stale-record]').length,
|
|
135
135
|
).toBe(2)
|
|
136
|
+
expect(document.querySelectorAll('p p').length).toBe(0)
|
|
137
|
+
expect(document.querySelectorAll('p ul').length).toBe(0)
|
|
136
138
|
})
|
|
137
139
|
|
|
138
140
|
it('renders the schema_drift "Schema changed" alert', () => {
|
|
@@ -189,7 +189,47 @@ describe('Alert primitive', () => {
|
|
|
189
189
|
</Alert>,
|
|
190
190
|
)
|
|
191
191
|
expect(screen.getByText('Saved').tagName).toBe('H5')
|
|
192
|
-
expect(screen.getByText('Your changes were saved.').tagName).toBe('
|
|
192
|
+
expect(screen.getByText('Your changes were saved.').tagName).toBe('DIV')
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
describe('AlertDescription accepts block-level children', () => {
|
|
196
|
+
it('renders a div so nested paragraphs stay valid HTML', () => {
|
|
197
|
+
const { container } = render(
|
|
198
|
+
<Alert status="information">
|
|
199
|
+
<AlertDescription>
|
|
200
|
+
<p>First paragraph.</p>
|
|
201
|
+
<p>Second paragraph.</p>
|
|
202
|
+
</AlertDescription>
|
|
203
|
+
</Alert>,
|
|
204
|
+
)
|
|
205
|
+
expect(screen.getByText('First paragraph.').parentElement?.tagName).toBe('DIV')
|
|
206
|
+
expect(container.querySelectorAll('p p')).toHaveLength(0)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('keeps a nested list out of a paragraph', () => {
|
|
210
|
+
const { container } = render(
|
|
211
|
+
<Alert status="warning">
|
|
212
|
+
<AlertDescription>
|
|
213
|
+
<p>These records changed:</p>
|
|
214
|
+
<ul>
|
|
215
|
+
<li>r-1</li>
|
|
216
|
+
</ul>
|
|
217
|
+
</AlertDescription>
|
|
218
|
+
</Alert>,
|
|
219
|
+
)
|
|
220
|
+
expect(container.querySelectorAll('p ul')).toHaveLength(0)
|
|
221
|
+
expect(container.querySelectorAll('p p')).toHaveLength(0)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('forwards a ref to the rendered div', () => {
|
|
225
|
+
const ref = React.createRef<HTMLDivElement>()
|
|
226
|
+
render(
|
|
227
|
+
<Alert>
|
|
228
|
+
<AlertDescription ref={ref}>Body</AlertDescription>
|
|
229
|
+
</Alert>,
|
|
230
|
+
)
|
|
231
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
232
|
+
})
|
|
193
233
|
})
|
|
194
234
|
|
|
195
235
|
describe('legacy variant prop (BC)', () => {
|
|
@@ -26,7 +26,7 @@ describe('Notification primitive', () => {
|
|
|
26
26
|
it('renders title as AlertTitle and description below', () => {
|
|
27
27
|
render(<Notification title="John commented" description="On the latest deal" />)
|
|
28
28
|
expect(screen.getByText('John commented').tagName).toBe('H5')
|
|
29
|
-
expect(screen.getByText('On the latest deal').tagName).toBe('
|
|
29
|
+
expect(screen.getByText('On the latest deal').tagName).toBe('DIV')
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
it('description gets opacity-70 (DS opacity scale; was opacity-72 in early v5, snapped to scale per .ai/ds-rules.md)', () => {
|
package/src/primitives/alert.tsx
CHANGED
|
@@ -252,9 +252,12 @@ const AlertTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTM
|
|
|
252
252
|
AlertTitle.displayName = 'AlertTitle'
|
|
253
253
|
|
|
254
254
|
// Figma "Paragraph/Small": Inter Regular 14 / 20.
|
|
255
|
-
|
|
255
|
+
// Renders a <div>, not a <p>: callers routinely nest paragraphs, lists and other
|
|
256
|
+
// block elements inside the description, which is invalid inside <p> and makes
|
|
257
|
+
// React fail hydration with "In HTML, <p> cannot be a descendant of <p>".
|
|
258
|
+
const AlertDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
256
259
|
({ className, ...props }, ref) => (
|
|
257
|
-
<
|
|
260
|
+
<div ref={ref} className={cn('text-sm leading-5', className)} {...props} />
|
|
258
261
|
),
|
|
259
262
|
)
|
|
260
263
|
AlertDescription.displayName = 'AlertDescription'
|