@propeller-commerce/propeller-v2-react-ui 0.15.11 → 0.18.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/dist/pure.d.cts CHANGED
@@ -245,6 +245,16 @@ interface OrderItemCardProps {
245
245
  orderItem: OrderItem;
246
246
  /** Child order items (rendered as indented sub-rows beneath the parent) */
247
247
  childItems?: OrderItem[];
248
+ /**
249
+ * Language used to resolve localized product names and the slugs in the
250
+ * item's PDP link. Defaults to the catalog's default language.
251
+ *
252
+ * This component is RSC-safe (no hooks, no context), so the host has to pass
253
+ * it — there is nothing to read it from. Without it a non-default storefront
254
+ * renders default-language names and, worse, default-language slugs in the
255
+ * links (PWP-940).
256
+ */
257
+ language?: string;
248
258
  /** Should the item title be a link to the PDP */
249
259
  titleLinkable?: boolean;
250
260
  /** Display a small thumbnail of the order item */
package/dist/pure.d.ts CHANGED
@@ -245,6 +245,16 @@ interface OrderItemCardProps {
245
245
  orderItem: OrderItem;
246
246
  /** Child order items (rendered as indented sub-rows beneath the parent) */
247
247
  childItems?: OrderItem[];
248
+ /**
249
+ * Language used to resolve localized product names and the slugs in the
250
+ * item's PDP link. Defaults to the catalog's default language.
251
+ *
252
+ * This component is RSC-safe (no hooks, no context), so the host has to pass
253
+ * it — there is nothing to read it from. Without it a non-default storefront
254
+ * renders default-language names and, worse, default-language slugs in the
255
+ * links (PWP-940).
256
+ */
257
+ language?: string;
248
258
  /** Should the item title be a link to the PDP */
249
259
  titleLinkable?: boolean;
250
260
  /** Display a small thumbnail of the order item */
package/dist/pure.js CHANGED
@@ -1,9 +1,14 @@
1
- import { buildClusterJsonLd, safeJsonStringify, buildItemListJsonLd, buildProductJsonLd, getLabel, isContentHidden, formatPrice, getCountryName } from '@propeller-commerce/propeller-v2-core-ui';
1
+ import { buildClusterJsonLd, safeJsonStringify, buildItemListJsonLd, buildProductJsonLd, getLabel, getLocalizedValue, isContentHidden, formatPrice, getCountryName } from '@propeller-commerce/propeller-v2-core-ui';
2
+ import { clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
2
4
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
5
  import * as React from 'react';
4
6
  import { OrderDiscountType, YesNo } from '@propeller-commerce/propeller-sdk-v2';
5
7
 
6
8
  // src/components/Breadcrumbs.tsx
9
+ function cn(...inputs) {
10
+ return twMerge(clsx(inputs));
11
+ }
7
12
  function Breadcrumbs(props) {
8
13
  const lang = props.language || "NL";
9
14
  const path = props.categoryPath || [];
@@ -36,7 +41,7 @@ function Breadcrumbs(props) {
36
41
  return index === displayItems.length - 1;
37
42
  }
38
43
  const showSeparatorBefore = (index) => props.showHome !== false || index > 0;
39
- return /* @__PURE__ */ jsx("nav", { "aria-label": getLabel(props.labels, "breadcrumbAriaLabel", "Breadcrumb"), className: `propeller-breadcrumbs ${props.className || ""}`, children: /* @__PURE__ */ jsxs("ol", { className: "propeller-breadcrumbs__list flex flex-wrap items-center text-sm text-muted-foreground", children: [
44
+ return /* @__PURE__ */ jsx("nav", { "aria-label": getLabel(props.labels, "breadcrumbAriaLabel", "Breadcrumb"), className: cn(`propeller-breadcrumbs ${props.className || ""}`), children: /* @__PURE__ */ jsxs("ol", { className: "propeller-breadcrumbs__list flex flex-wrap items-center text-sm text-muted-foreground", children: [
40
45
  props.showHome !== false ? /* @__PURE__ */ jsx("li", { className: "propeller-breadcrumbs__item flex items-center", "data-home": "true", children: /* @__PURE__ */ jsx(
41
46
  "a",
42
47
  {
@@ -142,7 +147,7 @@ function CategoryShortDescription(props) {
142
147
  (d) => d.language === props.language
143
148
  );
144
149
  const html = match?.value || "";
145
- return /* @__PURE__ */ jsx(Fragment, { children: !!html ? /* @__PURE__ */ jsx("div", { className: `propeller-category-short-description mb-6 ${props.className || ""}`, children: /* @__PURE__ */ jsx(
150
+ return /* @__PURE__ */ jsx(Fragment, { children: !!html ? /* @__PURE__ */ jsx("div", { className: cn(`propeller-category-short-description mb-6 ${props.className || ""}`), children: /* @__PURE__ */ jsx(
146
151
  "div",
147
152
  {
148
153
  className: "propeller-category-short-description__content prose prose-slate max-w-none text-muted-foreground",
@@ -152,7 +157,7 @@ function CategoryShortDescription(props) {
152
157
  }
153
158
  var CategoryShortDescription_default = CategoryShortDescription;
154
159
  function GridTitle(props) {
155
- return /* @__PURE__ */ jsx("div", { className: `propeller-grid-title mb-8 ${props.className || ""}`, children: /* @__PURE__ */ jsxs("div", { className: "propeller-grid-title__row flex items-baseline gap-3 mb-3", children: [
160
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-grid-title mb-8 ${props.className || ""}`), children: /* @__PURE__ */ jsxs("div", { className: "propeller-grid-title__row flex items-baseline gap-3 mb-3", children: [
156
161
  props.headingLevel === "h2" ? /* @__PURE__ */ jsx("h2", { className: "propeller-grid-title__heading text-3xl sm:text-4xl font-bold tracking-tight", children: props.title }) : null,
157
162
  props.headingLevel !== "h2" ? /* @__PURE__ */ jsx("h1", { className: "propeller-grid-title__heading text-3xl sm:text-4xl font-bold tracking-tight", children: props.title }) : null
158
163
  ] }) });
@@ -200,7 +205,7 @@ function ItemStock(props) {
200
205
  return /* @__PURE__ */ jsx(Fragment, { children: hasInventory() ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
201
206
  "div",
202
207
  {
203
- className: `propeller-item-stock flex flex-wrap items-center gap-1.5 ${props.className || ""}`,
208
+ className: cn(`propeller-item-stock flex flex-wrap items-center gap-1.5 ${props.className || ""}`),
204
209
  "data-available": isAvailable() ? "true" : "false",
205
210
  "data-stock": getStockStatusData(),
206
211
  children: [
@@ -239,22 +244,22 @@ function ItemStock(props) {
239
244
  ) }) : null });
240
245
  }
241
246
  var ItemStock_default = React.memo(ItemStock);
242
- function getProductName(orderItem) {
243
- return orderItem?.product?.names?.[0]?.value || orderItem?.name || "Unknown Product";
247
+ function getProductName(orderItem, language) {
248
+ return getLocalizedValue(orderItem?.product?.names, language, "") || orderItem?.name || "Unknown Product";
244
249
  }
245
- function getClusterUrl(orderItem) {
250
+ function getClusterUrl(orderItem, language) {
246
251
  const cluster = orderItem?.product?.cluster;
247
252
  if (!cluster) return "";
248
253
  const id = cluster.clusterId;
249
- const slug = cluster.slugs?.[0]?.value || "";
254
+ const slug = getLocalizedValue(cluster.slugs, language, "");
250
255
  if (!id || !slug) return "";
251
256
  return `/cluster/${id}/${slug}`;
252
257
  }
253
- function getProductUrl(orderItem) {
254
- const cu = getClusterUrl(orderItem);
258
+ function getProductUrl(orderItem, language) {
259
+ const cu = getClusterUrl(orderItem, language);
255
260
  if (cu) return cu;
256
261
  const id = orderItem?.product?.productId;
257
- const slug = orderItem?.product?.slugs?.[0]?.value || "";
262
+ const slug = getLocalizedValue(orderItem?.product?.slugs, language, "");
258
263
  if (id && slug) return `/product/${id}/${slug}`;
259
264
  return "";
260
265
  }
@@ -269,10 +274,10 @@ function OrderItemCard(props) {
269
274
  const showDiscount = props.showDiscount !== void 0 ? props.showDiscount : false;
270
275
  const showStockComponent = props.showStockComponent !== void 0 ? props.showStockComponent : false;
271
276
  const showItemNotes = props.showItemNotes !== void 0 ? props.showItemNotes : false;
272
- const productName = getProductName(item);
277
+ const productName = getProductName(item, props.language);
273
278
  const productSku = item?.product?.sku || item?.sku || "";
274
279
  const productImage = item?.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url || "";
275
- const productUrl = getProductUrl(item);
280
+ const productUrl = getProductUrl(item, props.language);
276
281
  const quantity = item?.quantity || 0;
277
282
  const priceTotal = item?.priceTotal || 0;
278
283
  const discount = item?.discount || 0;
@@ -387,7 +392,7 @@ function OrderItemCard(props) {
387
392
  className: "propeller-order-item-card__child-row border-0",
388
393
  "data-child": "true",
389
394
  children: [
390
- /* @__PURE__ */ jsx("td", { className: "propeller-order-item-card__cell propeller-order-item-card__cell--product px-6 py-2 pl-28", children: /* @__PURE__ */ jsx("span", { className: "propeller-order-item-card__child-title text-sm text-muted-foreground", children: child.product?.names?.[0]?.value || child.name || "Unknown" }) }),
395
+ /* @__PURE__ */ jsx("td", { className: "propeller-order-item-card__cell propeller-order-item-card__cell--product px-6 py-2 pl-28", children: /* @__PURE__ */ jsx("span", { className: "propeller-order-item-card__child-title text-sm text-muted-foreground", children: getLocalizedValue(child.product?.names, props.language, "") || child.name || "Unknown" }) }),
391
396
  showQuantity ? /* @__PURE__ */ jsx("td", { className: "propeller-order-item-card__cell propeller-order-item-card__cell--quantity px-6 py-2 text-center text-sm text-muted-foreground", children: child.quantity || 0 }) : null,
392
397
  showDiscount ? /* @__PURE__ */ jsx("td", { className: "propeller-order-item-card__cell propeller-order-item-card__cell--discount px-6 py-2 text-right text-sm text-muted-foreground" }) : null,
393
398
  showPrice ? /* @__PURE__ */ jsx("td", { className: "propeller-order-item-card__cell propeller-order-item-card__cell--price px-6 py-2 text-right whitespace-nowrap text-sm text-muted-foreground", children: formatItemPrice(child.priceTotal || 0) }) : null
@@ -676,7 +681,7 @@ function ProductBulkPrices(props) {
676
681
  return /* @__PURE__ */ jsx(Fragment, { children: !isHidden && hasItems ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
677
682
  "div",
678
683
  {
679
- className: `propeller-product-bulk-prices ${props.className || ""}`,
684
+ className: cn(`propeller-product-bulk-prices ${props.className || ""}`),
680
685
  "data-include-tax": includeTax ? "true" : "false",
681
686
  children: [
682
687
  getLabel(props.labels, "title", "Volume pricing") ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-bulk-prices__title text-base font-semibold text-foreground mb-3", children: getLabel(props.labels, "title", "Volume pricing") }) : null,
@@ -716,7 +721,7 @@ function ProductDownloads(props) {
716
721
  const match = alts.find((a) => a.language === lang);
717
722
  return match?.value || alts?.[0]?.value || "Download";
718
723
  }
719
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-downloads ${props.className || ""}`, children: [
724
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-downloads ${props.className || ""}`), children: [
720
725
  hasItems ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-downloads__title text-base font-semibold text-foreground mb-3", children: getLabel(props.labels, "title", "Downloads") }) : null,
721
726
  hasItems ? /* @__PURE__ */ jsx("ul", { className: "propeller-product-downloads__list space-y-2", children: items.map((doc, index) => /* @__PURE__ */ jsx("li", { className: "propeller-product-downloads__item", children: !!getDocumentUrl(doc) ? /* @__PURE__ */ jsxs(
722
727
  "a",
@@ -819,7 +824,7 @@ function ProductPriceDisplay(props) {
819
824
  function getSecondaryTaxLabel() {
820
825
  return props.includeTax ? getLabel(props.labels, "exclTax", "excl. VAT") : getLabel(props.labels, "inclTax", "incl. VAT");
821
826
  }
822
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-price ${props.className || ""}`, "data-hidden": isHidden() ? "true" : "false", children: [
827
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-price ${props.className || ""}`), "data-hidden": isHidden() ? "true" : "false", children: [
823
828
  isHidden() && props.showLoginPrompt !== false ? /* @__PURE__ */ jsx("p", { className: "propeller-product-price__login-prompt text-sm text-muted-foreground italic", children: getLabel(props.labels, "loginToSeePrices", "Log in to see prices") }) : null,
824
829
  !isHidden() && !!getLeadingPrice() ? /* @__PURE__ */ jsxs("div", { className: "propeller-product-price__content flex flex-col gap-0.5", children: [
825
830
  /* @__PURE__ */ jsxs("div", { className: "propeller-product-price__primary flex items-baseline gap-2", children: [
@@ -853,7 +858,7 @@ function ProductShortDescription(props) {
853
858
  "div",
854
859
  {
855
860
  dangerouslySetInnerHTML: { __html: html },
856
- className: `propeller-product-short-description prose prose-slate max-w-none text-muted-foreground ${props.className || ""}`
861
+ className: cn(`propeller-product-short-description prose prose-slate max-w-none text-muted-foreground ${props.className || ""}`)
857
862
  }
858
863
  ) : null });
859
864
  }
@@ -896,7 +901,7 @@ function ProductVideos(props) {
896
901
  }
897
902
  return uri;
898
903
  }
899
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-videos ${props.className || ""}`, children: [
904
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-videos ${props.className || ""}`), children: [
900
905
  hasItems ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-videos__title text-base font-semibold text-foreground mb-3", children: getLabel(props.labels, "title", "Videos") }) : null,
901
906
  hasItems ? /* @__PURE__ */ jsx("div", { className: "propeller-product-videos__list space-y-4", children: items.map((video, index) => /* @__PURE__ */ jsx(
902
907
  "div",