@propeller-commerce/propeller-v2-react-ui 0.4.25 → 0.4.26

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 CHANGED
@@ -8,6 +8,40 @@ 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.4.26] - 2026-07-21
12
+
13
+ ### Added
14
+
15
+ - **`SearchBar`: real anchor links for navigation.** New optional
16
+ `getResultHref(result)` and `getViewAllHref(term)` props. When provided, the
17
+ autosuggest result rows and the "View all results" CTA render as real
18
+ `<a href>` elements — middle-clickable, open-in-new-tab, hover-preview,
19
+ crawlable — while the existing `onResultClick`/`onViewAllClick` callbacks
20
+ still fire for SPA navigation (modified clicks fall through to the browser).
21
+ Omit the props to keep the previous behaviour.
22
+ - **`OrderList`: URL-persistable filters.** New optional `initialSearchForm`
23
+ (seed the filter form on mount, e.g. rehydrated from the URL) and
24
+ `onSearchApply(form)` (fires when the user applies/clears filters) props, so
25
+ the consuming page can keep the filter state in the URL — bookmarkable,
26
+ shareable, back-button-friendly. `useOrders` gained the matching
27
+ `initialSearchForm` option.
28
+
29
+ ### Changed
30
+
31
+ - **`AccountIconAndMenu`: account-menu items are now `<a href>` instead of
32
+ `<button>`** (both the sidebar and dropdown variants). They use each link's
33
+ existing `href`, so they are middle-clickable / new-tab-able / crawlable;
34
+ `onMenuItemClick` still handles plain-click SPA navigation.
35
+ - **`SearchBar`: the "View all results" fallback is now a `<button>`** (was a
36
+ non-focusable `<div>`), so it is keyboard-accessible even without the new
37
+ `getViewAllHref` prop.
38
+
39
+ ### Fixed
40
+
41
+ - **`OrderList`: clickable rows now show `cursor: pointer`.** When
42
+ `rowsClickable` is set, the row cursor matches its behaviour (was `auto`,
43
+ inconsistent with the favourites cards).
44
+
11
45
  ## [0.4.25] - 2026-07-20
12
46
 
13
47
  ### Fixed
package/dist/index.cjs CHANGED
@@ -1718,7 +1718,9 @@ function useOrders(options) {
1718
1718
  const [orders, setOrders] = React6.useState([]);
1719
1719
  const [loading, setLoading] = React6.useState(false);
1720
1720
  const [error, setError] = React6.useState(null);
1721
- const [searchForm, setSearchForm] = React6.useState({});
1721
+ const [searchForm, setSearchForm] = React6.useState(
1722
+ options.initialSearchForm ?? {}
1723
+ );
1722
1724
  const pagination = usePagination(options.itemsPerPage ?? 10);
1723
1725
  const fetchOrders = React6.useCallback(
1724
1726
  async (page = 1) => {
@@ -3575,6 +3577,13 @@ function AccountIconAndMenu(rawProps) {
3575
3577
  setMenuOpen(false);
3576
3578
  if (props.onMenuItemClick) props.onMenuItemClick(href);
3577
3579
  }
3580
+ function handleMenuLinkClick(event, href) {
3581
+ if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
3582
+ return;
3583
+ }
3584
+ event.preventDefault();
3585
+ handleMenuItemClick(href);
3586
+ }
3578
3587
  function handleLogoutClick() {
3579
3588
  setMenuOpen(false);
3580
3589
  if (props.onLogoutClick) props.onLogoutClick();
@@ -3623,10 +3632,10 @@ function AccountIconAndMenu(rawProps) {
3623
3632
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-account-menu__user-name font-medium text-foreground truncate", children: getUserName() })
3624
3633
  ] }),
3625
3634
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "propeller-account-menu__nav py-2", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "propeller-account-menu__list space-y-0.5", children: getMenuLinks()?.map((link) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "propeller-account-menu__item", children: /* @__PURE__ */ jsxRuntime.jsx(
3626
- "button",
3635
+ "a",
3627
3636
  {
3628
- type: "button",
3629
- onClick: (event) => handleMenuItemClick(link.href),
3637
+ href: link.href,
3638
+ onClick: (event) => handleMenuLinkClick(event, link.href),
3630
3639
  "data-active": isActiveLink(link.href) ? "true" : "false",
3631
3640
  className: `propeller-account-menu__link flex w-full items-center gap-3 px-4 py-2.5 text-sm font-medium transition-colors ${isActiveLink(link.href) ? "bg-secondary/5 text-secondary border-l-2 border-secondary" : "text-muted-foreground hover:bg-surface-hover hover:text-foreground"}`,
3632
3641
  children: link.label
@@ -3689,11 +3698,11 @@ function AccountIconAndMenu(rawProps) {
3689
3698
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-account-menu__user-name font-medium text-foreground truncate", children: getUserName() })
3690
3699
  ] }),
3691
3700
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "propeller-account-menu__nav", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "propeller-account-menu__list space-y-0.5", children: getMenuLinks()?.map((link) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "propeller-account-menu__item", children: /* @__PURE__ */ jsxRuntime.jsx(
3692
- "button",
3701
+ "a",
3693
3702
  {
3694
- type: "button",
3703
+ href: link.href,
3695
3704
  className: "propeller-account-menu__link flex w-full items-center gap-3 px-3 py-2 text-sm font-medium rounded-control text-muted-foreground hover:bg-surface-hover hover:text-foreground transition-colors",
3696
- onClick: (event) => handleMenuItemClick(link.href),
3705
+ onClick: (event) => handleMenuLinkClick(event, link.href),
3697
3706
  children: link.label
3698
3707
  }
3699
3708
  ) }, link.href)) }) }),
@@ -11850,7 +11859,8 @@ function OrderList(rawProps) {
11850
11859
  orderStatuses: props.orderStatus,
11851
11860
  termFields: props.termFields,
11852
11861
  itemsPerPage: props.initialItemsPerPage || 10,
11853
- channelIds: props.channelIds
11862
+ channelIds: props.channelIds,
11863
+ initialSearchForm: props.initialSearchForm
11854
11864
  });
11855
11865
  function handlePageChange(newPage) {
11856
11866
  if (newPage >= 1 && newPage <= totalPages) {
@@ -12163,6 +12173,7 @@ function OrderList(rawProps) {
12163
12173
  onClick: (event) => {
12164
12174
  setSearchForm({});
12165
12175
  fetchOrders(1);
12176
+ props.onSearchApply?.({});
12166
12177
  },
12167
12178
  children: propellerV2CoreUi.getLabel(props.labels, "clearButton", "Clear")
12168
12179
  }
@@ -12171,7 +12182,10 @@ function OrderList(rawProps) {
12171
12182
  "button",
12172
12183
  {
12173
12184
  className: "propeller-order-list__search-btn inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-control shadow-sm text-primary-foreground bg-primary hover:bg-primary/80 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary",
12174
- onClick: (event) => fetchOrders(1),
12185
+ onClick: (event) => {
12186
+ fetchOrders(1);
12187
+ props.onSearchApply?.(searchForm);
12188
+ },
12175
12189
  children: propellerV2CoreUi.getLabel(props.labels, "searchButton", "Search")
12176
12190
  }
12177
12191
  )
@@ -12191,7 +12205,7 @@ function OrderList(rawProps) {
12191
12205
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "propeller-order-list__tbody bg-card divide-y divide-border", children: orders?.map((order) => /* @__PURE__ */ jsxRuntime.jsx(
12192
12206
  "tr",
12193
12207
  {
12194
- className: "propeller-order-list__row hover:bg-surface-hover",
12208
+ className: `propeller-order-list__row hover:bg-surface-hover ${rowsClickable ? "cursor-pointer" : ""}`,
12195
12209
  "data-clickable": rowsClickable ? "true" : "false",
12196
12210
  onClick: (event) => rowsClickable && props.onOrderClick(order.id),
12197
12211
  children: columns?.map((col) => /* @__PURE__ */ jsxRuntime.jsxs(
@@ -17281,6 +17295,9 @@ function SearchBar(rawProps) {
17281
17295
  }
17282
17296
  setShowDropdown(false);
17283
17297
  }
17298
+ function isModifiedClick(event) {
17299
+ return event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
17300
+ }
17284
17301
  React6.useEffect(() => {
17285
17302
  const listener = (e) => {
17286
17303
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -17334,39 +17351,68 @@ function SearchBar(rawProps) {
17334
17351
  ] }) }),
17335
17352
  showDropdown ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-search-bar__dropdown absolute top-full left-0 right-0 mt-2 bg-card rounded-container shadow-xl border border-border z-50 flex flex-col max-h-96", children: [
17336
17353
  results.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17337
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-search-bar__results flex-1 overflow-y-auto", children: results?.map((result, index) => /* @__PURE__ */ jsxRuntime.jsxs(
17338
- "div",
17354
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-search-bar__results flex-1 overflow-y-auto", children: results?.map((result, index) => {
17355
+ const ResultTag = props.getResultHref ? "a" : "div";
17356
+ const resultProps = props.getResultHref ? {
17357
+ href: props.getResultHref(result),
17358
+ onClick: (event) => {
17359
+ if (isModifiedClick(event)) return;
17360
+ event.preventDefault();
17361
+ handleResultClick(result);
17362
+ }
17363
+ } : { onClick: (_event) => handleResultClick(result) };
17364
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17365
+ ResultTag,
17366
+ {
17367
+ className: "propeller-search-bar__result flex items-center gap-4 p-3 hover:bg-surface-hover cursor-pointer border-b border-border-subtle last:border-b-0",
17368
+ ...resultProps,
17369
+ children: [
17370
+ result.imageUrl || noImageUrl() ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-search-bar__result-media relative w-16 h-16 flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
17371
+ "img",
17372
+ {
17373
+ className: "propeller-search-bar__result-image w-full h-full object-contain",
17374
+ src: result.imageUrl || noImageUrl(),
17375
+ alt: result.name
17376
+ }
17377
+ ) }) : null,
17378
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
17379
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-search-bar__result-name font-semibold truncate", children: result.name }),
17380
+ result.sku ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-search-bar__result-sku text-sm text-muted-foreground", children: [
17381
+ "SKU: ",
17382
+ result.sku
17383
+ ] }) : null
17384
+ ] }),
17385
+ result.price !== void 0 && result.price !== null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-search-bar__result-price text-sm font-semibold text-foreground flex-shrink-0 text-right", children: [
17386
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-search-bar__result-price-value", children: formatItemPrice(leadingPrice(result)) }),
17387
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-search-bar__result-price-label block text-xs font-normal text-muted-foreground", children: priceTaxLabel() })
17388
+ ] }) : null
17389
+ ]
17390
+ },
17391
+ result.id + "-" + index
17392
+ );
17393
+ }) }),
17394
+ itemsFound > results.length ? props.getViewAllHref ? /* @__PURE__ */ jsxRuntime.jsxs(
17395
+ "a",
17339
17396
  {
17340
- className: "propeller-search-bar__result flex items-center gap-4 p-3 hover:bg-surface-hover cursor-pointer border-b border-border-subtle last:border-b-0",
17341
- onClick: (event) => handleResultClick(result),
17397
+ href: props.getViewAllHref(localTerm),
17398
+ className: "propeller-search-bar__view-all block flex-shrink-0 p-3 text-center text-primary hover:bg-primary/5 cursor-pointer font-semibold border-t border-border bg-card rounded-b-container",
17399
+ onClick: (event) => {
17400
+ if (isModifiedClick(event)) return;
17401
+ event.preventDefault();
17402
+ handleViewAllClick();
17403
+ },
17342
17404
  children: [
17343
- result.imageUrl || noImageUrl() ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-search-bar__result-media relative w-16 h-16 flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
17344
- "img",
17345
- {
17346
- className: "propeller-search-bar__result-image w-full h-full object-contain",
17347
- src: result.imageUrl || noImageUrl(),
17348
- alt: result.name
17349
- }
17350
- ) }) : null,
17351
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
17352
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-search-bar__result-name font-semibold truncate", children: result.name }),
17353
- result.sku ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-search-bar__result-sku text-sm text-muted-foreground", children: [
17354
- "SKU: ",
17355
- result.sku
17356
- ] }) : null
17357
- ] }),
17358
- result.price !== void 0 && result.price !== null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-search-bar__result-price text-sm font-semibold text-foreground flex-shrink-0 text-right", children: [
17359
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-search-bar__result-price-value", children: formatItemPrice(leadingPrice(result)) }),
17360
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-search-bar__result-price-label block text-xs font-normal text-muted-foreground", children: priceTaxLabel() })
17361
- ] }) : null
17405
+ propellerV2CoreUi.getLabel(props.labels, "viewAll", "View all results"),
17406
+ " (",
17407
+ itemsFound,
17408
+ ")"
17362
17409
  ]
17363
- },
17364
- result.id + "-" + index
17365
- )) }),
17366
- itemsFound > results.length ? /* @__PURE__ */ jsxRuntime.jsxs(
17367
- "div",
17410
+ }
17411
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
17412
+ "button",
17368
17413
  {
17369
- className: "propeller-search-bar__view-all flex-shrink-0 p-3 text-center text-primary hover:bg-primary/5 cursor-pointer font-semibold border-t border-border bg-card rounded-b-container",
17414
+ type: "button",
17415
+ className: "propeller-search-bar__view-all block w-full flex-shrink-0 p-3 text-center text-primary hover:bg-primary/5 cursor-pointer font-semibold border-t border-border bg-card rounded-b-container",
17370
17416
  onClick: (event) => handleViewAllClick(),
17371
17417
  children: [
17372
17418
  propellerV2CoreUi.getLabel(props.labels, "viewAll", "View all results"),