@open-mercato/ui 0.6.3-develop.3809.1.bde5459e65 → 0.6.3-develop.3811.1.be22750402

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
1
  Generated lucide registry with 135 icons -> /home/runner/work/open-mercato/open-mercato/packages/ui/src/backend/icons/lucideRegistry.generated.tsx
2
- [build:ui] found 353 entry points
2
+ [build:ui] found 354 entry points
3
3
  [build:ui] built successfully
package/AGENTS.md CHANGED
@@ -4,6 +4,41 @@ UI usage patterns based on customers, sales, and staff modules. Use these defaul
4
4
 
5
5
  > **DS reference:** [`.ai/ds-rules.md`](../../.ai/ds-rules.md) — color tokens, typography, spacing, decision trees. **Component reference (variants/sizes/props/examples/MUST rules):** [`.ai/ui-components.md`](../../.ai/ui-components.md).
6
6
 
7
+ ## Always
8
+
9
+ - Use existing UI primitives and backend components before creating new ones.
10
+ - Use `CrudForm` for create/edit flows and dialog forms unless the task explicitly needs a custom host.
11
+ - Use `DataTable` as the default list view, including portal list pages.
12
+ - Use `apiCall`/`apiCallOrThrow` for backend and portal data calls.
13
+ - Use `useGuardedMutation` for every write that cannot use `CrudForm`.
14
+ - Use i18n keys and `useT()` for user-facing copy.
15
+ - Keep UMES spot IDs, replacement handles, field/group IDs, and portal page metadata stable.
16
+ - Follow `.ai/ds-rules.md` and `.ai/ui-components.md` for tokens, primitives, and component contracts.
17
+
18
+ ## Ask First
19
+
20
+ - Ask before changing primitive APIs, DataTable/CrudForm contracts, portal shell behavior, frozen portal spots, or replacement handles.
21
+ - Ask before creating a new primitive or backend component when an existing component might fit.
22
+ - Ask before changing default interaction patterns for dialogs, bulk actions, row clicks, or portal navigation.
23
+
24
+ ## Never
25
+
26
+ - Never use raw `<button>`, raw checkbox inputs, or raw `<Link>` styled as a button.
27
+ - Never use raw `fetch` in UI data flows where `apiCall` is available.
28
+ - Never hard-code user-facing strings.
29
+ - Never use `window.confirm`; use the shared confirmation dialog.
30
+ - Never add custom per-page progress bars for DataTable bulk work.
31
+ - Never omit `page.meta.ts` for guarded portal pages.
32
+ - Never gate wildcard feature arrays with `includes(...)` or `Set.has(...)`.
33
+
34
+ ## Validation Commands
35
+
36
+ ```bash
37
+ yarn workspace @open-mercato/ui test
38
+ yarn workspace @open-mercato/ui build
39
+ yarn i18n:check
40
+ ```
41
+
7
42
  ## Reference Modules
8
43
 
9
44
  - Customers: `packages/core/src/modules/customers/backend/customers/people/create/page.tsx`, `…/people/page.tsx`, `…/components/detail/TaskForm.tsx`
@@ -45,7 +80,7 @@ When you need… use this. Details (variants, sizes, props, MUST rules) live in
45
80
  | Breadcrumb navigation (DS-aligned, slash/arrow/dot divider, ARIA correct) | `Breadcrumb` (with `BreadcrumbList` / `BreadcrumbItem` / `BreadcrumbLink` / `BreadcrumbPage` / `BreadcrumbStatic` / `BreadcrumbSeparator` / `BreadcrumbEllipsis`) | `@open-mercato/ui/primitives/breadcrumb` |
46
81
  | Wrap a `<Link>` as button | `Button asChild` / `IconButton asChild` | — |
47
82
 
48
- ## Critical MUST rules (top of mind)
83
+ ## Critical Primitive Rules
49
84
 
50
85
  1. **NEVER use raw `<button>` or `<input type="checkbox">`** — always use the primitives. Native checkboxes get `accent-color: var(--accent-indigo)` as a safety net for legacy code, but new code MUST use `Checkbox`.
51
86
  2. **Always pass `type="button"` explicitly** on non-submit `Button`/`IconButton` — HTML defaults to `submit`.
@@ -119,7 +154,7 @@ import { Avatar, AvatarStack } from '@open-mercato/ui/primitives/avatar'
119
154
  // renders: JK · OZ · AN · +1
120
155
  ```
121
156
 
122
- ### MUST rules
157
+ ### Usage Rules
123
158
 
124
159
  - NEVER render `<div className="rounded-full bg-muted ...">` for avatars — use `Avatar`
125
160
  - `size="sm"` uses `text-[9px]` — DS exception for tiny initials (same as notification badge count)
@@ -157,7 +192,7 @@ import { Kbd, KbdShortcut } from '@open-mercato/ui/primitives/kbd'
157
192
  </span>
158
193
  ```
159
194
 
160
- ### MUST rules
195
+ ### Usage Rules
161
196
 
162
197
  - NEVER use raw `<span>` or `<code>` to display keyboard keys — use `Kbd`
163
198
  - Platform-specific keys (`⌘` vs `Ctrl`): detect with `navigator.platform` or use `Ctrl/⌘` text when cross-platform
@@ -220,7 +255,7 @@ const leadTagMap: TagMap<'customer' | 'hot' | 'inactive' | 'renewal'> = {
220
255
  <Tag variant={leadTagMap[tag.type]} dot>{tag.label}</Tag>
221
256
  ```
222
257
 
223
- ### MUST rules
258
+ ### Usage Rules
224
259
 
225
260
  - NEVER hardcode colors on `Tag` — use variants only
226
261
  - Use `dot` for tags that represent a status-like category (Customer, Hot); omit for purely descriptive labels
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import Link from "next/link";
4
+ import { Button } from "@open-mercato/ui/primitives/button";
5
+ import { ErrorMessage } from "./ErrorMessage.js";
6
+ import { cn } from "@open-mercato/shared/lib/utils";
7
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
8
+ function RecordNotFoundState({
9
+ label,
10
+ description,
11
+ backHref,
12
+ backLabel,
13
+ action,
14
+ className
15
+ }) {
16
+ const t = useT();
17
+ const defaultAction = backHref ? /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: backHref, children: backLabel ?? t("ui.recordNotFound.backToList", "Back to list") }) }) : null;
18
+ return /* @__PURE__ */ jsx(
19
+ "div",
20
+ {
21
+ className: cn(
22
+ "flex flex-col items-center justify-center min-h-[50vh] px-4",
23
+ className
24
+ ),
25
+ children: /* @__PURE__ */ jsx(
26
+ ErrorMessage,
27
+ {
28
+ label,
29
+ description,
30
+ action: action ?? defaultAction
31
+ }
32
+ )
33
+ }
34
+ );
35
+ }
36
+ export {
37
+ RecordNotFoundState
38
+ };
39
+ //# sourceMappingURL=RecordNotFoundState.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/backend/detail/RecordNotFoundState.tsx"],
4
+ "sourcesContent": ["\"use client\";\n\nimport * as React from \"react\";\nimport Link from \"next/link\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { ErrorMessage } from \"./ErrorMessage\";\nimport { cn } from \"@open-mercato/shared/lib/utils\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\n\nexport type RecordNotFoundStateProps = {\n label: string;\n description?: string;\n backHref?: string;\n backLabel?: string;\n action?: React.ReactNode;\n className?: string;\n};\n\nexport function RecordNotFoundState({\n label,\n description,\n backHref,\n backLabel,\n action,\n className,\n}: RecordNotFoundStateProps) {\n const t = useT();\n const defaultAction = backHref ? (\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href={backHref}>{backLabel ?? t('ui.recordNotFound.backToList','Back to list')}</Link>\n </Button>\n ) : null;\n\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center min-h-[50vh] px-4\",\n className,\n )}\n >\n <ErrorMessage\n label={label}\n description={description}\n action={action ?? defaultAction}\n />\n </div>\n );\n}\n"],
5
+ "mappings": ";AA6BM;AA1BN,OAAO,UAAU;AACjB,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,UAAU;AACnB,SAAS,YAAY;AAWd,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6B;AAC3B,QAAM,IAAI,KAAK;AACf,QAAM,gBAAgB,WACpB,oBAAC,UAAO,SAAO,MAAC,SAAQ,WAAU,MAAK,MACrC,8BAAC,QAAK,MAAM,UAAW,uBAAa,EAAE,gCAA+B,cAAc,GAAE,GACvF,IACE;AAEJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,QAAQ,UAAU;AAAA;AAAA,MACpB;AAAA;AAAA,EACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -3,6 +3,7 @@ export * from "./DetailFieldsSection.js";
3
3
  export * from "./LoadingMessage.js";
4
4
  export * from "./ErrorMessage.js";
5
5
  export * from "./AccessDeniedMessage.js";
6
+ import { RecordNotFoundState } from "./RecordNotFoundState.js";
6
7
  export * from "./TabEmptyState.js";
7
8
  export * from "./CustomDataSection.js";
8
9
  export * from "./TagsSection.js";
@@ -28,6 +29,7 @@ export {
28
29
  AddressView,
29
30
  AddressesSection,
30
31
  NotesSection,
32
+ RecordNotFoundState,
31
33
  formatAddressJson,
32
34
  formatAddressLines,
33
35
  formatAddressString,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/detail/index.ts"],
4
- "sourcesContent": ["export * from './InlineEditors'\nexport * from './DetailFieldsSection'\nexport * from './LoadingMessage'\nexport * from './ErrorMessage'\nexport * from './AccessDeniedMessage'\nexport * from './TabEmptyState'\nexport * from './CustomDataSection'\nexport * from './TagsSection'\nexport { NotesSection, mapCommentSummary } from './NotesSection'\nexport type { NotesSectionProps, CommentSummary, SectionAction, TabEmptyStateConfig } from './NotesSection'\nexport { ActivitiesSection } from './ActivitiesSection'\nexport type {\n ActivitiesSectionProps,\n ActivitiesDataAdapter,\n ActivitySummary,\n ActivityCreatePayload,\n ActivityUpdatePayload,\n ActivityFormBaseValues,\n ActivityFormSubmitPayload,\n} from './ActivitiesSection'\nexport { AddressesSection } from './AddressesSection'\nexport type { AddressesSectionProps, AddressDataAdapter, AddressSummary } from './AddressesSection'\nexport { default as AddressTiles } from './AddressTiles'\nexport type { AddressInput, AddressValue as AddressTileValue, Translator as AddressTilesTranslator } from './AddressTiles'\nexport { default as AddressEditor } from './AddressEditor'\nexport type {\n AddressTypeOption,\n AddressTypesAdapter,\n AddressEditorDraft,\n AddressEditorField,\n} from './AddressEditor'\nexport {\n AddressView,\n formatAddressJson,\n formatAddressLines,\n formatAddressString,\n} from './addressFormat'\nexport type {\n AddressFormatStrategy,\n AddressJsonShape,\n AddressValue as AddressFormatValue,\n} from './addressFormat'\nexport * from './AttachmentMetadataDialog'\nexport * from './AttachmentDeleteDialog'\nexport * from './AttachmentsSection'\nexport * from './AttachmentVisualPreview'\n"],
5
- "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,cAAc,yBAAyB;AAEhD,SAAS,yBAAyB;AAUlC,SAAS,wBAAwB;AAEjC,SAAoB,WAAXA,gBAA+B;AAExC,SAAoB,WAAXA,gBAAgC;AAOzC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * from './InlineEditors'\nexport * from './DetailFieldsSection'\nexport * from './LoadingMessage'\nexport * from './ErrorMessage'\nexport * from './AccessDeniedMessage'\nexport { RecordNotFoundState } from './RecordNotFoundState'\nexport type { RecordNotFoundStateProps } from './RecordNotFoundState'\nexport * from './TabEmptyState'\nexport * from './CustomDataSection'\nexport * from './TagsSection'\nexport { NotesSection, mapCommentSummary } from './NotesSection'\nexport type { NotesSectionProps, CommentSummary, SectionAction, TabEmptyStateConfig } from './NotesSection'\nexport { ActivitiesSection } from './ActivitiesSection'\nexport type {\n ActivitiesSectionProps,\n ActivitiesDataAdapter,\n ActivitySummary,\n ActivityCreatePayload,\n ActivityUpdatePayload,\n ActivityFormBaseValues,\n ActivityFormSubmitPayload,\n} from './ActivitiesSection'\nexport { AddressesSection } from './AddressesSection'\nexport type { AddressesSectionProps, AddressDataAdapter, AddressSummary } from './AddressesSection'\nexport { default as AddressTiles } from './AddressTiles'\nexport type { AddressInput, AddressValue as AddressTileValue, Translator as AddressTilesTranslator } from './AddressTiles'\nexport { default as AddressEditor } from './AddressEditor'\nexport type {\n AddressTypeOption,\n AddressTypesAdapter,\n AddressEditorDraft,\n AddressEditorField,\n} from './AddressEditor'\nexport {\n AddressView,\n formatAddressJson,\n formatAddressLines,\n formatAddressString,\n} from './addressFormat'\nexport type {\n AddressFormatStrategy,\n AddressJsonShape,\n AddressValue as AddressFormatValue,\n} from './addressFormat'\nexport * from './AttachmentMetadataDialog'\nexport * from './AttachmentDeleteDialog'\nexport * from './AttachmentsSection'\nexport * from './AttachmentVisualPreview'\n"],
5
+ "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,2BAA2B;AAEpC,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,cAAc,yBAAyB;AAEhD,SAAS,yBAAyB;AAUlC,SAAS,wBAAwB;AAEjC,SAAoB,WAAXA,gBAA+B;AAExC,SAAoB,WAAXA,gBAAgC;AAOzC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
6
  "names": ["default"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/ui",
3
- "version": "0.6.3-develop.3809.1.bde5459e65",
3
+ "version": "0.6.3-develop.3811.1.be22750402",
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.3809.1.bde5459e65",
144
+ "@open-mercato/shared": "0.6.3-develop.3811.1.be22750402",
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.3809.1.bde5459e65",
150
+ "@open-mercato/shared": "0.6.3-develop.3811.1.be22750402",
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",
@@ -2,15 +2,34 @@
2
2
 
3
3
  Use `@open-mercato/ui/backend` for all admin/backend page components. See `packages/ui/AGENTS.md` for full UI patterns.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
7
  1. **MUST set stable `id` values on `RowActions` items** — use `edit`, `open`, `delete`, etc. DataTable resolves default row-click behavior from these ids
8
8
  2. **MUST use `apiCall`/`apiCallOrThrow`** from `@open-mercato/ui/backend/utils/apiCall` — never use raw `fetch`
9
9
  3. **MUST use `LoadingMessage`/`ErrorMessage`** from `@open-mercato/ui/backend/detail` for loading and error states
10
- 4. **MUST NOT hard-code user-facing strings** — use `useT()` for all labels and messages
10
+ 4. **MUST use `useT()`** for all labels and messages
11
11
  5. **MUST use `useGuardedMutation` when not using `CrudForm`** — wrap every write operation (`POST`/`PUT`/`PATCH`/`DELETE`) in `runMutation({ operation, context, mutationPayload })` so global mutation injections (record locks, conflict UI, future guards) run consistently
12
- 6. **MUST use `Button` or `IconButton`** for every interactive button — never use raw `<button>` elements. Use `IconButton` for icon-only buttons, `Button` for everything else. Always pass `type="button"` explicitly on non-submit buttons. See `packages/ui/AGENTS.md` → Button and IconButton Usage for full patterns and variant reference.
13
- 7. **MUST treat missing records as a dedicated page-level state** — distinguish `notFound` from generic `error`, return early, and render a shared `ErrorMessage`-based state with a clear recovery action (for example, back to the owning list page). Do not render `CrudForm`, detail sections, tabs, or record actions when the record is missing.
12
+ 6. **MUST use `Button` or `IconButton`** for every interactive button. Use `IconButton` for icon-only buttons, `Button` for everything else. Always pass `type="button"` explicitly on non-submit buttons. See `packages/ui/AGENTS.md` → Button and IconButton Usage for full patterns and variant reference.
13
+ 7. **MUST treat missing records as a dedicated page-level state** — distinguish `notFound` from generic `error`, return early, and render a shared `ErrorMessage`-based state with a clear recovery action (for example, back to the owning list page).
14
+
15
+ ## Ask First
16
+
17
+ - Ask before changing DataTable row-click defaults, UMES host surface IDs, CrudForm event behavior, or replacement handles.
18
+ - Ask before introducing backend-page write flows that do not fit `CrudForm` or `useGuardedMutation`.
19
+
20
+ ## Never
21
+
22
+ - Never use raw `fetch` from backend UI components.
23
+ - Never hard-code user-facing strings.
24
+ - Never use raw `<button>` elements.
25
+ - Never render `CrudForm`, detail sections, tabs, or record actions when the record is missing.
26
+
27
+ ## Validation Commands
28
+
29
+ ```bash
30
+ yarn workspace @open-mercato/ui test
31
+ yarn workspace @open-mercato/ui build
32
+ ```
14
33
 
15
34
  ## DataTable Row-Click Behavior
16
35
 
@@ -0,0 +1,48 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import Link from "next/link";
5
+ import { Button } from "@open-mercato/ui/primitives/button";
6
+ import { ErrorMessage } from "./ErrorMessage";
7
+ import { cn } from "@open-mercato/shared/lib/utils";
8
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
9
+
10
+ export type RecordNotFoundStateProps = {
11
+ label: string;
12
+ description?: string;
13
+ backHref?: string;
14
+ backLabel?: string;
15
+ action?: React.ReactNode;
16
+ className?: string;
17
+ };
18
+
19
+ export function RecordNotFoundState({
20
+ label,
21
+ description,
22
+ backHref,
23
+ backLabel,
24
+ action,
25
+ className,
26
+ }: RecordNotFoundStateProps) {
27
+ const t = useT();
28
+ const defaultAction = backHref ? (
29
+ <Button asChild variant="outline" size="sm">
30
+ <Link href={backHref}>{backLabel ?? t('ui.recordNotFound.backToList','Back to list')}</Link>
31
+ </Button>
32
+ ) : null;
33
+
34
+ return (
35
+ <div
36
+ className={cn(
37
+ "flex flex-col items-center justify-center min-h-[50vh] px-4",
38
+ className,
39
+ )}
40
+ >
41
+ <ErrorMessage
42
+ label={label}
43
+ description={description}
44
+ action={action ?? defaultAction}
45
+ />
46
+ </div>
47
+ );
48
+ }
@@ -3,6 +3,8 @@ export * from './DetailFieldsSection'
3
3
  export * from './LoadingMessage'
4
4
  export * from './ErrorMessage'
5
5
  export * from './AccessDeniedMessage'
6
+ export { RecordNotFoundState } from './RecordNotFoundState'
7
+ export type { RecordNotFoundStateProps } from './RecordNotFoundState'
6
8
  export * from './TabEmptyState'
7
9
  export * from './CustomDataSection'
8
10
  export * from './TagsSection'