@voyantjs/products-ui 0.33.0 → 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 +4 -0
- package/dist/components/product-categories-page.js +1 -1
- package/dist/components/product-detail-page.js +3 -3
- package/dist/components/product-tags-page.js +1 -1
- package/dist/components/product-types-page.js +1 -1
- package/dist/components/products-page.js +1 -1
- package/package.json +19 -19
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.
|
|
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.
|
|
49
|
-
"@voyantjs/catalog-react": "0.
|
|
50
|
-
"@voyantjs/finance": "0.
|
|
51
|
-
"@voyantjs/finance-ui": "0.
|
|
52
|
-
"@voyantjs/pricing-react": "0.
|
|
53
|
-
"@voyantjs/products-react": "0.
|
|
54
|
-
"@voyantjs/suppliers-react": "0.
|
|
55
|
-
"@voyantjs/ui": "0.
|
|
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.
|
|
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.
|
|
72
|
-
"@voyantjs/catalog-react": "0.
|
|
73
|
-
"@voyantjs/finance": "0.
|
|
74
|
-
"@voyantjs/finance-ui": "0.
|
|
75
|
-
"@voyantjs/i18n": "0.
|
|
76
|
-
"@voyantjs/pricing-react": "0.
|
|
77
|
-
"@voyantjs/products-react": "0.
|
|
78
|
-
"@voyantjs/suppliers-react": "0.
|
|
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.
|
|
80
|
+
"@voyantjs/ui": "0.34.0"
|
|
81
81
|
},
|
|
82
82
|
"files": [
|
|
83
83
|
"dist",
|