@propeller-commerce/propeller-v2-react-ui 0.7.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -8,6 +8,62 @@ 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.8.0] - 2026-07-28
12
+
13
+ ### Added
14
+
15
+ - **`<LoginToOrderButton>`** — a log-in call to action rendered in place of
16
+ add-to-cart for anonymous visitors of a semi-closed portal. Takes an
17
+ `onLoginClick` callback (the host owns navigation, mirroring
18
+ `RegisterForm.onLoginClick`) and a `loginToOrder` label. `ProductCard`,
19
+ `ProductInfo` and `ProductGrid` accept `onLoginClick` and forward it.
20
+ - **`showLoginPrompt` on `<ProductPrice>` and `<ProductBundles>`** — set
21
+ `false` to render nothing where the "log in to see prices" text would go.
22
+ Defaults to `true`, so existing behaviour is unchanged.
23
+ - **`portalMode` on `<ProductCard>`, `<ClusterCard>` and `<ClusterOptions>`** —
24
+ resolved from `<PropellerProvider>` like the other Tier 1 infra props; an
25
+ explicit prop still wins.
26
+
27
+ ### Fixed
28
+
29
+ - **Semi-closed portals leaked price and stock in listings.** `ProductCard`
30
+ never received `portalMode`, so the price it renders through `<ProductPrice>`
31
+ and its stock row stayed visible to anonymous visitors even though the toolbar
32
+ and price filter were correctly gated. `ClusterCard` had the same gap, and
33
+ `ClusterOptions` printed option prices in its dropdown labels and selection
34
+ preview. All now gate on the shared `isContentHidden(portalMode, user)`.
35
+ - **`ProductGrid` hid add-to-cart from signed-in users of a semi-closed
36
+ portal.** `showAddToCart()` tested `portalMode === 'open'` rather than
37
+ `isContentHidden`, so authenticated shoppers lost the control along with
38
+ anonymous ones. Signed-in users keep add-to-cart.
39
+ - **The CTA slot collapsed when content was hidden.** `ProductCard` gated the
40
+ slot on `allowAddToCart`, which `ProductGrid` passes as `false` in that case —
41
+ leaving no room for the log-in action. The slot now renders either control.
42
+
43
+ ## [0.7.1] - 2026-07-28
44
+
45
+ ### Fixed
46
+
47
+ - **`cartUpdateAddress` rejected a blank email** — optional address fields were
48
+ sent as empty strings when left blank, and the API validates optional fields
49
+ whenever they are present, so a blank email failed with
50
+ `email must be an email` (400). This blocked the address step for a delivery
51
+ address, where the email legitimately lives on the contact / customer record
52
+ rather than the address. Optional fields are now omitted when blank, matching
53
+ how `useAddress` already built its payloads. Affects every optional field
54
+ (`email`, `phone`, `mobile`, `company`, `notes`, …), not just email.
55
+ - **`<AddressCard>` required an email on every address** — the edit and create
56
+ forms hardcoded `required` plus a `*` on the email input, contradicting the
57
+ field being optional on the address itself. Email is now optional in both
58
+ forms.
59
+ - **`<AddressCard>` accepted undeliverable emails** — `type="email"` alone
60
+ permits dotless domains such as `aa@gg` (valid per the HTML5 spec for
61
+ intranet hosts, but rejected by the API). Both email inputs now carry a
62
+ pattern requiring a dotted top-level domain, so invalid input is caught in
63
+ the form instead of surfacing as a failed mutation. Subdomains
64
+ (`user@sub.co.uk`) and tagged addresses (`user+tag@example.com`) remain
65
+ valid.
66
+
11
67
  ## [0.7.0] - 2026-07-27
12
68
 
13
69
  ### Added
package/dist/index.cjs CHANGED
@@ -5,6 +5,7 @@ var propellerV2CoreUi = require('@propeller-commerce/propeller-v2-core-ui');
5
5
  var React6 = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var propellerSdkV2 = require('@propeller-commerce/propeller-sdk-v2');
8
+ var lucideReact = require('lucide-react');
8
9
 
9
10
  function _interopNamespace(e) {
10
11
  if (e && e.__esModule) return e;
@@ -888,6 +889,25 @@ function useCart(options) {
888
889
  }, [graphqlClient, language, configuration, user]);
889
890
  return { cart, cartId, loading, error, checkoutAllowed, resolveCart, addItem, updateItemQuantity, updateItemNotes, deleteItem, addActionCode, removeActionCode, requestAuthorization, processCart, getCrossupsells, getMinQuantity, getStep };
890
891
  }
892
+ function buildAddressInput(type, addr) {
893
+ return {
894
+ type,
895
+ firstName: addr.firstName || "",
896
+ lastName: addr.lastName || "",
897
+ street: addr.street || "",
898
+ postalCode: addr.postalCode || "",
899
+ city: addr.city || "",
900
+ ...addr.company && { company: addr.company },
901
+ ...addr.gender && { gender: addr.gender },
902
+ ...addr.middleName && { middleName: addr.middleName },
903
+ ...addr.number && { number: addr.number },
904
+ ...addr.numberExtension && { numberExtension: addr.numberExtension },
905
+ ...addr.country && { country: addr.country },
906
+ ...addr.email && { email: addr.email },
907
+ ...addr.mobile && { mobile: addr.mobile },
908
+ ...addr.phone && { phone: addr.phone }
909
+ };
910
+ }
891
911
  function useCheckout(options) {
892
912
  const { graphqlClient, user, companyId } = options;
893
913
  const language = options.language ?? "NL";
@@ -928,26 +948,9 @@ function useCheckout(options) {
928
948
  if (!hasInvoice) {
929
949
  const defaultInvoice = getUserDefaultAddress("invoice");
930
950
  if (defaultInvoice) {
931
- const input = {
932
- type: propellerSdkV2.CartAddressType.INVOICE,
933
- firstName: defaultInvoice.firstName || "",
934
- lastName: defaultInvoice.lastName || "",
935
- street: defaultInvoice.street || "",
936
- postalCode: defaultInvoice.postalCode || "",
937
- city: defaultInvoice.city || "",
938
- company: defaultInvoice.company,
939
- gender: defaultInvoice.gender,
940
- middleName: defaultInvoice.middleName,
941
- number: defaultInvoice.number,
942
- numberExtension: defaultInvoice.numberExtension,
943
- country: defaultInvoice.country,
944
- email: defaultInvoice.email,
945
- mobile: defaultInvoice.mobile,
946
- phone: defaultInvoice.phone
947
- };
948
951
  updatedCart = await cartService.updateCartAddress({
949
952
  id: updatedCart.cartId,
950
- input,
953
+ input: buildAddressInput(propellerSdkV2.CartAddressType.INVOICE, defaultInvoice),
951
954
  imageVariantFilters,
952
955
  imageSearchFilters,
953
956
  language
@@ -957,26 +960,9 @@ function useCheckout(options) {
957
960
  if (!hasDelivery) {
958
961
  const defaultDelivery = getUserDefaultAddress("delivery");
959
962
  if (defaultDelivery) {
960
- const input = {
961
- type: propellerSdkV2.CartAddressType.DELIVERY,
962
- firstName: defaultDelivery.firstName || "",
963
- lastName: defaultDelivery.lastName || "",
964
- street: defaultDelivery.street || "",
965
- postalCode: defaultDelivery.postalCode || "",
966
- city: defaultDelivery.city || "",
967
- company: defaultDelivery.company,
968
- gender: defaultDelivery.gender,
969
- middleName: defaultDelivery.middleName,
970
- number: defaultDelivery.number,
971
- numberExtension: defaultDelivery.numberExtension,
972
- country: defaultDelivery.country,
973
- email: defaultDelivery.email,
974
- mobile: defaultDelivery.mobile,
975
- phone: defaultDelivery.phone
976
- };
977
963
  updatedCart = await cartService.updateCartAddress({
978
964
  id: updatedCart.cartId,
979
- input,
965
+ input: buildAddressInput(propellerSdkV2.CartAddressType.DELIVERY, defaultDelivery),
980
966
  imageVariantFilters,
981
967
  imageSearchFilters,
982
968
  language
@@ -5065,6 +5051,7 @@ function AddToFavorite(rawProps) {
5065
5051
  ] }) }) : null });
5066
5052
  }
5067
5053
  var AddToFavorite_default = AddToFavorite;
5054
+ var EMAIL_PATTERN = "[^@\\s]+@[^@\\s.]+(?:\\.[^@\\s.]+)*\\.[A-Za-z]{2,}";
5068
5055
  var AddressCardContext = React6__namespace.createContext(null);
5069
5056
  function useAddressCardContext() {
5070
5057
  const ctx = React6__namespace.useContext(AddressCardContext);
@@ -5510,10 +5497,7 @@ function AddressCard(rawProps) {
5510
5497
  ] }),
5511
5498
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
5512
5499
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5513
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block text-sm font-medium mb-1", children: [
5514
- propellerV2CoreUi.getLabel(props.labels, "email", "Email"),
5515
- " *"
5516
- ] }),
5500
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium mb-1", children: propellerV2CoreUi.getLabel(props.labels, "email", "Email") }),
5517
5501
  /* @__PURE__ */ jsxRuntime.jsx(
5518
5502
  "input",
5519
5503
  {
@@ -5523,7 +5507,7 @@ function AddressCard(rawProps) {
5523
5507
  onChange: (e) => {
5524
5508
  setEditEmail(e.target.value);
5525
5509
  },
5526
- required: true
5510
+ pattern: EMAIL_PATTERN
5527
5511
  }
5528
5512
  )
5529
5513
  ] }),
@@ -5803,10 +5787,7 @@ function AddressCard(rawProps) {
5803
5787
  ] }),
5804
5788
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
5805
5789
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5806
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block text-sm font-medium mb-1", children: [
5807
- propellerV2CoreUi.getLabel(props.labels, "email", "Email"),
5808
- " *"
5809
- ] }),
5790
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium mb-1", children: propellerV2CoreUi.getLabel(props.labels, "email", "Email") }),
5810
5791
  /* @__PURE__ */ jsxRuntime.jsx(
5811
5792
  "input",
5812
5793
  {
@@ -5816,7 +5797,7 @@ function AddressCard(rawProps) {
5816
5797
  onChange: (e) => {
5817
5798
  setEditEmail(e.target.value);
5818
5799
  },
5819
- required: true
5800
+ pattern: EMAIL_PATTERN
5820
5801
  }
5821
5802
  )
5822
5803
  ] }),
@@ -7978,6 +7959,8 @@ var RESOLVE_SPEC = {
7978
7959
  includeTax: { infra: "includeTax" },
7979
7960
  language: { infra: "language", default: "NL" },
7980
7961
  currency: { infra: "currency", default: "\u20AC" },
7962
+ user: { infra: "user", default: null },
7963
+ portalMode: { infra: "portalMode" },
7981
7964
  columns: { grid: "columns", default: 3 },
7982
7965
  showPrice: { grid: "showPrice" },
7983
7966
  showStock: { grid: "showStock" },
@@ -8021,9 +8004,10 @@ function ClusterCard(rawProps) {
8021
8004
  const textLabelValues = resolveAttributeValues(cluster, props.textLabels).map((value) => ({
8022
8005
  value
8023
8006
  }));
8024
- const defaultProductInventory = cluster?.defaultProduct?.inventory;
8007
+ const contentHidden = propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
8008
+ const defaultProductInventory = contentHidden ? void 0 : cluster?.defaultProduct?.inventory;
8025
8009
  const useTax = props.includeTax !== void 0 ? !!props.includeTax : false;
8026
- const priceObj = cluster?.defaultProduct?.price;
8010
+ const priceObj = contentHidden ? void 0 : cluster?.defaultProduct?.price;
8027
8011
  const priceValue = useTax ? priceObj?.net : priceObj?.gross;
8028
8012
  const clusterPrice = props.showPrice === false ? "" : propellerV2CoreUi.formatPrice(priceValue, { symbol: props.currency ?? "\u20AC" });
8029
8013
  function handleClusterClick(e) {
@@ -8428,6 +8412,23 @@ function MachineCard(props) {
8428
8412
  }
8429
8413
  );
8430
8414
  }
8415
+ function LoginToOrderButton(props) {
8416
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8417
+ "button",
8418
+ {
8419
+ type: "button",
8420
+ className: `propeller-login-to-order inline-flex items-center justify-center gap-2 h-10 px-4 w-full rounded-control bg-primary text-primary-foreground text-sm font-medium hover:opacity-90 transition-opacity ${props.className || ""}`,
8421
+ onClick: () => {
8422
+ if (props.onLoginClick) props.onLoginClick();
8423
+ },
8424
+ children: [
8425
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "propeller-login-to-order__icon w-4 h-4", "aria-hidden": "true" }),
8426
+ propellerV2CoreUi.getLabel(props.labels, "loginToOrder", "Log in to order")
8427
+ ]
8428
+ }
8429
+ );
8430
+ }
8431
+ var LoginToOrderButton_default = LoginToOrderButton;
8431
8432
  function ProductPriceDisplay(props) {
8432
8433
  function isHidden2() {
8433
8434
  return propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
@@ -8478,7 +8479,7 @@ function ProductPriceDisplay(props) {
8478
8479
  return props.includeTax ? propellerV2CoreUi.getLabel(props.labels, "exclTax", "excl. VAT") : propellerV2CoreUi.getLabel(props.labels, "inclTax", "incl. VAT");
8479
8480
  }
8480
8481
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `propeller-product-price ${props.className || ""}`, "data-hidden": isHidden2() ? "true" : "false", children: [
8481
- isHidden2() ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-product-price__login-prompt text-sm text-muted-foreground italic", children: propellerV2CoreUi.getLabel(props.labels, "loginToSeePrices", "Log in to see prices") }) : null,
8482
+ isHidden2() && props.showLoginPrompt !== false ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-product-price__login-prompt text-sm text-muted-foreground italic", children: propellerV2CoreUi.getLabel(props.labels, "loginToSeePrices", "Log in to see prices") }) : null,
8482
8483
  !isHidden2() && !!getLeadingPrice() ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-product-price__content flex flex-col gap-0.5", children: [
8483
8484
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-product-price__primary flex items-baseline gap-2", children: [
8484
8485
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8521,6 +8522,7 @@ var RESOLVE_SPEC2 = {
8521
8522
  companyId: { infra: "companyId" },
8522
8523
  language: { infra: "language", default: "NL" },
8523
8524
  includeTax: { infra: "includeTax" },
8525
+ portalMode: { infra: "portalMode" },
8524
8526
  configuration: { infra: "configuration" },
8525
8527
  columns: { grid: "columns", default: 3 },
8526
8528
  showPrice: { grid: "showPrice" },
@@ -8542,6 +8544,7 @@ var RESOLVE_SPEC2 = {
8542
8544
  onCartCreated: { grid: "onCartCreated" },
8543
8545
  afterAddToCart: { grid: "afterAddToCart" },
8544
8546
  onProceedToCheckout: { grid: "onProceedToCheckout" },
8547
+ onLoginClick: { grid: "onLoginClick" },
8545
8548
  onRequestQuoteClick: { grid: "onRequestQuoteClick" },
8546
8549
  onProductClick: { grid: "onProductClick" },
8547
8550
  onToggleFavorite: {
@@ -8573,6 +8576,9 @@ function ProductCardRoot(rawProps) {
8573
8576
  const language = props.language || "NL";
8574
8577
  const product = props.product;
8575
8578
  const isRow = props.columns === 1;
8579
+ const contentHidden = propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
8580
+ const showStock = !!props.showStock && !contentHidden;
8581
+ const showCta = props.allowAddToCart !== false || contentHidden;
8576
8582
  const name = getProductName(product, language);
8577
8583
  const sku = propellerV2CoreUi.getProductSku(product);
8578
8584
  const imageUrl = propellerV2CoreUi.getProductImageUrl(product);
@@ -8643,10 +8649,10 @@ function ProductCardRoot(rawProps) {
8643
8649
  ] }) }),
8644
8650
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-product-card__footer w-full md:w-auto flex flex-col gap-2 md:flex-row md:items-center md:gap-3 px-4 py-2 md:py-0 border-t md:border-t-0 border-border-subtle", children: [
8645
8651
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-product-card__footer-meta flex items-center justify-between gap-3 md:contents", children: [
8646
- props.showStock && !!product.inventory ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardStock, {}) : null,
8652
+ showStock && !!product.inventory ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardStock, {}) : null,
8647
8653
  props.showPrice !== false && !!product?.price ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardPrice, { priceSize: "text-sm" }) : null
8648
8654
  ] }),
8649
- props.allowAddToCart !== false ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-card__cta w-full md:w-auto md:flex-shrink-0 md:ml-auto", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardAddToCart, {}) }) : null
8655
+ showCta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-card__cta w-full md:w-auto md:flex-shrink-0 md:ml-auto", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardAddToCart, {}) }) : null
8650
8656
  ] })
8651
8657
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8652
8658
  /* @__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: [
@@ -8654,16 +8660,16 @@ function ProductCardRoot(rawProps) {
8654
8660
  props.showName !== false ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardName, { linkable: true }) : null,
8655
8661
  /* @__PURE__ */ jsxRuntime.jsx(ProductCardBelowName, {}),
8656
8662
  textLabelValues.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardTextLabels, {}) : null,
8657
- props.showStock && !!product.inventory ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardStock, {}) }) : null,
8663
+ showStock && !!product.inventory ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardStock, {}) }) : null,
8658
8664
  props.showManufacturer && manufacturer ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardManufacturer, {}) : null,
8659
8665
  props.showShortDescription && shortDescription ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardShortDescription, {}) : null,
8660
8666
  props.showPrice !== false && !!product?.price ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-card__price mt-auto pt-1 hidden md:block", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardPrice, { priceSize: "text-base sm:text-lg" }) }) : null
8661
8667
  ] }),
8662
- props.showStock && !!product.inventory || props.showPrice !== false && !!product?.price ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-product-card__footer-meta flex flex-wrap items-center justify-between gap-x-2 gap-y-1 px-3 pt-1 sm:px-4 md:hidden", children: [
8663
- props.showStock && !!product.inventory ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardStock, {}) : null,
8668
+ showStock && !!product.inventory || props.showPrice !== false && !!product?.price ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-product-card__footer-meta flex flex-wrap items-center justify-between gap-x-2 gap-y-1 px-3 pt-1 sm:px-4 md:hidden", children: [
8669
+ showStock && !!product.inventory ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardStock, {}) : null,
8664
8670
  props.showPrice !== false && !!product?.price ? /* @__PURE__ */ jsxRuntime.jsx(ProductCardPrice, { priceSize: "text-base", className: "propeller-product-card__price min-w-0 text-right" }) : null
8665
8671
  ] }) : null,
8666
- props.allowAddToCart !== false ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-card__cta px-3 pb-3 pt-2 sm:px-4 sm:pb-4", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardAddToCart, {}) }) : null
8672
+ showCta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-card__cta px-3 pb-3 pt-2 sm:px-4 sm:pb-4", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCardAddToCart, {}) }) : null
8667
8673
  ] })
8668
8674
  ]
8669
8675
  }
@@ -8862,12 +8868,25 @@ function ProductCardPrice(props) {
8862
8868
  price: product.price,
8863
8869
  includeTax: derived.useTax,
8864
8870
  priceSize: props.priceSize ?? "text-base sm:text-lg",
8865
- labels: resolved.priceLabels
8871
+ labels: resolved.priceLabels,
8872
+ portalMode: resolved.portalMode,
8873
+ user: resolved.user,
8874
+ showLoginPrompt: false
8866
8875
  }
8867
8876
  ) });
8868
8877
  }
8869
8878
  function ProductCardAddToCart(props) {
8870
8879
  const { product, resolved } = useProductCard();
8880
+ if (propellerV2CoreUi.isContentHidden(resolved.portalMode, resolved.user)) {
8881
+ return /* @__PURE__ */ jsxRuntime.jsx(
8882
+ LoginToOrderButton_default,
8883
+ {
8884
+ className: props.className,
8885
+ labels: resolved.addToCartLabels,
8886
+ onLoginClick: resolved.onLoginClick
8887
+ }
8888
+ );
8889
+ }
8871
8890
  const InjectedAddToCart = resolved.addToCartComponent;
8872
8891
  if (InjectedAddToCart) {
8873
8892
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -9000,9 +9019,8 @@ function ProductGrid(rawProps) {
9000
9019
  return !!props.isLoading || isLoading;
9001
9020
  }
9002
9021
  function showAddToCart() {
9003
- const mode = props.portalMode || "open";
9004
9022
  const allow = props.allowAddToCart !== false;
9005
- return mode === "open" && allow;
9023
+ return !propellerV2CoreUi.isContentHidden(props.portalMode, props.user) && allow;
9006
9024
  }
9007
9025
  function getSkeletonItems() {
9008
9026
  const cols = props.columns || 3;
@@ -9029,6 +9047,7 @@ function ProductGrid(rawProps) {
9029
9047
  onCartCreated: props.onCartCreated,
9030
9048
  afterAddToCart: props.afterAddToCart,
9031
9049
  onProceedToCheckout: props.onProceedToCheckout,
9050
+ onLoginClick: props.onLoginClick,
9032
9051
  onRequestQuoteClick: props.onRequestQuoteClick,
9033
9052
  onToggleFavorite: (item, isFav) => props.onToggleFavorite?.(item, isFav),
9034
9053
  onProductClick: (p) => props.onProductClick?.(p),
@@ -9677,7 +9696,7 @@ function GridToolbar(rawProps) {
9677
9696
  const [currentSortOrder, setCurrentSortOrder] = React6.useState(propellerSdkV2.SortOrder.DESC);
9678
9697
  const [currentOffset, setCurrentOffset] = React6.useState(12);
9679
9698
  const [currentViewMode, setCurrentViewMode] = React6.useState("grid");
9680
- function getLabel55(key) {
9699
+ function getLabel56(key) {
9681
9700
  const labels = props.labels || {};
9682
9701
  return labels[key] !== void 0 ? labels[key] : DEFAULT_LABELS[key] || key;
9683
9702
  }
@@ -9756,7 +9775,7 @@ function GridToolbar(rawProps) {
9756
9775
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-grid-toolbar__count text-sm text-muted-foreground font-medium", children: props.itemsFound > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
9757
9776
  props.itemsFound,
9758
9777
  "\xA0",
9759
- props.itemsFound === 1 ? getLabel55("productSingular") : getLabel55("productPlural")
9778
+ props.itemsFound === 1 ? getLabel56("productSingular") : getLabel56("productPlural")
9760
9779
  ] }) : null }),
9761
9780
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-toolbar__controls flex flex-wrap items-center gap-3", children: [
9762
9781
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -9767,7 +9786,7 @@ function GridToolbar(rawProps) {
9767
9786
  onChange: (e) => handleOffsetChange(parseInt(e.target.value)),
9768
9787
  children: getOffsetOptions()?.map((n) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: n, children: [
9769
9788
  n,
9770
- getLabel55("perPage")
9789
+ getLabel56("perPage")
9771
9790
  ] }, n))
9772
9791
  }
9773
9792
  ),
@@ -9783,7 +9802,7 @@ function GridToolbar(rawProps) {
9783
9802
  {
9784
9803
  value: field,
9785
9804
  disabled: field === "PRICE" && isPriceSortDisabled(),
9786
- children: getLabel55(field)
9805
+ children: getLabel56(field)
9787
9806
  },
9788
9807
  field
9789
9808
  ))
@@ -9796,8 +9815,8 @@ function GridToolbar(rawProps) {
9796
9815
  value: currentSortOrder,
9797
9816
  onChange: (e) => handleSortOrderChange(e.target.value),
9798
9817
  children: [
9799
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.ASC, children: getLabel55("ASC") }),
9800
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.DESC, children: getLabel55("DESC") })
9818
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.ASC, children: getLabel56("ASC") }),
9819
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.DESC, children: getLabel56("DESC") })
9801
9820
  ]
9802
9821
  }
9803
9822
  ),
@@ -9807,7 +9826,7 @@ function GridToolbar(rawProps) {
9807
9826
  type: "button",
9808
9827
  className: "propeller-grid-toolbar__view-toggle h-9 w-9 flex items-center justify-center rounded-control border border-input bg-transparent hover:bg-accent hover:text-accent-foreground transition-colors",
9809
9828
  onClick: (event) => handleViewChange(),
9810
- title: currentViewMode === "grid" ? getLabel55("switchToList") : getLabel55("switchToGrid"),
9829
+ title: currentViewMode === "grid" ? getLabel56("switchToList") : getLabel56("switchToGrid"),
9811
9830
  children: [
9812
9831
  currentViewMode === "grid" ? /* @__PURE__ */ jsxRuntime.jsxs(
9813
9832
  "svg",
@@ -9865,7 +9884,7 @@ function GridToolbar(rawProps) {
9865
9884
  onClick: (event) => {
9866
9885
  if (props.onClearFilters) props.onClearFilters();
9867
9886
  },
9868
- children: getLabel55("clearAll")
9887
+ children: getLabel56("clearAll")
9869
9888
  }
9870
9889
  ),
9871
9890
  props.priceFilterMin !== void 0 || props.priceFilterMax !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
@@ -9876,7 +9895,7 @@ function GridToolbar(rawProps) {
9876
9895
  if (props.onPriceFilterRemove) props.onPriceFilterRemove();
9877
9896
  },
9878
9897
  children: [
9879
- getLabel55("price"),
9898
+ getLabel56("price"),
9880
9899
  ": \u20AC",
9881
9900
  props.priceFilterMin ?? 0,
9882
9901
  " \u2013 \u20AC",
@@ -9913,7 +9932,7 @@ var DEFAULT_LABELS2 = {
9913
9932
  of: "of"
9914
9933
  };
9915
9934
  function GridPagination(props) {
9916
- function getLabel55(key) {
9935
+ function getLabel56(key) {
9917
9936
  const labels = props.labels || {};
9918
9937
  return labels[key] !== void 0 ? labels[key] : DEFAULT_LABELS2[key] || key;
9919
9938
  }
@@ -9986,15 +10005,15 @@ function GridPagination(props) {
9986
10005
  className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--prev inline-flex items-center rounded-control border border-input bg-card px-4 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
9987
10006
  disabled: currentPage === 1,
9988
10007
  onClick: () => handlePageChange(currentPage - 1),
9989
- children: getLabel55("previous")
10008
+ children: getLabel56("previous")
9990
10009
  }
9991
10010
  ),
9992
10011
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "propeller-grid-pagination__info px-2 text-sm font-medium text-muted-foreground", children: [
9993
- getLabel55("page"),
10012
+ getLabel56("page"),
9994
10013
  "\xA0",
9995
10014
  currentPage,
9996
10015
  "\xA0",
9997
- getLabel55("of"),
10016
+ getLabel56("of"),
9998
10017
  "\xA0",
9999
10018
  totalPages
10000
10019
  ] }),
@@ -10005,7 +10024,7 @@ function GridPagination(props) {
10005
10024
  className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--next inline-flex items-center rounded-control border border-input bg-card px-4 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
10006
10025
  disabled: currentPage === totalPages,
10007
10026
  onClick: () => handlePageChange(currentPage + 1),
10008
- children: getLabel55("next")
10027
+ children: getLabel56("next")
10009
10028
  }
10010
10029
  )
10011
10030
  ] }) : null,
@@ -10017,7 +10036,7 @@ function GridPagination(props) {
10017
10036
  className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--prev inline-flex items-center rounded-control border border-input bg-card px-3 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
10018
10037
  disabled: currentPage === 1,
10019
10038
  onClick: () => handlePageChange(currentPage - 1),
10020
- children: getLabel55("previous")
10039
+ children: getLabel56("previous")
10021
10040
  }
10022
10041
  ),
10023
10042
  getFullPages().map((item, idx) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -10044,7 +10063,7 @@ function GridPagination(props) {
10044
10063
  className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--next inline-flex items-center rounded-control border border-input bg-card px-3 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
10045
10064
  disabled: currentPage === totalPages,
10046
10065
  onClick: () => handlePageChange(currentPage + 1),
10047
- children: getLabel55("next")
10066
+ children: getLabel56("next")
10048
10067
  }
10049
10068
  )
10050
10069
  ] }) : null
@@ -10536,13 +10555,14 @@ function ClusterOptions(props) {
10536
10555
  function getOptionsForRender() {
10537
10556
  const options = props.options || [];
10538
10557
  const sel = selectedProductIds;
10558
+ const hidePrices = propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
10539
10559
  return options.filter((option) => option.hidden !== propellerSdkV2.YesNo.Y).map((option) => {
10540
10560
  const idStr = option.id.toString();
10541
10561
  const selectedProductId = sel[idStr] || "";
10542
10562
  const products = (option.products || []).map((p) => ({
10543
10563
  productId: p.productId,
10544
10564
  productIdStr: p.productId.toString(),
10545
- label: `${getProductName2(p)} \u2014 ${formatPrice9(p.price?.gross || 0, props.currency ?? "\u20AC")}`
10565
+ label: hidePrices ? getProductName2(p) : `${getProductName2(p)} \u2014 ${formatPrice9(p.price?.gross || 0, props.currency ?? "\u20AC")}`
10546
10566
  }));
10547
10567
  let previewImageUrl = "";
10548
10568
  let previewName = "";
@@ -10554,7 +10574,7 @@ function ClusterOptions(props) {
10554
10574
  if (selectedProduct) {
10555
10575
  previewImageUrl = getProductImageUrl4(selectedProduct);
10556
10576
  previewName = getProductName2(selectedProduct);
10557
- previewPrice = formatPrice9(selectedProduct.price?.gross || 0, props.currency ?? "\u20AC");
10577
+ previewPrice = hidePrices ? "" : formatPrice9(selectedProduct.price?.gross || 0, props.currency ?? "\u20AC");
10558
10578
  }
10559
10579
  }
10560
10580
  const isRequired = option.isRequired === propellerSdkV2.YesNo.Y;
@@ -15026,11 +15046,11 @@ function ProductBundles(rawProps) {
15026
15046
  children: addingBundleId === bundle.id ? propellerV2CoreUi.getLabel(props.labels, "adding", "Adding...") : propellerV2CoreUi.getLabel(props.labels, "addToCart", "In cart")
15027
15047
  }
15028
15048
  )
15029
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-bundles__login-prompt text-center text-sm text-muted-foreground py-2", children: propellerV2CoreUi.getLabel(
15049
+ ] }) : props.showLoginPrompt !== false ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-product-bundles__login-prompt text-center text-sm text-muted-foreground py-2", children: propellerV2CoreUi.getLabel(
15030
15050
  props.labels,
15031
15051
  "loginToSeePrices",
15032
15052
  "Log in to see prices and add to cart"
15033
- ) })
15053
+ ) }) : null
15034
15054
  ] })
15035
15055
  ] })
15036
15056
  },
@@ -15813,6 +15833,7 @@ function ProductInfoPrice(props = {}) {
15813
15833
  function ProductInfoStock(props = {}) {
15814
15834
  const { product, resolved, derived } = useProductInfoContext();
15815
15835
  if (!product.inventory) return null;
15836
+ if (propellerV2CoreUi.isContentHidden(derived.portalMode, resolved.user)) return null;
15816
15837
  const Injected = resolved.stockComponent;
15817
15838
  if (Injected) {
15818
15839
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -15839,6 +15860,16 @@ function ProductInfoStock(props = {}) {
15839
15860
  }
15840
15861
  function ProductInfoAddToCart(props = {}) {
15841
15862
  const { product, resolved, derived } = useProductInfoContext();
15863
+ if (propellerV2CoreUi.isContentHidden(derived.portalMode, resolved.user)) {
15864
+ return /* @__PURE__ */ jsxRuntime.jsx(
15865
+ LoginToOrderButton_default,
15866
+ {
15867
+ className: props.className,
15868
+ labels: derived.labels,
15869
+ onLoginClick: resolved.onLoginClick
15870
+ }
15871
+ );
15872
+ }
15842
15873
  const Injected = resolved.addToCartComponent;
15843
15874
  if (Injected) {
15844
15875
  return /* @__PURE__ */ jsxRuntime.jsx(Injected, { product, labels: derived.labels, className: props.className });
@@ -18716,6 +18747,7 @@ exports.GridToolbar = GridToolbar_default;
18716
18747
  exports.ItemStock = ItemStock_default;
18717
18748
  exports.ItemsOverview = ItemsOverview_default;
18718
18749
  exports.LoginForm = LoginForm_default;
18750
+ exports.LoginToOrderButton = LoginToOrderButton_default;
18719
18751
  exports.MachineCard = MachineCard;
18720
18752
  exports.MachineGrid = MachineGrid;
18721
18753
  exports.Menu = Menu_default;