@voyantjs/products-ui 0.32.3 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,10 @@ pnpm add @voyantjs/products-ui @voyantjs/products-react @voyantjs/ui @tanstack/r
13
13
 
14
14
  All components accept a `className` prop and merge it with `cn()`. Wrap or compose to extend; use the registry copy-paste path (`npx shadcn add @voyant/...`) for components you want to fork outright.
15
15
 
16
+ Page components render with `p-6` outer padding by default and are intended to
17
+ mount directly into an app route outlet. Pass `className` to extend or override
18
+ that spacing when a shell owns the page chrome.
19
+
16
20
  ## Components
17
21
 
18
22
  - `ProductsPage` publishes the product list composition.
@@ -5,5 +5,5 @@ import { useProductsUiMessagesOrDefault } from "../i18n/index.js";
5
5
  import { ProductCategoryList } from "./product-category-list.js";
6
6
  export function ProductCategoriesPage({ pageSize, className } = {}) {
7
7
  const messages = useProductsUiMessagesOrDefault().productCategoriesPage;
8
- return (_jsxs("div", { "data-slot": "product-categories-page", className: cn("flex flex-col gap-6", className), children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold tracking-tight", children: messages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.description })] }), _jsx(ProductCategoryList, { pageSize: pageSize })] }));
8
+ return (_jsxs("div", { "data-slot": "product-categories-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold tracking-tight", children: messages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.description })] }), _jsx(ProductCategoryList, { pageSize: pageSize })] }));
9
9
  }
@@ -46,7 +46,7 @@ export function ProductDetailPage({ id, className, defaultTab = "overview", onBa
46
46
  setDeleteError(error instanceof Error ? error.message : pageMessages.states.deleteFailed);
47
47
  }
48
48
  };
49
- return (_jsxs("div", { "data-slot": "product-detail-page", className: cn("flex flex-col gap-6", className), children: [_jsx(ProductDetailHeader, { product: product, onBack: onBack, onEdit: () => setEditOpen(true), onDelete: () => void handleDelete(), onBookingCreate: onBookingCreate ? () => onBookingCreate(product) : undefined, deleting: remove.isPending, actionsSlot: slots?.header }), deleteError ? _jsx("p", { className: "text-sm text-destructive", children: deleteError }) : null, slots?.afterHeader, _jsxs(Tabs, { defaultValue: defaultTab, children: [_jsxs(TabsList, { className: "w-full justify-start overflow-x-auto", children: [_jsx(TabsTrigger, { value: "overview", children: pageMessages.tabs.overview }), _jsx(TabsTrigger, { value: "media", children: pageMessages.tabs.media }), _jsx(TabsTrigger, { value: "itinerary", children: pageMessages.tabs.itinerary }), _jsx(TabsTrigger, { value: "options", children: pageMessages.tabs.options }), _jsx(TabsTrigger, { value: "versions", children: pageMessages.tabs.versions })] }), _jsx(TabsContent, { value: "overview", className: "mt-4", children: _jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(0,1fr)_320px]", children: [_jsxs("div", { className: "flex flex-col gap-4", children: [slots?.overviewStart, _jsx(ProductOverviewCard, { product: product }), _jsx(ProductCommercialCard, { product: product }), slots?.overviewEnd] }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(ProductDetailSidebar, { product: product }), slots?.sidebar] })] }) }), _jsxs(TabsContent, { value: "media", className: "mt-4 space-y-4", children: [_jsx(ProductMediaSection, { productId: product.id, uploadMedia: uploadMedia }), slots?.mediaEnd] }), _jsxs(TabsContent, { value: "itinerary", className: "mt-4 space-y-4", children: [_jsx(ProductItinerarySection, { productId: product.id, renderDayDetails: renderItineraryDayDetails, renderServiceActions: renderItineraryServiceActions }), slots?.itineraryEnd] }), _jsxs(TabsContent, { value: "options", className: "mt-4 space-y-4", children: [_jsx(ProductOptionsSection, { productId: product.id, renderOptionDetails: renderOptionDetails }), slots?.optionsEnd] }), _jsxs(TabsContent, { value: "versions", className: "mt-4 space-y-4", children: [_jsx(ProductVersionsSection, { productId: product.id }), slots?.versionsEnd] })] }), _jsx(ProductDialog, { open: editOpen, onOpenChange: setEditOpen, product: product, onSuccess: () => setEditOpen(false) })] }));
49
+ return (_jsxs("div", { "data-slot": "product-detail-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsx(ProductDetailHeader, { product: product, onBack: onBack, onEdit: () => setEditOpen(true), onDelete: () => void handleDelete(), onBookingCreate: onBookingCreate ? () => onBookingCreate(product) : undefined, deleting: remove.isPending, actionsSlot: slots?.header }), deleteError ? _jsx("p", { className: "text-sm text-destructive", children: deleteError }) : null, slots?.afterHeader, _jsxs(Tabs, { defaultValue: defaultTab, children: [_jsxs(TabsList, { className: "w-full justify-start overflow-x-auto", children: [_jsx(TabsTrigger, { value: "overview", children: pageMessages.tabs.overview }), _jsx(TabsTrigger, { value: "media", children: pageMessages.tabs.media }), _jsx(TabsTrigger, { value: "itinerary", children: pageMessages.tabs.itinerary }), _jsx(TabsTrigger, { value: "options", children: pageMessages.tabs.options }), _jsx(TabsTrigger, { value: "versions", children: pageMessages.tabs.versions })] }), _jsx(TabsContent, { value: "overview", className: "mt-4", children: _jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(0,1fr)_320px]", children: [_jsxs("div", { className: "flex flex-col gap-4", children: [slots?.overviewStart, _jsx(ProductOverviewCard, { product: product }), _jsx(ProductCommercialCard, { product: product }), slots?.overviewEnd] }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(ProductDetailSidebar, { product: product }), slots?.sidebar] })] }) }), _jsxs(TabsContent, { value: "media", className: "mt-4 space-y-4", children: [_jsx(ProductMediaSection, { productId: product.id, uploadMedia: uploadMedia }), slots?.mediaEnd] }), _jsxs(TabsContent, { value: "itinerary", className: "mt-4 space-y-4", children: [_jsx(ProductItinerarySection, { productId: product.id, renderDayDetails: renderItineraryDayDetails, renderServiceActions: renderItineraryServiceActions }), slots?.itineraryEnd] }), _jsxs(TabsContent, { value: "options", className: "mt-4 space-y-4", children: [_jsx(ProductOptionsSection, { productId: product.id, renderOptionDetails: renderOptionDetails }), slots?.optionsEnd] }), _jsxs(TabsContent, { value: "versions", className: "mt-4 space-y-4", children: [_jsx(ProductVersionsSection, { productId: product.id }), slots?.versionsEnd] })] }), _jsx(ProductDialog, { open: editOpen, onOpenChange: setEditOpen, product: product, onSuccess: () => setEditOpen(false) })] }));
50
50
  }
51
51
  export function ProductDetailHeader({ product, onBack, onEdit, onDelete, onBookingCreate, deleting = false, actionsSlot, className, }) {
52
52
  const messages = useProductsUiMessagesOrDefault();
@@ -141,11 +141,11 @@ export function ProductItinerarySection({ productId, title, description, renderD
141
141
  }
142
142
  function ProductDetailPageLoading({ className }) {
143
143
  const messages = useProductsUiMessagesOrDefault();
144
- return (_jsx("div", { "data-slot": "product-detail-page-loading", className: cn("flex min-h-48 items-center justify-center", className), children: _jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }), messages.productDetailPage.states.loading] }) }));
144
+ return (_jsx("div", { "data-slot": "product-detail-page-loading", className: cn("flex min-h-48 items-center justify-center p-6", className), children: _jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }), messages.productDetailPage.states.loading] }) }));
145
145
  }
146
146
  function ProductDetailPageState({ className, title, description, onBack, }) {
147
147
  const messages = useProductsUiMessagesOrDefault();
148
- return (_jsxs("div", { "data-slot": "product-detail-page-state", className: cn("flex flex-col gap-4", className), children: [onBack ? (_jsxs(Button, { type: "button", variant: "ghost", className: "w-fit", onClick: onBack, children: [_jsx(ArrowLeft, { className: "mr-2 size-4", "aria-hidden": "true" }), messages.productDetailPage.actions.back] })) : null, _jsx(Card, { children: _jsxs(CardContent, { className: "flex min-h-40 flex-col items-center justify-center gap-2 text-center", children: [_jsx(FileText, { className: "size-5 text-muted-foreground", "aria-hidden": "true" }), _jsx("h2", { className: "text-lg font-semibold", children: title }), description ? _jsx("p", { className: "text-sm text-muted-foreground", children: description }) : null] }) })] }));
148
+ return (_jsxs("div", { "data-slot": "product-detail-page-state", className: cn("flex flex-col gap-4 p-6", className), children: [onBack ? (_jsxs(Button, { type: "button", variant: "ghost", className: "w-fit", onClick: onBack, children: [_jsx(ArrowLeft, { className: "mr-2 size-4", "aria-hidden": "true" }), messages.productDetailPage.actions.back] })) : null, _jsx(Card, { children: _jsxs(CardContent, { className: "flex min-h-40 flex-col items-center justify-center gap-2 text-center", children: [_jsx(FileText, { className: "size-5 text-muted-foreground", "aria-hidden": "true" }), _jsx("h2", { className: "text-lg font-semibold", children: title }), description ? _jsx("p", { className: "text-sm text-muted-foreground", children: description }) : null] }) })] }));
149
149
  }
150
150
  function ProductField({ label, value }) {
151
151
  const messages = useProductsUiMessagesOrDefault();
@@ -5,5 +5,5 @@ import { useProductsUiMessagesOrDefault } from "../i18n/index.js";
5
5
  import { ProductTagList } from "./product-tag-list.js";
6
6
  export function ProductTagsPage({ pageSize, className } = {}) {
7
7
  const messages = useProductsUiMessagesOrDefault().productTagsPage;
8
- return (_jsxs("div", { "data-slot": "product-tags-page", className: cn("flex flex-col gap-6", className), children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold tracking-tight", children: messages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.description })] }), _jsx(ProductTagList, { pageSize: pageSize })] }));
8
+ return (_jsxs("div", { "data-slot": "product-tags-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold tracking-tight", children: messages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.description })] }), _jsx(ProductTagList, { pageSize: pageSize })] }));
9
9
  }
@@ -33,7 +33,7 @@ export function ProductTypesPage({ pageSize = DEFAULT_PAGE_SIZE, className, } =
33
33
  const items = data?.data ?? [];
34
34
  const total = data?.total ?? 0;
35
35
  const pageCount = Math.max(1, Math.ceil(total / pageSize));
36
- return (_jsxs("div", { "data-slot": "product-types-page", className: cn("flex flex-col gap-6", className), children: [_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold tracking-tight", children: pageMessages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: pageMessages.description })] }), _jsxs(Button, { size: "sm", onClick: () => {
36
+ return (_jsxs("div", { "data-slot": "product-types-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold tracking-tight", children: pageMessages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: pageMessages.description })] }), _jsxs(Button, { size: "sm", onClick: () => {
37
37
  setEditing(undefined);
38
38
  setSheetOpen(true);
39
39
  }, children: [_jsx(Plus, { className: "mr-1.5 size-3.5" }), pageMessages.addType] })] }), isPending ? (_jsx(ProductTypesListLoading, { loadingLabel: messages.common.loading })) : (_jsx("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: items.length === 0 ? (_jsx("p", { className: "py-12 text-center text-sm text-muted-foreground", children: pageMessages.empty })) : (_jsx("div", { className: "flex flex-col divide-y", children: items.map((item) => (_jsxs("div", { className: "flex items-center justify-between gap-4 px-6 py-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium", children: item.name }), _jsx("span", { className: "font-mono text-xs text-muted-foreground", children: item.code }), !item.active ? (_jsx(Badge, { variant: "secondary", className: "text-xs", children: messages.common.inactive })) : null] }), item.description ? (_jsx("p", { className: "text-xs text-muted-foreground", children: item.description })) : null] }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "size-8 text-muted-foreground", children: _jsx(MoreHorizontal, { className: "size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { onClick: () => {
@@ -4,5 +4,5 @@ import { useProductsUiMessagesOrDefault } from "../i18n/index.js";
4
4
  import { ProductList } from "./product-list.js";
5
5
  export function ProductsPage({ pageSize, onProductOpen, className } = {}) {
6
6
  const productMessages = useProductsUiMessagesOrDefault().productsPage;
7
- return (_jsxs("div", { "data-slot": "products-page", className: cn("flex flex-col gap-6", className), children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold tracking-tight", children: productMessages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: productMessages.description })] }), _jsx(ProductList, { pageSize: pageSize, onSelectProduct: onProductOpen })] }));
7
+ return (_jsxs("div", { "data-slot": "products-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold tracking-tight", children: productMessages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: productMessages.description })] }), _jsx(ProductList, { pageSize: pageSize, onSelectProduct: onProductOpen })] }));
8
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/products-ui",
3
- "version": "0.32.3",
3
+ "version": "0.34.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,17 +45,17 @@
45
45
  "react-dom": "^19.0.0",
46
46
  "react-hook-form": "^7.60.0",
47
47
  "zod": "^4.3.6",
48
- "@voyantjs/availability-react": "0.32.3",
49
- "@voyantjs/catalog-react": "0.32.3",
50
- "@voyantjs/finance": "0.32.3",
51
- "@voyantjs/finance-ui": "0.32.3",
52
- "@voyantjs/pricing-react": "0.32.3",
53
- "@voyantjs/products-react": "0.32.3",
54
- "@voyantjs/suppliers-react": "0.32.3",
55
- "@voyantjs/ui": "0.32.3"
48
+ "@voyantjs/availability-react": "0.34.0",
49
+ "@voyantjs/catalog-react": "0.34.0",
50
+ "@voyantjs/finance": "0.34.0",
51
+ "@voyantjs/finance-ui": "0.34.0",
52
+ "@voyantjs/pricing-react": "0.34.0",
53
+ "@voyantjs/products-react": "0.34.0",
54
+ "@voyantjs/suppliers-react": "0.34.0",
55
+ "@voyantjs/ui": "0.34.0"
56
56
  },
57
57
  "dependencies": {
58
- "@voyantjs/i18n": "0.32.3"
58
+ "@voyantjs/i18n": "0.34.0"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@tanstack/react-query": "^5.96.2",
@@ -68,16 +68,16 @@
68
68
  "typescript": "^6.0.2",
69
69
  "vitest": "^4.1.2",
70
70
  "zod": "^4.3.6",
71
- "@voyantjs/availability-react": "0.32.3",
72
- "@voyantjs/catalog-react": "0.32.3",
73
- "@voyantjs/finance": "0.32.3",
74
- "@voyantjs/finance-ui": "0.32.3",
75
- "@voyantjs/i18n": "0.32.3",
76
- "@voyantjs/pricing-react": "0.32.3",
77
- "@voyantjs/products-react": "0.32.3",
78
- "@voyantjs/suppliers-react": "0.32.3",
71
+ "@voyantjs/availability-react": "0.34.0",
72
+ "@voyantjs/catalog-react": "0.34.0",
73
+ "@voyantjs/finance": "0.34.0",
74
+ "@voyantjs/finance-ui": "0.34.0",
75
+ "@voyantjs/i18n": "0.34.0",
76
+ "@voyantjs/pricing-react": "0.34.0",
77
+ "@voyantjs/products-react": "0.34.0",
78
+ "@voyantjs/suppliers-react": "0.34.0",
79
79
  "@voyantjs/voyant-typescript-config": "0.1.0",
80
- "@voyantjs/ui": "0.32.3"
80
+ "@voyantjs/ui": "0.34.0"
81
81
  },
82
82
  "files": [
83
83
  "dist",