@propeller-commerce/propeller-v2-react-ui 0.4.16 → 0.4.18
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/CHANGELOG.md +26 -0
- package/dist/index.cjs +53 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +53 -23
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,32 @@ once it reaches 1.0. Until then (the `0.x` line) the public API may change
|
|
|
8
8
|
between minor versions; breaking changes are called out below and in
|
|
9
9
|
[MIGRATION.md](./MIGRATION.md).
|
|
10
10
|
|
|
11
|
+
## [0.4.18] - 2026-07-10
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `ProductSpecifications`: new `beforeSpecs?` / `afterSpecs?` render-prop slots.
|
|
16
|
+
Each receives `{ layout: 'table' | 'list' }` and returns arbitrary content
|
|
17
|
+
injected at the start / end of the specifications — inside `<tbody>` for the
|
|
18
|
+
table layout (return a `<tr>`, e.g. a labelled "Unit of measure" row) or in
|
|
19
|
+
the list stack for the list layout (return a block). In grouped mode they
|
|
20
|
+
render once, above the first group / below the last. General replacement for
|
|
21
|
+
hardcoding extra rows; the existing `packageDescription` prop is unchanged.
|
|
22
|
+
- `ProductTabs`: `specificationsBeforeSpecs?` / `specificationsAfterSpecs?`
|
|
23
|
+
passthrough props that forward to the specifications section's new slots.
|
|
24
|
+
|
|
25
|
+
## [0.4.17] - 2026-07-09
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `ProductCard` / `ProductGrid`: new `belowName?: (product: Product) => ReactNode`
|
|
30
|
+
render prop. Renders arbitrary host-supplied content directly below the
|
|
31
|
+
product name (and above the short description / price) in both the grid and
|
|
32
|
+
row layouts, without forking the card — e.g. package descriptions or custom
|
|
33
|
+
badges. On `ProductGrid` it cascades to every card via `ProductGridConfig`;
|
|
34
|
+
on `ProductCard` it can also be set per-card (explicit prop wins over grid
|
|
35
|
+
context). Also exposed as the `<ProductCard.BelowName>` compound subcomponent.
|
|
36
|
+
|
|
11
37
|
## [0.4.16] - 2026-07-09
|
|
12
38
|
|
|
13
39
|
### Added
|
package/dist/index.cjs
CHANGED
|
@@ -13322,7 +13322,8 @@ var RESOLVE_SPEC2 = {
|
|
|
13322
13322
|
addToCartComponent: { grid: "addToCartComponent" },
|
|
13323
13323
|
imageComponent: { grid: "imageComponent" },
|
|
13324
13324
|
badgesComponent: { grid: "badgesComponent" },
|
|
13325
|
-
favoriteComponent: { grid: "favoriteComponent" }
|
|
13325
|
+
favoriteComponent: { grid: "favoriteComponent" },
|
|
13326
|
+
belowName: { grid: "belowName" }
|
|
13326
13327
|
};
|
|
13327
13328
|
var ProductCardContext = React6.createContext(null);
|
|
13328
13329
|
function useProductCard() {
|
|
@@ -13403,6 +13404,7 @@ function ProductCardRoot(rawProps) {
|
|
|
13403
13404
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-card__body flex flex-1 flex-row items-center gap-4 px-4 py-2 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5 flex-1 min-w-0", children: [
|
|
13404
13405
|
props.showSku !== false && sku ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardSku, {}) : null,
|
|
13405
13406
|
props.showName !== false ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardName, { linkable: true }) : null,
|
|
13407
|
+
/* @__PURE__ */ jsxRuntime.jsx(ProductCardBelowName, {}),
|
|
13406
13408
|
textLabelValues.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardTextLabels, {}) : null,
|
|
13407
13409
|
props.showManufacturer && manufacturer ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardManufacturer, {}) : null,
|
|
13408
13410
|
props.showShortDescription && shortDescription ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardShortDescription, {}) : null
|
|
@@ -13418,6 +13420,7 @@ function ProductCardRoot(rawProps) {
|
|
|
13418
13420
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-product-card__body flex flex-1 flex-col gap-1.5 p-3 sm:gap-2 sm:p-4", children: [
|
|
13419
13421
|
props.showSku !== false && sku ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardSku, {}) : null,
|
|
13420
13422
|
props.showName !== false ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardName, { linkable: true }) : null,
|
|
13423
|
+
/* @__PURE__ */ jsxRuntime.jsx(ProductCardBelowName, {}),
|
|
13421
13424
|
textLabelValues.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardTextLabels, {}) : null,
|
|
13422
13425
|
props.showStock && !!product.inventory ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardStock, {}) }) : null,
|
|
13423
13426
|
props.showManufacturer && manufacturer ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardManufacturer, {}) : null,
|
|
@@ -13600,6 +13603,13 @@ function ProductCardStock(props) {
|
|
|
13600
13603
|
}
|
|
13601
13604
|
);
|
|
13602
13605
|
}
|
|
13606
|
+
function ProductCardBelowName() {
|
|
13607
|
+
const { product, resolved } = useProductCard();
|
|
13608
|
+
if (!resolved.belowName) return null;
|
|
13609
|
+
const content = resolved.belowName(product);
|
|
13610
|
+
if (content == null || content === false) return null;
|
|
13611
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-card__below-name", children: content });
|
|
13612
|
+
}
|
|
13603
13613
|
function ProductCardPrice(props) {
|
|
13604
13614
|
const { product, derived, resolved } = useProductCard();
|
|
13605
13615
|
if (!product?.price) return null;
|
|
@@ -13678,6 +13688,7 @@ ProductCard.Badges = ProductCardBadges;
|
|
|
13678
13688
|
ProductCard.Favorite = ProductCardFavorite;
|
|
13679
13689
|
ProductCard.Name = ProductCardName;
|
|
13680
13690
|
ProductCard.Sku = ProductCardSku;
|
|
13691
|
+
ProductCard.BelowName = ProductCardBelowName;
|
|
13681
13692
|
ProductCard.ShortDescription = ProductCardShortDescription;
|
|
13682
13693
|
ProductCard.Manufacturer = ProductCardManufacturer;
|
|
13683
13694
|
ProductCard.TextLabels = ProductCardTextLabels;
|
|
@@ -14060,7 +14071,8 @@ function ProductGrid(rawProps) {
|
|
|
14060
14071
|
badgesComponent: props.badgesComponent,
|
|
14061
14072
|
favoriteComponent: props.favoriteComponent,
|
|
14062
14073
|
productCardComponent: props.productCardComponent,
|
|
14063
|
-
clusterCardComponent: props.clusterCardComponent
|
|
14074
|
+
clusterCardComponent: props.clusterCardComponent,
|
|
14075
|
+
belowName: props.belowName
|
|
14064
14076
|
};
|
|
14065
14077
|
if (rawProps.children !== void 0) {
|
|
14066
14078
|
const compoundCtx = {
|
|
@@ -15103,7 +15115,11 @@ function ProductSpecifications(rawProps) {
|
|
|
15103
15115
|
if (!props.productId || !props.graphqlClient) return;
|
|
15104
15116
|
fetchSpecs(props.productId);
|
|
15105
15117
|
}, [props.productId]);
|
|
15106
|
-
|
|
15118
|
+
const layoutMode = props.layout === "list" ? "list" : "table";
|
|
15119
|
+
const before = props.beforeSpecs?.({ layout: layoutMode });
|
|
15120
|
+
const after = props.afterSpecs?.({ layout: layoutMode });
|
|
15121
|
+
const hasSlotContent = before != null || after != null;
|
|
15122
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: !loading && (hasPublicAttributes() || props.packageDescription || hasSlotContent) ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15107
15123
|
"div",
|
|
15108
15124
|
{
|
|
15109
15125
|
className: `propeller-product-specifications ${props.className || ""}`,
|
|
@@ -15112,26 +15128,38 @@ function ProductSpecifications(rawProps) {
|
|
|
15112
15128
|
children: [
|
|
15113
15129
|
props.packageDescription ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-product-specifications__package-description mb-4 text-sm text-muted-foreground", children: props.packageDescription }) : null,
|
|
15114
15130
|
!props.grouping ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
15115
|
-
props.layout !== "list" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-lg border border-border", children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: "w-full text-sm", children: /* @__PURE__ */ jsxRuntime.
|
|
15116
|
-
|
|
15117
|
-
/* @__PURE__ */ jsxRuntime.
|
|
15118
|
-
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
|
|
15122
|
-
] }
|
|
15131
|
+
props.layout !== "list" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-lg border border-border", children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: "w-full text-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("tbody", { className: "divide-y divide-border", children: [
|
|
15132
|
+
before,
|
|
15133
|
+
getAttributes()?.map((attr, i) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "propeller-product-specifications__row odd:bg-card even:bg-muted/20", children: [
|
|
15134
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2 font-medium text-foreground w-1/2", children: getAttributeLabel(attr) }),
|
|
15135
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2 text-muted-foreground", children: getAttributeValue(attr) })
|
|
15136
|
+
] }, i)),
|
|
15137
|
+
after
|
|
15138
|
+
] }) }) }) : null,
|
|
15139
|
+
props.layout === "list" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
15140
|
+
before,
|
|
15141
|
+
getAttributes()?.map((attr, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
15142
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: getAttributeLabel(attr) }),
|
|
15143
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground", children: getAttributeValue(attr) })
|
|
15144
|
+
] }, i)),
|
|
15145
|
+
after
|
|
15146
|
+
] }) : null
|
|
15123
15147
|
] }) : null,
|
|
15124
|
-
!!props.grouping ? /* @__PURE__ */ jsxRuntime.
|
|
15125
|
-
|
|
15126
|
-
|
|
15127
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
15128
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
15129
|
-
|
|
15130
|
-
|
|
15131
|
-
|
|
15132
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
15133
|
-
|
|
15134
|
-
|
|
15148
|
+
!!props.grouping ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
15149
|
+
before ? layoutMode === "table" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 overflow-hidden rounded-lg border border-border", children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: "w-full text-sm", children: /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: before }) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 space-y-3", children: before }) : null,
|
|
15150
|
+
getGroups()?.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
|
|
15151
|
+
!!group ? /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-2", children: group }) : null,
|
|
15152
|
+
props.layout !== "list" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-lg border border-border", children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: "w-full text-sm", children: /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: getAttributesByGroup(group)?.map((attr, i) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "propeller-product-specifications__row odd:bg-card even:bg-muted/20", children: [
|
|
15153
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2 font-medium text-foreground w-1/2", children: getAttributeLabel(attr) }),
|
|
15154
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2 text-muted-foreground", children: getAttributeValue(attr) })
|
|
15155
|
+
] }, i)) }) }) }) : null,
|
|
15156
|
+
props.layout === "list" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: getAttributesByGroup(group)?.map((attr, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
15157
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: getAttributeLabel(attr) }),
|
|
15158
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground", children: getAttributeValue(attr) })
|
|
15159
|
+
] }, i)) }) : null
|
|
15160
|
+
] }, group)),
|
|
15161
|
+
after ? layoutMode === "table" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 overflow-hidden rounded-lg border border-border", children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: "w-full text-sm", children: /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: after }) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: after }) : null
|
|
15162
|
+
] }) : null
|
|
15135
15163
|
]
|
|
15136
15164
|
}
|
|
15137
15165
|
) }) : null });
|
|
@@ -15340,7 +15368,9 @@ function ProductTabs(rawProps) {
|
|
|
15340
15368
|
language: props.language,
|
|
15341
15369
|
layout: props.specificationsLayout,
|
|
15342
15370
|
grouping: props.specificationsGrouping,
|
|
15343
|
-
packageDescription: props.specificationsPackageDescription
|
|
15371
|
+
packageDescription: props.specificationsPackageDescription,
|
|
15372
|
+
beforeSpecs: props.specificationsBeforeSpecs,
|
|
15373
|
+
afterSpecs: props.specificationsAfterSpecs
|
|
15344
15374
|
}
|
|
15345
15375
|
) }) : null,
|
|
15346
15376
|
isActive("downloads") && isTabVisible("downloads") ? /* @__PURE__ */ jsxRuntime.jsx(
|