@propeller-commerce/propeller-v2-react-ui 0.20.0 → 0.21.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 +78 -0
- package/dist/index.cjs +22 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +547 -525
- package/dist/index.d.ts +547 -525
- package/dist/index.js +22 -16
- package/dist/index.js.map +1 -1
- package/dist/shared.d.cts +24 -0
- package/dist/shared.d.ts +24 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,84 @@ 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.21.0] - 2026-09-23
|
|
12
|
+
|
|
13
|
+
`MachineGrid` stops losing rows, and becomes usable in a translated or
|
|
14
|
+
customised storefront. One project had given up on it and rebuilt the surface
|
|
15
|
+
by hand (~450 lines), losing the breadcrumb, module grid and filter wiring.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **A machine with no slug in the tree language is no longer dropped from the
|
|
20
|
+
list.** `childSlugHref` returned `null` and the card was filtered out, so a
|
|
21
|
+
customer saw three of four machines with nothing saying so — and the same
|
|
22
|
+
helper guards the child-module grid, so a module could vanish from a machine
|
|
23
|
+
the same way. Two changes: `ROOT_MACHINE_FIELDS` no longer passes
|
|
24
|
+
`(language: $language)` to `name` / `description` / `slug`, so the
|
|
25
|
+
cross-language fallback in `getLocalizedValue` has entries to fall back to;
|
|
26
|
+
and a machine with no slug in *any* language now renders as an unlinked card
|
|
27
|
+
rather than vanishing. Needs SDK ≥ 0.17.0 for the child-machine half, which
|
|
28
|
+
comes through `getMachine`. (PWP-993)
|
|
29
|
+
|
|
30
|
+
The asymmetry that made this hard to spot: the **name** falls back across
|
|
31
|
+
languages, the **slug** did not — so a half-translated tree rendered names in
|
|
32
|
+
the wrong language rather than failing, but lost whole rows when the slug was
|
|
33
|
+
the missing half.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **`MachineGrid` forwards label overrides to the parts list.** It rendered its
|
|
38
|
+
parts through `ProductGrid` but forwarded none of `productCardLabels`,
|
|
39
|
+
`addToCartLabels`, `stockLabels`, `priceLabels` or `labels`, and there was no
|
|
40
|
+
way to reach them from outside — so "In stock", "Add" and "Search parts…"
|
|
41
|
+
appeared in English in the middle of translated copy. A monolingual shop
|
|
42
|
+
never noticed. (PWP-995a)
|
|
43
|
+
- **`MachineGrid.productCardComponent`** — the `ProductGrid` prop of the same
|
|
44
|
+
name, forwarded. Without it a quote-only product rendered with the host's
|
|
45
|
+
custom card on a normal listing and with the stock card inside a machine, so
|
|
46
|
+
the same product looked different depending on the page it was reached from.
|
|
47
|
+
(PWP-995c)
|
|
48
|
+
- **`useSpareParts({ page })`** — a controlled page, mirroring the existing
|
|
49
|
+
controlled `parts`. Every other listing input (`term`, `textFilters`,
|
|
50
|
+
`sortField`, `pageSize`) was already an option, so the absence of `page` read
|
|
51
|
+
as "paging is internal" — and it was not: driving the hook from URL state and
|
|
52
|
+
rendering `<GridPagination>` changed the URL and re-rendered the same first
|
|
53
|
+
twelve parts. The only way in was a `useEffect(() => goToPage(page))` that
|
|
54
|
+
`MachineGrid` did internally and nothing documented. `goToPage` still works
|
|
55
|
+
for uncontrolled hosts; omit `page` for the previous behaviour. (PWP-995b)
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- `MachineCard.href` is now optional — a machine with no URL renders as a
|
|
60
|
+
`<div>` instead of an `<a>`.
|
|
61
|
+
- **`MachineGrid` drives `useSpareParts` with `page` directly** instead of the
|
|
62
|
+
internal `goToPage` effect.
|
|
63
|
+
|
|
64
|
+
### Documentation
|
|
65
|
+
|
|
66
|
+
- **`MachineCardProps.labels` documented one key while `MachineGrid` read
|
|
67
|
+
three.** The doc named only `viewMachine`; `MachineGrid` also reads `loading`
|
|
68
|
+
and `noMachines` off the same object, so anyone following the doc left those
|
|
69
|
+
two in English. Both sides now say so. (PWP-995d)
|
|
70
|
+
|
|
71
|
+
## [0.20.1] - 2026-09-23
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- The `/shared` entry shipped without type declarations. `tsup.config.ts`
|
|
76
|
+
builds three entries as concurrent processes and the `index` one carried
|
|
77
|
+
`clean: true`, so its clean raced the siblings DTS writes. `shared` emits the
|
|
78
|
+
smallest declaration and finishes first, which made its `.d.ts`/`.d.cts` the
|
|
79
|
+
reliable casualty — about one build in five locally, and the one that
|
|
80
|
+
produced the published 0.20.0 tarball. Consumers importing
|
|
81
|
+
`propeller-v2-react-ui/shared` then failed to type check with TS7016
|
|
82
|
+
("Could not find a declaration file"); propeller-next hits it in five files.
|
|
83
|
+
Cleaning now happens once in the `clean` script, before tsup starts, and no
|
|
84
|
+
tsup config cleans. `clean` is also no longer PowerShell-only, so it works on
|
|
85
|
+
the Linux CI runner.
|
|
86
|
+
|
|
87
|
+
No component or API change — 0.20.0 and 0.20.1 differ only in the tarball.
|
|
88
|
+
|
|
11
89
|
## [0.20.0] - 2026-09-21
|
|
12
90
|
|
|
13
91
|
### Fixed
|
package/dist/index.cjs
CHANGED
|
@@ -2776,7 +2776,8 @@ function useSpareParts(options) {
|
|
|
2776
2776
|
const [childMachines, setChildMachines] = React6.useState([]);
|
|
2777
2777
|
const [itemsFound, setItemsFound] = React6.useState(0);
|
|
2778
2778
|
const [internalLoading, setInternalLoading] = React6.useState(false);
|
|
2779
|
-
const [
|
|
2779
|
+
const [internalPage, setInternalPage] = React6.useState(1);
|
|
2780
|
+
const currentPage = options.page ?? internalPage;
|
|
2780
2781
|
const [totalPages, setTotalPages] = React6.useState(1);
|
|
2781
2782
|
const fetchIdRef = React6.useRef(0);
|
|
2782
2783
|
const displayParts = React6.useMemo(
|
|
@@ -2925,7 +2926,7 @@ function useSpareParts(options) {
|
|
|
2925
2926
|
userKey
|
|
2926
2927
|
]);
|
|
2927
2928
|
const goToPage = React6.useCallback((page) => {
|
|
2928
|
-
|
|
2929
|
+
setInternalPage((prev) => {
|
|
2929
2930
|
if (page >= 1 && (totalPages <= 1 || page <= totalPages)) return page;
|
|
2930
2931
|
return prev;
|
|
2931
2932
|
});
|
|
@@ -2944,9 +2945,9 @@ function useSpareParts(options) {
|
|
|
2944
2945
|
var inflightFetches4 = /* @__PURE__ */ new Set();
|
|
2945
2946
|
var ROOT_MACHINE_FIELDS = `
|
|
2946
2947
|
id
|
|
2947
|
-
name
|
|
2948
|
-
description
|
|
2949
|
-
slug
|
|
2948
|
+
name { language value }
|
|
2949
|
+
description { language value }
|
|
2950
|
+
slug { language value }
|
|
2950
2951
|
media {
|
|
2951
2952
|
images {
|
|
2952
2953
|
items { imageVariants(input: $imageVariantFilters) { url } }
|
|
@@ -8549,6 +8550,7 @@ function getMachineImageUrl(machine) {
|
|
|
8549
8550
|
}
|
|
8550
8551
|
function MachineCard(props) {
|
|
8551
8552
|
const { machine, href, language } = props;
|
|
8553
|
+
const Wrapper = href ? "a" : "div";
|
|
8552
8554
|
const showImage = props.showImage ?? true;
|
|
8553
8555
|
const showDescription = props.showDescription ?? false;
|
|
8554
8556
|
const name = propellerV2CoreUi.getLocalizedValue(machine.name, language);
|
|
@@ -8560,10 +8562,9 @@ function MachineCard(props) {
|
|
|
8560
8562
|
{
|
|
8561
8563
|
className: cn(`propeller-machine-card group relative flex h-full flex-col overflow-hidden rounded-lg border border-border bg-background ${props.className ?? ""}`),
|
|
8562
8564
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8563
|
-
|
|
8565
|
+
Wrapper,
|
|
8564
8566
|
{
|
|
8565
|
-
href,
|
|
8566
|
-
onClick: handleClick,
|
|
8567
|
+
...href ? { href, onClick: handleClick } : {},
|
|
8567
8568
|
className: "flex h-full flex-col focus:outline-none focus-visible:ring-2 focus-visible:ring-primary",
|
|
8568
8569
|
children: [
|
|
8569
8570
|
showImage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-machine-card__image aspect-square w-full overflow-hidden bg-background-subtle", children: imageUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -10468,7 +10469,7 @@ function MachineGrid(rawProps) {
|
|
|
10468
10469
|
// node query threads through useSpareParts.
|
|
10469
10470
|
imageVariantFilters: configuration?.imageVariantFiltersMedium
|
|
10470
10471
|
});
|
|
10471
|
-
const { displayParts, childMachines, isLoading: partsLoading, currentPage, totalPages
|
|
10472
|
+
const { displayParts, childMachines, isLoading: partsLoading, currentPage, totalPages } = useSpareParts({
|
|
10472
10473
|
graphqlClient: props.graphqlClient,
|
|
10473
10474
|
// Idle at the root (no slug).
|
|
10474
10475
|
slug: isRoot ? void 0 : currentSlug,
|
|
@@ -10484,6 +10485,10 @@ function MachineGrid(rawProps) {
|
|
|
10484
10485
|
sortField,
|
|
10485
10486
|
sortOrder,
|
|
10486
10487
|
pageSize: offset,
|
|
10488
|
+
// The hook takes the controlled page directly now. It used to own its own
|
|
10489
|
+
// counter, so the only way to drive it from URL state was the effect
|
|
10490
|
+
// below — undiscoverable unless you read this file (PWP-995b).
|
|
10491
|
+
page: listing.page,
|
|
10487
10492
|
configuration: rawProps.configuration ?? props.configuration,
|
|
10488
10493
|
onFiltersChange: setGridFilters,
|
|
10489
10494
|
onPriceBoundsChange: (min, max) => {
|
|
@@ -10493,9 +10498,6 @@ function MachineGrid(rawProps) {
|
|
|
10493
10498
|
onItemsFoundChange: setItemsFound,
|
|
10494
10499
|
onMachineChange: setMachine
|
|
10495
10500
|
});
|
|
10496
|
-
React6.useEffect(() => {
|
|
10497
|
-
goToPage(listing.page);
|
|
10498
|
-
}, [listing.page, goToPage]);
|
|
10499
10501
|
const machineName = machine ? propellerV2CoreUi.getLocalizedValue(machine.name, machineLanguage) : slugToLabel(currentSlug);
|
|
10500
10502
|
const partProducts = React6.useMemo(
|
|
10501
10503
|
() => displayParts.map((p) => p.product).filter(Boolean),
|
|
@@ -10552,11 +10554,10 @@ function MachineGrid(rawProps) {
|
|
|
10552
10554
|
);
|
|
10553
10555
|
const childSlugHref = (child) => {
|
|
10554
10556
|
const slug = propellerV2CoreUi.getLocalizedValue(child.slug, machineLanguage);
|
|
10555
|
-
|
|
10556
|
-
return `${currentPath}/${slug}`;
|
|
10557
|
+
return slug ? `${currentPath}/${slug}` : void 0;
|
|
10557
10558
|
};
|
|
10558
10559
|
if (isRoot) {
|
|
10559
|
-
const cards = rootMachines.map((m) => ({ machine: m, href: childSlugHref(m) }))
|
|
10560
|
+
const cards = rootMachines.map((m) => ({ machine: m, href: childSlugHref(m) }));
|
|
10560
10561
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rawProps.className, children: [
|
|
10561
10562
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "propeller-grid-title mb-6 text-2xl font-semibold", children: rawProps.rootTitle ?? "Machines" }),
|
|
10562
10563
|
rootLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-12 text-center text-foreground-subtle", children: propellerV2CoreUi.getLabel(rawProps.machineCardLabels, "loading", "Loading\u2026") }) : cards.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-12 text-center text-foreground-subtle", children: propellerV2CoreUi.getLabel(rawProps.machineCardLabels, "noMachines", "No machines found.") }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4", children: cards.map(({ machine: m, href }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -10588,7 +10589,6 @@ function MachineGrid(rawProps) {
|
|
|
10588
10589
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "propeller-grid-title mb-6 text-2xl font-semibold", children: machineName }),
|
|
10589
10590
|
childMachines.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-machine-children mb-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4", children: childMachines.map((child) => {
|
|
10590
10591
|
const href = childSlugHref(child);
|
|
10591
|
-
if (!href) return null;
|
|
10592
10592
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10593
10593
|
MachineCard,
|
|
10594
10594
|
{
|
|
@@ -10666,6 +10666,12 @@ function MachineGrid(rawProps) {
|
|
|
10666
10666
|
columns: viewMode === "list" ? 1 : 3,
|
|
10667
10667
|
showAvailability: rawProps.showAvailability ?? false,
|
|
10668
10668
|
showStock: rawProps.showStock ?? true,
|
|
10669
|
+
productCardComponent: rawProps.productCardComponent,
|
|
10670
|
+
productCardLabels: rawProps.productCardLabels,
|
|
10671
|
+
addToCartLabels: rawProps.addToCartLabels,
|
|
10672
|
+
stockLabels: rawProps.stockLabels,
|
|
10673
|
+
priceLabels: rawProps.priceLabels,
|
|
10674
|
+
labels: rawProps.labels,
|
|
10669
10675
|
belowName: (product) => {
|
|
10670
10676
|
const qty = quantityBySku.get(product.sku);
|
|
10671
10677
|
if (!qty) return null;
|