@open-mercato/ui 0.6.8-develop.7082.1.f2a845b020 → 0.6.8-develop.7090.1.4dbca7b350

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.
@@ -1,3 +1,3 @@
1
- Generated lucide registry with 160 icons -> /home/runner/work/open-mercato/open-mercato/packages/ui/src/backend/icons/lucideRegistry.generated.tsx
1
+ Generated lucide registry with 161 icons -> /home/runner/work/open-mercato/open-mercato/packages/ui/src/backend/icons/lucideRegistry.generated.tsx
2
2
  [build:ui] found 400 entry points
3
3
  [build:ui] built successfully
@@ -10,7 +10,7 @@ import {
10
10
  Phone,
11
11
  StickyNote
12
12
  } from "lucide-react";
13
- import { useT } from "@open-mercato/shared/lib/i18n/context";
13
+ import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
14
14
  import { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from "./RecordCardShell.js";
15
15
  import { formatDate } from "../../utils/format.js";
16
16
  function pickActivityIcon(type) {
@@ -26,10 +26,11 @@ function pickActivityIcon(type) {
26
26
  }
27
27
  function ActivityCard(props) {
28
28
  const t = useT();
29
+ const locale = useLocale();
29
30
  const Icon = pickActivityIcon(props.type);
30
31
  const status = props.status ? { label: props.status, variant: statusToTagVariant(props.status) } : null;
31
- const dueDate = formatDate(props.dueDate);
32
- const completedAt = formatDate(props.completedAt);
32
+ const dueDate = formatDate(props.dueDate, locale);
33
+ const completedAt = formatDate(props.completedAt, locale);
33
34
  const items = [
34
35
  props.type ? { label: t("ai_assistant.chat.records.fields.type", "Type"), value: props.type } : null,
35
36
  dueDate ? {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/ai/records/ActivityCard.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n Activity as ActivityIcon,\n CalendarClock,\n CheckCircle2,\n ListChecks,\n Mail,\n MessageSquare,\n Phone,\n StickyNote,\n} from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'\nimport type { ActivityRecordPayload } from './types'\nimport { formatDate } from '../../utils/format'\n\nfunction pickActivityIcon(type: string | null | undefined): LucideIcon {\n if (!type) return ActivityIcon\n const t = type.toLowerCase()\n if (t.includes('call')) return Phone\n if (t.includes('mail') || t.includes('email')) return Mail\n if (t.includes('meeting') || t.includes('chat')) return MessageSquare\n if (t.includes('task') || t.includes('todo')) return ListChecks\n if (t.includes('note')) return StickyNote\n if (t.includes('done') || t.includes('complete')) return CheckCircle2\n return ActivityIcon\n}\n\nexport interface ActivityCardProps extends ActivityRecordPayload {}\n\nexport function ActivityCard(props: ActivityCardProps) {\n const t = useT()\n const Icon = pickActivityIcon(props.type)\n const status = props.status\n ? { label: props.status, variant: statusToTagVariant(props.status) }\n : null\n const dueDate = formatDate(props.dueDate)\n const completedAt = formatDate(props.completedAt)\n\n const items = [\n props.type ? { label: t('ai_assistant.chat.records.fields.type', 'Type'), value: props.type } : null,\n dueDate\n ? {\n label: t('ai_assistant.chat.records.fields.due', 'Due'),\n value: (\n <span className=\"inline-flex items-center gap-1\">\n <CalendarClock className=\"size-3 text-muted-foreground\" aria-hidden />\n {dueDate}\n </span>\n ),\n }\n : null,\n completedAt\n ? {\n label: t('ai_assistant.chat.records.fields.completed', 'Completed'),\n value: (\n <span className=\"inline-flex items-center gap-1\">\n <CheckCircle2 className=\"size-3 text-status-success-icon\" aria-hidden />\n {completedAt}\n </span>\n ),\n }\n : null,\n props.relatedTo ? { label: t('ai_assistant.chat.records.fields.related', 'Related'), value: props.relatedTo } : null,\n props.ownerName ? { label: t('ai_assistant.chat.records.fields.owner', 'Owner'), value: props.ownerName } : null,\n ].filter(Boolean) as { label: string; value: React.ReactNode }[]\n\n const subtitle = [props.type, props.relatedTo].filter(Boolean).join(' \u2022 ')\n\n return (\n <RecordCardShell\n kindLabel={t('ai_assistant.chat.records.kinds.activity', 'Activity')}\n kindIcon={<Icon className=\"size-4\" aria-hidden />}\n title={props.title}\n subtitle={subtitle || undefined}\n status={status}\n href={props.href}\n id={props.id}\n className={props.className}\n dataKind=\"activity\"\n >\n <div className=\"space-y-2\">\n <KeyValueList items={items} />\n {props.description ? (\n <p className=\"line-clamp-3 text-muted-foreground\">{props.description}</p>\n ) : null}\n {props.tags && props.tags.length > 0 ? <TagRow tags={props.tags} /> : null}\n </div>\n </RecordCardShell>\n )\n}\n\nexport default ActivityCard\n"],
5
- "mappings": ";AAgDY,SACE,KADF;AA7CZ;AAAA,EACE,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,YAAY;AACrB,SAAS,cAAc,iBAAiB,QAAQ,0BAA0B;AAE1E,SAAS,kBAAkB;AAE3B,SAAS,iBAAiB,MAA6C;AACrE,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,KAAK,YAAY;AAC3B,MAAI,EAAE,SAAS,MAAM,EAAG,QAAO;AAC/B,MAAI,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,OAAO,EAAG,QAAO;AACtD,MAAI,EAAE,SAAS,SAAS,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO;AACxD,MAAI,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO;AACrD,MAAI,EAAE,SAAS,MAAM,EAAG,QAAO;AAC/B,MAAI,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,UAAU,EAAG,QAAO;AACzD,SAAO;AACT;AAIO,SAAS,aAAa,OAA0B;AACrD,QAAM,IAAI,KAAK;AACf,QAAM,OAAO,iBAAiB,MAAM,IAAI;AACxC,QAAM,SAAS,MAAM,SACjB,EAAE,OAAO,MAAM,QAAQ,SAAS,mBAAmB,MAAM,MAAM,EAAE,IACjE;AACJ,QAAM,UAAU,WAAW,MAAM,OAAO;AACxC,QAAM,cAAc,WAAW,MAAM,WAAW;AAEhD,QAAM,QAAQ;AAAA,IACZ,MAAM,OAAO,EAAE,OAAO,EAAE,yCAAyC,MAAM,GAAG,OAAO,MAAM,KAAK,IAAI;AAAA,IAChG,UACI;AAAA,MACE,OAAO,EAAE,wCAAwC,KAAK;AAAA,MACtD,OACE,qBAAC,UAAK,WAAU,kCACd;AAAA,4BAAC,iBAAc,WAAU,gCAA+B,eAAW,MAAC;AAAA,QACnE;AAAA,SACH;AAAA,IAEJ,IACA;AAAA,IACJ,cACI;AAAA,MACE,OAAO,EAAE,8CAA8C,WAAW;AAAA,MAClE,OACE,qBAAC,UAAK,WAAU,kCACd;AAAA,4BAAC,gBAAa,WAAU,mCAAkC,eAAW,MAAC;AAAA,QACrE;AAAA,SACH;AAAA,IAEJ,IACA;AAAA,IACJ,MAAM,YAAY,EAAE,OAAO,EAAE,4CAA4C,SAAS,GAAG,OAAO,MAAM,UAAU,IAAI;AAAA,IAChH,MAAM,YAAY,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,MAAM,UAAU,IAAI;AAAA,EAC9G,EAAE,OAAO,OAAO;AAEhB,QAAM,WAAW,CAAC,MAAM,MAAM,MAAM,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK;AAEzE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,EAAE,4CAA4C,UAAU;AAAA,MACnE,UAAU,oBAAC,QAAK,WAAU,UAAS,eAAW,MAAC;AAAA,MAC/C,OAAO,MAAM;AAAA,MACb,UAAU,YAAY;AAAA,MACtB;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,UAAS;AAAA,MAET,+BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,gBAAa,OAAc;AAAA,QAC3B,MAAM,cACL,oBAAC,OAAE,WAAU,sCAAsC,gBAAM,aAAY,IACnE;AAAA,QACH,MAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,oBAAC,UAAO,MAAM,MAAM,MAAM,IAAK;AAAA,SACxE;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,uBAAQ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n Activity as ActivityIcon,\n CalendarClock,\n CheckCircle2,\n ListChecks,\n Mail,\n MessageSquare,\n Phone,\n StickyNote,\n} from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'\nimport type { ActivityRecordPayload } from './types'\nimport { formatDate } from '../../utils/format'\n\nfunction pickActivityIcon(type: string | null | undefined): LucideIcon {\n if (!type) return ActivityIcon\n const t = type.toLowerCase()\n if (t.includes('call')) return Phone\n if (t.includes('mail') || t.includes('email')) return Mail\n if (t.includes('meeting') || t.includes('chat')) return MessageSquare\n if (t.includes('task') || t.includes('todo')) return ListChecks\n if (t.includes('note')) return StickyNote\n if (t.includes('done') || t.includes('complete')) return CheckCircle2\n return ActivityIcon\n}\n\nexport interface ActivityCardProps extends ActivityRecordPayload {}\n\nexport function ActivityCard(props: ActivityCardProps) {\n const t = useT()\n const locale = useLocale()\n const Icon = pickActivityIcon(props.type)\n const status = props.status\n ? { label: props.status, variant: statusToTagVariant(props.status) }\n : null\n const dueDate = formatDate(props.dueDate, locale)\n const completedAt = formatDate(props.completedAt, locale)\n\n const items = [\n props.type ? { label: t('ai_assistant.chat.records.fields.type', 'Type'), value: props.type } : null,\n dueDate\n ? {\n label: t('ai_assistant.chat.records.fields.due', 'Due'),\n value: (\n <span className=\"inline-flex items-center gap-1\">\n <CalendarClock className=\"size-3 text-muted-foreground\" aria-hidden />\n {dueDate}\n </span>\n ),\n }\n : null,\n completedAt\n ? {\n label: t('ai_assistant.chat.records.fields.completed', 'Completed'),\n value: (\n <span className=\"inline-flex items-center gap-1\">\n <CheckCircle2 className=\"size-3 text-status-success-icon\" aria-hidden />\n {completedAt}\n </span>\n ),\n }\n : null,\n props.relatedTo ? { label: t('ai_assistant.chat.records.fields.related', 'Related'), value: props.relatedTo } : null,\n props.ownerName ? { label: t('ai_assistant.chat.records.fields.owner', 'Owner'), value: props.ownerName } : null,\n ].filter(Boolean) as { label: string; value: React.ReactNode }[]\n\n const subtitle = [props.type, props.relatedTo].filter(Boolean).join(' \u2022 ')\n\n return (\n <RecordCardShell\n kindLabel={t('ai_assistant.chat.records.kinds.activity', 'Activity')}\n kindIcon={<Icon className=\"size-4\" aria-hidden />}\n title={props.title}\n subtitle={subtitle || undefined}\n status={status}\n href={props.href}\n id={props.id}\n className={props.className}\n dataKind=\"activity\"\n >\n <div className=\"space-y-2\">\n <KeyValueList items={items} />\n {props.description ? (\n <p className=\"line-clamp-3 text-muted-foreground\">{props.description}</p>\n ) : null}\n {props.tags && props.tags.length > 0 ? <TagRow tags={props.tags} /> : null}\n </div>\n </RecordCardShell>\n )\n}\n\nexport default ActivityCard\n"],
5
+ "mappings": ";AAiDY,SACE,KADF;AA9CZ;AAAA,EACE,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,MAAM,iBAAiB;AAChC,SAAS,cAAc,iBAAiB,QAAQ,0BAA0B;AAE1E,SAAS,kBAAkB;AAE3B,SAAS,iBAAiB,MAA6C;AACrE,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,KAAK,YAAY;AAC3B,MAAI,EAAE,SAAS,MAAM,EAAG,QAAO;AAC/B,MAAI,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,OAAO,EAAG,QAAO;AACtD,MAAI,EAAE,SAAS,SAAS,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO;AACxD,MAAI,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO;AACrD,MAAI,EAAE,SAAS,MAAM,EAAG,QAAO;AAC/B,MAAI,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,UAAU,EAAG,QAAO;AACzD,SAAO;AACT;AAIO,SAAS,aAAa,OAA0B;AACrD,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,OAAO,iBAAiB,MAAM,IAAI;AACxC,QAAM,SAAS,MAAM,SACjB,EAAE,OAAO,MAAM,QAAQ,SAAS,mBAAmB,MAAM,MAAM,EAAE,IACjE;AACJ,QAAM,UAAU,WAAW,MAAM,SAAS,MAAM;AAChD,QAAM,cAAc,WAAW,MAAM,aAAa,MAAM;AAExD,QAAM,QAAQ;AAAA,IACZ,MAAM,OAAO,EAAE,OAAO,EAAE,yCAAyC,MAAM,GAAG,OAAO,MAAM,KAAK,IAAI;AAAA,IAChG,UACI;AAAA,MACE,OAAO,EAAE,wCAAwC,KAAK;AAAA,MACtD,OACE,qBAAC,UAAK,WAAU,kCACd;AAAA,4BAAC,iBAAc,WAAU,gCAA+B,eAAW,MAAC;AAAA,QACnE;AAAA,SACH;AAAA,IAEJ,IACA;AAAA,IACJ,cACI;AAAA,MACE,OAAO,EAAE,8CAA8C,WAAW;AAAA,MAClE,OACE,qBAAC,UAAK,WAAU,kCACd;AAAA,4BAAC,gBAAa,WAAU,mCAAkC,eAAW,MAAC;AAAA,QACrE;AAAA,SACH;AAAA,IAEJ,IACA;AAAA,IACJ,MAAM,YAAY,EAAE,OAAO,EAAE,4CAA4C,SAAS,GAAG,OAAO,MAAM,UAAU,IAAI;AAAA,IAChH,MAAM,YAAY,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,MAAM,UAAU,IAAI;AAAA,EAC9G,EAAE,OAAO,OAAO;AAEhB,QAAM,WAAW,CAAC,MAAM,MAAM,MAAM,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK;AAEzE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,EAAE,4CAA4C,UAAU;AAAA,MACnE,UAAU,oBAAC,QAAK,WAAU,UAAS,eAAW,MAAC;AAAA,MAC/C,OAAO,MAAM;AAAA,MACb,UAAU,YAAY;AAAA,MACtB;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,UAAS;AAAA,MAET,+BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,gBAAa,OAAc;AAAA,QAC3B,MAAM,cACL,oBAAC,OAAE,WAAU,sCAAsC,gBAAM,aAAY,IACnE;AAAA,QACH,MAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,oBAAC,UAAO,MAAM,MAAM,MAAM,IAAK;AAAA,SACxE;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,uBAAQ;",
6
6
  "names": []
7
7
  }
@@ -1,15 +1,16 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Briefcase, Building2, CalendarDays, CircleDollarSign, User } from "lucide-react";
4
- import { useT } from "@open-mercato/shared/lib/i18n/context";
4
+ import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
5
5
  import { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from "./RecordCardShell.js";
6
6
  import { formatCurrency, formatDate } from "../../utils/format.js";
7
7
  function DealCard(props) {
8
8
  const t = useT();
9
+ const locale = useLocale();
9
10
  const status = props.status ? { label: props.status, variant: statusToTagVariant(props.status) } : null;
10
11
  const stage = props.stage && props.stage !== props.status ? props.stage : null;
11
- const amount = formatCurrency(props.amount, props.currency);
12
- const closeDate = formatDate(props.closeDate);
12
+ const amount = formatCurrency(props.amount, props.currency, locale);
13
+ const closeDate = formatDate(props.closeDate, locale);
13
14
  const items = [
14
15
  stage ? { label: t("ai_assistant.chat.records.fields.stage", "Stage"), value: stage } : null,
15
16
  amount ? { label: t("ai_assistant.chat.records.fields.amount", "Amount"), value: /* @__PURE__ */ jsx("span", { className: "font-medium", children: amount }) } : null,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/ai/records/DealCard.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Briefcase, Building2, CalendarDays, CircleDollarSign, User } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'\nimport type { DealRecordPayload } from './types'\nimport { formatCurrency, formatDate } from '../../utils/format'\n\nexport interface DealCardProps extends DealRecordPayload {}\n\nexport function DealCard(props: DealCardProps) {\n const t = useT()\n const status = props.status\n ? { label: props.status, variant: statusToTagVariant(props.status) }\n : null\n const stage = props.stage && props.stage !== props.status ? props.stage : null\n const amount = formatCurrency(props.amount, props.currency)\n const closeDate = formatDate(props.closeDate)\n\n const items = [\n stage ? { label: t('ai_assistant.chat.records.fields.stage', 'Stage'), value: stage } : null,\n amount ? { label: t('ai_assistant.chat.records.fields.amount', 'Amount'), value: <span className=\"font-medium\">{amount}</span> } : null,\n closeDate ? { label: t('ai_assistant.chat.records.fields.close', 'Close'), value: closeDate } : null,\n props.companyName ? { label: t('ai_assistant.chat.records.fields.company', 'Company'), value: props.companyName } : null,\n props.personName ? { label: t('ai_assistant.chat.records.fields.contact', 'Contact'), value: props.personName } : null,\n props.ownerName ? { label: t('ai_assistant.chat.records.fields.owner', 'Owner'), value: props.ownerName } : null,\n ].filter(Boolean) as { label: string; value: React.ReactNode }[]\n\n const subtitleParts: string[] = []\n if (props.companyName) subtitleParts.push(props.companyName)\n if (props.personName && !props.companyName) subtitleParts.push(props.personName)\n if (amount) subtitleParts.push(amount)\n\n return (\n <RecordCardShell\n kindLabel={t('ai_assistant.chat.records.kinds.deal', 'Deal')}\n kindIcon={<Briefcase className=\"size-4\" aria-hidden />}\n title={props.title}\n subtitle={subtitleParts.join(' \u2022 ')}\n status={status}\n href={props.href}\n id={props.id}\n className={props.className}\n dataKind=\"deal\"\n >\n <div className=\"space-y-2\">\n <KeyValueList items={items} />\n {props.description ? (\n <p className=\"line-clamp-2 text-muted-foreground\">{props.description}</p>\n ) : null}\n {props.tags && props.tags.length > 0 ? <TagRow tags={props.tags} /> : null}\n </div>\n </RecordCardShell>\n )\n}\n\nexport default DealCard\n\n// Re-export icons consumers may want when extending the layout\nexport { Briefcase, Building2, CalendarDays, CircleDollarSign, User }\n"],
5
- "mappings": ";AAsBqF,cAwB/E,YAxB+E;AAnBrF,SAAS,WAAW,WAAW,cAAc,kBAAkB,YAAY;AAC3E,SAAS,YAAY;AACrB,SAAS,cAAc,iBAAiB,QAAQ,0BAA0B;AAE1E,SAAS,gBAAgB,kBAAkB;AAIpC,SAAS,SAAS,OAAsB;AAC7C,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,MAAM,SACjB,EAAE,OAAO,MAAM,QAAQ,SAAS,mBAAmB,MAAM,MAAM,EAAE,IACjE;AACJ,QAAM,QAAQ,MAAM,SAAS,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ;AAC1E,QAAM,SAAS,eAAe,MAAM,QAAQ,MAAM,QAAQ;AAC1D,QAAM,YAAY,WAAW,MAAM,SAAS;AAE5C,QAAM,QAAQ;AAAA,IACZ,QAAQ,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,MAAM,IAAI;AAAA,IACxF,SAAS,EAAE,OAAO,EAAE,2CAA2C,QAAQ,GAAG,OAAO,oBAAC,UAAK,WAAU,eAAe,kBAAO,EAAQ,IAAI;AAAA,IACnI,YAAY,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,UAAU,IAAI;AAAA,IAChG,MAAM,cAAc,EAAE,OAAO,EAAE,4CAA4C,SAAS,GAAG,OAAO,MAAM,YAAY,IAAI;AAAA,IACpH,MAAM,aAAa,EAAE,OAAO,EAAE,4CAA4C,SAAS,GAAG,OAAO,MAAM,WAAW,IAAI;AAAA,IAClH,MAAM,YAAY,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,MAAM,UAAU,IAAI;AAAA,EAC9G,EAAE,OAAO,OAAO;AAEhB,QAAM,gBAA0B,CAAC;AACjC,MAAI,MAAM,YAAa,eAAc,KAAK,MAAM,WAAW;AAC3D,MAAI,MAAM,cAAc,CAAC,MAAM,YAAa,eAAc,KAAK,MAAM,UAAU;AAC/E,MAAI,OAAQ,eAAc,KAAK,MAAM;AAErC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,EAAE,wCAAwC,MAAM;AAAA,MAC3D,UAAU,oBAAC,aAAU,WAAU,UAAS,eAAW,MAAC;AAAA,MACpD,OAAO,MAAM;AAAA,MACb,UAAU,cAAc,KAAK,UAAK;AAAA,MAClC;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,UAAS;AAAA,MAET,+BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,gBAAa,OAAc;AAAA,QAC3B,MAAM,cACL,oBAAC,OAAE,WAAU,sCAAsC,gBAAM,aAAY,IACnE;AAAA,QACH,MAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,oBAAC,UAAO,MAAM,MAAM,MAAM,IAAK;AAAA,SACxE;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,mBAAQ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Briefcase, Building2, CalendarDays, CircleDollarSign, User } from 'lucide-react'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'\nimport type { DealRecordPayload } from './types'\nimport { formatCurrency, formatDate } from '../../utils/format'\n\nexport interface DealCardProps extends DealRecordPayload {}\n\nexport function DealCard(props: DealCardProps) {\n const t = useT()\n const locale = useLocale()\n const status = props.status\n ? { label: props.status, variant: statusToTagVariant(props.status) }\n : null\n const stage = props.stage && props.stage !== props.status ? props.stage : null\n const amount = formatCurrency(props.amount, props.currency, locale)\n const closeDate = formatDate(props.closeDate, locale)\n\n const items = [\n stage ? { label: t('ai_assistant.chat.records.fields.stage', 'Stage'), value: stage } : null,\n amount ? { label: t('ai_assistant.chat.records.fields.amount', 'Amount'), value: <span className=\"font-medium\">{amount}</span> } : null,\n closeDate ? { label: t('ai_assistant.chat.records.fields.close', 'Close'), value: closeDate } : null,\n props.companyName ? { label: t('ai_assistant.chat.records.fields.company', 'Company'), value: props.companyName } : null,\n props.personName ? { label: t('ai_assistant.chat.records.fields.contact', 'Contact'), value: props.personName } : null,\n props.ownerName ? { label: t('ai_assistant.chat.records.fields.owner', 'Owner'), value: props.ownerName } : null,\n ].filter(Boolean) as { label: string; value: React.ReactNode }[]\n\n const subtitleParts: string[] = []\n if (props.companyName) subtitleParts.push(props.companyName)\n if (props.personName && !props.companyName) subtitleParts.push(props.personName)\n if (amount) subtitleParts.push(amount)\n\n return (\n <RecordCardShell\n kindLabel={t('ai_assistant.chat.records.kinds.deal', 'Deal')}\n kindIcon={<Briefcase className=\"size-4\" aria-hidden />}\n title={props.title}\n subtitle={subtitleParts.join(' \u2022 ')}\n status={status}\n href={props.href}\n id={props.id}\n className={props.className}\n dataKind=\"deal\"\n >\n <div className=\"space-y-2\">\n <KeyValueList items={items} />\n {props.description ? (\n <p className=\"line-clamp-2 text-muted-foreground\">{props.description}</p>\n ) : null}\n {props.tags && props.tags.length > 0 ? <TagRow tags={props.tags} /> : null}\n </div>\n </RecordCardShell>\n )\n}\n\nexport default DealCard\n\n// Re-export icons consumers may want when extending the layout\nexport { Briefcase, Building2, CalendarDays, CircleDollarSign, User }\n"],
5
+ "mappings": ";AAuBqF,cAwB/E,YAxB+E;AApBrF,SAAS,WAAW,WAAW,cAAc,kBAAkB,YAAY;AAC3E,SAAS,MAAM,iBAAiB;AAChC,SAAS,cAAc,iBAAiB,QAAQ,0BAA0B;AAE1E,SAAS,gBAAgB,kBAAkB;AAIpC,SAAS,SAAS,OAAsB;AAC7C,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,SAAS,MAAM,SACjB,EAAE,OAAO,MAAM,QAAQ,SAAS,mBAAmB,MAAM,MAAM,EAAE,IACjE;AACJ,QAAM,QAAQ,MAAM,SAAS,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ;AAC1E,QAAM,SAAS,eAAe,MAAM,QAAQ,MAAM,UAAU,MAAM;AAClE,QAAM,YAAY,WAAW,MAAM,WAAW,MAAM;AAEpD,QAAM,QAAQ;AAAA,IACZ,QAAQ,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,MAAM,IAAI;AAAA,IACxF,SAAS,EAAE,OAAO,EAAE,2CAA2C,QAAQ,GAAG,OAAO,oBAAC,UAAK,WAAU,eAAe,kBAAO,EAAQ,IAAI;AAAA,IACnI,YAAY,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,UAAU,IAAI;AAAA,IAChG,MAAM,cAAc,EAAE,OAAO,EAAE,4CAA4C,SAAS,GAAG,OAAO,MAAM,YAAY,IAAI;AAAA,IACpH,MAAM,aAAa,EAAE,OAAO,EAAE,4CAA4C,SAAS,GAAG,OAAO,MAAM,WAAW,IAAI;AAAA,IAClH,MAAM,YAAY,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,MAAM,UAAU,IAAI;AAAA,EAC9G,EAAE,OAAO,OAAO;AAEhB,QAAM,gBAA0B,CAAC;AACjC,MAAI,MAAM,YAAa,eAAc,KAAK,MAAM,WAAW;AAC3D,MAAI,MAAM,cAAc,CAAC,MAAM,YAAa,eAAc,KAAK,MAAM,UAAU;AAC/E,MAAI,OAAQ,eAAc,KAAK,MAAM;AAErC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,EAAE,wCAAwC,MAAM;AAAA,MAC3D,UAAU,oBAAC,aAAU,WAAU,UAAS,eAAW,MAAC;AAAA,MACpD,OAAO,MAAM;AAAA,MACb,UAAU,cAAc,KAAK,UAAK;AAAA,MAClC;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,UAAS;AAAA,MAET,+BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,gBAAa,OAAc;AAAA,QAC3B,MAAM,cACL,oBAAC,OAAE,WAAU,sCAAsC,gBAAM,aAAY,IACnE;AAAA,QACH,MAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,oBAAC,UAAO,MAAM,MAAM,MAAM,IAAK;AAAA,SACxE;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,mBAAQ;",
6
6
  "names": []
7
7
  }
@@ -1,13 +1,14 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Package, Tag as TagIcon } from "lucide-react";
4
- import { useT } from "@open-mercato/shared/lib/i18n/context";
4
+ import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
5
5
  import { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from "./RecordCardShell.js";
6
6
  import { formatCurrency } from "../../utils/format.js";
7
7
  function ProductCard(props) {
8
8
  const t = useT();
9
+ const locale = useLocale();
9
10
  const status = props.status ? { label: props.status, variant: statusToTagVariant(props.status) } : null;
10
- const price = formatCurrency(props.price, props.currency);
11
+ const price = formatCurrency(props.price, props.currency, locale);
11
12
  const leading = props.imageUrl ? /* @__PURE__ */ jsx("div", { className: "relative size-12 overflow-hidden rounded-md border border-border bg-muted", children: /* @__PURE__ */ jsx(
12
13
  "img",
13
14
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/ai/records/ProductCard.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Package, Tag as TagIcon } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'\nimport type { ProductRecordPayload } from './types'\nimport { formatCurrency } from '../../utils/format'\n\nexport interface ProductCardProps extends ProductRecordPayload {}\n\nexport function ProductCard(props: ProductCardProps) {\n const t = useT()\n const status = props.status\n ? { label: props.status, variant: statusToTagVariant(props.status) }\n : null\n const price = formatCurrency(props.price, props.currency)\n\n const leading = props.imageUrl ? (\n <div className=\"relative size-12 overflow-hidden rounded-md border border-border bg-muted\">\n <img\n src={props.imageUrl}\n alt={props.name}\n className=\"size-full object-cover\"\n loading=\"lazy\"\n />\n </div>\n ) : (\n <div className=\"flex size-12 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground\" aria-hidden>\n <Package className=\"size-5\" />\n </div>\n )\n\n const items = [\n props.sku ? { label: t('ai_assistant.chat.records.fields.sku', 'SKU'), value: <span className=\"font-mono text-[11px]\">{props.sku}</span> } : null,\n price ? { label: t('ai_assistant.chat.records.fields.price', 'Price'), value: <span className=\"font-medium\">{price}</span> } : null,\n props.category ? { label: t('ai_assistant.chat.records.fields.category', 'Category'), value: props.category } : null,\n ].filter(Boolean) as { label: string; value: React.ReactNode }[]\n\n return (\n <RecordCardShell\n kindLabel={t('ai_assistant.chat.records.kinds.product', 'Product')}\n kindIcon={<Package className=\"size-4\" aria-hidden />}\n leading={leading}\n title={props.name}\n subtitle={[props.sku, price].filter(Boolean).join(' \u2022 ') || undefined}\n status={status}\n href={props.href}\n id={props.id}\n className={props.className}\n dataKind=\"product\"\n >\n <div className=\"space-y-2\">\n <KeyValueList items={items} />\n {props.description ? (\n <p className=\"line-clamp-2 text-muted-foreground\">{props.description}</p>\n ) : null}\n {props.tags && props.tags.length > 0 ? <TagRow tags={props.tags} /> : null}\n </div>\n </RecordCardShell>\n )\n}\n\nexport default ProductCard\n\nexport { Package, TagIcon }\n"],
5
- "mappings": ";AAoBM,cAgCA,YAhCA;AAjBN,SAAS,SAAS,OAAO,eAAe;AACxC,SAAS,YAAY;AACrB,SAAS,cAAc,iBAAiB,QAAQ,0BAA0B;AAE1E,SAAS,sBAAsB;AAIxB,SAAS,YAAY,OAAyB;AACnD,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,MAAM,SACjB,EAAE,OAAO,MAAM,QAAQ,SAAS,mBAAmB,MAAM,MAAM,EAAE,IACjE;AACJ,QAAM,QAAQ,eAAe,MAAM,OAAO,MAAM,QAAQ;AAExD,QAAM,UAAU,MAAM,WACpB,oBAAC,SAAI,WAAU,6EACb;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,MAAM;AAAA,MACX,KAAK,MAAM;AAAA,MACX,WAAU;AAAA,MACV,SAAQ;AAAA;AAAA,EACV,GACF,IAEA,oBAAC,SAAI,WAAU,2GAA0G,eAAW,MAClI,8BAAC,WAAQ,WAAU,UAAS,GAC9B;AAGF,QAAM,QAAQ;AAAA,IACZ,MAAM,MAAM,EAAE,OAAO,EAAE,wCAAwC,KAAK,GAAG,OAAO,oBAAC,UAAK,WAAU,yBAAyB,gBAAM,KAAI,EAAQ,IAAI;AAAA,IAC7I,QAAQ,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,oBAAC,UAAK,WAAU,eAAe,iBAAM,EAAQ,IAAI;AAAA,IAC/H,MAAM,WAAW,EAAE,OAAO,EAAE,6CAA6C,UAAU,GAAG,OAAO,MAAM,SAAS,IAAI;AAAA,EAClH,EAAE,OAAO,OAAO;AAEhB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,EAAE,2CAA2C,SAAS;AAAA,MACjE,UAAU,oBAAC,WAAQ,WAAU,UAAS,eAAW,MAAC;AAAA,MAClD;AAAA,MACA,OAAO,MAAM;AAAA,MACb,UAAU,CAAC,MAAM,KAAK,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK,KAAK;AAAA,MAC5D;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,UAAS;AAAA,MAET,+BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,gBAAa,OAAc;AAAA,QAC3B,MAAM,cACL,oBAAC,OAAE,WAAU,sCAAsC,gBAAM,aAAY,IACnE;AAAA,QACH,MAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,oBAAC,UAAO,MAAM,MAAM,MAAM,IAAK;AAAA,SACxE;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,sBAAQ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Package, Tag as TagIcon } from 'lucide-react'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'\nimport type { ProductRecordPayload } from './types'\nimport { formatCurrency } from '../../utils/format'\n\nexport interface ProductCardProps extends ProductRecordPayload {}\n\nexport function ProductCard(props: ProductCardProps) {\n const t = useT()\n const locale = useLocale()\n const status = props.status\n ? { label: props.status, variant: statusToTagVariant(props.status) }\n : null\n const price = formatCurrency(props.price, props.currency, locale)\n\n const leading = props.imageUrl ? (\n <div className=\"relative size-12 overflow-hidden rounded-md border border-border bg-muted\">\n <img\n src={props.imageUrl}\n alt={props.name}\n className=\"size-full object-cover\"\n loading=\"lazy\"\n />\n </div>\n ) : (\n <div className=\"flex size-12 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground\" aria-hidden>\n <Package className=\"size-5\" />\n </div>\n )\n\n const items = [\n props.sku ? { label: t('ai_assistant.chat.records.fields.sku', 'SKU'), value: <span className=\"font-mono text-[11px]\">{props.sku}</span> } : null,\n price ? { label: t('ai_assistant.chat.records.fields.price', 'Price'), value: <span className=\"font-medium\">{price}</span> } : null,\n props.category ? { label: t('ai_assistant.chat.records.fields.category', 'Category'), value: props.category } : null,\n ].filter(Boolean) as { label: string; value: React.ReactNode }[]\n\n return (\n <RecordCardShell\n kindLabel={t('ai_assistant.chat.records.kinds.product', 'Product')}\n kindIcon={<Package className=\"size-4\" aria-hidden />}\n leading={leading}\n title={props.name}\n subtitle={[props.sku, price].filter(Boolean).join(' \u2022 ') || undefined}\n status={status}\n href={props.href}\n id={props.id}\n className={props.className}\n dataKind=\"product\"\n >\n <div className=\"space-y-2\">\n <KeyValueList items={items} />\n {props.description ? (\n <p className=\"line-clamp-2 text-muted-foreground\">{props.description}</p>\n ) : null}\n {props.tags && props.tags.length > 0 ? <TagRow tags={props.tags} /> : null}\n </div>\n </RecordCardShell>\n )\n}\n\nexport default ProductCard\n\nexport { Package, TagIcon }\n"],
5
+ "mappings": ";AAqBM,cAgCA,YAhCA;AAlBN,SAAS,SAAS,OAAO,eAAe;AACxC,SAAS,MAAM,iBAAiB;AAChC,SAAS,cAAc,iBAAiB,QAAQ,0BAA0B;AAE1E,SAAS,sBAAsB;AAIxB,SAAS,YAAY,OAAyB;AACnD,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,SAAS,MAAM,SACjB,EAAE,OAAO,MAAM,QAAQ,SAAS,mBAAmB,MAAM,MAAM,EAAE,IACjE;AACJ,QAAM,QAAQ,eAAe,MAAM,OAAO,MAAM,UAAU,MAAM;AAEhE,QAAM,UAAU,MAAM,WACpB,oBAAC,SAAI,WAAU,6EACb;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,MAAM;AAAA,MACX,KAAK,MAAM;AAAA,MACX,WAAU;AAAA,MACV,SAAQ;AAAA;AAAA,EACV,GACF,IAEA,oBAAC,SAAI,WAAU,2GAA0G,eAAW,MAClI,8BAAC,WAAQ,WAAU,UAAS,GAC9B;AAGF,QAAM,QAAQ;AAAA,IACZ,MAAM,MAAM,EAAE,OAAO,EAAE,wCAAwC,KAAK,GAAG,OAAO,oBAAC,UAAK,WAAU,yBAAyB,gBAAM,KAAI,EAAQ,IAAI;AAAA,IAC7I,QAAQ,EAAE,OAAO,EAAE,0CAA0C,OAAO,GAAG,OAAO,oBAAC,UAAK,WAAU,eAAe,iBAAM,EAAQ,IAAI;AAAA,IAC/H,MAAM,WAAW,EAAE,OAAO,EAAE,6CAA6C,UAAU,GAAG,OAAO,MAAM,SAAS,IAAI;AAAA,EAClH,EAAE,OAAO,OAAO;AAEhB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,EAAE,2CAA2C,SAAS;AAAA,MACjE,UAAU,oBAAC,WAAQ,WAAU,UAAS,eAAW,MAAC;AAAA,MAClD;AAAA,MACA,OAAO,MAAM;AAAA,MACb,UAAU,CAAC,MAAM,KAAK,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK,KAAK;AAAA,MAC5D;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,UAAS;AAAA,MAET,+BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,gBAAa,OAAc;AAAA,QAC3B,MAAM,cACL,oBAAC,OAAE,WAAU,sCAAsC,gBAAM,aAAY,IACnE;AAAA,QACH,MAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,oBAAC,UAAO,MAAM,MAAM,MAAM,IAAK;AAAA,SACxE;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,sBAAQ;",
6
6
  "names": []
7
7
  }
@@ -17,6 +17,7 @@ import {
17
17
  Bolt,
18
18
  Book,
19
19
  Bookmark,
20
+ Bot,
20
21
  Box,
21
22
  Boxes,
22
23
  Briefcase,
@@ -179,6 +180,7 @@ const LUCIDE_ICON_REGISTRY = {
179
180
  "bolt": Bolt,
180
181
  "book": Book,
181
182
  "bookmark": Bookmark,
183
+ "bot": Bot,
182
184
  "box": Box,
183
185
  "boxes": Boxes,
184
186
  "briefcase": Briefcase,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/icons/lucideRegistry.generated.tsx"],
4
- "sourcesContent": ["/* eslint-disable */\n// AUTO-GENERATED by @open-mercato/ui build. Do not edit by hand.\n// Generated from discovered icon string usages across the repo.\n\nimport type { LucideIcon } from 'lucide-react';\nimport {\n Activity,\n AlarmClock,\n AlertCircle,\n AlertOctagon,\n AlertTriangle,\n Apple,\n Archive,\n AtSign,\n Award,\n BadgeCheck,\n Ban,\n Banknote,\n BarChart2,\n BarChart3,\n Bell,\n Bolt,\n Book,\n Bookmark,\n Box,\n Boxes,\n Briefcase,\n BriefcaseBusiness,\n Building,\n Building2,\n Calendar,\n CalendarCheck,\n CalendarClock,\n CalendarCog,\n CalendarMinus,\n CalendarOff,\n CalendarX,\n Check,\n CheckCircle,\n CheckCircle2,\n CheckSquare,\n Circle,\n ClipboardCheck,\n ClipboardList,\n Clock,\n Clock3,\n Coins,\n Copy,\n CopyX,\n CreditCard,\n Crown,\n Database,\n DollarSign,\n Download,\n ExternalLink,\n Eye,\n FileCheck,\n FileMinus,\n FilePenLine,\n Files,\n FileSpreadsheet,\n FileText,\n FilterX,\n Flag,\n Flame,\n FolderTree,\n Gauge,\n GitBranch,\n GitCompareArrows,\n GitPullRequestArrow,\n Globe,\n GraduationCap,\n Hammer,\n Hand,\n Handshake,\n Headphones,\n Heart,\n HelpCircle,\n Hourglass,\n Inbox,\n Key,\n KeyRound,\n Layers,\n Leaf,\n Lightbulb,\n LineChart,\n Link,\n List,\n ListX,\n Loader,\n Loader2,\n Lock,\n Mail,\n MailOpen,\n Map,\n MapPin,\n MapPinned,\n Megaphone,\n MessageCircle,\n MessageSquareReply,\n MinusCircle,\n Notebook,\n Package,\n PackageCheck,\n PackagePlus,\n PackageSearch,\n PackageX,\n PauseCircle,\n Percent,\n Phone,\n PhoneCall,\n PieChart,\n PlusSquare,\n Receipt,\n ReceiptText,\n RefreshCcw,\n RefreshCw,\n Repeat2,\n Reply,\n RotateCcw,\n Ruler,\n Send,\n Settings,\n Shapes,\n Share2,\n Shield,\n ShieldAlert,\n ShieldCheck,\n ShoppingBag,\n ShoppingCart,\n Shuffle,\n Sliders,\n Smartphone,\n Snowflake,\n Sparkles,\n Star,\n StickyNote,\n Store,\n Tag,\n Target,\n ThumbsUp,\n Ticket,\n Timer,\n Trash2,\n TrendingUp,\n TriangleAlert,\n Trophy,\n Truck,\n Undo,\n Undo2,\n Unlock,\n User,\n UserCheck,\n UserMinus,\n UserPlus,\n UserRound,\n Users,\n UserX,\n Wallet,\n Warehouse,\n Webhook,\n Workflow,\n Wrench,\n X,\n XCircle,\n ZapOff,\n} from 'lucide-react';\n\nexport const LUCIDE_ICON_REGISTRY: Record<string, LucideIcon> = {\n 'activity': Activity,\n 'alarm-clock': AlarmClock,\n 'alert-circle': AlertCircle,\n 'alert-octagon': AlertOctagon,\n 'alert-triangle': AlertTriangle,\n 'apple': Apple,\n 'archive': Archive,\n 'at-sign': AtSign,\n 'award': Award,\n 'badge-check': BadgeCheck,\n 'ban': Ban,\n 'banknote': Banknote,\n 'bar-chart-2': BarChart2,\n 'bar-chart-3': BarChart3,\n 'bell': Bell,\n 'bolt': Bolt,\n 'book': Book,\n 'bookmark': Bookmark,\n 'box': Box,\n 'boxes': Boxes,\n 'briefcase': Briefcase,\n 'briefcase-business': BriefcaseBusiness,\n 'building': Building,\n 'building2': Building2,\n 'calendar': Calendar,\n 'calendar-check': CalendarCheck,\n 'calendar-clock': CalendarClock,\n 'calendar-cog': CalendarCog,\n 'calendar-minus': CalendarMinus,\n 'calendar-off': CalendarOff,\n 'calendar-x': CalendarX,\n 'check': Check,\n 'check-circle': CheckCircle,\n 'check-circle-2': CheckCircle2,\n 'check-square': CheckSquare,\n 'circle': Circle,\n 'clipboard-check': ClipboardCheck,\n 'clipboard-list': ClipboardList,\n 'clock': Clock,\n 'clock-3': Clock3,\n 'coins': Coins,\n 'copy': Copy,\n 'copy-x': CopyX,\n 'credit-card': CreditCard,\n 'crown': Crown,\n 'database': Database,\n 'dollar-sign': DollarSign,\n 'download': Download,\n 'external-link': ExternalLink,\n 'eye': Eye,\n 'file-check': FileCheck,\n 'file-minus': FileMinus,\n 'file-pen-line': FilePenLine,\n 'file-spreadsheet': FileSpreadsheet,\n 'file-text': FileText,\n 'files': Files,\n 'filter-x': FilterX,\n 'flag': Flag,\n 'flame': Flame,\n 'folder-tree': FolderTree,\n 'gauge': Gauge,\n 'git-branch': GitBranch,\n 'git-compare-arrows': GitCompareArrows,\n 'git-pull-request-arrow': GitPullRequestArrow,\n 'globe': Globe,\n 'graduation-cap': GraduationCap,\n 'hammer': Hammer,\n 'hand': Hand,\n 'handshake': Handshake,\n 'headphones': Headphones,\n 'heart': Heart,\n 'help-circle': HelpCircle,\n 'hourglass': Hourglass,\n 'inbox': Inbox,\n 'key': Key,\n 'key-round': KeyRound,\n 'layers': Layers,\n 'leaf': Leaf,\n 'lightbulb': Lightbulb,\n 'line-chart': LineChart,\n 'link': Link,\n 'list': List,\n 'list-x': ListX,\n 'loader': Loader,\n 'loader-2': Loader2,\n 'lock': Lock,\n 'mail': Mail,\n 'mail-open': MailOpen,\n 'map': Map,\n 'map-pin': MapPin,\n 'map-pinned': MapPinned,\n 'megaphone': Megaphone,\n 'message-circle': MessageCircle,\n 'message-square-reply': MessageSquareReply,\n 'minus-circle': MinusCircle,\n 'notebook': Notebook,\n 'package': Package,\n 'package-check': PackageCheck,\n 'package-plus': PackagePlus,\n 'package-search': PackageSearch,\n 'package-x': PackageX,\n 'pause-circle': PauseCircle,\n 'percent': Percent,\n 'phone': Phone,\n 'phone-call': PhoneCall,\n 'pie-chart': PieChart,\n 'plus-square': PlusSquare,\n 'receipt': Receipt,\n 'receipt-text': ReceiptText,\n 'refresh-ccw': RefreshCcw,\n 'refresh-cw': RefreshCw,\n 'repeat-2': Repeat2,\n 'reply': Reply,\n 'rotate-ccw': RotateCcw,\n 'ruler': Ruler,\n 'send': Send,\n 'settings': Settings,\n 'shapes': Shapes,\n 'share-2': Share2,\n 'shield': Shield,\n 'shield-alert': ShieldAlert,\n 'shield-check': ShieldCheck,\n 'shopping-bag': ShoppingBag,\n 'shopping-cart': ShoppingCart,\n 'shuffle': Shuffle,\n 'sliders': Sliders,\n 'smartphone': Smartphone,\n 'snowflake': Snowflake,\n 'sparkles': Sparkles,\n 'star': Star,\n 'sticky-note': StickyNote,\n 'store': Store,\n 'tag': Tag,\n 'target': Target,\n 'thumbs-up': ThumbsUp,\n 'ticket': Ticket,\n 'timer': Timer,\n 'trash-2': Trash2,\n 'trending-up': TrendingUp,\n 'triangle-alert': TriangleAlert,\n 'trophy': Trophy,\n 'truck': Truck,\n 'undo': Undo,\n 'undo-2': Undo2,\n 'unlock': Unlock,\n 'user': User,\n 'user-check': UserCheck,\n 'user-minus': UserMinus,\n 'user-plus': UserPlus,\n 'user-round': UserRound,\n 'user-x': UserX,\n 'users': Users,\n 'wallet': Wallet,\n 'warehouse': Warehouse,\n 'webhook': Webhook,\n 'workflow': Workflow,\n 'wrench': Wrench,\n 'x': X,\n 'x-circle': XCircle,\n 'zap-off': ZapOff,\n};\n"],
5
- "mappings": "AAKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,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",
4
+ "sourcesContent": ["/* eslint-disable */\n// AUTO-GENERATED by @open-mercato/ui build. Do not edit by hand.\n// Generated from discovered icon string usages across the repo.\n\nimport type { LucideIcon } from 'lucide-react';\nimport {\n Activity,\n AlarmClock,\n AlertCircle,\n AlertOctagon,\n AlertTriangle,\n Apple,\n Archive,\n AtSign,\n Award,\n BadgeCheck,\n Ban,\n Banknote,\n BarChart2,\n BarChart3,\n Bell,\n Bolt,\n Book,\n Bookmark,\n Bot,\n Box,\n Boxes,\n Briefcase,\n BriefcaseBusiness,\n Building,\n Building2,\n Calendar,\n CalendarCheck,\n CalendarClock,\n CalendarCog,\n CalendarMinus,\n CalendarOff,\n CalendarX,\n Check,\n CheckCircle,\n CheckCircle2,\n CheckSquare,\n Circle,\n ClipboardCheck,\n ClipboardList,\n Clock,\n Clock3,\n Coins,\n Copy,\n CopyX,\n CreditCard,\n Crown,\n Database,\n DollarSign,\n Download,\n ExternalLink,\n Eye,\n FileCheck,\n FileMinus,\n FilePenLine,\n Files,\n FileSpreadsheet,\n FileText,\n FilterX,\n Flag,\n Flame,\n FolderTree,\n Gauge,\n GitBranch,\n GitCompareArrows,\n GitPullRequestArrow,\n Globe,\n GraduationCap,\n Hammer,\n Hand,\n Handshake,\n Headphones,\n Heart,\n HelpCircle,\n Hourglass,\n Inbox,\n Key,\n KeyRound,\n Layers,\n Leaf,\n Lightbulb,\n LineChart,\n Link,\n List,\n ListX,\n Loader,\n Loader2,\n Lock,\n Mail,\n MailOpen,\n Map,\n MapPin,\n MapPinned,\n Megaphone,\n MessageCircle,\n MessageSquareReply,\n MinusCircle,\n Notebook,\n Package,\n PackageCheck,\n PackagePlus,\n PackageSearch,\n PackageX,\n PauseCircle,\n Percent,\n Phone,\n PhoneCall,\n PieChart,\n PlusSquare,\n Receipt,\n ReceiptText,\n RefreshCcw,\n RefreshCw,\n Repeat2,\n Reply,\n RotateCcw,\n Ruler,\n Send,\n Settings,\n Shapes,\n Share2,\n Shield,\n ShieldAlert,\n ShieldCheck,\n ShoppingBag,\n ShoppingCart,\n Shuffle,\n Sliders,\n Smartphone,\n Snowflake,\n Sparkles,\n Star,\n StickyNote,\n Store,\n Tag,\n Target,\n ThumbsUp,\n Ticket,\n Timer,\n Trash2,\n TrendingUp,\n TriangleAlert,\n Trophy,\n Truck,\n Undo,\n Undo2,\n Unlock,\n User,\n UserCheck,\n UserMinus,\n UserPlus,\n UserRound,\n Users,\n UserX,\n Wallet,\n Warehouse,\n Webhook,\n Workflow,\n Wrench,\n X,\n XCircle,\n ZapOff,\n} from 'lucide-react';\n\nexport const LUCIDE_ICON_REGISTRY: Record<string, LucideIcon> = {\n 'activity': Activity,\n 'alarm-clock': AlarmClock,\n 'alert-circle': AlertCircle,\n 'alert-octagon': AlertOctagon,\n 'alert-triangle': AlertTriangle,\n 'apple': Apple,\n 'archive': Archive,\n 'at-sign': AtSign,\n 'award': Award,\n 'badge-check': BadgeCheck,\n 'ban': Ban,\n 'banknote': Banknote,\n 'bar-chart-2': BarChart2,\n 'bar-chart-3': BarChart3,\n 'bell': Bell,\n 'bolt': Bolt,\n 'book': Book,\n 'bookmark': Bookmark,\n 'bot': Bot,\n 'box': Box,\n 'boxes': Boxes,\n 'briefcase': Briefcase,\n 'briefcase-business': BriefcaseBusiness,\n 'building': Building,\n 'building2': Building2,\n 'calendar': Calendar,\n 'calendar-check': CalendarCheck,\n 'calendar-clock': CalendarClock,\n 'calendar-cog': CalendarCog,\n 'calendar-minus': CalendarMinus,\n 'calendar-off': CalendarOff,\n 'calendar-x': CalendarX,\n 'check': Check,\n 'check-circle': CheckCircle,\n 'check-circle-2': CheckCircle2,\n 'check-square': CheckSquare,\n 'circle': Circle,\n 'clipboard-check': ClipboardCheck,\n 'clipboard-list': ClipboardList,\n 'clock': Clock,\n 'clock-3': Clock3,\n 'coins': Coins,\n 'copy': Copy,\n 'copy-x': CopyX,\n 'credit-card': CreditCard,\n 'crown': Crown,\n 'database': Database,\n 'dollar-sign': DollarSign,\n 'download': Download,\n 'external-link': ExternalLink,\n 'eye': Eye,\n 'file-check': FileCheck,\n 'file-minus': FileMinus,\n 'file-pen-line': FilePenLine,\n 'file-spreadsheet': FileSpreadsheet,\n 'file-text': FileText,\n 'files': Files,\n 'filter-x': FilterX,\n 'flag': Flag,\n 'flame': Flame,\n 'folder-tree': FolderTree,\n 'gauge': Gauge,\n 'git-branch': GitBranch,\n 'git-compare-arrows': GitCompareArrows,\n 'git-pull-request-arrow': GitPullRequestArrow,\n 'globe': Globe,\n 'graduation-cap': GraduationCap,\n 'hammer': Hammer,\n 'hand': Hand,\n 'handshake': Handshake,\n 'headphones': Headphones,\n 'heart': Heart,\n 'help-circle': HelpCircle,\n 'hourglass': Hourglass,\n 'inbox': Inbox,\n 'key': Key,\n 'key-round': KeyRound,\n 'layers': Layers,\n 'leaf': Leaf,\n 'lightbulb': Lightbulb,\n 'line-chart': LineChart,\n 'link': Link,\n 'list': List,\n 'list-x': ListX,\n 'loader': Loader,\n 'loader-2': Loader2,\n 'lock': Lock,\n 'mail': Mail,\n 'mail-open': MailOpen,\n 'map': Map,\n 'map-pin': MapPin,\n 'map-pinned': MapPinned,\n 'megaphone': Megaphone,\n 'message-circle': MessageCircle,\n 'message-square-reply': MessageSquareReply,\n 'minus-circle': MinusCircle,\n 'notebook': Notebook,\n 'package': Package,\n 'package-check': PackageCheck,\n 'package-plus': PackagePlus,\n 'package-search': PackageSearch,\n 'package-x': PackageX,\n 'pause-circle': PauseCircle,\n 'percent': Percent,\n 'phone': Phone,\n 'phone-call': PhoneCall,\n 'pie-chart': PieChart,\n 'plus-square': PlusSquare,\n 'receipt': Receipt,\n 'receipt-text': ReceiptText,\n 'refresh-ccw': RefreshCcw,\n 'refresh-cw': RefreshCw,\n 'repeat-2': Repeat2,\n 'reply': Reply,\n 'rotate-ccw': RotateCcw,\n 'ruler': Ruler,\n 'send': Send,\n 'settings': Settings,\n 'shapes': Shapes,\n 'share-2': Share2,\n 'shield': Shield,\n 'shield-alert': ShieldAlert,\n 'shield-check': ShieldCheck,\n 'shopping-bag': ShoppingBag,\n 'shopping-cart': ShoppingCart,\n 'shuffle': Shuffle,\n 'sliders': Sliders,\n 'smartphone': Smartphone,\n 'snowflake': Snowflake,\n 'sparkles': Sparkles,\n 'star': Star,\n 'sticky-note': StickyNote,\n 'store': Store,\n 'tag': Tag,\n 'target': Target,\n 'thumbs-up': ThumbsUp,\n 'ticket': Ticket,\n 'timer': Timer,\n 'trash-2': Trash2,\n 'trending-up': TrendingUp,\n 'triangle-alert': TriangleAlert,\n 'trophy': Trophy,\n 'truck': Truck,\n 'undo': Undo,\n 'undo-2': Undo2,\n 'unlock': Unlock,\n 'user': User,\n 'user-check': UserCheck,\n 'user-minus': UserMinus,\n 'user-plus': UserPlus,\n 'user-round': UserRound,\n 'user-x': UserX,\n 'users': Users,\n 'wallet': Wallet,\n 'warehouse': Warehouse,\n 'webhook': Webhook,\n 'workflow': Workflow,\n 'wrench': Wrench,\n 'x': X,\n 'x-circle': XCircle,\n 'zap-off': ZapOff,\n};\n"],
5
+ "mappings": "AAKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,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",
6
6
  "names": []
7
7
  }
@@ -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("p", { ref, className: cn("text-sm leading-5", className), ...props })
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": "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",
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": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,4 @@
1
- function formatCurrency(value, currency) {
1
+ function formatCurrency(value, currency, locale) {
2
2
  if (value === null || value === void 0 || value === "") return null;
3
3
  const numeric = typeof value === "number" ? value : Number(value);
4
4
  if (!Number.isFinite(numeric)) {
@@ -7,18 +7,18 @@ function formatCurrency(value, currency) {
7
7
  const code = currency && currency.length === 3 ? currency.toUpperCase() : void 0;
8
8
  try {
9
9
  if (code) {
10
- return new Intl.NumberFormat(void 0, { style: "currency", currency: code }).format(numeric);
10
+ return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(numeric);
11
11
  }
12
12
  } catch {
13
13
  }
14
- const formatted = new Intl.NumberFormat().format(numeric);
14
+ const formatted = new Intl.NumberFormat(locale).format(numeric);
15
15
  return code ? `${formatted} ${code}` : formatted;
16
16
  }
17
- function formatDate(value) {
17
+ function formatDate(value, locale) {
18
18
  if (!value) return null;
19
19
  const date = new Date(value);
20
20
  if (Number.isNaN(date.getTime())) return value;
21
- return date.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
21
+ return date.toLocaleDateString(locale, { year: "numeric", month: "short", day: "numeric" });
22
22
  }
23
23
  export {
24
24
  formatCurrency,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/format.ts"],
4
- "sourcesContent": ["/**\n * Format a monetary value with an optional ISO-4217 currency code.\n *\n * Returns `null` for empty input, the original string for non-numeric input,\n * and falls back to a plain number format (optionally suffixed with the code)\n * when the currency code is missing or rejected by `Intl.NumberFormat`.\n */\nexport function formatCurrency(\n value: string | number | null | undefined,\n currency?: string | null,\n): string | null {\n if (value === null || value === undefined || value === '') return null\n const numeric = typeof value === 'number' ? value : Number(value)\n if (!Number.isFinite(numeric)) {\n return typeof value === 'string' ? value : null\n }\n const code = currency && currency.length === 3 ? currency.toUpperCase() : undefined\n try {\n if (code) {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency: code }).format(numeric)\n }\n } catch {\n // fall through to plain number formatting\n }\n const formatted = new Intl.NumberFormat().format(numeric)\n return code ? `${formatted} ${code}` : formatted\n}\n\n/**\n * Format an ISO date string as a localized short date (e.g. `Jun 9, 2026`).\n *\n * Returns `null` for empty input and echoes the original value back when it is\n * not a parseable date.\n */\nexport function formatDate(value: string | null | undefined): string | null {\n if (!value) return null\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })\n}\n"],
5
- "mappings": "AAOO,SAAS,eACd,OACA,UACe;AACf,MAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,GAAI,QAAO;AAClE,QAAM,UAAU,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAChE,MAAI,CAAC,OAAO,SAAS,OAAO,GAAG;AAC7B,WAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,EAC7C;AACA,QAAM,OAAO,YAAY,SAAS,WAAW,IAAI,SAAS,YAAY,IAAI;AAC1E,MAAI;AACF,QAAI,MAAM;AACR,aAAO,IAAI,KAAK,aAAa,QAAW,EAAE,OAAO,YAAY,UAAU,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,IAC/F;AAAA,EACF,QAAQ;AAAA,EAER;AACA,QAAM,YAAY,IAAI,KAAK,aAAa,EAAE,OAAO,OAAO;AACxD,SAAO,OAAO,GAAG,SAAS,IAAI,IAAI,KAAK;AACzC;AAQO,SAAS,WAAW,OAAiD;AAC1E,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,SAAO,KAAK,mBAAmB,QAAW,EAAE,MAAM,WAAW,OAAO,SAAS,KAAK,UAAU,CAAC;AAC/F;",
4
+ "sourcesContent": ["/**\n * Format a monetary value with an optional ISO-4217 currency code.\n *\n * Returns `null` for empty input, the original string for non-numeric input,\n * and falls back to a plain number format (optionally suffixed with the code)\n * when the currency code is missing or rejected by `Intl.NumberFormat`.\n *\n * Pass `locale` to format in the application locale (`useLocale()` in client\n * components). Omitting it keeps the runtime default, which varies per machine\n * and is therefore not assertable in tests.\n */\nexport function formatCurrency(\n value: string | number | null | undefined,\n currency?: string | null,\n locale?: string,\n): string | null {\n if (value === null || value === undefined || value === '') return null\n const numeric = typeof value === 'number' ? value : Number(value)\n if (!Number.isFinite(numeric)) {\n return typeof value === 'string' ? value : null\n }\n const code = currency && currency.length === 3 ? currency.toUpperCase() : undefined\n try {\n if (code) {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(numeric)\n }\n } catch {\n // fall through to plain number formatting\n }\n const formatted = new Intl.NumberFormat(locale).format(numeric)\n return code ? `${formatted} ${code}` : formatted\n}\n\n/**\n * Format an ISO date string as a localized short date (e.g. `Jun 9, 2026`).\n *\n * Returns `null` for empty input and echoes the original value back when it is\n * not a parseable date. Pass `locale` to format in the application locale.\n */\nexport function formatDate(value: string | null | undefined, locale?: string): string | null {\n if (!value) return null\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' })\n}\n"],
5
+ "mappings": "AAWO,SAAS,eACd,OACA,UACA,QACe;AACf,MAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,GAAI,QAAO;AAClE,QAAM,UAAU,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAChE,MAAI,CAAC,OAAO,SAAS,OAAO,GAAG;AAC7B,WAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,EAC7C;AACA,QAAM,OAAO,YAAY,SAAS,WAAW,IAAI,SAAS,YAAY,IAAI;AAC1E,MAAI;AACF,QAAI,MAAM;AACR,aAAO,IAAI,KAAK,aAAa,QAAQ,EAAE,OAAO,YAAY,UAAU,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,IAC5F;AAAA,EACF,QAAQ;AAAA,EAER;AACA,QAAM,YAAY,IAAI,KAAK,aAAa,MAAM,EAAE,OAAO,OAAO;AAC9D,SAAO,OAAO,GAAG,SAAS,IAAI,IAAI,KAAK;AACzC;AAQO,SAAS,WAAW,OAAkC,QAAgC;AAC3F,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,SAAO,KAAK,mBAAmB,QAAQ,EAAE,MAAM,WAAW,OAAO,SAAS,KAAK,UAAU,CAAC;AAC5F;",
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.7082.1.f2a845b020",
3
+ "version": "0.6.8-develop.7090.1.4dbca7b350",
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.7082.1.f2a845b020",
158
+ "@open-mercato/shared": "0.6.8-develop.7090.1.4dbca7b350",
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.7082.1.f2a845b020",
165
+ "@open-mercato/shared": "0.6.8-develop.7090.1.4dbca7b350",
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', () => {
@@ -12,7 +12,7 @@ import {
12
12
  StickyNote,
13
13
  } from 'lucide-react'
14
14
  import type { LucideIcon } from 'lucide-react'
15
- import { useT } from '@open-mercato/shared/lib/i18n/context'
15
+ import { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'
16
16
  import { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'
17
17
  import type { ActivityRecordPayload } from './types'
18
18
  import { formatDate } from '../../utils/format'
@@ -33,12 +33,13 @@ export interface ActivityCardProps extends ActivityRecordPayload {}
33
33
 
34
34
  export function ActivityCard(props: ActivityCardProps) {
35
35
  const t = useT()
36
+ const locale = useLocale()
36
37
  const Icon = pickActivityIcon(props.type)
37
38
  const status = props.status
38
39
  ? { label: props.status, variant: statusToTagVariant(props.status) }
39
40
  : null
40
- const dueDate = formatDate(props.dueDate)
41
- const completedAt = formatDate(props.completedAt)
41
+ const dueDate = formatDate(props.dueDate, locale)
42
+ const completedAt = formatDate(props.completedAt, locale)
42
43
 
43
44
  const items = [
44
45
  props.type ? { label: t('ai_assistant.chat.records.fields.type', 'Type'), value: props.type } : null,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { Briefcase, Building2, CalendarDays, CircleDollarSign, User } from 'lucide-react'
5
- import { useT } from '@open-mercato/shared/lib/i18n/context'
5
+ import { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'
6
6
  import { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'
7
7
  import type { DealRecordPayload } from './types'
8
8
  import { formatCurrency, formatDate } from '../../utils/format'
@@ -11,12 +11,13 @@ export interface DealCardProps extends DealRecordPayload {}
11
11
 
12
12
  export function DealCard(props: DealCardProps) {
13
13
  const t = useT()
14
+ const locale = useLocale()
14
15
  const status = props.status
15
16
  ? { label: props.status, variant: statusToTagVariant(props.status) }
16
17
  : null
17
18
  const stage = props.stage && props.stage !== props.status ? props.stage : null
18
- const amount = formatCurrency(props.amount, props.currency)
19
- const closeDate = formatDate(props.closeDate)
19
+ const amount = formatCurrency(props.amount, props.currency, locale)
20
+ const closeDate = formatDate(props.closeDate, locale)
20
21
 
21
22
  const items = [
22
23
  stage ? { label: t('ai_assistant.chat.records.fields.stage', 'Stage'), value: stage } : null,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { Package, Tag as TagIcon } from 'lucide-react'
5
- import { useT } from '@open-mercato/shared/lib/i18n/context'
5
+ import { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'
6
6
  import { KeyValueList, RecordCardShell, TagRow, statusToTagVariant } from './RecordCardShell'
7
7
  import type { ProductRecordPayload } from './types'
8
8
  import { formatCurrency } from '../../utils/format'
@@ -11,10 +11,11 @@ export interface ProductCardProps extends ProductRecordPayload {}
11
11
 
12
12
  export function ProductCard(props: ProductCardProps) {
13
13
  const t = useT()
14
+ const locale = useLocale()
14
15
  const status = props.status
15
16
  ? { label: props.status, variant: statusToTagVariant(props.status) }
16
17
  : null
17
- const price = formatCurrency(props.price, props.currency)
18
+ const price = formatCurrency(props.price, props.currency, locale)
18
19
 
19
20
  const leading = props.imageUrl ? (
20
21
  <div className="relative size-12 overflow-hidden rounded-md border border-border bg-muted">
@@ -22,6 +22,7 @@ import {
22
22
  Bolt,
23
23
  Book,
24
24
  Bookmark,
25
+ Bot,
25
26
  Box,
26
27
  Boxes,
27
28
  Briefcase,
@@ -185,6 +186,7 @@ export const LUCIDE_ICON_REGISTRY: Record<string, LucideIcon> = {
185
186
  'bolt': Bolt,
186
187
  'book': Book,
187
188
  'bookmark': Bookmark,
189
+ 'bot': Bot,
188
190
  'box': Box,
189
191
  'boxes': Boxes,
190
192
  'briefcase': Briefcase,
@@ -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('P')
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('P')
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)', () => {
@@ -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
- const AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
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
- <p ref={ref} className={cn('text-sm leading-5', className)} {...props} />
260
+ <div ref={ref} className={cn('text-sm leading-5', className)} {...props} />
258
261
  ),
259
262
  )
260
263
  AlertDescription.displayName = 'AlertDescription'
@@ -1,5 +1,17 @@
1
1
  import { formatCurrency, formatDate } from '../format'
2
2
 
3
+ // Every assertion below pins the locale explicitly (#5105). Without it these tests read the
4
+ // runtime's default locale, so they pass in en-US and fail on any contributor machine whose
5
+ // default is something else.
6
+ const EN = 'en-US'
7
+ const PL = 'pl-PL'
8
+
9
+ // A date-time literal without an offset is parsed as *local* time, so it lands on the same
10
+ // calendar day in every timezone and both the month and the day can be asserted exactly. The
11
+ // instant form cannot: midday UTC keeps the month stable but still shifts the day at the
12
+ // extremes (UTC+14 / UTC-12), which is why the assertions below no longer use one.
13
+ const LOCAL_MIDDAY = '2026-06-09T12:00:00'
14
+
3
15
  describe('formatCurrency', () => {
4
16
  it('returns null for empty input', () => {
5
17
  expect(formatCurrency(null)).toBeNull()
@@ -16,21 +28,25 @@ describe('formatCurrency', () => {
16
28
  })
17
29
 
18
30
  it('formats a numeric value with an ISO currency code', () => {
19
- const result = formatCurrency(1234.5, 'usd')
20
- expect(result).toMatch(/1,234\.5/)
21
- expect(result).toMatch(/\$|USD/)
31
+ expect(formatCurrency(1234.5, 'usd', EN)).toBe('$1,234.50')
22
32
  })
23
33
 
24
34
  it('formats a numeric string the same as a number', () => {
25
- expect(formatCurrency('1234.5', 'USD')).toBe(formatCurrency(1234.5, 'USD'))
35
+ expect(formatCurrency('1234.5', 'USD', EN)).toBe(formatCurrency(1234.5, 'USD', EN))
26
36
  })
27
37
 
28
38
  it('falls back to a plain number without a currency code', () => {
29
- expect(formatCurrency(1000)).toBe(new Intl.NumberFormat().format(1000))
39
+ expect(formatCurrency(1000, null, EN)).toBe('1,000')
30
40
  })
31
41
 
32
42
  it('ignores currency codes that are not three characters', () => {
33
- expect(formatCurrency(1000, 'US')).toBe(new Intl.NumberFormat().format(1000))
43
+ expect(formatCurrency(1000, 'US', EN)).toBe('1,000')
44
+ })
45
+
46
+ it('formats in the requested locale rather than the runtime default', () => {
47
+ expect(formatCurrency(1234.5, 'USD', PL)).toMatch(/^1234,50/)
48
+ expect(formatCurrency(1234.5, 'USD', PL)).toMatch(/USD/)
49
+ expect(formatCurrency(1000, null, PL)).toBe('1000')
34
50
  })
35
51
  })
36
52
 
@@ -46,13 +62,10 @@ describe('formatDate', () => {
46
62
  })
47
63
 
48
64
  it('formats a valid ISO date as a localized short date', () => {
49
- const result = formatDate('2026-06-09T00:00:00.000Z')
50
- expect(result).toEqual(
51
- new Date('2026-06-09T00:00:00.000Z').toLocaleDateString(undefined, {
52
- year: 'numeric',
53
- month: 'short',
54
- day: 'numeric',
55
- }),
56
- )
65
+ expect(formatDate(LOCAL_MIDDAY, EN)).toBe('Jun 9, 2026')
66
+ })
67
+
68
+ it('formats in the requested locale rather than the runtime default', () => {
69
+ expect(formatDate(LOCAL_MIDDAY, PL)).toBe('9 cze 2026')
57
70
  })
58
71
  })
@@ -4,10 +4,15 @@
4
4
  * Returns `null` for empty input, the original string for non-numeric input,
5
5
  * and falls back to a plain number format (optionally suffixed with the code)
6
6
  * when the currency code is missing or rejected by `Intl.NumberFormat`.
7
+ *
8
+ * Pass `locale` to format in the application locale (`useLocale()` in client
9
+ * components). Omitting it keeps the runtime default, which varies per machine
10
+ * and is therefore not assertable in tests.
7
11
  */
8
12
  export function formatCurrency(
9
13
  value: string | number | null | undefined,
10
14
  currency?: string | null,
15
+ locale?: string,
11
16
  ): string | null {
12
17
  if (value === null || value === undefined || value === '') return null
13
18
  const numeric = typeof value === 'number' ? value : Number(value)
@@ -17,12 +22,12 @@ export function formatCurrency(
17
22
  const code = currency && currency.length === 3 ? currency.toUpperCase() : undefined
18
23
  try {
19
24
  if (code) {
20
- return new Intl.NumberFormat(undefined, { style: 'currency', currency: code }).format(numeric)
25
+ return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(numeric)
21
26
  }
22
27
  } catch {
23
28
  // fall through to plain number formatting
24
29
  }
25
- const formatted = new Intl.NumberFormat().format(numeric)
30
+ const formatted = new Intl.NumberFormat(locale).format(numeric)
26
31
  return code ? `${formatted} ${code}` : formatted
27
32
  }
28
33
 
@@ -30,11 +35,11 @@ export function formatCurrency(
30
35
  * Format an ISO date string as a localized short date (e.g. `Jun 9, 2026`).
31
36
  *
32
37
  * Returns `null` for empty input and echoes the original value back when it is
33
- * not a parseable date.
38
+ * not a parseable date. Pass `locale` to format in the application locale.
34
39
  */
35
- export function formatDate(value: string | null | undefined): string | null {
40
+ export function formatDate(value: string | null | undefined, locale?: string): string | null {
36
41
  if (!value) return null
37
42
  const date = new Date(value)
38
43
  if (Number.isNaN(date.getTime())) return value
39
- return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })
44
+ return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' })
40
45
  }