@open-mercato/ui 0.6.3-develop.3876.1.d40fe4ec2d → 0.6.3-develop.3894.1.352abf4240
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.
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { AlertCircle } from "lucide-react";
|
|
4
4
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
5
|
+
const TECHNICAL_MESSAGE_PATTERN = /^[a-z0-9]+(?:[._-][a-z0-9]+)+$/;
|
|
6
|
+
function formatErrorMessageLabel(label) {
|
|
7
|
+
const trimmed = label.trim();
|
|
8
|
+
if (!TECHNICAL_MESSAGE_PATTERN.test(trimmed)) return label;
|
|
9
|
+
const parts = trimmed.split(/[._-]+/).filter(Boolean);
|
|
10
|
+
const meaningfulParts = parts.length > 2 ? parts.slice(-2) : parts;
|
|
11
|
+
const sentence = meaningfulParts.join(" ");
|
|
12
|
+
return sentence.charAt(0).toUpperCase() + sentence.slice(1);
|
|
13
|
+
}
|
|
5
14
|
function ErrorMessage({ label, description, action, className, iconClassName }) {
|
|
15
|
+
const displayLabel = formatErrorMessageLabel(label);
|
|
16
|
+
const displayDescription = description ? formatErrorMessageLabel(description) : void 0;
|
|
6
17
|
return /* @__PURE__ */ jsxs(
|
|
7
18
|
"div",
|
|
8
19
|
{
|
|
@@ -14,8 +25,8 @@ function ErrorMessage({ label, description, action, className, iconClassName })
|
|
|
14
25
|
children: [
|
|
15
26
|
/* @__PURE__ */ jsx(AlertCircle, { className: cn("h-4 w-4 flex-none", iconClassName), "aria-hidden": true }),
|
|
16
27
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
17
|
-
/* @__PURE__ */ jsx("p", { className: "leading-tight", children:
|
|
18
|
-
|
|
28
|
+
/* @__PURE__ */ jsx("p", { className: "leading-tight", children: displayLabel }),
|
|
29
|
+
displayDescription ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: displayDescription }) : null,
|
|
19
30
|
action ? /* @__PURE__ */ jsx("div", { className: "pt-1", children: action }) : null
|
|
20
31
|
] })
|
|
21
32
|
]
|
|
@@ -23,6 +34,7 @@ function ErrorMessage({ label, description, action, className, iconClassName })
|
|
|
23
34
|
);
|
|
24
35
|
}
|
|
25
36
|
export {
|
|
26
|
-
ErrorMessage
|
|
37
|
+
ErrorMessage,
|
|
38
|
+
formatErrorMessageLabel
|
|
27
39
|
};
|
|
28
40
|
//# sourceMappingURL=ErrorMessage.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/detail/ErrorMessage.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertCircle } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype ErrorMessageProps = {\n label: string\n description?: string\n action?: React.ReactNode\n className?: string\n iconClassName?: string\n}\n\nexport function ErrorMessage({ label, description, action, className, iconClassName }: ErrorMessageProps) {\n return (\n <div\n className={cn(\n 'flex items-start gap-3 rounded border border-destructive/50 bg-destructive/5 px-3 py-2 text-sm text-destructive',\n className\n )}\n role=\"alert\"\n >\n <AlertCircle className={cn('h-4 w-4 flex-none', iconClassName)} aria-hidden />\n <div className=\"space-y-1\">\n <p className=\"leading-tight\">{
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertCircle } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype ErrorMessageProps = {\n label: string\n description?: string\n action?: React.ReactNode\n className?: string\n iconClassName?: string\n}\n\nconst TECHNICAL_MESSAGE_PATTERN = /^[a-z0-9]+(?:[._-][a-z0-9]+)+$/\n\nexport function formatErrorMessageLabel(label: string): string {\n const trimmed = label.trim()\n if (!TECHNICAL_MESSAGE_PATTERN.test(trimmed)) return label\n\n const parts = trimmed.split(/[._-]+/).filter(Boolean)\n const meaningfulParts = parts.length > 2 ? parts.slice(-2) : parts\n const sentence = meaningfulParts.join(' ')\n return sentence.charAt(0).toUpperCase() + sentence.slice(1)\n}\n\nexport function ErrorMessage({ label, description, action, className, iconClassName }: ErrorMessageProps) {\n const displayLabel = formatErrorMessageLabel(label)\n const displayDescription = description ? formatErrorMessageLabel(description) : undefined\n\n return (\n <div\n className={cn(\n 'flex items-start gap-3 rounded border border-destructive/50 bg-destructive/5 px-3 py-2 text-sm text-destructive',\n className\n )}\n role=\"alert\"\n >\n <AlertCircle className={cn('h-4 w-4 flex-none', iconClassName)} aria-hidden />\n <div className=\"space-y-1\">\n <p className=\"leading-tight\">{displayLabel}</p>\n {displayDescription ? <p className=\"text-muted-foreground\">{displayDescription}</p> : null}\n {action ? <div className=\"pt-1\">{action}</div> : null}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAsCM,cACA,YADA;AAnCN,SAAS,mBAAmB;AAC5B,SAAS,UAAU;AAUnB,MAAM,4BAA4B;AAE3B,SAAS,wBAAwB,OAAuB;AAC7D,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,0BAA0B,KAAK,OAAO,EAAG,QAAO;AAErD,QAAM,QAAQ,QAAQ,MAAM,QAAQ,EAAE,OAAO,OAAO;AACpD,QAAM,kBAAkB,MAAM,SAAS,IAAI,MAAM,MAAM,EAAE,IAAI;AAC7D,QAAM,WAAW,gBAAgB,KAAK,GAAG;AACzC,SAAO,SAAS,OAAO,CAAC,EAAE,YAAY,IAAI,SAAS,MAAM,CAAC;AAC5D;AAEO,SAAS,aAAa,EAAE,OAAO,aAAa,QAAQ,WAAW,cAAc,GAAsB;AACxG,QAAM,eAAe,wBAAwB,KAAK;AAClD,QAAM,qBAAqB,cAAc,wBAAwB,WAAW,IAAI;AAEhF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAK;AAAA,MAEL;AAAA,4BAAC,eAAY,WAAW,GAAG,qBAAqB,aAAa,GAAG,eAAW,MAAC;AAAA,QAC5E,qBAAC,SAAI,WAAU,aACb;AAAA,8BAAC,OAAE,WAAU,iBAAiB,wBAAa;AAAA,UAC1C,qBAAqB,oBAAC,OAAE,WAAU,yBAAyB,8BAAmB,IAAO;AAAA,UACrF,SAAS,oBAAC,SAAI,WAAU,QAAQ,kBAAO,IAAS;AAAA,WACnD;AAAA;AAAA;AAAA,EACF;AAEJ;",
|
|
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.3-develop.
|
|
3
|
+
"version": "0.6.3-develop.3894.1.352abf4240",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -141,13 +141,13 @@
|
|
|
141
141
|
"remark-gfm": "^4.0.1"
|
|
142
142
|
},
|
|
143
143
|
"peerDependencies": {
|
|
144
|
-
"@open-mercato/shared": "0.6.3-develop.
|
|
144
|
+
"@open-mercato/shared": "0.6.3-develop.3894.1.352abf4240",
|
|
145
145
|
"react": ">=18.0.0",
|
|
146
146
|
"react-dom": ">=18.0.0",
|
|
147
147
|
"react-is": ">=18.0.0"
|
|
148
148
|
},
|
|
149
149
|
"devDependencies": {
|
|
150
|
-
"@open-mercato/shared": "0.6.3-develop.
|
|
150
|
+
"@open-mercato/shared": "0.6.3-develop.3894.1.352abf4240",
|
|
151
151
|
"@testing-library/dom": "^10.4.1",
|
|
152
152
|
"@testing-library/jest-dom": "^6.9.1",
|
|
153
153
|
"@testing-library/react": "^16.3.1",
|
|
@@ -12,7 +12,22 @@ type ErrorMessageProps = {
|
|
|
12
12
|
iconClassName?: string
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
const TECHNICAL_MESSAGE_PATTERN = /^[a-z0-9]+(?:[._-][a-z0-9]+)+$/
|
|
16
|
+
|
|
17
|
+
export function formatErrorMessageLabel(label: string): string {
|
|
18
|
+
const trimmed = label.trim()
|
|
19
|
+
if (!TECHNICAL_MESSAGE_PATTERN.test(trimmed)) return label
|
|
20
|
+
|
|
21
|
+
const parts = trimmed.split(/[._-]+/).filter(Boolean)
|
|
22
|
+
const meaningfulParts = parts.length > 2 ? parts.slice(-2) : parts
|
|
23
|
+
const sentence = meaningfulParts.join(' ')
|
|
24
|
+
return sentence.charAt(0).toUpperCase() + sentence.slice(1)
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
export function ErrorMessage({ label, description, action, className, iconClassName }: ErrorMessageProps) {
|
|
28
|
+
const displayLabel = formatErrorMessageLabel(label)
|
|
29
|
+
const displayDescription = description ? formatErrorMessageLabel(description) : undefined
|
|
30
|
+
|
|
16
31
|
return (
|
|
17
32
|
<div
|
|
18
33
|
className={cn(
|
|
@@ -23,8 +38,8 @@ export function ErrorMessage({ label, description, action, className, iconClassN
|
|
|
23
38
|
>
|
|
24
39
|
<AlertCircle className={cn('h-4 w-4 flex-none', iconClassName)} aria-hidden />
|
|
25
40
|
<div className="space-y-1">
|
|
26
|
-
<p className="leading-tight">{
|
|
27
|
-
{
|
|
41
|
+
<p className="leading-tight">{displayLabel}</p>
|
|
42
|
+
{displayDescription ? <p className="text-muted-foreground">{displayDescription}</p> : null}
|
|
28
43
|
{action ? <div className="pt-1">{action}</div> : null}
|
|
29
44
|
</div>
|
|
30
45
|
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { formatErrorMessageLabel } from '../ErrorMessage'
|
|
2
|
+
|
|
3
|
+
describe('formatErrorMessageLabel', () => {
|
|
4
|
+
it('keeps normal user-facing labels unchanged', () => {
|
|
5
|
+
expect(formatErrorMessageLabel('Failed to load product details.')).toBe('Failed to load product details.')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it('formats technical snake-case labels into readable text', () => {
|
|
9
|
+
expect(formatErrorMessageLabel('load_failed')).toBe('Load failed')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('uses the meaningful tail of dotted error keys', () => {
|
|
13
|
+
expect(formatErrorMessageLabel('catalog.products.load_failed')).toBe('Load failed')
|
|
14
|
+
})
|
|
15
|
+
})
|