@tapcart/mobile-components 0.18.0 → 0.19.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.
Files changed (35) hide show
  1. package/dist/components/core/text.d.ts +1 -1
  2. package/dist/components/core/text.d.ts.map +1 -1
  3. package/dist/components/core/text.js +5 -1
  4. package/dist/components/hooks/swr-retry.d.ts.map +1 -1
  5. package/dist/components/hooks/swr-retry.js +47 -1
  6. package/dist/components/hooks/swr-retry.test.js +79 -0
  7. package/dist/components/hooks/use-create-question.d.ts +33 -0
  8. package/dist/components/hooks/use-create-question.d.ts.map +1 -0
  9. package/dist/components/hooks/use-create-question.js +98 -0
  10. package/dist/components/hooks/use-questions.d.ts +35 -0
  11. package/dist/components/hooks/use-questions.d.ts.map +1 -0
  12. package/dist/components/hooks/use-questions.js +198 -0
  13. package/dist/components/hooks/use-recommendations.d.ts.map +1 -1
  14. package/dist/components/hooks/use-recommendations.js +4 -3
  15. package/dist/components/ui/__tests__/text-self-translates.test.d.ts +2 -0
  16. package/dist/components/ui/__tests__/text-self-translates.test.d.ts.map +1 -0
  17. package/dist/components/ui/__tests__/text-self-translates.test.js +19 -0
  18. package/dist/components/ui/money.d.ts +1 -1
  19. package/dist/components/ui/money.d.ts.map +1 -1
  20. package/dist/components/ui/price.d.ts.map +1 -1
  21. package/dist/components/ui/price.js +1 -1
  22. package/dist/components/ui/video-enhanced.d.ts +1 -0
  23. package/dist/components/ui/video-enhanced.d.ts.map +1 -1
  24. package/dist/components/ui/video-enhanced.js +8 -2
  25. package/dist/core/index.d.ts +1 -0
  26. package/dist/core/index.d.ts.map +1 -1
  27. package/dist/core/index.js +1 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/lib/price.d.ts +1 -1
  32. package/dist/lib/price.d.ts.map +1 -1
  33. package/dist/lib/price.js +3 -0
  34. package/dist/styles.css +44 -8
  35. package/package.json +1 -1
@@ -8,7 +8,7 @@ type Injections = Record<string, {
8
8
  };
9
9
  }>;
10
10
  declare const textVariants: (props?: ({
11
- kind?: "title" | "caption" | "body" | "header" | "headline" | "subtitle" | null | undefined;
11
+ kind?: "title" | "caption" | "body" | "header" | "label" | "headline" | "subtitle" | null | undefined;
12
12
  } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
13
13
  export type TextKind = NonNullable<VariantProps<typeof textVariants>["kind"]>;
14
14
  export interface TextProps extends React.HTMLAttributes<HTMLParagraphElement> {
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../components/core/text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAQjE,KAAK,UAAU,GAAG,MAAM,CACtB,MAAM,EACN;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAC7E,CAAA;AAgDD,QAAA,MAAM,YAAY;;mFAchB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AAE7E,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,oBAAoB,CAAC;IAC3E,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,IAAI,EACJ,SAAS,EACT,UAAU,EACV,UAAU,EACV,QAAQ,EACR,aAAa,EACb,UAAU,EACV,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,SAAS,2CAyCX;kBArDQ,IAAI;;;AAyDb,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../components/core/text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAQjE,KAAK,UAAU,GAAG,MAAM,CACtB,MAAM,EACN;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAC7E,CAAA;AAmDD,QAAA,MAAM,YAAY;;mFAehB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AAE7E,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,oBAAoB,CAAC;IAC3E,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,IAAI,EACJ,SAAS,EACT,UAAU,EACV,UAAU,EACV,QAAQ,EACR,aAAa,EACb,UAAU,EACV,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,SAAS,2CAyCX;kBArDQ,IAAI;;;AAyDb,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAA"}
@@ -44,7 +44,10 @@ function injectString(template, injections) {
44
44
  }
45
45
  return parts.length ? parts : undefined;
46
46
  }
47
- // V2 kind tokens only — no legacy h1/h2/h3/body-primary/body-secondary/label.
47
+ // V2 kind tokens only — no legacy h1/h2/h3/body-primary/body-secondary.
48
+ // `label` is a first-class V2 scale (brand-label lives in TYPOGRAPHY_DEFAULTS /
49
+ // TYPOGRAPHY_CLASS_MAP / ElementTypographyClasses with full overrides), so it
50
+ // belongs here alongside the other kinds.
48
51
  const textVariants = cva("", {
49
52
  variants: {
50
53
  kind: {
@@ -53,6 +56,7 @@ const textVariants = cva("", {
53
56
  subtitle: "brand-subtitle",
54
57
  body: "brand-body",
55
58
  caption: "brand-caption",
59
+ label: "brand-label",
56
60
  header: "brand-header",
57
61
  },
58
62
  },
@@ -1 +1 @@
1
- {"version":3,"file":"swr-retry.d.ts","sourceRoot":"","sources":["../../../components/hooks/swr-retry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAA;AAE3C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAOtC,eAAO,MAAM,YAAY,QAAS,OAAO,KAAG,OAG3C,CAAA;AAED,eAAO,MAAM,kBAAkB,QAAS,OAAO,KAAG,OAA6B,CAAA;AAiC/E,KAAK,YAAY,GAAG,WAAW,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAA;AACjE,KAAK,SAAS,GAAG,WAAW,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAA;AAE3D,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;IAC1D,YAAY,EAAE,YAAY,CAAA;IAC1B,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,QAAO,cAkCpC,CAAA"}
1
+ {"version":3,"file":"swr-retry.d.ts","sourceRoot":"","sources":["../../../components/hooks/swr-retry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAA;AAE3C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAOtC,eAAO,MAAM,YAAY,QAAS,OAAO,KAAG,OAG3C,CAAA;AAmDD,eAAO,MAAM,kBAAkB,QAAS,OAAO,KAAG,OACE,CAAA;AAiCpD,KAAK,YAAY,GAAG,WAAW,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAA;AACjE,KAAK,SAAS,GAAG,WAAW,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAA;AAE3D,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;IAC1D,YAAY,EAAE,YAAY,CAAA;IAC1B,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,QAAO,cAkCpC,CAAA"}
@@ -8,7 +8,53 @@ export const isAbortError = (err) => {
8
8
  return false;
9
9
  return err.name === "AbortError";
10
10
  };
11
- export const shouldRetryOnError = (err) => !isAbortError(err);
11
+ /**
12
+ * The 4xx statuses that mean "later", not "never" — the request may well succeed
13
+ * unchanged, so retrying is not wasted.
14
+ *
15
+ * 425 Too Early is deliberately absent: it only arises from TLS 1.3 early data,
16
+ * which we never send, so treating it as retryable would describe a state this
17
+ * client cannot reach.
18
+ */
19
+ const RETRYABLE_CLIENT_STATUSES = new Set([
20
+ // The server gave up waiting for the request, rather than refusing what it
21
+ // received. Nothing about the request is wrong, so a retry is the correct
22
+ // response — note `getRetryAfterMs` still only honors `Retry-After` on 429,
23
+ // so a 408 takes the normal backoff.
24
+ 408,
25
+ 429,
26
+ ]);
27
+ /**
28
+ * A 4xx outside RETRYABLE_CLIENT_STATUSES is deterministic: the request itself
29
+ * is what the upstream refused, so every retry earns the identical rejection.
30
+ *
31
+ * WHY THIS MATTERS: retrying spends the upstream's quota for no chance of
32
+ * success. Google Retail calls are billed and quota'd against the *merchant's*
33
+ * GCP project, and on 2026-08-14 one store's filter — referencing a catalog
34
+ * attribute that was never marked indexable — was retried 4x per page view
35
+ * until it exhausted that quota. Google then 429'd every search for that store,
36
+ * including the ones that would have succeeded. A permanent rejection has to
37
+ * cost one call, not four.
38
+ *
39
+ * This predicate is shared across consumers (the cluster feed included), which
40
+ * is why the retryable set is defined by HTTP semantics rather than by what any
41
+ * one upstream happens to emit. The google-retail proxy collapses every upstream
42
+ * 4xx to 400 or 429 (see tapcart-microservices integrations/app/googleRetail/
43
+ * errors.js), so 408 reaches this predicate only from the other consumers.
44
+ *
45
+ * Errors carrying no `status` keep the previous behaviour (retry unless
46
+ * aborted), so integrations that do not populate it are unaffected.
47
+ */
48
+ const isPermanentClientError = (err) => {
49
+ if (!err || typeof err !== "object")
50
+ return false;
51
+ const { status } = err;
52
+ return (typeof status === "number" &&
53
+ status >= 400 &&
54
+ status < 500 &&
55
+ !RETRYABLE_CLIENT_STATUSES.has(status));
56
+ };
57
+ export const shouldRetryOnError = (err) => !isAbortError(err) && !isPermanentClientError(err);
12
58
  const parseRetryAfter = (value) => {
13
59
  if (value === null || value === undefined)
14
60
  return null;
@@ -31,6 +31,85 @@ describe("swr-retry helpers", () => {
31
31
  expect(shouldRetryOnError(new Error("boom"))).toBe(true);
32
32
  expect(shouldRetryOnError({ status: 500 })).toBe(true);
33
33
  });
34
+ // A 4xx is deterministic — retrying it burns the upstream's quota for no
35
+ // chance of success. This is the guard that stopped one bad Google Retail
36
+ // filter costing 4 API calls per page view.
37
+ it("returns false for a 4xx, which cannot succeed on retry", () => {
38
+ expect(shouldRetryOnError({ status: 400 })).toBe(false);
39
+ expect(shouldRetryOnError({ status: 403 })).toBe(false);
40
+ expect(shouldRetryOnError({ status: 404 })).toBe(false);
41
+ expect(shouldRetryOnError({ status: 499 })).toBe(false);
42
+ });
43
+ // 429 is the 4xx that means "later", not "never".
44
+ it("returns true for 429 so Retry-After is honored", () => {
45
+ expect(shouldRetryOnError({ status: 429 })).toBe(true);
46
+ });
47
+ /**
48
+ * 408 is the other one: the server gave up waiting for the request rather
49
+ * than refusing what it received, so the same request may well succeed. The
50
+ * google-retail proxy collapses upstream 408s to 400 before they get here,
51
+ * so this matters for the cluster feed and any future consumer — which is
52
+ * the reason the retryable set is defined by HTTP semantics and not by what
53
+ * one upstream emits.
54
+ */
55
+ it("returns true for 408, which is transient rather than deterministic", () => {
56
+ expect(shouldRetryOnError({ status: 408 })).toBe(true);
57
+ const clusterFeed408 = Object.assign(new Error("Cluster feed HTTP 408"), {
58
+ reason: "cluster-feed-http",
59
+ status: 408,
60
+ retryAfter: null,
61
+ });
62
+ expect(shouldRetryOnError(clusterFeed408)).toBe(true);
63
+ });
64
+ // 425 Too Early is retryable in the abstract but unreachable here — we send
65
+ // no TLS early data — so it stays in the permanent set deliberately.
66
+ it("returns false for 425, which this client cannot receive", () => {
67
+ expect(shouldRetryOnError({ status: 425 })).toBe(false);
68
+ });
69
+ it("returns true for 5xx and for statuses below 400", () => {
70
+ expect(shouldRetryOnError({ status: 500 })).toBe(true);
71
+ expect(shouldRetryOnError({ status: 503 })).toBe(true);
72
+ expect(shouldRetryOnError({ status: 399 })).toBe(true);
73
+ });
74
+ // Integrations that never set `status` must behave exactly as before.
75
+ it("retries when status is absent or not a number", () => {
76
+ expect(shouldRetryOnError(new Error("network down"))).toBe(true);
77
+ expect(shouldRetryOnError({ status: undefined })).toBe(true);
78
+ expect(shouldRetryOnError({ status: "400" })).toBe(true);
79
+ expect(shouldRetryOnError({})).toBe(true);
80
+ });
81
+ // An abort still wins even if a status rode along.
82
+ it("returns false for an AbortError carrying a retryable status", () => {
83
+ const err = Object.assign(new Error("aborted"), {
84
+ name: "AbortError",
85
+ status: 500,
86
+ });
87
+ expect(shouldRetryOnError(err)).toBe(false);
88
+ });
89
+ it("does not throw on null / undefined / primitives", () => {
90
+ expect(shouldRetryOnError(null)).toBe(true);
91
+ expect(shouldRetryOnError(undefined)).toBe(true);
92
+ expect(shouldRetryOnError(404)).toBe(true);
93
+ });
94
+ /**
95
+ * This hook is shared. Both known callers — use-infinite-scroll (the
96
+ * search-client path) and usePersonalizedClusterFeed — throw errors that
97
+ * carry `status`, so both stop retrying 4xx. That is deliberate: a 4xx is
98
+ * deterministic whichever API produced it, and the cluster feed already
99
+ * attached `status`/`retryAfter` (see use-personalized-cluster-feed-core.ts
100
+ * :258) purely so this layer could act on them.
101
+ */
102
+ it("applies to the cluster-feed error shape too, not just search", () => {
103
+ const clusterFeed4xx = Object.assign(new Error("Cluster feed HTTP 404"), {
104
+ reason: "cluster-feed-http",
105
+ status: 404,
106
+ retryAfter: null,
107
+ });
108
+ expect(shouldRetryOnError(clusterFeed4xx)).toBe(false);
109
+ // A network failure there has no status, so it still retries.
110
+ const clusterFeedNetwork = Object.assign(new Error("Cluster feed request failed"), { reason: "cluster-feed-network" });
111
+ expect(shouldRetryOnError(clusterFeedNetwork)).toBe(true);
112
+ });
34
113
  });
35
114
  });
36
115
  describe("useSwrRetryConfig", () => {
@@ -0,0 +1,33 @@
1
+ type CreateQuestionInput = {
2
+ provider: string;
3
+ productId: string;
4
+ productHandle?: string;
5
+ productTitle?: string;
6
+ productUrl?: string;
7
+ displayName: string;
8
+ email: string;
9
+ questionContent: string;
10
+ };
11
+ type UseCreateQuestionProps = {
12
+ baseURL: string;
13
+ };
14
+ type CreateQuestionOutcome = {
15
+ ok: boolean;
16
+ };
17
+ type UseCreateQuestionReturn = {
18
+ createQuestion: (input: CreateQuestionInput) => Promise<CreateQuestionOutcome>;
19
+ isSubmitting: boolean;
20
+ isSuccess: boolean;
21
+ error: string | null;
22
+ reset: () => void;
23
+ };
24
+ /**
25
+ * Mutation counterpart to `useQuestions`. Submits a new question through the
26
+ * app-scoped API route (`POST {baseURL}/questions/create`), which proxies to
27
+ * the Q&A provider (currently Yotpo only). Yotpo emails the asker a
28
+ * confirmation link; the question appears after email confirmation and
29
+ * merchant moderation.
30
+ */
31
+ export declare function useCreateQuestion({ baseURL, }: UseCreateQuestionProps): UseCreateQuestionReturn;
32
+ export {};
33
+ //# sourceMappingURL=use-create-question.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-create-question.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-create-question.ts"],"names":[],"mappings":"AAGA,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IAGjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,KAAK,sBAAsB,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,qBAAqB,GAAG;IAC3B,EAAE,EAAE,OAAO,CAAA;CACZ,CAAA;AAED,KAAK,uBAAuB,GAAG;IAC7B,cAAc,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC9E,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,GACR,EAAE,sBAAsB,GAAG,uBAAuB,CAkFlD"}
@@ -0,0 +1,98 @@
1
+ "use client";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ import { useCallback, useEffect, useRef, useState } from "react";
12
+ /**
13
+ * Mutation counterpart to `useQuestions`. Submits a new question through the
14
+ * app-scoped API route (`POST {baseURL}/questions/create`), which proxies to
15
+ * the Q&A provider (currently Yotpo only). Yotpo emails the asker a
16
+ * confirmation link; the question appears after email confirmation and
17
+ * merchant moderation.
18
+ */
19
+ export function useCreateQuestion({ baseURL, }) {
20
+ const [isSubmitting, setIsSubmitting] = useState(false);
21
+ const [isSuccess, setIsSuccess] = useState(false);
22
+ const [error, setError] = useState(null);
23
+ // Track the in-flight request so a closing/reset drawer can abort it; a
24
+ // late resolution must not write success/error state onto a form the user
25
+ // left.
26
+ const createAbortRef = useRef(null);
27
+ const createQuestion = useCallback((input) => __awaiter(this, void 0, void 0, function* () {
28
+ setIsSubmitting(true);
29
+ setError(null);
30
+ const controller = new AbortController();
31
+ createAbortRef.current = controller;
32
+ try {
33
+ const response = yield fetch(`${baseURL}/questions/create`, {
34
+ method: "POST",
35
+ headers: { "Content-Type": "application/json" },
36
+ body: JSON.stringify(input),
37
+ signal: controller.signal,
38
+ });
39
+ if (!response.ok) {
40
+ let message = "Something went wrong. Please try again.";
41
+ // Only surface the server's message for client errors (validation
42
+ // strings meant for the user). 5xx bodies can carry internal error
43
+ // detail and get the generic copy instead.
44
+ if (response.status >= 400 && response.status < 500) {
45
+ try {
46
+ const body = yield response.json();
47
+ if (typeof (body === null || body === void 0 ? void 0 : body.error) === "string") {
48
+ message = body.error;
49
+ }
50
+ }
51
+ catch (_a) {
52
+ // non-JSON error body; keep the generic message
53
+ }
54
+ }
55
+ setError(message);
56
+ return { ok: false };
57
+ }
58
+ setIsSuccess(true);
59
+ return { ok: true };
60
+ }
61
+ catch (error) {
62
+ // Aborted because the drawer closed — leave state untouched so a
63
+ // reopened drawer isn't painted with this abandoned submission.
64
+ if (controller.signal.aborted)
65
+ return { ok: false };
66
+ console.error("Error creating question:", error);
67
+ setError("Something went wrong. Please try again.");
68
+ return { ok: false };
69
+ }
70
+ finally {
71
+ setIsSubmitting(false);
72
+ }
73
+ }), [baseURL]);
74
+ const reset = useCallback(() => {
75
+ var _a;
76
+ // Cancel any in-flight request so it can't resolve into stale UI state.
77
+ (_a = createAbortRef.current) === null || _a === void 0 ? void 0 : _a.abort();
78
+ setIsSubmitting(false);
79
+ setIsSuccess(false);
80
+ setError(null);
81
+ }, []);
82
+ // The drawer only wires reset() to its own close; if the whole subtree
83
+ // unmounts mid-submit (accordion collapse, navigation), abort here too so
84
+ // the request is actually cancelled.
85
+ useEffect(() => {
86
+ return () => {
87
+ var _a;
88
+ (_a = createAbortRef.current) === null || _a === void 0 ? void 0 : _a.abort();
89
+ };
90
+ }, []);
91
+ return {
92
+ createQuestion,
93
+ isSubmitting,
94
+ isSuccess,
95
+ error,
96
+ reset,
97
+ };
98
+ }
@@ -0,0 +1,35 @@
1
+ import { QnaSummaryData, QnaSearchData } from "app-studio-types";
2
+ type UseQuestionsProps = {
3
+ baseURL: string;
4
+ productId: string;
5
+ provider: string;
6
+ fetcher?: (url: string) => Promise<any>;
7
+ dataType: "summary" | "search" | null;
8
+ perPage?: number;
9
+ page?: number;
10
+ };
11
+ type UseQuestionsReturn = {
12
+ data: QnaSummaryData | QnaSearchData | null;
13
+ error: any;
14
+ isLoading: boolean;
15
+ questionsMockData?: any;
16
+ mockQnaSummaryData?: QnaSummaryData;
17
+ };
18
+ /**
19
+ * Read counterpart to `useReviews` for Q&A. Fetches the question summary
20
+ * (total questions/answers) or a page of questions through the app-scoped
21
+ * API route (`GET {baseURL}/questions/by-id`), which proxies to the Q&A
22
+ * provider (currently Yotpo only) with the merchant key held server-side.
23
+ */
24
+ export declare function useQuestions(props: UseQuestionsProps | null): UseQuestionsReturn;
25
+ type UseQuestionsInfiniteReturn = UseQuestionsReturn & {
26
+ ref: (node?: Element | null) => void;
27
+ retry: () => void;
28
+ };
29
+ /**
30
+ * Infinite-scroll variant for the question list, mirroring
31
+ * `useReviewsInfinite` (page-number pagination against pagination.total).
32
+ */
33
+ export declare function useQuestionsInfinite(props: UseQuestionsProps | null): UseQuestionsInfiniteReturn;
34
+ export {};
35
+ //# sourceMappingURL=use-questions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-questions.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-questions.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGhE,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAGvC,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAA;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,cAAc,GAAG,aAAa,GAAG,IAAI,CAAA;IAC3C,KAAK,EAAE,GAAG,CAAA;IACV,SAAS,EAAE,OAAO,CAAA;IAClB,iBAAiB,CAAC,EAAE,GAAG,CAAA;IACvB,kBAAkB,CAAC,EAAE,cAAc,CAAA;CACpC,CAAA;AAsFD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAC9B,kBAAkB,CAsCpB;AAED,KAAK,0BAA0B,GAAG,kBAAkB,GAAG;IACrD,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,CAAA;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAC9B,0BAA0B,CAsG5B"}
@@ -0,0 +1,198 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef } from "react";
3
+ import useSWR from "swr";
4
+ import useSWRInfinite from "swr/infinite";
5
+ import { useInView } from "react-intersection-observer";
6
+ const YOTPO = "yotpo";
7
+ const SUPPORTED_PROVIDERS = [YOTPO];
8
+ // Placeholder Q&A rendered in the dashboard preview (where there's no live
9
+ // product), mirroring reviewsMockData in use-reviews.
10
+ const questionsMockData = [
11
+ {
12
+ id: 1,
13
+ content: "Does this run true to size?",
14
+ date: "2024-10-10T00:00:00.000Z",
15
+ asker: {
16
+ displayName: "Name",
17
+ },
18
+ answers: [
19
+ {
20
+ id: 11,
21
+ content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua...",
22
+ date: "2024-10-11T00:00:00.000Z",
23
+ storeOwner: true,
24
+ answerer: {
25
+ displayName: "Store Owner",
26
+ },
27
+ },
28
+ ],
29
+ },
30
+ {
31
+ id: 2,
32
+ content: "Is this machine washable?",
33
+ date: "2024-08-10T00:00:00.000Z",
34
+ asker: {
35
+ displayName: "Name",
36
+ },
37
+ answers: [
38
+ {
39
+ id: 21,
40
+ content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
41
+ date: "2024-08-11T00:00:00.000Z",
42
+ storeOwner: false,
43
+ answerer: {
44
+ displayName: "Name",
45
+ },
46
+ },
47
+ ],
48
+ },
49
+ ];
50
+ const mockQnaSummaryData = {
51
+ totalQuestions: questionsMockData.length,
52
+ totalAnswers: questionsMockData.reduce((sum, question) => sum + question.answers.length, 0),
53
+ };
54
+ // Shared by both hooks. The route 404s when the yotpo-qa flag is off or the
55
+ // merchant's Yotpo plan lacks Q&A; surface that as an error (not data) so
56
+ // the block hides the Q&A row.
57
+ const defaultFetcher = (url) => fetch(url).then((res) => {
58
+ if (!res.ok)
59
+ throw new Error(`questions request failed: ${res.status}`);
60
+ return res.json();
61
+ });
62
+ function buildQueryParams(props) {
63
+ var _a, _b;
64
+ const queryParams = new URLSearchParams();
65
+ if (((_a = props.productId) === null || _a === void 0 ? void 0 : _a.length) > 0) {
66
+ queryParams.set("id", props.productId);
67
+ }
68
+ if (((_b = props.provider) === null || _b === void 0 ? void 0 : _b.length) > 0) {
69
+ queryParams.set("provider", props.provider);
70
+ }
71
+ queryParams.set("dataType", props.dataType);
72
+ if (props.perPage) {
73
+ queryParams.set("perPage", String(props.perPage));
74
+ }
75
+ return queryParams;
76
+ }
77
+ /**
78
+ * Read counterpart to `useReviews` for Q&A. Fetches the question summary
79
+ * (total questions/answers) or a page of questions through the app-scoped
80
+ * API route (`GET {baseURL}/questions/by-id`), which proxies to the Q&A
81
+ * provider (currently Yotpo only) with the merchant key held server-side.
82
+ */
83
+ export function useQuestions(props) {
84
+ let url = null;
85
+ if (props) {
86
+ const queryParams = buildQueryParams(props);
87
+ if (props.page) {
88
+ queryParams.set("page", String(props.page));
89
+ }
90
+ if (props.dataType === null ||
91
+ !props.productId ||
92
+ !SUPPORTED_PROVIDERS.includes(props.provider)) {
93
+ url = null;
94
+ }
95
+ else {
96
+ url = `${props.baseURL}/questions/by-id?${queryParams.toString()}`;
97
+ }
98
+ }
99
+ const fetcher = (props === null || props === void 0 ? void 0 : props.fetcher) || defaultFetcher;
100
+ const { data, error } = useSWR(url, fetcher, {
101
+ revalidateOnFocus: false,
102
+ revalidateOnReconnect: false,
103
+ revalidateIfStale: false,
104
+ dedupingInterval: 60000,
105
+ // The 404 from a disabled flag/plan is an expected state, not a
106
+ // transient failure — don't let SWR retry-loop the probe.
107
+ shouldRetryOnError: false,
108
+ });
109
+ return {
110
+ data: data || null,
111
+ error,
112
+ isLoading: Boolean(url) && !data && !error,
113
+ questionsMockData,
114
+ mockQnaSummaryData,
115
+ };
116
+ }
117
+ /**
118
+ * Infinite-scroll variant for the question list, mirroring
119
+ * `useReviewsInfinite` (page-number pagination against pagination.total).
120
+ */
121
+ export function useQuestionsInfinite(props) {
122
+ var _a, _b;
123
+ const { ref, inView } = useInView({ rootMargin: "800px" });
124
+ const isEndReached = useRef(false);
125
+ const getKey = (pageIndex, previousPageData) => {
126
+ if (!props ||
127
+ props.dataType == null ||
128
+ !props.productId ||
129
+ !SUPPORTED_PROVIDERS.includes(props.provider)) {
130
+ return null;
131
+ }
132
+ if (previousPageData && previousPageData.pagination) {
133
+ const { perPage, total } = previousPageData.pagination;
134
+ isEndReached.current = (pageIndex + 1) * perPage >= total;
135
+ }
136
+ const queryParams = buildQueryParams(props);
137
+ return `${props.baseURL}/questions/by-id?${queryParams.toString()}&page=${pageIndex + 1}`;
138
+ };
139
+ const fetcher = (props === null || props === void 0 ? void 0 : props.fetcher) || defaultFetcher;
140
+ const { data: dataInfinite, error: errorInfinite, size, setSize, isLoading, isValidating, mutate, } = useSWRInfinite(getKey, fetcher, {
141
+ revalidateOnFocus: false,
142
+ revalidateOnReconnect: false,
143
+ revalidateIfStale: false,
144
+ dedupingInterval: 60000,
145
+ // Failures surface in the block's error state with a manual retry;
146
+ // don't also auto-retry on backoff.
147
+ shouldRetryOnError: false,
148
+ });
149
+ const mergedQuestions = dataInfinite
150
+ ? dataInfinite
151
+ .filter((page) => page && page.questions)
152
+ .flatMap((page) => page.questions)
153
+ : [];
154
+ const searchResponse = {
155
+ pagination: (dataInfinite === null || dataInfinite === void 0 ? void 0 : dataInfinite.length) ? dataInfinite[0].pagination : null,
156
+ questions: mergedQuestions,
157
+ };
158
+ // Recomputed from the loaded pages: once page 1 has landed, we've reached
159
+ // the end when everything the pagination promised is loaded — including
160
+ // total === 0 (e.g. all questions pending moderation), which must not
161
+ // keep loadMore incrementing size forever.
162
+ isEndReached.current = (dataInfinite === null || dataInfinite === void 0 ? void 0 : dataInfinite.length)
163
+ ? mergedQuestions.length >= ((_b = (_a = searchResponse.pagination) === null || _a === void 0 ? void 0 : _a.total) !== null && _b !== void 0 ? _b : 0)
164
+ : false;
165
+ const loadMore = useCallback(() => {
166
+ if (!isLoading && !isValidating && !isEndReached.current) {
167
+ setSize(size + 1);
168
+ }
169
+ }, [isLoading, isValidating, setSize, size]);
170
+ useEffect(() => {
171
+ if (inView) {
172
+ loadMore();
173
+ }
174
+ }, [inView, loadMore]);
175
+ // Reset on the real fetch inputs, not the props object (the block passes a
176
+ // fresh literal every render, which would make an object-keyed effect fire
177
+ // on every commit).
178
+ const productId = props === null || props === void 0 ? void 0 : props.productId;
179
+ const dataType = props === null || props === void 0 ? void 0 : props.dataType;
180
+ const provider = props === null || props === void 0 ? void 0 : props.provider;
181
+ useEffect(() => {
182
+ isEndReached.current = false;
183
+ }, [productId, dataType, provider]);
184
+ // Revalidates every loaded page — the block's error state wires this to a
185
+ // "Try Again" button.
186
+ const retry = useCallback(() => {
187
+ mutate();
188
+ }, [mutate]);
189
+ return {
190
+ data: searchResponse,
191
+ error: errorInfinite,
192
+ isLoading: isValidating,
193
+ ref,
194
+ retry,
195
+ questionsMockData,
196
+ mockQnaSummaryData,
197
+ };
198
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"use-recommendations.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-recommendations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAOxE,UAAU,sBAAsB;IAE9B,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAGxC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;IAEd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAUD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,EAAE,GAAG,EAAE,CAAA;IACb,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,GAAG,CAAA;CACX;AAmBD,QAAA,MAAM,kBAAkB,kFAWrB,sBAAsB,KAAG,uBA8H3B,CAAA;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
1
+ {"version":3,"file":"use-recommendations.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-recommendations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAOxE,UAAU,sBAAsB;IAE9B,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAGxC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;IAEd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAUD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,EAAE,GAAG,EAAE,CAAA;IACb,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,GAAG,CAAA;CACX;AAqBD,QAAA,MAAM,kBAAkB,kFAWrB,sBAAsB,KAAG,uBA8H3B,CAAA;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
@@ -17,9 +17,10 @@ const constructURL = (apiURL) => {
17
17
  return url.toString();
18
18
  };
19
19
  const getCollections = (collections) => {
20
- return collections
21
- ? collections === null || collections === void 0 ? void 0 : collections.filter((obj) => obj.handle !== "empty-collection")
22
- : [];
20
+ if (!Array.isArray(collections)) {
21
+ return [];
22
+ }
23
+ return collections.filter((obj) => obj.handle !== "empty-collection");
23
24
  };
24
25
  const recommendationsLocalStorage = new RecommendationsLocalStorage();
25
26
  const MIN_QUERY_LENGTH = 3;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=text-self-translates.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-self-translates.test.d.ts","sourceRoot":"","sources":["../../../../components/ui/__tests__/text-self-translates.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { Text } from "../text";
4
+ import { TranslationProvider } from "../../contexts/translation-context";
5
+ // Block code relies on this: <Text> translates its own children via
6
+ // TranslationContext, so callers must NOT pre-translate text that only
7
+ // ever reaches the DOM through <Text> (see ShareButton/ReferralCode).
8
+ describe("Text self-translation via TranslationContext", () => {
9
+ it("translates plain children with no explicit lookup at the call site", () => {
10
+ render(_jsx(TranslationProvider, Object.assign({ translations: {
11
+ "share with your friends": "Compartir con tus amigos",
12
+ } }, { children: _jsx(Text, { children: "Share with your friends" }) })));
13
+ expect(screen.getByText("Compartir con tus amigos")).not.toBeNull();
14
+ });
15
+ it("falls back to the raw children when no provider is mounted", () => {
16
+ render(_jsx(Text, { children: "Share with your friends" }));
17
+ expect(screen.getByText("Share with your friends")).not.toBeNull();
18
+ });
19
+ });
@@ -6,7 +6,7 @@ interface MoneyType {
6
6
  price: number;
7
7
  }
8
8
  declare const moneyVariants: (props?: ({} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
9
- export interface MoneyProps extends MoneyType, VariantProps<typeof moneyVariants> {
9
+ export interface MoneyProps extends MoneyType, VariantProps<typeof moneyVariants>, React.HTMLAttributes<HTMLSpanElement> {
10
10
  hideZeroCents?: boolean;
11
11
  styles?: React.CSSProperties;
12
12
  }
@@ -1 +1 @@
1
- {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../../../components/ui/money.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd;AAED,QAAA,MAAM,aAAa,gGAMjB,CAAA;AAEF,MAAM,WAAW,UACf,SAAQ,SAAS,EACf,YAAY,CAAC,OAAO,aAAa,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAC7B;AAED,iBAAS,KAAK,CAAC,EACb,KAAK,EACL,MAAM,EACN,QAAQ,EACR,aAAqB,EACrB,MAAM,EACN,GAAG,KAAK,EACT,EAAE,UAAU,2CAiFZ;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../../../components/ui/money.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd;AAED,QAAA,MAAM,aAAa,gGAMjB,CAAA;AAEF,MAAM,WAAW,UACf,SAAQ,SAAS,EACf,YAAY,CAAC,OAAO,aAAa,CAAC,EAClC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAC7B;AAED,iBAAS,KAAK,CAAC,EACb,KAAK,EACL,MAAM,EACN,QAAQ,EACR,aAAqB,EACrB,MAAM,EACN,GAAG,KAAK,EACT,EAAE,UAAU,2CAiFZ;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../../components/ui/price.tsx"],"names":[],"mappings":";AAIA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,EAAE,CAAA;IAChD,cAAc,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACpC,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,mBAAmB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAC1C;AAED,iBAAS,KAAK,CAAC,EACb,KAAK,EACL,SAAS,EACT,WAAmB,EACnB,MAAc,EACd,cAAc,EACd,kBAAkB,EAClB,QAAgB,EAChB,MAAgB,EAChB,QAAa,EACb,aAAkB,EAClB,cAAc,EACd,UAAU,EACV,mBAAmB,EACnB,aAAa,GACd,EAAE,UAAU,2CA6EZ;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
1
+ {"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../../components/ui/price.tsx"],"names":[],"mappings":";AAIA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,EAAE,CAAA;IAChD,cAAc,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACpC,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,mBAAmB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAC1C;AAED,iBAAS,KAAK,CAAC,EACb,KAAK,EACL,SAAS,EACT,WAAmB,EACnB,MAAc,EACd,cAAc,EACd,kBAAkB,EAClB,QAAgB,EAChB,MAAgB,EAChB,QAAa,EACb,aAAkB,EAClB,cAAc,EACd,UAAU,EACV,mBAAmB,EACnB,aAAa,GACd,EAAE,UAAU,2CAiFZ;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -9,7 +9,7 @@ function Price({ price, priceHigh, priceRanges = false, isSale = false, compareA
9
9
  const colorClass = isSale
10
10
  ? "text-textColors-salePriceText"
11
11
  : "text-textColors-priceText";
12
- return (_jsx(Text, Object.assign({ className: `${colorClass} flex-shrink-0 max-w-full`, style: { fontSize: `${fontSize}px` } }, { children: _jsxs("span", Object.assign({ className: "flex-grow min-w-[fit-content] break-all" }, { children: [_jsx(Money, { price: price, currency: currency, locale: locale, styles: priceStyles, hideZeroCents: hideZeroCents }), priceRanges && priceHigh !== undefined && _jsx(Spacer, {}), priceRanges && priceHigh !== undefined && (_jsx(Money, { price: priceHigh, currency: currency, locale: locale, styles: priceStyles, hideZeroCents: hideZeroCents }))] })) })));
12
+ return (_jsx(Text, Object.assign({ className: `${colorClass} flex-shrink-0 max-w-full`, style: { fontSize: `${fontSize}px` } }, { children: _jsxs("span", Object.assign({ className: "flex-grow" }, { children: [_jsx(Money, { className: "whitespace-nowrap", price: price, currency: currency, locale: locale, styles: priceStyles, hideZeroCents: hideZeroCents }), priceRanges && priceHigh !== undefined && _jsx(Spacer, {}), priceRanges && priceHigh !== undefined && (_jsx(Money, { className: "whitespace-nowrap", price: priceHigh, currency: currency, locale: locale, styles: priceStyles, hideZeroCents: hideZeroCents }))] })) })));
13
13
  };
14
14
  const StrikeThroughPrice = () => {
15
15
  if (!isSale || !compareAtPrice)
@@ -6,6 +6,7 @@ type VideoAttributes = {
6
6
  overlayOpacity: number;
7
7
  autoplay: boolean;
8
8
  videoSound: boolean;
9
+ loop?: boolean;
9
10
  };
10
11
  interface VideoProps extends Omit<React.VideoHTMLAttributes<HTMLVideoElement>, "onLoadedData"> {
11
12
  src: string;
@@ -1 +1 @@
1
- {"version":3,"file":"video-enhanced.d.ts","sourceRoot":"","sources":["../../../components/ui/video-enhanced.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAkB9B,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,UAAU,UACR,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,cAAc,CAAC;IACzE,GAAG,EAAE,MAAM,CAAA;IACX,eAAe,EAAE,eAAe,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAKlB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,GAAG,KAAK,KAAK,IAAI,CAAA;CAC1D;AAED,QAAA,MAAM,KAAK,qFAkQV,CAAA;AAID,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"video-enhanced.d.ts","sourceRoot":"","sources":["../../../components/ui/video-enhanced.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAkB9B,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IAEnB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,UAAU,UACR,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,cAAc,CAAC;IACzE,GAAG,EAAE,MAAM,CAAA;IACX,eAAe,EAAE,eAAe,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAKlB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,GAAG,KAAK,KAAK,IAAI,CAAA;CAC1D;AAED,QAAA,MAAM,KAAK,qFAuQV,CAAA;AAID,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,CAAA"}
@@ -35,7 +35,13 @@ const videoVariants = {
35
35
  // first frame well within this window, so they still reveal via `loadeddata`.
36
36
  const LOADED_DATA_FALLBACK_MS = 1000;
37
37
  const Video = React.forwardRef((_a, ref) => {
38
- var { src, videoAttributes, naturalAspectRatio = "1/1", className, onLoadedData } = _a, props = __rest(_a, ["src", "videoAttributes", "naturalAspectRatio", "className", "onLoadedData"]);
38
+ var _b;
39
+ var { src, videoAttributes, naturalAspectRatio = "1/1", className, onLoadedData,
40
+ // Pull `loop` out of the spread: it's a native <video> attribute, so
41
+ // leaving it in `...props` (which is applied AFTER our computed value)
42
+ // would let a passed-in prop silently override the attribute-driven
43
+ // loop logic below. An explicit prop still wins, but explicitly.
44
+ loop: loopProp } = _a, props = __rest(_a, ["src", "videoAttributes", "naturalAspectRatio", "className", "onLoadedData", "loop"]);
39
45
  const autoPlayEnabled = videoAttributes.autoplay && !videoAttributes.videoSound;
40
46
  const internalRef = React.useRef(null);
41
47
  const videoRef = ref || internalRef;
@@ -226,7 +232,7 @@ const Video = React.forwardRef((_a, ref) => {
226
232
  };
227
233
  return (_jsxs("div", Object.assign({ className: "relative w-full" }, { children: [_jsx("video", Object.assign({ ref: videoRef, className: cn(videoVariants.base, videoAttributes.videoFit === "fill"
228
234
  ? videoVariants.fit.cover
229
- : videoVariants.fit.contain, className), style: videoStyle, preload: "metadata", playsInline: true, loop: videoAttributes.enabled, controls: false }, props)), isLoaded && !isPlaying && (_jsx("button", Object.assign({ onClick: handlePlayPause, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50\n w-16 h-16 rounded-full bg-black/75 \n flex items-center justify-center transition-all duration-300\n focus:outline-none focus:ring-2 focus:ring-white", "aria-label": "Play video" }, { children: _jsx("div", { className: "w-0 h-0 border-y-8 border-y-transparent \n border-l-[16px] border-l-white \n translate-x-[2px]" }) })))] })));
235
+ : videoVariants.fit.contain, className), style: videoStyle, preload: "metadata", playsInline: true, loop: (_b = loopProp !== null && loopProp !== void 0 ? loopProp : videoAttributes.loop) !== null && _b !== void 0 ? _b : videoAttributes.enabled, controls: false }, props)), isLoaded && !isPlaying && (_jsx("button", Object.assign({ onClick: handlePlayPause, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50\n w-16 h-16 rounded-full bg-black/75 \n flex items-center justify-center transition-all duration-300\n focus:outline-none focus:ring-2 focus:ring-white", "aria-label": "Play video" }, { children: _jsx("div", { className: "w-0 h-0 border-y-8 border-y-transparent \n border-l-[16px] border-l-white \n translate-x-[2px]" }) })))] })));
230
236
  });
231
237
  Video.displayName = "Video";
232
238
  export { Video as VideoEnhanced };
@@ -84,6 +84,7 @@ export * from "../components/core/html";
84
84
  export * from "../components/hooks/use-shop";
85
85
  export * from "../components/libs/sort-filter/search-integration";
86
86
  export * from "../components/hooks/use-reviews";
87
+ export * from "../components/hooks/use-questions";
87
88
  export * from "../components/hooks/use-style-parent";
88
89
  export * from "../components/ui/subcollection-tabs";
89
90
  export * from "../components/ui/ProductCard/utils";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../core/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../core/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EACjB,EAAE,EACF,wBAAwB,EACxB,GAAG,EACH,kBAAkB,EAClB,4BAA4B,EAC5B,4BAA4B,EAC5B,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,QAAQ,GACT,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EACL,qBAAqB,EACrB,6BAA6B,EAC7B,cAAc,EACd,YAAY,EACZ,4BAA4B,EAC5B,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,4BAA4B,EAC5B,4BAA4B,EAC5B,OAAO,EACP,kBAAkB,EAClB,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACtD,cAAc,kBAAkB,CAAA;AAChC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,4CAA4C,CAAA;AAC1D,cAAc,oCAAoC,CAAA;AAClD,cAAc,yCAAyC,CAAA;AACvD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2CAA2C,CAAA;AACzD,cAAc,yCAAyC,CAAA;AACvD,cAAc,uDAAuD,CAAA;AACrE,cAAc,kCAAkC,CAAA;AAChD,cAAc,mDAAmD,CAAA;AACjE,cAAc,uCAAuC,CAAA;AACrD,cAAc,0CAA0C,CAAA;AACxD,cAAc,qCAAqC,CAAA;AACnD,cAAc,yCAAyC,CAAA;AACvD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,uCAAuC,CAAA;AACrD,cAAc,qDAAqD,CAAA;AACnE,cAAc,mCAAmC,CAAA;AACjD,cAAc,4BAA4B,CAAA;AAC1C,cAAc,oCAAoC,CAAA;AAClD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,mCAAmC,CAAA;AACjD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,wCAAwC,CAAA;AACtD,cAAc,2BAA2B,CAAA;AACzC,cAAc,wCAAwC,CAAA;AACtD,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,uCAAuC,CAAA;AACrD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,kCAAkC,CAAA;AAChD,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,kCAAkC,CAAA;AAEhD,cAAc,qCAAqC,CAAA;AACnD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,2BAA2B,CAAA;AACzC,cAAc,kCAAkC,CAAA;AAChD,cAAc,yBAAyB,CAAA;AACvC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,mDAAmD,CAAA;AACjE,cAAc,iCAAiC,CAAA;AAC/C,cAAc,mCAAmC,CAAA;AACjD,cAAc,sCAAsC,CAAA;AACpD,cAAc,qCAAqC,CAAA;AACnD,cAAc,oCAAoC,CAAA;AAClD,cAAc,cAAc,CAAA;AAC5B,cAAc,8CAA8C,CAAA;AAC5D,cAAc,mDAAmD,CAAA;AACjE,cAAc,sBAAsB,CAAA;AACpC,cAAc,oCAAoC,CAAA;AAClD,cAAc,sCAAsC,CAAA;AACpD,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+CAA+C,CAAA"}
@@ -84,6 +84,7 @@ export * from "../components/core/html";
84
84
  export * from "../components/hooks/use-shop";
85
85
  export * from "../components/libs/sort-filter/search-integration";
86
86
  export * from "../components/hooks/use-reviews";
87
+ export * from "../components/hooks/use-questions";
87
88
  export * from "../components/hooks/use-style-parent";
88
89
  export * from "../components/ui/subcollection-tabs";
89
90
  export * from "../components/ui/ProductCard/utils";
package/dist/index.d.ts CHANGED
@@ -86,6 +86,8 @@ export * from "./components/hooks/use-shop";
86
86
  export * from "./components/libs/sort-filter/search-integration";
87
87
  export * from "./components/hooks/use-reviews";
88
88
  export * from "./components/hooks/use-create-review";
89
+ export * from "./components/hooks/use-questions";
90
+ export * from "./components/hooks/use-create-question";
89
91
  export * from "./components/hooks/use-style-parent";
90
92
  export * from "./components/ui/subcollection-tabs";
91
93
  export * from "./components/ui/ProductCard/utils";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -86,6 +86,8 @@ export * from "./components/hooks/use-shop";
86
86
  export * from "./components/libs/sort-filter/search-integration";
87
87
  export * from "./components/hooks/use-reviews";
88
88
  export * from "./components/hooks/use-create-review";
89
+ export * from "./components/hooks/use-questions";
90
+ export * from "./components/hooks/use-create-question";
89
91
  export * from "./components/hooks/use-style-parent";
90
92
  export * from "./components/ui/subcollection-tabs";
91
93
  export * from "./components/ui/ProductCard/utils";
@@ -1,5 +1,5 @@
1
1
  import { ProductVariant, Product } from "app-studio-types";
2
- export declare const getCheapestProductFromVariantsFn: (productVariants: ProductVariant[]) => ProductVariant;
2
+ export declare const getCheapestProductFromVariantsFn: (productVariants: ProductVariant[]) => ProductVariant | undefined;
3
3
  export declare function getPriceRangesFn(product: Product): {
4
4
  price: number;
5
5
  isSale: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../lib/price.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AA0B1D,eAAO,MAAM,gCAAgC,oBAC1B,cAAc,EAAE,mBAelC,CAAA;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO;WAsBtC,MAAM;YACL,OAAO;;;;EAclB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO;;;;EAQ1C"}
1
+ {"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../lib/price.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AA0B1D,eAAO,MAAM,gCAAgC,oBAC1B,cAAc,EAAE,+BAmBlC,CAAA;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO;WAsBtC,MAAM;YACL,OAAO;;;;EAclB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO;;;;EAQ1C"}
package/dist/lib/price.js CHANGED
@@ -1,5 +1,8 @@
1
1
  // Return the cheapest available variant for pricing details
2
2
  export const getCheapestProductFromVariantsFn = (productVariants) => {
3
+ if (!Array.isArray(productVariants) || productVariants.length === 0) {
4
+ return undefined;
5
+ }
3
6
  const availableVariants = productVariants.filter((variant) => variant.availableForSale);
4
7
  // Use pricing from in-stock variants only. If all are out of stock use all variants.
5
8
  const activeVariants = availableVariants.length
package/dist/styles.css CHANGED
@@ -612,11 +612,16 @@ video {
612
612
  --productBadging-fill: #000000;
613
613
  --productBadging-text: #fefefe;
614
614
 
615
+ /* Legacy v1 tokens — kept for backwards compat with existing blocks. */
615
616
  --productImage-aspectRatio: "2:3";
616
617
  --productImage-scaling: cover;
617
618
  --productImage-isCustom: "false";
618
619
 
619
- --standard-shadow: 0px 5px 25px 0px rgba (0,  0,  0,  0.10);
620
+ /* V2 brand-kit tokens (fall back to legacy values). */
621
+ --brand-image-ratio: 2/3;
622
+ --brand-image-scaling: var(--productImage-scaling);
623
+
624
+ --standard-shadow: 0px 5px 25px 0px rgba (0, 0, 0, 0.10);
620
625
  }
621
626
  .textarea-component::-webkit-scrollbar {
622
627
  width: 4px;
@@ -1134,7 +1139,7 @@ video {
1134
1139
  aspect-ratio: 327/316;
1135
1140
  }
1136
1141
  .aspect-productImages {
1137
- aspect-ratio: var(--productImage-aspectRatio);
1142
+ aspect-ratio: var(--brand-image-ratio);
1138
1143
  }
1139
1144
  .aspect-square {
1140
1145
  aspect-ratio: 1 / 1;
@@ -1511,6 +1516,9 @@ video {
1511
1516
  .min-w-8 {
1512
1517
  min-width: 2rem;
1513
1518
  }
1519
+ .min-w-\[104px\] {
1520
+ min-width: 104px;
1521
+ }
1514
1522
  .min-w-\[150px\] {
1515
1523
  min-width: 150px;
1516
1524
  }
@@ -1520,10 +1528,6 @@ video {
1520
1528
  .min-w-\[8rem\] {
1521
1529
  min-width: 8rem;
1522
1530
  }
1523
- .min-w-\[fit-content\] {
1524
- min-width: -moz-fit-content;
1525
- min-width: fit-content;
1526
- }
1527
1531
  .max-w-\[140px\] {
1528
1532
  max-width: 140px;
1529
1533
  }
@@ -1902,6 +1906,9 @@ video {
1902
1906
  .gap-5 {
1903
1907
  gap: 1.25rem;
1904
1908
  }
1909
+ .gap-6 {
1910
+ gap: 1.5rem;
1911
+ }
1905
1912
  .gap-\[7px\] {
1906
1913
  gap: 7px;
1907
1914
  }
@@ -2018,6 +2025,9 @@ video {
2018
2025
  .text-ellipsis {
2019
2026
  text-overflow: ellipsis;
2020
2027
  }
2028
+ .text-clip {
2029
+ text-overflow: clip;
2030
+ }
2021
2031
  .whitespace-normal {
2022
2032
  white-space: normal;
2023
2033
  }
@@ -2133,6 +2143,9 @@ video {
2133
2143
  .border-l {
2134
2144
  border-left-width: 1px;
2135
2145
  }
2146
+ .border-l-2 {
2147
+ border-left-width: 2px;
2148
+ }
2136
2149
  .border-l-\[16px\] {
2137
2150
  border-left-width: 16px;
2138
2151
  }
@@ -2193,6 +2206,10 @@ video {
2193
2206
  .border-coreColors-dividingLines {
2194
2207
  border-color: var(--coreColors-dividingLines);
2195
2208
  }
2209
+ .border-gray-100 {
2210
+ --tw-border-opacity: 1;
2211
+ border-color: rgb(243 244 246 / var(--tw-border-opacity, 1));
2212
+ }
2196
2213
  .border-gray-300 {
2197
2214
  --tw-border-opacity: 1;
2198
2215
  border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
@@ -2555,6 +2572,9 @@ video {
2555
2572
  .pl-2 {
2556
2573
  padding-left: 0.5rem;
2557
2574
  }
2575
+ .pl-3 {
2576
+ padding-left: 0.75rem;
2577
+ }
2558
2578
  .pl-4 {
2559
2579
  padding-left: 1rem;
2560
2580
  }
@@ -2630,6 +2650,9 @@ video {
2630
2650
  .font-fontRegular {
2631
2651
  font-family: var(--fontRegular);
2632
2652
  }
2653
+ .font-mono {
2654
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
2655
+ }
2633
2656
  .text-5xl {
2634
2657
  font-size: 3rem;
2635
2658
  line-height: 1;
@@ -2764,6 +2787,9 @@ video {
2764
2787
  .tracking-tight {
2765
2788
  letter-spacing: -0.025em;
2766
2789
  }
2790
+ .tracking-wider {
2791
+ letter-spacing: 0.05em;
2792
+ }
2767
2793
  .text-\[\#666666\] {
2768
2794
  --tw-text-opacity: 1;
2769
2795
  color: rgb(102 102 102 / var(--tw-text-opacity, 1));
@@ -2882,6 +2908,10 @@ video {
2882
2908
  .text-foreground\/50 {
2883
2909
  color: hsl(var(--foreground) / 0.5);
2884
2910
  }
2911
+ .text-gray-400 {
2912
+ --tw-text-opacity: 1;
2913
+ color: rgb(156 163 175 / var(--tw-text-opacity, 1));
2914
+ }
2885
2915
  .text-gray-500 {
2886
2916
  --tw-text-opacity: 1;
2887
2917
  color: rgb(107 114 128 / var(--tw-text-opacity, 1));
@@ -3267,11 +3297,11 @@ video {
3267
3297
  .paused {
3268
3298
  animation-play-state: paused;
3269
3299
  }
3270
- .\!container {
3300
+ .\!container {
3271
3301
  padding-right: 16px !important;
3272
3302
  padding-left: 16px !important;
3273
3303
  }
3274
- .container {
3304
+ .container {
3275
3305
  padding-right: 16px;
3276
3306
  padding-left: 16px;
3277
3307
  }
@@ -3904,6 +3934,12 @@ body::-webkit-scrollbar {
3904
3934
  .\[\&_\*\]\:placeholder\:text-stateColors-error *::placeholder {
3905
3935
  color: var(--stateColors-error);
3906
3936
  }
3937
+ .\[\&_a\]\:text-inherit a {
3938
+ color: inherit;
3939
+ }
3940
+ .\[\&_a\]\:underline a {
3941
+ text-decoration-line: underline;
3942
+ }
3907
3943
  .\[\&_label\]\:focus-within\:\!text-stateColors-error:focus-within label {
3908
3944
  color: var(--stateColors-error) !important;
3909
3945
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapcart/mobile-components",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "style": "dist/styles.css",