@propeller-commerce/propeller-v2-react-ui 0.26.1 → 0.27.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 +27 -0
- package/dist/index.cjs +69 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +69 -22
- package/dist/index.js.map +1 -1
- package/dist/pure.cjs +23 -0
- package/dist/pure.cjs.map +1 -1
- package/dist/pure.js +23 -0
- package/dist/pure.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1548,6 +1548,8 @@ interface QuickOrderMatch {
|
|
|
1548
1548
|
grossPrice: number;
|
|
1549
1549
|
/** Minimum order quantity (defaults to 1). */
|
|
1550
1550
|
minQuantity: number;
|
|
1551
|
+
/** Order step: quantities run min, min+step, min+2*step, … (defaults to 1). */
|
|
1552
|
+
step: number;
|
|
1551
1553
|
/** Thumbnail URL, if any. */
|
|
1552
1554
|
imageUrl: string;
|
|
1553
1555
|
/** Price is quoted on request — not orderable through a bulk flow. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1548,6 +1548,8 @@ interface QuickOrderMatch {
|
|
|
1548
1548
|
grossPrice: number;
|
|
1549
1549
|
/** Minimum order quantity (defaults to 1). */
|
|
1550
1550
|
minQuantity: number;
|
|
1551
|
+
/** Order step: quantities run min, min+step, min+2*step, … (defaults to 1). */
|
|
1552
|
+
step: number;
|
|
1551
1553
|
/** Thumbnail URL, if any. */
|
|
1552
1554
|
imageUrl: string;
|
|
1553
1555
|
/** Price is quoted on request — not orderable through a bulk flow. */
|
package/dist/index.js
CHANGED
|
@@ -2614,6 +2614,7 @@ function toMatch(item, language) {
|
|
|
2614
2614
|
const netPrice = displayItem?.price?.net ?? 0;
|
|
2615
2615
|
const grossPrice = displayItem?.price?.gross ?? 0;
|
|
2616
2616
|
const minQuantity = Math.max(1, displayItem?.minimumQuantity ?? 1);
|
|
2617
|
+
const step = Math.max(1, displayItem?.unit ?? 1);
|
|
2617
2618
|
const imageUrl = isCluster ? getClusterImageUrl(item) : getProductImageUrl(item);
|
|
2618
2619
|
return {
|
|
2619
2620
|
productId,
|
|
@@ -2623,6 +2624,7 @@ function toMatch(item, language) {
|
|
|
2623
2624
|
netPrice,
|
|
2624
2625
|
grossPrice,
|
|
2625
2626
|
minQuantity,
|
|
2627
|
+
step,
|
|
2626
2628
|
imageUrl,
|
|
2627
2629
|
priceOnRequest: isPriceOnRequest(item)
|
|
2628
2630
|
};
|
|
@@ -4759,6 +4761,7 @@ function AddToCart(rawProps) {
|
|
|
4759
4761
|
onCartCreated: props.onCartCreated
|
|
4760
4762
|
});
|
|
4761
4763
|
const [quantity, setQuantity] = useState(() => getMinQuantity(props.product));
|
|
4764
|
+
const [quantityDraft, setQuantityDraft] = useState(null);
|
|
4762
4765
|
const [toastMessage, setToastMessage] = useState(() => "");
|
|
4763
4766
|
const [toastType, setToastType] = useState(() => "");
|
|
4764
4767
|
const [toastVisible, setToastVisible] = useState(() => false);
|
|
@@ -4781,16 +4784,42 @@ function AddToCart(rawProps) {
|
|
|
4781
4784
|
function dismissToast() {
|
|
4782
4785
|
setToastVisible(false);
|
|
4783
4786
|
}
|
|
4787
|
+
function snapQuantity(value) {
|
|
4788
|
+
const min = getMinQuantity(props.product);
|
|
4789
|
+
const step = getStep(props.product);
|
|
4790
|
+
if (value <= min) return min;
|
|
4791
|
+
return Math.round((value - min) / step) * step + min;
|
|
4792
|
+
}
|
|
4784
4793
|
function increment() {
|
|
4785
|
-
|
|
4794
|
+
setQuantityDraft(null);
|
|
4795
|
+
const snapped = snapQuantity(quantity);
|
|
4796
|
+
setQuantity(snapped === quantity ? quantity + getStep(props.product) : snapped);
|
|
4786
4797
|
}
|
|
4787
4798
|
function decrement() {
|
|
4788
4799
|
const min = getMinQuantity(props.product);
|
|
4789
4800
|
const step = getStep(props.product);
|
|
4801
|
+
setQuantityDraft(null);
|
|
4802
|
+
const snapped = snapQuantity(quantity);
|
|
4803
|
+
if (snapped !== quantity) {
|
|
4804
|
+
setQuantity(snapped);
|
|
4805
|
+
return;
|
|
4806
|
+
}
|
|
4790
4807
|
if (quantity - step >= min) {
|
|
4791
4808
|
setQuantity(quantity - step);
|
|
4792
4809
|
}
|
|
4793
4810
|
}
|
|
4811
|
+
function handleQuantityInput(raw) {
|
|
4812
|
+
setQuantityDraft(raw);
|
|
4813
|
+
const val = parseInt(raw, 10);
|
|
4814
|
+
if (!isNaN(val) && val >= getMinQuantity(props.product)) {
|
|
4815
|
+
setQuantity(snapQuantity(val));
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
function handleQuantityBlur() {
|
|
4819
|
+
const val = parseInt(quantityDraft ?? "", 10);
|
|
4820
|
+
setQuantity(isNaN(val) ? getMinQuantity(props.product) : snapQuantity(val));
|
|
4821
|
+
setQuantityDraft(null);
|
|
4822
|
+
}
|
|
4794
4823
|
function getModalImageUrl() {
|
|
4795
4824
|
if (addedCartItem) {
|
|
4796
4825
|
const img = addedCartItem.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url;
|
|
@@ -4920,15 +4949,9 @@ function AddToCart(rawProps) {
|
|
|
4920
4949
|
className: "propeller-add-to-cart__quantity flex-1 md:flex-none md:w-12 text-center text-sm bg-transparent border-none focus:ring-0 focus:outline-none h-full [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
|
4921
4950
|
min: getMinQuantity(props.product),
|
|
4922
4951
|
step: getStep(props.product),
|
|
4923
|
-
value: quantity,
|
|
4924
|
-
onChange: (e) =>
|
|
4925
|
-
|
|
4926
|
-
const min = getMinQuantity(props.product);
|
|
4927
|
-
const step = getStep(props.product);
|
|
4928
|
-
if (!isNaN(val) && val >= min) {
|
|
4929
|
-
setQuantity(Math.round((val - min) / step) * step + min);
|
|
4930
|
-
}
|
|
4931
|
-
}
|
|
4952
|
+
value: quantityDraft ?? quantity,
|
|
4953
|
+
onChange: (e) => handleQuantityInput(e.target.value),
|
|
4954
|
+
onBlur: handleQuantityBlur
|
|
4932
4955
|
}
|
|
4933
4956
|
),
|
|
4934
4957
|
/* @__PURE__ */ jsxs(
|
|
@@ -4953,15 +4976,9 @@ function AddToCart(rawProps) {
|
|
|
4953
4976
|
className: "propeller-add-to-cart__quantity w-full md:w-16 h-10 text-center text-sm border border-input rounded-control focus:ring-2 focus:ring-secondary focus:border-transparent [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
|
4954
4977
|
min: getMinQuantity(props.product),
|
|
4955
4978
|
step: getStep(props.product),
|
|
4956
|
-
value: quantity,
|
|
4957
|
-
onChange: (e) =>
|
|
4958
|
-
|
|
4959
|
-
const min = getMinQuantity(props.product);
|
|
4960
|
-
const step = getStep(props.product);
|
|
4961
|
-
if (!isNaN(val) && val >= min) {
|
|
4962
|
-
setQuantity(Math.round((val - min) / step) * step + min);
|
|
4963
|
-
}
|
|
4964
|
-
}
|
|
4979
|
+
value: quantityDraft ?? quantity,
|
|
4980
|
+
onChange: (e) => handleQuantityInput(e.target.value),
|
|
4981
|
+
onBlur: handleQuantityBlur
|
|
4965
4982
|
}
|
|
4966
4983
|
) : null,
|
|
4967
4984
|
/* @__PURE__ */ jsxs(
|
|
@@ -13883,6 +13900,28 @@ function OrderActions(rawProps) {
|
|
|
13883
13900
|
);
|
|
13884
13901
|
}
|
|
13885
13902
|
var OrderActions_default = OrderActions;
|
|
13903
|
+
var warnedOnce = /* @__PURE__ */ new Set();
|
|
13904
|
+
function warnOnce(key, message) {
|
|
13905
|
+
if (warnedOnce.has(key)) return;
|
|
13906
|
+
warnedOnce.add(key);
|
|
13907
|
+
console.warn(message);
|
|
13908
|
+
}
|
|
13909
|
+
function warnMissingProps(props) {
|
|
13910
|
+
if (process.env.NODE_ENV === "production") return;
|
|
13911
|
+
if (!props.language) {
|
|
13912
|
+
warnOnce(
|
|
13913
|
+
"language",
|
|
13914
|
+
"[OrderItemCard] No `language` prop: product names resolve in the default catalogue language, whatever page they are on. This component reads no context (it ships from the RSC-safe /pure entry), so the host must pass it."
|
|
13915
|
+
);
|
|
13916
|
+
}
|
|
13917
|
+
const linkable = props.titleLinkable !== void 0 ? props.titleLinkable : true;
|
|
13918
|
+
if (linkable && !props.configuration?.urls) {
|
|
13919
|
+
warnOnce(
|
|
13920
|
+
"urls",
|
|
13921
|
+
"[OrderItemCard] Title is linkable but no `configuration.urls` was passed: links fall back to a literal /product/:id/:slug and lose the locale prefix. Pass the url builders from the host, or set titleLinkable={false}."
|
|
13922
|
+
);
|
|
13923
|
+
}
|
|
13924
|
+
}
|
|
13886
13925
|
function getProductName3(orderItem, language) {
|
|
13887
13926
|
return getLocalizedValue(orderItem?.product?.names, language, "") || orderItem?.name || "Unknown Product";
|
|
13888
13927
|
}
|
|
@@ -13906,6 +13945,7 @@ function getProductUrl(orderItem, language, urls) {
|
|
|
13906
13945
|
function OrderItemCard(props) {
|
|
13907
13946
|
const item = props.orderItem;
|
|
13908
13947
|
const isChildItem = props.isChildItem || false;
|
|
13948
|
+
warnMissingProps(props);
|
|
13909
13949
|
const titleLinkable = props.titleLinkable !== void 0 ? props.titleLinkable : true;
|
|
13910
13950
|
const showImage = isChildItem ? false : props.showImage !== void 0 ? props.showImage : true;
|
|
13911
13951
|
const showSku = isChildItem ? false : props.showSku !== void 0 ? props.showSku : true;
|
|
@@ -14677,6 +14717,10 @@ function RequestPriceButton(props) {
|
|
|
14677
14717
|
}
|
|
14678
14718
|
var RequestPriceButton_default = RequestPriceButton;
|
|
14679
14719
|
var ROW_SEQ = 0;
|
|
14720
|
+
function snapToStep(value, min, step) {
|
|
14721
|
+
if (!Number.isFinite(value) || value <= min) return min;
|
|
14722
|
+
return Math.round((value - min) / (step || 1)) * (step || 1) + min;
|
|
14723
|
+
}
|
|
14680
14724
|
function blankRow() {
|
|
14681
14725
|
ROW_SEQ += 1;
|
|
14682
14726
|
return {
|
|
@@ -14688,6 +14732,7 @@ function blankRow() {
|
|
|
14688
14732
|
grossPrice: 0,
|
|
14689
14733
|
quantity: 1,
|
|
14690
14734
|
minQuantity: 1,
|
|
14735
|
+
step: 1,
|
|
14691
14736
|
matches: [],
|
|
14692
14737
|
searching: false,
|
|
14693
14738
|
searched: false
|
|
@@ -14781,6 +14826,7 @@ function QuickOrderInner(props) {
|
|
|
14781
14826
|
grossPrice: match.grossPrice,
|
|
14782
14827
|
quantity: match.minQuantity,
|
|
14783
14828
|
minQuantity: match.minQuantity,
|
|
14829
|
+
step: match.step,
|
|
14784
14830
|
matches: [],
|
|
14785
14831
|
searching: false,
|
|
14786
14832
|
searched: false
|
|
@@ -14793,7 +14839,7 @@ function QuickOrderInner(props) {
|
|
|
14793
14839
|
const n = parseInt(raw, 10);
|
|
14794
14840
|
setRows(
|
|
14795
14841
|
(prev) => prev.map(
|
|
14796
|
-
(r) => r.key === key ? { ...r, quantity:
|
|
14842
|
+
(r) => r.key === key ? { ...r, quantity: snapToStep(n, r.minQuantity, r.step) } : r
|
|
14797
14843
|
)
|
|
14798
14844
|
);
|
|
14799
14845
|
},
|
|
@@ -14846,7 +14892,8 @@ function QuickOrderInner(props) {
|
|
|
14846
14892
|
netPrice: exact.netPrice,
|
|
14847
14893
|
grossPrice: exact.grossPrice,
|
|
14848
14894
|
quantity: Math.max(exact.minQuantity, line.quantity),
|
|
14849
|
-
minQuantity: exact.minQuantity
|
|
14895
|
+
minQuantity: exact.minQuantity,
|
|
14896
|
+
step: exact.step
|
|
14850
14897
|
});
|
|
14851
14898
|
}
|
|
14852
14899
|
if (resolved.length) {
|
|
@@ -14977,7 +15024,7 @@ function QuickOrderInner(props) {
|
|
|
14977
15024
|
{
|
|
14978
15025
|
type: "number",
|
|
14979
15026
|
min: r.minQuantity,
|
|
14980
|
-
step: 1,
|
|
15027
|
+
step: r.step || 1,
|
|
14981
15028
|
value: r.productId ? r.quantity : "",
|
|
14982
15029
|
disabled: !r.productId,
|
|
14983
15030
|
onChange: (e) => setQuantity(r.key, e.target.value),
|