@snowcone-app/ui 0.8.3 → 0.9.1

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
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4074](https://github.com/snowcone-app/snowcone-monorepo/pull/4074) [`8682d87`](https://github.com/snowcone-app/snowcone-monorepo/commit/8682d876466cee5ee80ff05b1401a5679a410007) Thanks [@kevinsproles](https://github.com/kevinsproles)! - A selected size with no scene previews a listed variant that differs only by size. The cart, SKU and price keep the selected size.
8
+
9
+ - Updated dependencies [[`8682d87`](https://github.com/snowcone-app/snowcone-monorepo/commit/8682d876466cee5ee80ff05b1401a5679a410007)]:
10
+ - @snowcone-app/sdk@0.24.3
11
+
12
+ ## 0.9.0
13
+
14
+ ### Minor Changes
15
+
16
+ - [#2936](https://github.com/snowcone-app/snowcone-monorepo/pull/2936) [`3c37e27`](https://github.com/snowcone-app/snowcone-monorepo/commit/3c37e27da40c8865b4c4bd71ec9454ec7e64bc4c) Thanks [@kevinsproles](https://github.com/kevinsproles)! - `AddToCart` waits for your add and never reports a failure as success. An async `onClick` is awaited: the button shows
17
+ "Added!" only after it resolves, and a rejection (or throw) shows `errorText` (new prop, default
18
+ "Couldn't add — try again"), announces the error's message in a `role="alert"`, calls `onError`, and leaves the button
19
+ enabled to retry. Previously `onClick` was called without awaiting after a fixed simulated delay, so a failed add still
20
+ said "Added!". The button exposes `data-add-to-cart="idle | adding | added | error"` (type `AddToCartStatus`) for tests.
21
+ `simulateDelay` now applies only when there is no `onClick` (demos).
22
+
3
23
  ## 0.8.3
4
24
 
5
25
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -4921,6 +4921,7 @@ function AddToCart({
4921
4921
  text = "Add to Bag",
4922
4922
  loadingText = "Adding...",
4923
4923
  successText = "Added!",
4924
+ errorText = "Couldn't add \u2014 try again",
4924
4925
  disabled = false,
4925
4926
  className = "",
4926
4927
  quantity = 1,
@@ -4930,8 +4931,10 @@ function AddToCart({
4930
4931
  }) {
4931
4932
  const context = useProduct();
4932
4933
  const shopContext = useShopOptional();
4933
- const [loading, setLoading] = (0, import_react15.useState)(false);
4934
- const [success, setSuccess] = (0, import_react15.useState)(false);
4934
+ const [status, setStatus] = (0, import_react15.useState)("idle");
4935
+ const [errorMessage, setErrorMessage] = (0, import_react15.useState)(null);
4936
+ const loading = status === "adding";
4937
+ const success = status === "added";
4935
4938
  (0, import_react15.useEffect)(() => {
4936
4939
  checkProviders(
4937
4940
  "AddToCart",
@@ -4954,7 +4957,8 @@ function AddToCart({
4954
4957
  const handleClick = async () => {
4955
4958
  if (isDisabled || !product) return;
4956
4959
  try {
4957
- setLoading(true);
4960
+ setStatus("adding");
4961
+ setErrorMessage(null);
4958
4962
  const cartDetail = (0, import_sdk7.createCartDetail)({
4959
4963
  productId: product.id,
4960
4964
  quantity,
@@ -4965,20 +4969,23 @@ function AddToCart({
4965
4969
  if (!cartDetail) {
4966
4970
  throw new Error("Invalid selection - unable to create cart detail");
4967
4971
  }
4968
- await (0, import_sdk7.simulateCartOperation)(simulateDelay);
4969
- onClick?.(cartDetail);
4970
- setSuccess(true);
4972
+ if (onClick) {
4973
+ await onClick(cartDetail);
4974
+ } else {
4975
+ await (0, import_sdk7.simulateCartOperation)(simulateDelay);
4976
+ }
4977
+ setStatus("added");
4971
4978
  setTimeout(() => {
4972
- setSuccess(false);
4979
+ setStatus((s) => s === "added" ? "idle" : s);
4973
4980
  }, 2e3);
4974
4981
  } catch (error) {
4975
- onError?.(error);
4976
- console.error("Add to cart failed:", error);
4977
- } finally {
4978
- setLoading(false);
4982
+ const err = error instanceof Error ? error : new Error(String(error));
4983
+ setStatus("error");
4984
+ setErrorMessage(err.message);
4985
+ onError?.(err);
4979
4986
  }
4980
4987
  };
4981
- const buttonText = loading ? loadingText : success ? successText : text;
4988
+ const buttonText = loading ? loadingText : success ? successText : status === "error" ? errorText : text;
4982
4989
  const defaultStyles = "w-full bg-primary text-primary-foreground hover:bg-primary/90 px-6 py-3 rounded-button font-medium transition-colors";
4983
4990
  const buttonClasses = `
4984
4991
  ${defaultStyles}
@@ -4989,6 +4996,7 @@ function AddToCart({
4989
4996
  const getAriaLabel = () => {
4990
4997
  if (loading) return loadingText;
4991
4998
  if (success) return successText;
4999
+ if (status === "error") return `${errorText} - ${product?.name || "product"}`;
4992
5000
  if (!product) return text;
4993
5001
  return `${text} - ${product.name || "product"}`;
4994
5002
  };
@@ -5002,9 +5010,11 @@ function AddToCart({
5002
5010
  onClick: handleClick,
5003
5011
  "aria-label": getAriaLabel(),
5004
5012
  "aria-busy": loading,
5013
+ "data-add-to-cart": status,
5005
5014
  children: buttonText
5006
5015
  }
5007
- )
5016
+ ),
5017
+ status === "error" && errorMessage && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { role: "alert", className: "mt-2 text-sm text-destructive", children: errorMessage })
5008
5018
  ] });
5009
5019
  }
5010
5020
 
@@ -6499,10 +6509,9 @@ function RealtimeProvider({
6499
6509
  const product = productContext.product;
6500
6510
  const productId = product.id;
6501
6511
  const placements = product.placements || [];
6502
- const variantId = (0, import_sdk8.resolveVariantId)(
6512
+ const variantId = (0, import_sdk8.resolvePreviewVariantId)(
6503
6513
  productContext,
6504
- void 0,
6505
- void 0
6514
+ (0, import_sdk8.resolveVariantId)(productContext, void 0, void 0)
6506
6515
  );
6507
6516
  const isFirstSend = !configSentRef.current;
6508
6517
  const variantChanged = lastSentVariantIdRef.current !== null && lastSentVariantIdRef.current !== variantId;
@@ -10483,12 +10492,15 @@ var HeroProductImage = (0, import_react46.memo)(function HeroProductImage2({
10483
10492
  const contextRef = (0, import_react46.useRef)(context);
10484
10493
  contextRef.current = context;
10485
10494
  const actualProductId = product?.id || productId || context?.product?.id;
10486
- const actualGvid = (0, import_react46.useMemo)(() => {
10495
+ const selectedGvid = (0, import_react46.useMemo)(() => {
10487
10496
  return (0, import_sdk10.resolveVariantId)(context, gvid, variantId);
10488
10497
  }, [gvid, variantId, context?.selection, context?.combinations]);
10489
10498
  const actualMockupId = (0, import_react46.useMemo)(() => {
10490
- return (0, import_sdk10.resolveMockupId)(context, actualGvid, mockupId);
10491
- }, [mockupId, actualGvid, context]);
10499
+ return (0, import_sdk10.resolveMockupId)(context, selectedGvid, mockupId);
10500
+ }, [mockupId, selectedGvid, context]);
10501
+ const actualGvid = (0, import_react46.useMemo)(() => {
10502
+ return gvid || variantId ? selectedGvid : (0, import_sdk10.resolvePreviewVariantId)(context, selectedGvid, actualMockupId);
10503
+ }, [gvid, variantId, selectedGvid, actualMockupId, context]);
10492
10504
  const unavailable = actualMockupId ? realtimeContext?.unavailableMockups?.get(actualMockupId) ?? null : null;
10493
10505
  const artworkSrc = artwork?.src;
10494
10506
  const selectedArtworkSrc = designContext?.selectedArtwork?.src;