@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/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,33 @@ 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.27.0] - 2026-09-28
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **A quantity field could not be cleared and retyped.** The typed-input handler
|
|
16
|
+
only committed a value once it was at or above the minimum, so with a minimum
|
|
17
|
+
of 2, backspacing to empty or typing "1" was ignored and the previous number
|
|
18
|
+
stayed stuck in the box. The field now accepts any keystroke while editing and
|
|
19
|
+
resolves to a valid quantity on blur. (PWP-970)
|
|
20
|
+
|
|
21
|
+
- **Incrementing an off-grid quantity kept it off-grid.** `increment()` added the
|
|
22
|
+
step without first snapping to the `min + n*step` grid, so a quantity that was
|
|
23
|
+
already off it never returned. Both steppers now snap first. (PWP-970)
|
|
24
|
+
|
|
25
|
+
- **Quick order ignored the order step.** Its quantity input was hardcoded to
|
|
26
|
+
`step={1}` and nothing snapped, while bulk paste and spreadsheet upload are the
|
|
27
|
+
primary ordering route for a wholesale account. `QuickOrderMatch` now carries
|
|
28
|
+
`step` alongside `minQuantity`, and typed quantities snap to it. (PWP-970)
|
|
29
|
+
|
|
30
|
+
- **`OrderItemCard` accepted a misconfiguration in silence.** It ships from the
|
|
31
|
+
RSC-safe `/pure` entry and reads no context, so the host must supply `language`
|
|
32
|
+
and `configuration.urls` — but both are optional, nothing warned, and the
|
|
33
|
+
failure only showed as a wrong-language name or a link that dropped the locale
|
|
34
|
+
prefix two clicks later. A development-only warning now names each omission
|
|
35
|
+
once. `titleLinkable` defaults to true, so the link case applies unless a host
|
|
36
|
+
opts out. (PWP-972)
|
|
37
|
+
|
|
11
38
|
## [0.26.1] - 2026-09-28
|
|
12
39
|
|
|
13
40
|
### Fixed
|
package/dist/index.cjs
CHANGED
|
@@ -2634,6 +2634,7 @@ function toMatch(item, language) {
|
|
|
2634
2634
|
const netPrice = displayItem?.price?.net ?? 0;
|
|
2635
2635
|
const grossPrice = displayItem?.price?.gross ?? 0;
|
|
2636
2636
|
const minQuantity = Math.max(1, displayItem?.minimumQuantity ?? 1);
|
|
2637
|
+
const step = Math.max(1, displayItem?.unit ?? 1);
|
|
2637
2638
|
const imageUrl = isCluster ? propellerV2CoreUi.getClusterImageUrl(item) : propellerV2CoreUi.getProductImageUrl(item);
|
|
2638
2639
|
return {
|
|
2639
2640
|
productId,
|
|
@@ -2643,6 +2644,7 @@ function toMatch(item, language) {
|
|
|
2643
2644
|
netPrice,
|
|
2644
2645
|
grossPrice,
|
|
2645
2646
|
minQuantity,
|
|
2647
|
+
step,
|
|
2646
2648
|
imageUrl,
|
|
2647
2649
|
priceOnRequest: isPriceOnRequest(item)
|
|
2648
2650
|
};
|
|
@@ -4779,6 +4781,7 @@ function AddToCart(rawProps) {
|
|
|
4779
4781
|
onCartCreated: props.onCartCreated
|
|
4780
4782
|
});
|
|
4781
4783
|
const [quantity, setQuantity] = React6.useState(() => getMinQuantity(props.product));
|
|
4784
|
+
const [quantityDraft, setQuantityDraft] = React6.useState(null);
|
|
4782
4785
|
const [toastMessage, setToastMessage] = React6.useState(() => "");
|
|
4783
4786
|
const [toastType, setToastType] = React6.useState(() => "");
|
|
4784
4787
|
const [toastVisible, setToastVisible] = React6.useState(() => false);
|
|
@@ -4801,16 +4804,42 @@ function AddToCart(rawProps) {
|
|
|
4801
4804
|
function dismissToast() {
|
|
4802
4805
|
setToastVisible(false);
|
|
4803
4806
|
}
|
|
4807
|
+
function snapQuantity(value) {
|
|
4808
|
+
const min = getMinQuantity(props.product);
|
|
4809
|
+
const step = getStep(props.product);
|
|
4810
|
+
if (value <= min) return min;
|
|
4811
|
+
return Math.round((value - min) / step) * step + min;
|
|
4812
|
+
}
|
|
4804
4813
|
function increment() {
|
|
4805
|
-
|
|
4814
|
+
setQuantityDraft(null);
|
|
4815
|
+
const snapped = snapQuantity(quantity);
|
|
4816
|
+
setQuantity(snapped === quantity ? quantity + getStep(props.product) : snapped);
|
|
4806
4817
|
}
|
|
4807
4818
|
function decrement() {
|
|
4808
4819
|
const min = getMinQuantity(props.product);
|
|
4809
4820
|
const step = getStep(props.product);
|
|
4821
|
+
setQuantityDraft(null);
|
|
4822
|
+
const snapped = snapQuantity(quantity);
|
|
4823
|
+
if (snapped !== quantity) {
|
|
4824
|
+
setQuantity(snapped);
|
|
4825
|
+
return;
|
|
4826
|
+
}
|
|
4810
4827
|
if (quantity - step >= min) {
|
|
4811
4828
|
setQuantity(quantity - step);
|
|
4812
4829
|
}
|
|
4813
4830
|
}
|
|
4831
|
+
function handleQuantityInput(raw) {
|
|
4832
|
+
setQuantityDraft(raw);
|
|
4833
|
+
const val = parseInt(raw, 10);
|
|
4834
|
+
if (!isNaN(val) && val >= getMinQuantity(props.product)) {
|
|
4835
|
+
setQuantity(snapQuantity(val));
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
function handleQuantityBlur() {
|
|
4839
|
+
const val = parseInt(quantityDraft ?? "", 10);
|
|
4840
|
+
setQuantity(isNaN(val) ? getMinQuantity(props.product) : snapQuantity(val));
|
|
4841
|
+
setQuantityDraft(null);
|
|
4842
|
+
}
|
|
4814
4843
|
function getModalImageUrl() {
|
|
4815
4844
|
if (addedCartItem) {
|
|
4816
4845
|
const img = addedCartItem.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url;
|
|
@@ -4940,15 +4969,9 @@ function AddToCart(rawProps) {
|
|
|
4940
4969
|
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",
|
|
4941
4970
|
min: getMinQuantity(props.product),
|
|
4942
4971
|
step: getStep(props.product),
|
|
4943
|
-
value: quantity,
|
|
4944
|
-
onChange: (e) =>
|
|
4945
|
-
|
|
4946
|
-
const min = getMinQuantity(props.product);
|
|
4947
|
-
const step = getStep(props.product);
|
|
4948
|
-
if (!isNaN(val) && val >= min) {
|
|
4949
|
-
setQuantity(Math.round((val - min) / step) * step + min);
|
|
4950
|
-
}
|
|
4951
|
-
}
|
|
4972
|
+
value: quantityDraft ?? quantity,
|
|
4973
|
+
onChange: (e) => handleQuantityInput(e.target.value),
|
|
4974
|
+
onBlur: handleQuantityBlur
|
|
4952
4975
|
}
|
|
4953
4976
|
),
|
|
4954
4977
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -4973,15 +4996,9 @@ function AddToCart(rawProps) {
|
|
|
4973
4996
|
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",
|
|
4974
4997
|
min: getMinQuantity(props.product),
|
|
4975
4998
|
step: getStep(props.product),
|
|
4976
|
-
value: quantity,
|
|
4977
|
-
onChange: (e) =>
|
|
4978
|
-
|
|
4979
|
-
const min = getMinQuantity(props.product);
|
|
4980
|
-
const step = getStep(props.product);
|
|
4981
|
-
if (!isNaN(val) && val >= min) {
|
|
4982
|
-
setQuantity(Math.round((val - min) / step) * step + min);
|
|
4983
|
-
}
|
|
4984
|
-
}
|
|
4999
|
+
value: quantityDraft ?? quantity,
|
|
5000
|
+
onChange: (e) => handleQuantityInput(e.target.value),
|
|
5001
|
+
onBlur: handleQuantityBlur
|
|
4985
5002
|
}
|
|
4986
5003
|
) : null,
|
|
4987
5004
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -13903,6 +13920,28 @@ function OrderActions(rawProps) {
|
|
|
13903
13920
|
);
|
|
13904
13921
|
}
|
|
13905
13922
|
var OrderActions_default = OrderActions;
|
|
13923
|
+
var warnedOnce = /* @__PURE__ */ new Set();
|
|
13924
|
+
function warnOnce(key, message) {
|
|
13925
|
+
if (warnedOnce.has(key)) return;
|
|
13926
|
+
warnedOnce.add(key);
|
|
13927
|
+
console.warn(message);
|
|
13928
|
+
}
|
|
13929
|
+
function warnMissingProps(props) {
|
|
13930
|
+
if (process.env.NODE_ENV === "production") return;
|
|
13931
|
+
if (!props.language) {
|
|
13932
|
+
warnOnce(
|
|
13933
|
+
"language",
|
|
13934
|
+
"[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."
|
|
13935
|
+
);
|
|
13936
|
+
}
|
|
13937
|
+
const linkable = props.titleLinkable !== void 0 ? props.titleLinkable : true;
|
|
13938
|
+
if (linkable && !props.configuration?.urls) {
|
|
13939
|
+
warnOnce(
|
|
13940
|
+
"urls",
|
|
13941
|
+
"[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}."
|
|
13942
|
+
);
|
|
13943
|
+
}
|
|
13944
|
+
}
|
|
13906
13945
|
function getProductName3(orderItem, language) {
|
|
13907
13946
|
return propellerV2CoreUi.getLocalizedValue(orderItem?.product?.names, language, "") || orderItem?.name || "Unknown Product";
|
|
13908
13947
|
}
|
|
@@ -13926,6 +13965,7 @@ function getProductUrl(orderItem, language, urls) {
|
|
|
13926
13965
|
function OrderItemCard(props) {
|
|
13927
13966
|
const item = props.orderItem;
|
|
13928
13967
|
const isChildItem = props.isChildItem || false;
|
|
13968
|
+
warnMissingProps(props);
|
|
13929
13969
|
const titleLinkable = props.titleLinkable !== void 0 ? props.titleLinkable : true;
|
|
13930
13970
|
const showImage = isChildItem ? false : props.showImage !== void 0 ? props.showImage : true;
|
|
13931
13971
|
const showSku = isChildItem ? false : props.showSku !== void 0 ? props.showSku : true;
|
|
@@ -14697,6 +14737,10 @@ function RequestPriceButton(props) {
|
|
|
14697
14737
|
}
|
|
14698
14738
|
var RequestPriceButton_default = RequestPriceButton;
|
|
14699
14739
|
var ROW_SEQ = 0;
|
|
14740
|
+
function snapToStep(value, min, step) {
|
|
14741
|
+
if (!Number.isFinite(value) || value <= min) return min;
|
|
14742
|
+
return Math.round((value - min) / (step || 1)) * (step || 1) + min;
|
|
14743
|
+
}
|
|
14700
14744
|
function blankRow() {
|
|
14701
14745
|
ROW_SEQ += 1;
|
|
14702
14746
|
return {
|
|
@@ -14708,6 +14752,7 @@ function blankRow() {
|
|
|
14708
14752
|
grossPrice: 0,
|
|
14709
14753
|
quantity: 1,
|
|
14710
14754
|
minQuantity: 1,
|
|
14755
|
+
step: 1,
|
|
14711
14756
|
matches: [],
|
|
14712
14757
|
searching: false,
|
|
14713
14758
|
searched: false
|
|
@@ -14801,6 +14846,7 @@ function QuickOrderInner(props) {
|
|
|
14801
14846
|
grossPrice: match.grossPrice,
|
|
14802
14847
|
quantity: match.minQuantity,
|
|
14803
14848
|
minQuantity: match.minQuantity,
|
|
14849
|
+
step: match.step,
|
|
14804
14850
|
matches: [],
|
|
14805
14851
|
searching: false,
|
|
14806
14852
|
searched: false
|
|
@@ -14813,7 +14859,7 @@ function QuickOrderInner(props) {
|
|
|
14813
14859
|
const n = parseInt(raw, 10);
|
|
14814
14860
|
setRows(
|
|
14815
14861
|
(prev) => prev.map(
|
|
14816
|
-
(r) => r.key === key ? { ...r, quantity:
|
|
14862
|
+
(r) => r.key === key ? { ...r, quantity: snapToStep(n, r.minQuantity, r.step) } : r
|
|
14817
14863
|
)
|
|
14818
14864
|
);
|
|
14819
14865
|
},
|
|
@@ -14866,7 +14912,8 @@ function QuickOrderInner(props) {
|
|
|
14866
14912
|
netPrice: exact.netPrice,
|
|
14867
14913
|
grossPrice: exact.grossPrice,
|
|
14868
14914
|
quantity: Math.max(exact.minQuantity, line.quantity),
|
|
14869
|
-
minQuantity: exact.minQuantity
|
|
14915
|
+
minQuantity: exact.minQuantity,
|
|
14916
|
+
step: exact.step
|
|
14870
14917
|
});
|
|
14871
14918
|
}
|
|
14872
14919
|
if (resolved.length) {
|
|
@@ -14997,7 +15044,7 @@ function QuickOrderInner(props) {
|
|
|
14997
15044
|
{
|
|
14998
15045
|
type: "number",
|
|
14999
15046
|
min: r.minQuantity,
|
|
15000
|
-
step: 1,
|
|
15047
|
+
step: r.step || 1,
|
|
15001
15048
|
value: r.productId ? r.quantity : "",
|
|
15002
15049
|
disabled: !r.productId,
|
|
15003
15050
|
onChange: (e) => setQuantity(r.key, e.target.value),
|