@propeller-commerce/propeller-v2-react-ui 0.28.0 → 0.29.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 +63 -0
- package/dist/index.cjs +121 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +122 -67
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,69 @@ 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.29.0] - 2026-10-05
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Listings no longer drop the company's orderlist on a client-side fetch.**
|
|
16
|
+
`useProductSearch` sent `applyOrderlists: false` whenever the caller passed
|
|
17
|
+
no explicit `orderlistIds` — which is every app — so the backend was told to
|
|
18
|
+
ignore the company's own orderlists. The server render omits the flag and is
|
|
19
|
+
correctly scoped, so a category page painted the right products and then the
|
|
20
|
+
first sort, filter, page or company change replaced them with the unscoped
|
|
21
|
+
catalogue, priced and orderable. The flag is now sent only when the caller
|
|
22
|
+
actually asks for it, in both the grid fetch and the search-bar preview.
|
|
23
|
+
`useQuickOrder` had the same default, which let a bulk paste resolve SKUs
|
|
24
|
+
outside the contract.
|
|
25
|
+
|
|
26
|
+
Callers that relied on the implicit `false` for an intentionally unscoped
|
|
27
|
+
listing must now pass `applyOrderlists={false}` explicitly.
|
|
28
|
+
|
|
29
|
+
- **`<ProductSlider>` is scoped to the viewer and priced for their company.**
|
|
30
|
+
`fetchProducts` sent no `userId`, no `companyId` and no
|
|
31
|
+
`priceCalculateProductInput`, and resolved its ids through the flat
|
|
32
|
+
`products` resolver, which does not apply orderlist scoping. A featured
|
|
33
|
+
slider therefore showed products outside the company's assortment at the
|
|
34
|
+
default company's prices. Its `filterToAssortment` step — whose only job is
|
|
35
|
+
dropping out-of-assortment crossupsells — asked the same resolver and so
|
|
36
|
+
could never filter anything. Both now go through `category.products` over
|
|
37
|
+
`configuration.baseCategoryId`, the path the grid and quick order already
|
|
38
|
+
use. Without a resolved base category the primary fetch returns nothing
|
|
39
|
+
rather than an unscoped list, while the crossupsell check falls through to
|
|
40
|
+
the unverified items so a slider is never blanked by a failed check.
|
|
41
|
+
|
|
42
|
+
- **Cart quantity steppers keep the line on the order grid.** `CartItem` read
|
|
43
|
+
`minimumQuantity` and the step but used them only to disable the decrement
|
|
44
|
+
button: the buttons added or subtracted the step from whatever was there, so
|
|
45
|
+
a line already off the grid stayed off it (min 2, step 3: 9 → 12). The typed
|
|
46
|
+
field committed only values at or above the minimum, so clearing it or typing
|
|
47
|
+
below the minimum left the old quantity stuck. Both steppers now resolve to
|
|
48
|
+
the grid first, and editing goes through a draft value that resolves on blur
|
|
49
|
+
— the same rule `<AddToCart>` and `<QuickOrder>` already followed.
|
|
50
|
+
|
|
51
|
+
- **Add to cart recovers when the remembered cart is gone.** A cart ordered in
|
|
52
|
+
another browser or deleted leaves its id behind in the host's storage, and
|
|
53
|
+
every later `cartAddItem` answered `CART_NOT_FOUND_ERROR`. Nothing forgot the
|
|
54
|
+
id, so each retry failed identically and the badge kept showing the dead
|
|
55
|
+
cart. `addItem` now forgets it and starts a fresh cart once, then re-adds;
|
|
56
|
+
the recovery is bounded because cart initialisation only ever returns an
|
|
57
|
+
`OPEN` cart, and it is skipped when the caller passed `createCart: false`.
|
|
58
|
+
|
|
59
|
+
- **`useProductInfo` no longer sends every company orderlist as an allowlist.**
|
|
60
|
+
It fetched all orderlists for the company and passed their ids to
|
|
61
|
+
`product(orderlistIds:)` with no filter on type, so a NEGATIVE (exclusion)
|
|
62
|
+
list was applied as an allowlist and inverted the filter. Scoping is left to
|
|
63
|
+
the backend, which merges positive and negative lists itself — one fewer
|
|
64
|
+
request per product page.
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
|
|
68
|
+
- **The min/step rule comes from `propeller-v2-core-ui`.** `AddToCart`,
|
|
69
|
+
`QuickOrder` and `CartItem` each carried their own copy, and they had
|
|
70
|
+
drifted — two of them divided by an unguarded step. All now call
|
|
71
|
+
`resolveOrderableQuantity` from core-ui 0.11.0, which is the new minimum for
|
|
72
|
+
this package.
|
|
73
|
+
|
|
11
74
|
## [0.28.0] - 2026-10-02
|
|
12
75
|
|
|
13
76
|
### Added
|
package/dist/index.cjs
CHANGED
|
@@ -620,6 +620,14 @@ function useAuth(options) {
|
|
|
620
620
|
}, [graphqlClient]);
|
|
621
621
|
return { loading, error, login, magicLogin, createMagicToken, registerContact, registerCustomer, forgotPassword };
|
|
622
622
|
}
|
|
623
|
+
var CART_NOT_FOUND = "CART_NOT_FOUND_ERROR";
|
|
624
|
+
function isCartNotFound(error) {
|
|
625
|
+
const entries = error?.errors;
|
|
626
|
+
if (!Array.isArray(entries)) return false;
|
|
627
|
+
return entries.some(
|
|
628
|
+
(e) => e?.extensions?.code === CART_NOT_FOUND || /cart:?\s*\S+\s+not found/i.test(e?.message ?? "")
|
|
629
|
+
);
|
|
630
|
+
}
|
|
623
631
|
async function initCart(config) {
|
|
624
632
|
const {
|
|
625
633
|
services,
|
|
@@ -759,6 +767,11 @@ function useCart(options) {
|
|
|
759
767
|
setCreatedCartId(c.cartId);
|
|
760
768
|
cartIdRef.current = c.cartId;
|
|
761
769
|
}, []);
|
|
770
|
+
const forgetCart = React6.useCallback(() => {
|
|
771
|
+
setCart(null);
|
|
772
|
+
setCreatedCartId("");
|
|
773
|
+
cartIdRef.current = "";
|
|
774
|
+
}, []);
|
|
762
775
|
const imageSearchFilters = React6.useCallback(
|
|
763
776
|
() => configuration?.imageSearchFiltersGrid ?? DEFAULT_IMAGE_SEARCH_FILTERS,
|
|
764
777
|
[configuration]
|
|
@@ -842,13 +855,28 @@ function useCart(options) {
|
|
|
842
855
|
} else return propellerV2CoreUi.err("No cart ID provided");
|
|
843
856
|
}
|
|
844
857
|
const service = propellerV2CoreUi.createServices(graphqlClient).cart;
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
858
|
+
const input = { productId: opts.product.productId, quantity: opts.quantity, ...opts.cluster?.clusterId !== void 0 && { clusterId: opts.cluster.clusterId }, ...childItemInputs && { childItems: childItemInputs }, ...opts.notes && { notes: opts.notes }, ...opts.price !== void 0 && { price: opts.price } };
|
|
859
|
+
let resultCart;
|
|
860
|
+
try {
|
|
861
|
+
resultCart = await service.addItemToCart({
|
|
862
|
+
id: resolvedCartId,
|
|
863
|
+
input,
|
|
864
|
+
language,
|
|
865
|
+
imageSearchFilters: imageSearchFilters(),
|
|
866
|
+
imageVariantFilters: imageVariantFilters()
|
|
867
|
+
});
|
|
868
|
+
} catch (e) {
|
|
869
|
+
if (!isCartNotFound(e) || !opts.createCart) throw e;
|
|
870
|
+
forgetCart();
|
|
871
|
+
const fresh = await resolveCart();
|
|
872
|
+
resultCart = await service.addItemToCart({
|
|
873
|
+
id: fresh.cartId,
|
|
874
|
+
input,
|
|
875
|
+
language,
|
|
876
|
+
imageSearchFilters: imageSearchFilters(),
|
|
877
|
+
imageVariantFilters: imageVariantFilters()
|
|
878
|
+
});
|
|
879
|
+
}
|
|
852
880
|
rememberCart(resultCart);
|
|
853
881
|
const addedItem = resultCart.items?.find((i) => i.productId === opts.product.productId) ?? null;
|
|
854
882
|
opts.afterAddToCart?.(resultCart, addedItem);
|
|
@@ -860,7 +888,7 @@ function useCart(options) {
|
|
|
860
888
|
} finally {
|
|
861
889
|
setLoading(false);
|
|
862
890
|
}
|
|
863
|
-
}, [graphqlClient, cartId, language, configuration, resolveCart, rememberCart, imageSearchFilters, imageVariantFilters]);
|
|
891
|
+
}, [graphqlClient, cartId, language, configuration, resolveCart, rememberCart, forgetCart, imageSearchFilters, imageVariantFilters]);
|
|
864
892
|
const addItems = React6.useCallback(async (items) => {
|
|
865
893
|
const added = [];
|
|
866
894
|
let lastCart = null;
|
|
@@ -2146,19 +2174,8 @@ function useProductInfo(options) {
|
|
|
2146
2174
|
setLoading(true);
|
|
2147
2175
|
setError(null);
|
|
2148
2176
|
try {
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
if (options.orderlistIds && options.orderlistIds.length > 0) {
|
|
2152
|
-
orderlistIds = options.orderlistIds;
|
|
2153
|
-
applyOrderlists = options.applyOrderlists !== false;
|
|
2154
|
-
} else if (options.applyOrderlists === false) {
|
|
2155
|
-
applyOrderlists = false;
|
|
2156
|
-
} else if (options.user && options.companyId) {
|
|
2157
|
-
const orderlistService = propellerV2CoreUi.createServices(graphqlClient).orderlist;
|
|
2158
|
-
const searchInput = { companyIds: [options.companyId] };
|
|
2159
|
-
const orderlists = await orderlistService.getOrderlists(searchInput);
|
|
2160
|
-
orderlistIds = (orderlists?.items ?? []).map((ol) => ol.id);
|
|
2161
|
-
}
|
|
2177
|
+
const orderlistIds = options.orderlistIds ?? [];
|
|
2178
|
+
const applyOrderlists = options.applyOrderlists !== false;
|
|
2162
2179
|
const service = propellerV2CoreUi.createServices(graphqlClient).product;
|
|
2163
2180
|
const attributeInput = buildAttributeInput2();
|
|
2164
2181
|
const variables = {
|
|
@@ -2369,7 +2386,7 @@ function useProductSearch(options) {
|
|
|
2369
2386
|
const orderlistScope = options.orderlistIds && options.orderlistIds.length > 0 ? {
|
|
2370
2387
|
applyOrderlists: options.applyOrderlists !== false,
|
|
2371
2388
|
orderlistIds: options.orderlistIds
|
|
2372
|
-
} : { applyOrderlists: false };
|
|
2389
|
+
} : options.applyOrderlists === false ? { applyOrderlists: false } : {};
|
|
2373
2390
|
const categoryProductSearchInput = {
|
|
2374
2391
|
language: lang,
|
|
2375
2392
|
page: pagination.currentPage,
|
|
@@ -2499,7 +2516,7 @@ function useProductSearch(options) {
|
|
|
2499
2516
|
const orderlistScope = options.orderlistIds && options.orderlistIds.length > 0 ? {
|
|
2500
2517
|
applyOrderlists: options.applyOrderlists !== false,
|
|
2501
2518
|
orderlistIds: options.orderlistIds
|
|
2502
|
-
} : { applyOrderlists: false };
|
|
2519
|
+
} : options.applyOrderlists === false ? { applyOrderlists: false } : {};
|
|
2503
2520
|
const userId = resolveListingUserId(options.user, configuration);
|
|
2504
2521
|
const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
|
|
2505
2522
|
const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
|
|
@@ -2675,7 +2692,7 @@ function useQuickOrder(options) {
|
|
|
2675
2692
|
if (!catId) return [];
|
|
2676
2693
|
try {
|
|
2677
2694
|
const service = propellerV2CoreUi.createServices(graphqlClient).category;
|
|
2678
|
-
const orderlistScope = orderlistIds && orderlistIds.length > 0 ? { applyOrderlists: applyOrderlists !== false, orderlistIds } : { applyOrderlists: false };
|
|
2695
|
+
const orderlistScope = orderlistIds && orderlistIds.length > 0 ? { applyOrderlists: applyOrderlists !== false, orderlistIds } : applyOrderlists === false ? { applyOrderlists: false } : {};
|
|
2679
2696
|
const userId = resolveListingUserId(user, configuration);
|
|
2680
2697
|
const contactId = user && "contactId" in user ? user.contactId : void 0;
|
|
2681
2698
|
const customerId = user && "customerId" in user ? user.customerId : void 0;
|
|
@@ -3284,28 +3301,33 @@ function useProductSlider(options) {
|
|
|
3284
3301
|
}
|
|
3285
3302
|
}
|
|
3286
3303
|
if (!productIds.length && !clusterIds.length) return items;
|
|
3304
|
+
const catId = configuration.baseCategoryId;
|
|
3305
|
+
if (!catId) return items;
|
|
3287
3306
|
const userId = resolveUserId();
|
|
3288
3307
|
const companyId = resolveCompanyId();
|
|
3289
|
-
const
|
|
3308
|
+
const categoryProductSearchInput = {
|
|
3290
3309
|
...productIds.length && { productIds },
|
|
3291
3310
|
...clusterIds.length && { clusterIds },
|
|
3292
3311
|
language,
|
|
3293
3312
|
page: 1,
|
|
3294
3313
|
offset: 50,
|
|
3295
3314
|
statuses: [propellerSdkV2.ProductStatus.A, propellerSdkV2.ProductStatus.P, propellerSdkV2.ProductStatus.T, propellerSdkV2.ProductStatus.S],
|
|
3315
|
+
hidden: false,
|
|
3296
3316
|
...userId !== void 0 && { userId },
|
|
3297
3317
|
...companyId !== void 0 && { companyId }
|
|
3298
3318
|
};
|
|
3299
3319
|
const filterAvailableAttributeInput = { isSearchable: true };
|
|
3300
3320
|
const variables = {
|
|
3301
|
-
|
|
3321
|
+
categoryId: catId,
|
|
3322
|
+
language,
|
|
3323
|
+
categoryProductSearchInput,
|
|
3324
|
+
filterAvailableAttributeInput,
|
|
3302
3325
|
imageSearchFilters: configuration.imageSearchFiltersGrid,
|
|
3303
|
-
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3304
|
-
filterAvailableAttributeInput
|
|
3326
|
+
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3305
3327
|
};
|
|
3306
3328
|
try {
|
|
3307
|
-
const response = await propellerV2CoreUi.createServices(graphqlClient).
|
|
3308
|
-
const resolved = response?.items ?? [];
|
|
3329
|
+
const response = await propellerV2CoreUi.createServices(graphqlClient).category.getCategory(variables);
|
|
3330
|
+
const resolved = response?.products?.items ?? [];
|
|
3309
3331
|
const allowed = /* @__PURE__ */ new Set();
|
|
3310
3332
|
for (const r of resolved) {
|
|
3311
3333
|
const id = r.productId ?? r.clusterId;
|
|
@@ -3361,10 +3383,17 @@ function useProductSlider(options) {
|
|
|
3361
3383
|
setLoading(true);
|
|
3362
3384
|
setError(null);
|
|
3363
3385
|
try {
|
|
3364
|
-
const
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3386
|
+
const catId = configuration.baseCategoryId;
|
|
3387
|
+
if (!catId) {
|
|
3388
|
+
setProducts([]);
|
|
3389
|
+
return;
|
|
3390
|
+
}
|
|
3391
|
+
const service = propellerV2CoreUi.createServices(graphqlClient).category;
|
|
3392
|
+
const userId = resolveUserId();
|
|
3393
|
+
const companyId = resolveCompanyId();
|
|
3394
|
+
const categoryProductSearchInput = {
|
|
3395
|
+
...productIds.length && { productIds },
|
|
3396
|
+
...clusterIds.length && { clusterIds },
|
|
3368
3397
|
language,
|
|
3369
3398
|
page: 1,
|
|
3370
3399
|
offset: 50,
|
|
@@ -3373,17 +3402,24 @@ function useProductSlider(options) {
|
|
|
3373
3402
|
propellerSdkV2.ProductStatus.P,
|
|
3374
3403
|
propellerSdkV2.ProductStatus.T,
|
|
3375
3404
|
propellerSdkV2.ProductStatus.S
|
|
3376
|
-
]
|
|
3405
|
+
],
|
|
3406
|
+
hidden: false,
|
|
3407
|
+
...userId !== void 0 && { userId },
|
|
3408
|
+
...companyId !== void 0 && { companyId }
|
|
3377
3409
|
};
|
|
3378
3410
|
const filterAvailableAttributeInput = { isSearchable: true };
|
|
3379
3411
|
const variables = {
|
|
3380
|
-
|
|
3412
|
+
categoryId: catId,
|
|
3413
|
+
language,
|
|
3414
|
+
categoryProductSearchInput,
|
|
3415
|
+
priceCalculateProductInput: buildPriceInput(),
|
|
3416
|
+
filterAvailableAttributeInput,
|
|
3381
3417
|
imageSearchFilters: configuration.imageSearchFiltersGrid,
|
|
3382
|
-
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3383
|
-
filterAvailableAttributeInput
|
|
3418
|
+
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3384
3419
|
};
|
|
3385
|
-
const response = await service.
|
|
3386
|
-
|
|
3420
|
+
const response = await service.getCategory(variables);
|
|
3421
|
+
const productsResponse = response?.products;
|
|
3422
|
+
setProducts(productsResponse?.items ?? []);
|
|
3387
3423
|
} catch (e) {
|
|
3388
3424
|
setError(e instanceof Error ? e.message : "Failed to fetch products");
|
|
3389
3425
|
setProducts([]);
|
|
@@ -4827,10 +4863,7 @@ function AddToCart(rawProps) {
|
|
|
4827
4863
|
setToastVisible(false);
|
|
4828
4864
|
}
|
|
4829
4865
|
function snapQuantity(value) {
|
|
4830
|
-
|
|
4831
|
-
const step = getStep(props.product);
|
|
4832
|
-
if (value <= min) return min;
|
|
4833
|
-
return Math.round((value - min) / step) * step + min;
|
|
4866
|
+
return propellerV2CoreUi.resolveOrderableQuantity(value, getMinQuantity(props.product), getStep(props.product));
|
|
4834
4867
|
}
|
|
4835
4868
|
function increment() {
|
|
4836
4869
|
setQuantityDraft(null);
|
|
@@ -6939,6 +6972,7 @@ function CartItem(rawProps) {
|
|
|
6939
6972
|
companyId: props.companyId
|
|
6940
6973
|
});
|
|
6941
6974
|
const [quantity, setQuantity] = React6.useState(() => props.cartItem.quantity || 1);
|
|
6975
|
+
const [quantityDraft, setQuantityDraft] = React6.useState(() => null);
|
|
6942
6976
|
const [notes, setNotes] = React6.useState(() => props.cartItem.notes || "");
|
|
6943
6977
|
const [loading, setLoading] = React6.useState(() => false);
|
|
6944
6978
|
const [deleting, setDeleting] = React6.useState(() => false);
|
|
@@ -7062,6 +7096,34 @@ function CartItem(rawProps) {
|
|
|
7062
7096
|
setLoading(false);
|
|
7063
7097
|
}
|
|
7064
7098
|
}
|
|
7099
|
+
function handleQuantityDecrement() {
|
|
7100
|
+
setQuantityDraft(null);
|
|
7101
|
+
const orderable = propellerV2CoreUi.resolveOrderableQuantity(quantity, minQuantity, step);
|
|
7102
|
+
if (orderable !== quantity) {
|
|
7103
|
+
handleQuantityChange(orderable);
|
|
7104
|
+
return;
|
|
7105
|
+
}
|
|
7106
|
+
if (quantity - step >= minQuantity) handleQuantityChange(quantity - step);
|
|
7107
|
+
}
|
|
7108
|
+
function handleQuantityIncrement() {
|
|
7109
|
+
setQuantityDraft(null);
|
|
7110
|
+
const orderable = propellerV2CoreUi.resolveOrderableQuantity(quantity, minQuantity, step);
|
|
7111
|
+
handleQuantityChange(orderable === quantity ? quantity + step : orderable);
|
|
7112
|
+
}
|
|
7113
|
+
function handleQuantityInput(raw) {
|
|
7114
|
+
setQuantityDraft(raw);
|
|
7115
|
+
const val = parseInt(raw, 10);
|
|
7116
|
+
if (!isNaN(val) && val >= minQuantity) {
|
|
7117
|
+
handleQuantityChange(propellerV2CoreUi.resolveOrderableQuantity(val, minQuantity, step));
|
|
7118
|
+
}
|
|
7119
|
+
}
|
|
7120
|
+
function handleQuantityBlur() {
|
|
7121
|
+
if (quantityDraft === null) return;
|
|
7122
|
+
const val = parseInt(quantityDraft, 10);
|
|
7123
|
+
setQuantityDraft(null);
|
|
7124
|
+
const orderable = propellerV2CoreUi.resolveOrderableQuantity(val, minQuantity, step);
|
|
7125
|
+
if (orderable !== quantity) handleQuantityChange(orderable);
|
|
7126
|
+
}
|
|
7065
7127
|
function handleNoteChange(note) {
|
|
7066
7128
|
setNotes(note);
|
|
7067
7129
|
if (props.onNoteChange) {
|
|
@@ -7164,7 +7226,8 @@ function CartItem(rawProps) {
|
|
|
7164
7226
|
deleting,
|
|
7165
7227
|
crossupsells,
|
|
7166
7228
|
visibleCrossupsells: getVisibleCrossupsells(),
|
|
7167
|
-
addingCrossupsellId
|
|
7229
|
+
addingCrossupsellId,
|
|
7230
|
+
quantityDraft
|
|
7168
7231
|
},
|
|
7169
7232
|
helpers: {
|
|
7170
7233
|
getBundleItemName,
|
|
@@ -7177,6 +7240,10 @@ function CartItem(rawProps) {
|
|
|
7177
7240
|
},
|
|
7178
7241
|
handlers: {
|
|
7179
7242
|
onQuantityChange: handleQuantityChange,
|
|
7243
|
+
onQuantityDecrement: handleQuantityDecrement,
|
|
7244
|
+
onQuantityIncrement: handleQuantityIncrement,
|
|
7245
|
+
onQuantityInput: handleQuantityInput,
|
|
7246
|
+
onQuantityBlur: handleQuantityBlur,
|
|
7180
7247
|
onNoteChange: handleNoteChange,
|
|
7181
7248
|
onDelete: handleDelete,
|
|
7182
7249
|
onTitleClick: (e) => props.onTitleClick?.(e, props.cartItem),
|
|
@@ -7491,7 +7558,7 @@ function CartItemQuantity(props = {}) {
|
|
|
7491
7558
|
{
|
|
7492
7559
|
type: "button",
|
|
7493
7560
|
className: "propeller-cart-item__decrement px-2.5 h-full text-muted-foreground hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors rounded-l-control select-none",
|
|
7494
|
-
onClick:
|
|
7561
|
+
onClick: handlers.onQuantityDecrement,
|
|
7495
7562
|
disabled: derived.quantity <= derived.minQuantity || state.loading,
|
|
7496
7563
|
children: "-"
|
|
7497
7564
|
}
|
|
@@ -7503,13 +7570,9 @@ function CartItemQuantity(props = {}) {
|
|
|
7503
7570
|
className: "propeller-cart-item__quantity w-10 text-center text-sm bg-transparent border-x border-input h-full focus:ring-0 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
|
7504
7571
|
min: derived.minQuantity,
|
|
7505
7572
|
step: derived.step,
|
|
7506
|
-
value: derived.quantity,
|
|
7507
|
-
onChange: (e) =>
|
|
7508
|
-
|
|
7509
|
-
if (!isNaN(val) && val >= derived.minQuantity) {
|
|
7510
|
-
handlers.onQuantityChange(Math.round((val - derived.minQuantity) / derived.step) * derived.step + derived.minQuantity);
|
|
7511
|
-
}
|
|
7512
|
-
}
|
|
7573
|
+
value: state.quantityDraft ?? derived.quantity,
|
|
7574
|
+
onChange: (e) => handlers.onQuantityInput(e.target.value),
|
|
7575
|
+
onBlur: handlers.onQuantityBlur
|
|
7513
7576
|
}
|
|
7514
7577
|
),
|
|
7515
7578
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -7517,7 +7580,7 @@ function CartItemQuantity(props = {}) {
|
|
|
7517
7580
|
{
|
|
7518
7581
|
type: "button",
|
|
7519
7582
|
className: "propeller-cart-item__increment px-2.5 h-full text-muted-foreground hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors rounded-r-control select-none",
|
|
7520
|
-
onClick:
|
|
7583
|
+
onClick: handlers.onQuantityIncrement,
|
|
7521
7584
|
disabled: state.loading,
|
|
7522
7585
|
children: "+"
|
|
7523
7586
|
}
|
|
@@ -7531,13 +7594,9 @@ function CartItemQuantity(props = {}) {
|
|
|
7531
7594
|
className: props.className ?? "propeller-cart-item__quantity w-14 h-9 text-center text-sm border border-input rounded-control focus:ring-2 focus:ring-primary focus:border-transparent [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
|
7532
7595
|
min: derived.minQuantity,
|
|
7533
7596
|
step: derived.step,
|
|
7534
|
-
value: derived.quantity,
|
|
7535
|
-
onChange: (e) =>
|
|
7536
|
-
|
|
7537
|
-
if (!isNaN(val) && val >= derived.minQuantity) {
|
|
7538
|
-
handlers.onQuantityChange(Math.round((val - derived.minQuantity) / derived.step) * derived.step + derived.minQuantity);
|
|
7539
|
-
}
|
|
7540
|
-
}
|
|
7597
|
+
value: state.quantityDraft ?? derived.quantity,
|
|
7598
|
+
onChange: (e) => handlers.onQuantityInput(e.target.value),
|
|
7599
|
+
onBlur: handlers.onQuantityBlur
|
|
7541
7600
|
}
|
|
7542
7601
|
);
|
|
7543
7602
|
}
|
|
@@ -14795,10 +14854,6 @@ function RequestPriceButton(props) {
|
|
|
14795
14854
|
}
|
|
14796
14855
|
var RequestPriceButton_default = RequestPriceButton;
|
|
14797
14856
|
var ROW_SEQ = 0;
|
|
14798
|
-
function snapToStep(value, min, step) {
|
|
14799
|
-
if (!Number.isFinite(value) || value <= min) return min;
|
|
14800
|
-
return Math.round((value - min) / (step || 1)) * (step || 1) + min;
|
|
14801
|
-
}
|
|
14802
14857
|
function blankRow() {
|
|
14803
14858
|
ROW_SEQ += 1;
|
|
14804
14859
|
return {
|
|
@@ -14918,7 +14973,7 @@ function QuickOrderInner(props) {
|
|
|
14918
14973
|
const n = parseInt(raw, 10);
|
|
14919
14974
|
setRows(
|
|
14920
14975
|
(prev) => prev.map(
|
|
14921
|
-
(r) => r.key === key ? { ...r, quantity:
|
|
14976
|
+
(r) => r.key === key ? { ...r, quantity: propellerV2CoreUi.resolveOrderableQuantity(n, r.minQuantity, r.step) } : r
|
|
14922
14977
|
)
|
|
14923
14978
|
);
|
|
14924
14979
|
},
|