@propeller-commerce/propeller-v2-react-ui 0.11.3 → 0.12.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 +53 -0
- package/dist/index.cjs +23 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +23 -12
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,59 @@ 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.12.0] - 2026-07-31
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`productTrackAttributes` on `<ProductGrid>`, `<SearchBar>` and
|
|
16
|
+
`useProductSearch`.** Pass the attribute names a card renders — e.g.
|
|
17
|
+
`productTrackAttributes={['MPN']}` — and they arrive on
|
|
18
|
+
`product.attributes` for every item in the result, ready to read from a
|
|
19
|
+
card slot like `belowName`. `useProductInfo` has had an option of this name
|
|
20
|
+
since the PDP work; the grid side simply never forwarded one, so hosts that
|
|
21
|
+
set it in their portal config saw it silently ignored on listings and had
|
|
22
|
+
to fetch attributes themselves in a second request.
|
|
23
|
+
|
|
24
|
+
Requires `propeller-sdk-v2` >= 0.16.0, where the `category` and `products`
|
|
25
|
+
operations gained `$attributeResultSearchInput` and `ProductGridFields`
|
|
26
|
+
gained the matching `attributes(input:)` selection.
|
|
27
|
+
|
|
28
|
+
Naming the attributes you render is not just a payload optimisation — it is
|
|
29
|
+
the correct behaviour. With no input the server returns the *first page* of
|
|
30
|
+
a product's attributes (12 per product), so on a product carrying more than
|
|
31
|
+
12 the ones on later pages are missing with no error. Filtering to the names
|
|
32
|
+
you need also cut a 24-product category response from ~168 KB to ~124 KB in
|
|
33
|
+
our testing.
|
|
34
|
+
|
|
35
|
+
## [0.11.4] - 2026-07-31
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- **The add-to-cart button overflowed its product card in narrow columns.**
|
|
40
|
+
The submit button is `flex-1`, but a flex item defaults to
|
|
41
|
+
`min-width: auto` and so refuses to shrink below its content width — icon
|
|
42
|
+
plus label plus `px-6` of padding. In a slider or a dense grid the button
|
|
43
|
+
ran past the card's edge instead of fitting inside it. Longer non-English
|
|
44
|
+
labels hit this first: Dutch "Toevoegen" is roughly twice the width of the
|
|
45
|
+
"Add" the padding was sized around. The button now carries `min-w-0`, eases
|
|
46
|
+
its padding to `px-3 sm:px-6`, and wraps its label in a `truncate` span, so
|
|
47
|
+
it shrinks to the column and ellipsises rather than overflowing. Same fix
|
|
48
|
+
for `<ClusterCard>`'s "View cluster" link, which had the identical shape.
|
|
49
|
+
- **Hovering a card's CTA lit up the whole card.** The card root is a
|
|
50
|
+
`group` with `hover:shadow-md`, so hovering the button — a descendant —
|
|
51
|
+
raised the card shadow, shifted its border and zoomed the product image at
|
|
52
|
+
the same time as the button's own hover state. Three things answering one
|
|
53
|
+
intent read as the card being clickable rather than the button. While the
|
|
54
|
+
pointer is on a CTA the card-level highlight and the image zoom now stand
|
|
55
|
+
down and the button owns the hover; moving anywhere else on the card is
|
|
56
|
+
unchanged. Browsers without `:has()` keep the previous behaviour.
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
- **`<AddToCart>`'s hover shade now matches the other CTAs.** It darkened to
|
|
61
|
+
`bg-secondary/90` where every other solid button in the package uses `/80`.
|
|
62
|
+
Now `/80` as well.
|
|
63
|
+
|
|
11
64
|
## [0.11.3] - 2026-07-31
|
|
12
65
|
|
|
13
66
|
### Fixed
|
package/dist/index.cjs
CHANGED
|
@@ -2090,7 +2090,7 @@ function useProductInfo(options) {
|
|
|
2090
2090
|
if (options.user && "customerId" in options.user) input.customerId = options.user.customerId;
|
|
2091
2091
|
return input;
|
|
2092
2092
|
}
|
|
2093
|
-
function
|
|
2093
|
+
function buildAttributeInput2() {
|
|
2094
2094
|
const names = options.productTrackAttributes;
|
|
2095
2095
|
if (!names || names.length === 0) return void 0;
|
|
2096
2096
|
return { attributeDescription: { names } };
|
|
@@ -2113,7 +2113,7 @@ function useProductInfo(options) {
|
|
|
2113
2113
|
orderlistIds = (orderlists?.items ?? []).map((ol) => ol.id);
|
|
2114
2114
|
}
|
|
2115
2115
|
const service = propellerV2CoreUi.createServices(graphqlClient).product;
|
|
2116
|
-
const attributeInput =
|
|
2116
|
+
const attributeInput = buildAttributeInput2();
|
|
2117
2117
|
const variables = {
|
|
2118
2118
|
productId,
|
|
2119
2119
|
language,
|
|
@@ -2203,6 +2203,10 @@ function useProductInfo(options) {
|
|
|
2203
2203
|
};
|
|
2204
2204
|
}
|
|
2205
2205
|
var inflightFetches2 = /* @__PURE__ */ new Set();
|
|
2206
|
+
function buildAttributeInput(names) {
|
|
2207
|
+
if (!names || names.length === 0) return void 0;
|
|
2208
|
+
return { attributeDescription: { names } };
|
|
2209
|
+
}
|
|
2206
2210
|
function useProductSearch(options) {
|
|
2207
2211
|
const { graphqlClient, configuration } = options;
|
|
2208
2212
|
const isControlled = options.products !== void 0;
|
|
@@ -2335,6 +2339,7 @@ function useProductSearch(options) {
|
|
|
2335
2339
|
const filterAvailableAttributeInput = {
|
|
2336
2340
|
isSearchable: true
|
|
2337
2341
|
};
|
|
2342
|
+
const attributeInput = buildAttributeInput(options.productTrackAttributes);
|
|
2338
2343
|
const variables = {
|
|
2339
2344
|
categoryId: catId,
|
|
2340
2345
|
language: lang,
|
|
@@ -2342,7 +2347,8 @@ function useProductSearch(options) {
|
|
|
2342
2347
|
priceCalculateProductInput,
|
|
2343
2348
|
filterAvailableAttributeInput,
|
|
2344
2349
|
imageSearchFilters: configuration?.imageSearchFiltersGrid,
|
|
2345
|
-
imageVariantFilters: configuration?.imageVariantFiltersMedium
|
|
2350
|
+
imageVariantFilters: configuration?.imageVariantFiltersMedium,
|
|
2351
|
+
...attributeInput && { attributeResultSearchInput: attributeInput }
|
|
2346
2352
|
};
|
|
2347
2353
|
const response = await service.getCategory(variables);
|
|
2348
2354
|
if (thisId !== fetchIdRef.current) return;
|
|
@@ -2403,7 +2409,9 @@ function useProductSearch(options) {
|
|
|
2403
2409
|
taxZone,
|
|
2404
2410
|
pageSize,
|
|
2405
2411
|
pagination.currentPage,
|
|
2406
|
-
configuration
|
|
2412
|
+
configuration,
|
|
2413
|
+
// Stringified: callers pass an array literal, so identity changes each render.
|
|
2414
|
+
JSON.stringify(options.productTrackAttributes ?? [])
|
|
2407
2415
|
]);
|
|
2408
2416
|
const search = React6.useCallback(
|
|
2409
2417
|
(term) => {
|
|
@@ -2482,13 +2490,15 @@ function useProductSearch(options) {
|
|
|
2482
2490
|
...contactId !== void 0 && { contactId },
|
|
2483
2491
|
...customerId !== void 0 && { customerId }
|
|
2484
2492
|
};
|
|
2493
|
+
const attributeInput = buildAttributeInput(options.productTrackAttributes);
|
|
2485
2494
|
const variables = {
|
|
2486
2495
|
categoryId: catId,
|
|
2487
2496
|
language,
|
|
2488
2497
|
categoryProductSearchInput,
|
|
2489
2498
|
priceCalculateProductInput,
|
|
2490
2499
|
imageSearchFilters: configuration?.imageSearchFiltersGrid,
|
|
2491
|
-
imageVariantFilters: configuration?.imageVariantFiltersMedium
|
|
2500
|
+
imageVariantFilters: configuration?.imageVariantFiltersMedium,
|
|
2501
|
+
...attributeInput && { attributeResultSearchInput: attributeInput }
|
|
2492
2502
|
};
|
|
2493
2503
|
const response = await service.getCategory(variables);
|
|
2494
2504
|
const productsResponse = response?.products;
|
|
@@ -2507,7 +2517,7 @@ function useProductSearch(options) {
|
|
|
2507
2517
|
}, 300);
|
|
2508
2518
|
},
|
|
2509
2519
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2510
|
-
[graphqlClient, language, configuration, userKey, JSON.stringify(options.orderlistIds ?? []), options.applyOrderlists]
|
|
2520
|
+
[graphqlClient, language, configuration, userKey, JSON.stringify(options.orderlistIds ?? []), options.applyOrderlists, JSON.stringify(options.productTrackAttributes ?? [])]
|
|
2511
2521
|
);
|
|
2512
2522
|
React6.useEffect(() => {
|
|
2513
2523
|
if (!isControlled) fetchProducts();
|
|
@@ -4607,7 +4617,7 @@ function AddToCart(rawProps) {
|
|
|
4607
4617
|
"button",
|
|
4608
4618
|
{
|
|
4609
4619
|
type: "button",
|
|
4610
|
-
className: "propeller-add-to-cart__submit flex-1 basis-full md:basis-auto inline-flex justify-center items-center gap-2 h-10 px-6 border border-transparent text-sm font-medium rounded-control text-secondary-foreground bg-secondary hover:bg-secondary/
|
|
4620
|
+
className: "propeller-add-to-cart__submit flex-1 min-w-0 basis-full md:basis-auto inline-flex justify-center items-center gap-2 h-10 px-3 sm:px-6 border border-transparent text-sm font-medium rounded-control text-secondary-foreground bg-secondary hover:bg-secondary/80 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-secondary disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
4611
4621
|
onClick: () => handleAddToCart(),
|
|
4612
4622
|
disabled: loading,
|
|
4613
4623
|
children: [
|
|
@@ -4629,8 +4639,7 @@ function AddToCart(rawProps) {
|
|
|
4629
4639
|
]
|
|
4630
4640
|
}
|
|
4631
4641
|
),
|
|
4632
|
-
|
|
4633
|
-
!loading ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: propellerV2CoreUi.getLabel(props.labels, "add", "Add") }) : null
|
|
4642
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-add-to-cart__submit-label min-w-0 truncate", children: loading ? propellerV2CoreUi.getLabel(props.labels, "adding", "Adding...") : propellerV2CoreUi.getLabel(props.labels, "add", "Add") })
|
|
4634
4643
|
]
|
|
4635
4644
|
}
|
|
4636
4645
|
)
|
|
@@ -8383,8 +8392,8 @@ function ClusterCardViewClusterLink(props) {
|
|
|
8383
8392
|
{
|
|
8384
8393
|
href: derived.clusterUrl,
|
|
8385
8394
|
onClick: handleClusterClick,
|
|
8386
|
-
className: props.className ?? "propeller-cluster-card__cta-link flex w-full items-center justify-center rounded-control bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/80 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2",
|
|
8387
|
-
children: props.label ?? derived.viewClusterLabel
|
|
8395
|
+
className: props.className ?? "propeller-cluster-card__cta-link flex w-full min-w-0 items-center justify-center rounded-control bg-primary px-3 sm:px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/80 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2",
|
|
8396
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cluster-card__cta-label min-w-0 truncate", children: props.label ?? derived.viewClusterLabel })
|
|
8388
8397
|
}
|
|
8389
8398
|
);
|
|
8390
8399
|
}
|
|
@@ -9035,6 +9044,7 @@ function ProductGrid(rawProps) {
|
|
|
9035
9044
|
brand: props.brand,
|
|
9036
9045
|
orderlistIds: props.orderlistIds,
|
|
9037
9046
|
applyOrderlists: props.applyOrderlists,
|
|
9047
|
+
productTrackAttributes: props.productTrackAttributes,
|
|
9038
9048
|
language: props.language,
|
|
9039
9049
|
taxZone: props.taxZone,
|
|
9040
9050
|
user: props.user,
|
|
@@ -18397,7 +18407,8 @@ function SearchBar(rawProps) {
|
|
|
18397
18407
|
user: props.user,
|
|
18398
18408
|
companyId: props.companyId,
|
|
18399
18409
|
orderlistIds: props.orderlistIds,
|
|
18400
|
-
applyOrderlists: props.applyOrderlists
|
|
18410
|
+
applyOrderlists: props.applyOrderlists,
|
|
18411
|
+
productTrackAttributes: props.productTrackAttributes
|
|
18401
18412
|
});
|
|
18402
18413
|
const results = searchResults.slice(0, maxResults).map((item) => mapToSearchBarResult(item, props.language));
|
|
18403
18414
|
const itemsFound = searchItemsFound;
|