@vtex/faststore 0.0.8 → 0.0.10
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 +59 -0
- package/dist/actions.json +42 -0
- package/dist/catalog.json +731 -16
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/components.d.ts +9 -4
- package/dist/components.js +11 -6
- package/dist/content-types.json +300 -0
- package/dist/core/dist/define-component.d.ts +6 -1
- package/dist/docs/account-entry-point.md +4 -4
- package/dist/docs/account-menu.md +2 -2
- package/dist/docs/account-saved-cards.md +301 -0
- package/dist/docs/binding-switcher.md +154 -0
- package/dist/docs/card-entry.md +3 -3
- package/dist/docs/card-summary.md +175 -0
- package/dist/docs/cart-destination.md +238 -0
- package/dist/docs/cart-item.md +21 -3
- package/dist/docs/cart-totalizer.md +1 -1
- package/dist/docs/cart.md +118 -11
- package/dist/docs/footer-social.md +1 -1
- package/dist/docs/free-shipping-progress.md +13 -9
- package/dist/docs/incentives.md +2 -2
- package/dist/docs/logo.md +1 -1
- package/dist/docs/payment-method-badges.md +2 -2
- package/dist/docs/payment-methods.md +1 -1
- package/dist/docs/product-information.md +2 -2
- package/dist/docs/product-shelf.md +7 -0
- package/dist/docs/select.md +3 -4
- package/dist/docs/sign-in-redirect.md +1 -1
- package/dist/docs/toast.md +30 -12
- package/dist/index.d.ts +2 -1
- package/dist/internal/client.d.ts +4 -1
- package/dist/internal/client.js +4 -1
- package/dist/internal/server.d.ts +4 -2
- package/dist/internal/server.js +4 -2
- package/dist/matter/account-saved-cards/account-saved-cards.d.ts +383 -0
- package/dist/matter/account-saved-cards/account-saved-cards.js +956 -0
- package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
- package/dist/matter/billing-address/billing-address.js.map +1 -1
- package/dist/matter/cart/cart-namespace.d.ts +5 -1
- package/dist/matter/cart/cart-namespace.js +5 -1
- package/dist/matter/cart/cart-namespace.js.map +1 -1
- package/dist/matter/cart/cart.d.ts +34 -4
- package/dist/matter/cart/cart.js +238 -28
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/cart-destination/cart-destination.d.ts +222 -0
- package/dist/matter/cart-destination/cart-destination.js +613 -0
- package/dist/matter/cart-destination/cart-destination.js.map +1 -0
- package/dist/matter/cart-item/cart-item.d.ts +4 -2
- package/dist/matter/cart-item/cart-item.js +75 -16
- package/dist/matter/cart-item/cart-item.js.map +1 -1
- package/dist/matter/cart-totalizer/cart-totalizer.js +3 -2
- package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
- package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +6 -3
- package/dist/matter/free-shipping-progress/free-shipping-progress.js +76 -33
- package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
- package/dist/matter/pricing/pricing.js.map +1 -1
- package/dist/matter/product-shelf/product-shelf.d.ts +7 -0
- package/dist/matter/product-shelf/product-shelf.js +115 -1
- package/dist/matter/product-shelf/product-shelf.js.map +1 -1
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.d.ts +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.js +6 -2
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/particles/binding-switcher/binding-switcher.d.ts +38 -0
- package/dist/particles/binding-switcher/binding-switcher.js +183 -0
- package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
- package/dist/particles/card-summary/card-network.d.ts +17 -0
- package/dist/particles/card-summary/card-network.js +25 -0
- package/dist/particles/card-summary/card-network.js.map +1 -0
- package/dist/particles/card-summary/card-summary.d.ts +83 -0
- package/dist/particles/card-summary/card-summary.js +188 -0
- package/dist/particles/card-summary/card-summary.js.map +1 -0
- package/dist/particles/footer-social/footer-social.d.ts +1 -1
- package/dist/particles/footer-social/footer-social.js +1 -1
- package/dist/particles/footer-social/footer-social.js.map +1 -1
- package/dist/particles/incentives/incentives.d.ts +1 -1
- package/dist/particles/incentives/incentives.js +1 -1
- package/dist/particles/incentives/incentives.js.map +1 -1
- package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
- package/dist/particles/payment-methods/payment-methods.js +1 -1
- package/dist/particles/payment-methods/payment-methods.js.map +1 -1
- package/dist/particles/toast/toast.d.ts +20 -6
- package/dist/particles/toast/toast.js +49 -7
- package/dist/particles/toast/toast.js.map +1 -1
- package/dist/schema.graphql +298 -34
- package/dist/sdk/actions/index.d.ts +3 -1
- package/dist/sdk/actions/index.js +3 -1
- package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
- package/dist/sdk/actions/locale-action-provider.js +20 -0
- package/dist/sdk/actions/locale-action-provider.js.map +1 -0
- package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
- package/dist/sdk/actions/saved-card-action-provider.js +16 -0
- package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
- package/dist/sdk/actions/types.d.ts +6 -2
- package/dist/sdk/cache/storefront-cache.js +2 -1
- package/dist/sdk/cache/storefront-cache.js.map +1 -1
- package/dist/sdk/cart/operations.d.ts +2 -1
- package/dist/sdk/cart/operations.js +55 -1
- package/dist/sdk/cart/operations.js.map +1 -1
- package/dist/sdk/cart/optimistic.d.ts +30 -7
- package/dist/sdk/cart/optimistic.js +78 -41
- package/dist/sdk/cart/optimistic.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
- package/dist/sdk/cart/use-cart-actions.js +61 -15
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
- package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
- package/dist/sdk/generated/gql.js +15 -11
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.d.ts +177 -46
- package/dist/sdk/generated/graphql.js +2314 -93
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/i18n/messages/en-US.js +19 -0
- package/dist/sdk/i18n/messages/en-US.json +19 -0
- package/dist/sdk/i18n/messages/en-US.json.d.ts +19 -0
- package/dist/sdk/i18n/messages/es-ES.js +19 -0
- package/dist/sdk/i18n/messages/es-ES.json +19 -0
- package/dist/sdk/i18n/messages/pt-BR.js +19 -0
- package/dist/sdk/i18n/messages/pt-BR.json +19 -0
- package/dist/sdk/i18n/provider.js +1 -1
- package/dist/sdk/i18n/provider.js.map +1 -1
- package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
- package/dist/sdk/locale/binding-switch-provider.js +20 -0
- package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
- package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
- package/dist/sdk/locale/use-locale-actions.js +70 -0
- package/dist/sdk/locale/use-locale-actions.js.map +1 -0
- package/dist/sdk/navigation/binding-switch.d.ts +39 -0
- package/dist/sdk/navigation/binding-switch.js +129 -0
- package/dist/sdk/navigation/binding-switch.js.map +1 -0
- package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
- package/dist/sdk/navigation/decode-route-params.js +32 -0
- package/dist/sdk/navigation/decode-route-params.js.map +1 -0
- package/dist/sdk/saved-cards/operations.d.ts +16 -0
- package/dist/sdk/saved-cards/operations.js +41 -0
- package/dist/sdk/saved-cards/operations.js.map +1 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
- package/dist/sdk/seo/page-alternates.d.ts +5 -3
- package/dist/sdk/seo/page-alternates.js +7 -12
- package/dist/sdk/seo/page-alternates.js.map +1 -1
- package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
- package/dist/sdk/shipping/shipping-operations.js +13 -0
- package/dist/sdk/shipping/shipping-operations.js.map +1 -1
- package/dist/sdk/state/cart.d.ts +9 -2
- package/dist/sdk/state/cart.js +9 -2
- package/dist/sdk/state/cart.js.map +1 -1
- package/package.json +2 -2
- package/src/styles/tailwind.css +1 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ComponentDefinition } from "../../core/dist/define-component.js";
|
|
2
|
+
import "../../core/dist/index.js";
|
|
3
|
+
import { ComponentActions } from "../../sdk/actions/types.js";
|
|
4
|
+
import { ComponentPropsWithRef } from "react";
|
|
5
|
+
//#region src/particles/binding-switcher/binding-switcher.d.ts
|
|
6
|
+
export type BindingSwitcherBinding = {
|
|
7
|
+
locale?: unknown;
|
|
8
|
+
currency?: unknown;
|
|
9
|
+
salesChannel?: unknown;
|
|
10
|
+
url?: unknown;
|
|
11
|
+
country?: unknown;
|
|
12
|
+
timezone?: unknown;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* `foundation.json` `localization.bindings`, keyed by binding id. An entry counts only when it is an
|
|
16
|
+
* own key, the value is a non-null object, and `locale` is a string. Fewer than two counted
|
|
17
|
+
* entries yields an empty list.
|
|
18
|
+
*/
|
|
19
|
+
export declare function bindingSwitcherOptions(bindings: Record<string, BindingSwitcherBinding> | null | undefined, activeLocale: string): {
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
}[];
|
|
23
|
+
export declare const NOTICE_DEFAULT = "This page isn't available in the selected language.";
|
|
24
|
+
export declare const LABEL_DEFAULT = "Language";
|
|
25
|
+
export type BindingSwitcherProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {
|
|
26
|
+
/** `foundation.json` `localization.bindings`, keyed by binding id. No library default. */
|
|
27
|
+
bindings?: Record<string, BindingSwitcherBinding> | null;
|
|
28
|
+
/** Accessible name, rendered as `Select.Label`. */
|
|
29
|
+
label?: string;
|
|
30
|
+
/** Shown when the page loaded with `fs_notice=no-equivalent`. */
|
|
31
|
+
notice?: string;
|
|
32
|
+
/** Injected from `actions: { locale: ['set'] }`. */
|
|
33
|
+
$actions?: ComponentActions;
|
|
34
|
+
};
|
|
35
|
+
export declare const BindingSwitcherDefinition: ComponentDefinition<BindingSwitcherProps>;
|
|
36
|
+
export declare function BindingSwitcher({ bindings, label, notice, $actions: $actionsProp, className, ...props }: BindingSwitcherProps): import("react/jsx-runtime").JSX.Element | null;
|
|
37
|
+
//#endregion
|
|
38
|
+
//# sourceMappingURL=binding-switcher.d.ts.map
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { defineComponent } from "../../core/dist/define-component.js";
|
|
3
|
+
import "../../core/dist/index.js";
|
|
4
|
+
import { useStorefrontContext } from "../../sdk/context/storefront-context.js";
|
|
5
|
+
import { useStorefrontRoute } from "../../sdk/navigation/use-storefront-route.js";
|
|
6
|
+
import { useActionsOverride } from "../../sdk/actions/actions-override-context.js";
|
|
7
|
+
import { resolveAuthoredCopy } from "../../utils/resolve-authored-copy.js";
|
|
8
|
+
import { Select } from "../select/select.js";
|
|
9
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
//#region src/particles/binding-switcher/binding-switcher.tsx
|
|
12
|
+
/**
|
|
13
|
+
* `foundation.json` `localization.bindings`, keyed by binding id. An entry counts only when it is an
|
|
14
|
+
* own key, the value is a non-null object, and `locale` is a string. Fewer than two counted
|
|
15
|
+
* entries yields an empty list.
|
|
16
|
+
*/
|
|
17
|
+
function bindingSwitcherOptions(bindings, activeLocale) {
|
|
18
|
+
if (bindings == null) return [];
|
|
19
|
+
const counted = [];
|
|
20
|
+
for (const [id, value] of Object.entries(bindings)) {
|
|
21
|
+
if (!isCountedBinding(value)) continue;
|
|
22
|
+
counted.push({
|
|
23
|
+
id,
|
|
24
|
+
locale: value.locale,
|
|
25
|
+
currency: value.currency
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (counted.length < 2) return [];
|
|
29
|
+
const localeCount = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const entry of counted) localeCount.set(entry.locale, (localeCount.get(entry.locale) ?? 0) + 1);
|
|
31
|
+
const options = counted.map((entry) => {
|
|
32
|
+
let label = languageName(entry.locale);
|
|
33
|
+
if ((localeCount.get(entry.locale) ?? 0) > 1 && typeof entry.currency === "string" && entry.currency.length > 0) label += ` (${entry.currency})`;
|
|
34
|
+
return {
|
|
35
|
+
id: entry.id,
|
|
36
|
+
label
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
options.sort((a, b) => compareOptions(a, b, activeLocale));
|
|
40
|
+
return options;
|
|
41
|
+
}
|
|
42
|
+
function isCountedBinding(value) {
|
|
43
|
+
return typeof value === "object" && value !== null && typeof value.locale === "string";
|
|
44
|
+
}
|
|
45
|
+
function languageName(locale) {
|
|
46
|
+
try {
|
|
47
|
+
const name = new Intl.DisplayNames([locale], {
|
|
48
|
+
type: "language",
|
|
49
|
+
languageDisplay: "standard"
|
|
50
|
+
}).of(locale);
|
|
51
|
+
if (!name) return locale;
|
|
52
|
+
return name;
|
|
53
|
+
} catch {
|
|
54
|
+
return locale;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function compareOptions(a, b, activeLocale) {
|
|
58
|
+
try {
|
|
59
|
+
return a.label.localeCompare(b.label, activeLocale) || a.id.localeCompare(b.id, activeLocale);
|
|
60
|
+
} catch {
|
|
61
|
+
return a.label.localeCompare(b.label) || a.id.localeCompare(b.id);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const NOTICE_DEFAULT = "This page isn't available in the selected language.";
|
|
65
|
+
/** How long the control stays disabled after a started navigation that never unloads the page. */
|
|
66
|
+
const NAVIGATION_TIMEOUT_MS = 1e4;
|
|
67
|
+
const LABEL_DEFAULT = "Language";
|
|
68
|
+
const BindingSwitcherDefinition = defineComponent({
|
|
69
|
+
name: "BindingSwitcher",
|
|
70
|
+
importPath: "@vtex/faststore/components",
|
|
71
|
+
component: BindingSwitcher,
|
|
72
|
+
editor: {
|
|
73
|
+
label: "Binding Switcher",
|
|
74
|
+
category: "action"
|
|
75
|
+
},
|
|
76
|
+
actions: { locale: ["set"] },
|
|
77
|
+
schema: {
|
|
78
|
+
bindings: {
|
|
79
|
+
type: "object",
|
|
80
|
+
label: "Bindings"
|
|
81
|
+
},
|
|
82
|
+
label: {
|
|
83
|
+
type: "string",
|
|
84
|
+
default: "Language",
|
|
85
|
+
label: "Label"
|
|
86
|
+
},
|
|
87
|
+
notice: {
|
|
88
|
+
type: "string",
|
|
89
|
+
default: "This page isn't available in the selected language.",
|
|
90
|
+
label: "Notice"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
guideline: "Lists the bindings a store declares and switches the whole binding (locale, currency, sales channel) through locale.set. Renders nothing when fewer than two bindings are present; the store passes bindings as $data.Global.localization.bindings."
|
|
94
|
+
});
|
|
95
|
+
function BindingSwitcher({ bindings, label, notice, $actions: $actionsProp, className, ...props }) {
|
|
96
|
+
const $actions = useActionsOverride($actionsProp);
|
|
97
|
+
const { bindingId, locale } = useStorefrontContext();
|
|
98
|
+
const options = useMemo(() => bindingSwitcherOptions(bindings, locale), [bindings, locale]);
|
|
99
|
+
const [pending, setPending] = useState(false);
|
|
100
|
+
const { path } = useStorefrontRoute();
|
|
101
|
+
const [noticePath, setNoticePath] = useState(null);
|
|
102
|
+
const noticeVisible = noticePath !== null && noticePath === path;
|
|
103
|
+
const pendingTimeout = useRef(void 0);
|
|
104
|
+
const labelText = resolveAuthoredCopy(label, LABEL_DEFAULT);
|
|
105
|
+
const noticeText = resolveAuthoredCopy(notice, NOTICE_DEFAULT);
|
|
106
|
+
const optionCount = options.length;
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (optionCount < 2) return;
|
|
109
|
+
const url = new URL(globalThis.location.href);
|
|
110
|
+
if (url.searchParams.get("fs_notice") !== "no-equivalent") return;
|
|
111
|
+
setNoticePath(path);
|
|
112
|
+
url.searchParams.delete("fs_notice");
|
|
113
|
+
globalThis.history.replaceState(globalThis.history.state, "", `${url.pathname}${url.search}${url.hash}`);
|
|
114
|
+
}, [optionCount, path]);
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (noticePath !== null && path !== noticePath) setNoticePath(null);
|
|
117
|
+
}, [noticePath, path]);
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
function onPageShow(event) {
|
|
120
|
+
if (!event.persisted) return;
|
|
121
|
+
clearTimeout(pendingTimeout.current);
|
|
122
|
+
setPending(false);
|
|
123
|
+
}
|
|
124
|
+
globalThis.addEventListener("pageshow", onPageShow);
|
|
125
|
+
return () => {
|
|
126
|
+
globalThis.removeEventListener("pageshow", onPageShow);
|
|
127
|
+
clearTimeout(pendingTimeout.current);
|
|
128
|
+
};
|
|
129
|
+
}, []);
|
|
130
|
+
async function handleChange(value) {
|
|
131
|
+
if (value === null || value === bindingId) return;
|
|
132
|
+
const set = $actions?.locale?.set;
|
|
133
|
+
if (!set) {
|
|
134
|
+
console.error("[BindingSwitcher] no locale.set");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
setPending(true);
|
|
138
|
+
let navigated = false;
|
|
139
|
+
try {
|
|
140
|
+
navigated = await set({ bindingId: value }) === true;
|
|
141
|
+
} finally {
|
|
142
|
+
if (navigated) pendingTimeout.current = setTimeout(() => setPending(false), NAVIGATION_TIMEOUT_MS);
|
|
143
|
+
else setPending(false);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (optionCount < 2) return null;
|
|
147
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
148
|
+
...props,
|
|
149
|
+
className,
|
|
150
|
+
"data-fs-binding-switcher": "",
|
|
151
|
+
"aria-busy": pending || void 0,
|
|
152
|
+
...pending ? { "data-fs-binding-switcher-pending": "" } : {},
|
|
153
|
+
children: [noticeVisible ? /* @__PURE__ */ jsx("output", {
|
|
154
|
+
"data-fs-binding-switcher-notice": "",
|
|
155
|
+
children: noticeText
|
|
156
|
+
}) : null, /* @__PURE__ */ jsxs(Select.Root, {
|
|
157
|
+
value: bindingId,
|
|
158
|
+
onValueChange: handleChange,
|
|
159
|
+
disabled: pending,
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ jsx(Select.Label, { children: labelText }),
|
|
162
|
+
/* @__PURE__ */ jsxs(Select.Trigger, {
|
|
163
|
+
disabled: pending,
|
|
164
|
+
children: [/* @__PURE__ */ jsx(Select.Value, { children: (value) => options.find((option) => option.id === value)?.label ?? value ?? "" }), /* @__PURE__ */ jsx(Select.Icon, { children: "▾" })]
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ jsx(Select.Positioner, {
|
|
167
|
+
align: "start",
|
|
168
|
+
sideOffset: 4,
|
|
169
|
+
alignItemWithTrigger: false,
|
|
170
|
+
children: /* @__PURE__ */ jsx(Select.Popup, { children: /* @__PURE__ */ jsx(Select.List, { children: options.map((option) => /* @__PURE__ */ jsx(Select.Item, {
|
|
171
|
+
value: option.id,
|
|
172
|
+
label: option.label,
|
|
173
|
+
children: option.label
|
|
174
|
+
}, option.id)) }) })
|
|
175
|
+
})
|
|
176
|
+
]
|
|
177
|
+
})]
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
//#endregion
|
|
181
|
+
export { BindingSwitcher, BindingSwitcherDefinition, LABEL_DEFAULT, NOTICE_DEFAULT, bindingSwitcherOptions };
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=binding-switcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding-switcher.js","names":[],"sources":["../../../src/particles/binding-switcher/binding-switcher.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport { type ComponentPropsWithRef, useEffect, useMemo, useRef, useState } from 'react';\nimport { useActionsOverride } from '../../sdk/actions/actions-override-context.js';\nimport type { ComponentActions } from '../../sdk/actions/types.js';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useStorefrontRoute } from '../../sdk/navigation/use-storefront-route.js';\nimport { resolveAuthoredCopy } from '../../utils/resolve-authored-copy.js';\nimport { Select } from '../select/select.js';\n\nexport type BindingSwitcherBinding = {\n locale?: unknown;\n currency?: unknown;\n salesChannel?: unknown;\n url?: unknown;\n country?: unknown;\n timezone?: unknown;\n};\n\ntype BindingSwitcherOption = {\n id: string;\n label: string;\n};\n\n/**\n * `foundation.json` `localization.bindings`, keyed by binding id. An entry counts only when it is an\n * own key, the value is a non-null object, and `locale` is a string. Fewer than two counted\n * entries yields an empty list.\n */\nexport function bindingSwitcherOptions(\n bindings: Record<string, BindingSwitcherBinding> | null | undefined,\n activeLocale: string,\n): { id: string; label: string }[] {\n if (bindings == null) return [];\n\n const counted: { id: string; locale: string; currency: unknown }[] = [];\n for (const [id, value] of Object.entries(bindings)) {\n if (!isCountedBinding(value)) continue;\n counted.push({ id, locale: value.locale, currency: value.currency });\n }\n if (counted.length < 2) return [];\n\n const localeCount = new Map<string, number>();\n for (const entry of counted) {\n localeCount.set(entry.locale, (localeCount.get(entry.locale) ?? 0) + 1);\n }\n\n const options = counted.map((entry) => {\n let label = languageName(entry.locale);\n const shared = (localeCount.get(entry.locale) ?? 0) > 1;\n if (shared && typeof entry.currency === 'string' && entry.currency.length > 0) {\n label += ` (${entry.currency})`;\n }\n return { id: entry.id, label };\n });\n\n options.sort((a, b) => compareOptions(a, b, activeLocale));\n return options;\n}\n\nfunction isCountedBinding(value: unknown): value is BindingSwitcherBinding & { locale: string } {\n return typeof value === 'object' && value !== null && typeof (value as BindingSwitcherBinding).locale === 'string';\n}\n\nfunction languageName(locale: string): string {\n try {\n const name = new Intl.DisplayNames([locale], { type: 'language', languageDisplay: 'standard' }).of(locale);\n if (!name) return locale;\n return name;\n } catch {\n return locale;\n }\n}\n\nfunction compareOptions(a: BindingSwitcherOption, b: BindingSwitcherOption, activeLocale: string): number {\n try {\n return a.label.localeCompare(b.label, activeLocale) || a.id.localeCompare(b.id, activeLocale);\n } catch {\n return a.label.localeCompare(b.label) || a.id.localeCompare(b.id);\n }\n}\n\nexport const NOTICE_DEFAULT = \"This page isn't available in the selected language.\";\n/** How long the control stays disabled after a started navigation that never unloads the page. */\nconst NAVIGATION_TIMEOUT_MS = 10_000;\n\nexport const LABEL_DEFAULT = 'Language';\n\nexport type BindingSwitcherProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {\n /** `foundation.json` `localization.bindings`, keyed by binding id. No library default. */\n bindings?: Record<string, BindingSwitcherBinding> | null;\n /** Accessible name, rendered as `Select.Label`. */\n label?: string;\n /** Shown when the page loaded with `fs_notice=no-equivalent`. */\n notice?: string;\n /** Injected from `actions: { locale: ['set'] }`. */\n $actions?: ComponentActions;\n};\n\nexport const BindingSwitcherDefinition = defineComponent<BindingSwitcherProps>({\n name: 'BindingSwitcher',\n importPath: '@vtex/faststore/components',\n component: BindingSwitcher,\n editor: { label: 'Binding Switcher', category: 'action' },\n actions: { locale: ['set'] },\n schema: {\n bindings: { type: 'object', label: 'Bindings' },\n // Inline rather than `LABEL_DEFAULT` / `NOTICE_DEFAULT`: the catalog scanner reads this file\n // statically and drops a nested identifier it cannot evaluate. The strings match those constants.\n label: { type: 'string', default: 'Language', label: 'Label' },\n notice: {\n type: 'string',\n default: \"This page isn't available in the selected language.\",\n label: 'Notice',\n },\n },\n guideline:\n 'Lists the bindings a store declares and switches the whole binding (locale, currency, sales channel) through locale.set. Renders nothing when fewer than two bindings are present; the store passes bindings as $data.Global.localization.bindings.',\n});\n\nexport function BindingSwitcher({\n bindings,\n label,\n notice,\n $actions: $actionsProp,\n className,\n ...props\n}: BindingSwitcherProps) {\n const $actions = useActionsOverride($actionsProp);\n const { bindingId, locale } = useStorefrontContext();\n const options = useMemo(() => bindingSwitcherOptions(bindings, locale), [bindings, locale]);\n const [pending, setPending] = useState(false);\n const { path } = useStorefrontRoute();\n // The path the notice arrived on: the layout stays mounted across client navigations, and the\n // notice belongs to that one visit of the page it was shown on.\n const [noticePath, setNoticePath] = useState<string | null>(null);\n const noticeVisible = noticePath !== null && noticePath === path;\n const pendingTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const labelText = resolveAuthoredCopy(label, LABEL_DEFAULT);\n const noticeText = resolveAuthoredCopy(notice, NOTICE_DEFAULT);\n const optionCount = options.length;\n\n // Hidden on the first render. `location` is read after mount so the notice cannot mismatch\n // hydration, and so a store with fewer than two bindings leaves the query alone.\n useEffect(() => {\n if (optionCount < 2) return;\n const url = new URL(globalThis.location.href);\n if (url.searchParams.get('fs_notice') !== 'no-equivalent') return;\n setNoticePath(path);\n url.searchParams.delete('fs_notice');\n globalThis.history.replaceState(globalThis.history.state, '', `${url.pathname}${url.search}${url.hash}`);\n }, [optionCount, path]);\n\n useEffect(() => {\n if (noticePath !== null && path !== noticePath) setNoticePath(null);\n }, [noticePath, path]);\n\n // A page restored from the back/forward cache comes back with the state it left with.\n useEffect(() => {\n function onPageShow(event: PageTransitionEvent) {\n if (!event.persisted) return;\n clearTimeout(pendingTimeout.current);\n setPending(false);\n }\n globalThis.addEventListener('pageshow', onPageShow);\n return () => {\n globalThis.removeEventListener('pageshow', onPageShow);\n clearTimeout(pendingTimeout.current);\n };\n }, []);\n\n async function handleChange(value: string | null) {\n if (value === null || value === bindingId) return;\n const set = $actions?.locale?.set;\n if (!set) {\n console.error('[BindingSwitcher] no locale.set');\n return;\n }\n setPending(true);\n let navigated = false;\n try {\n navigated = (await set({ bindingId: value })) === true;\n } finally {\n // A started navigation keeps the control disabled until the next document replaces this one, or\n // until the timeout when the page never unloads (a cancelled `beforeunload`, a 204, a download).\n if (navigated) {\n pendingTimeout.current = setTimeout(() => setPending(false), NAVIGATION_TIMEOUT_MS);\n } else {\n setPending(false);\n }\n }\n }\n\n if (optionCount < 2) return null;\n\n return (\n <div\n {...props}\n className={className}\n data-fs-binding-switcher=\"\"\n aria-busy={pending || undefined}\n {...(pending ? { 'data-fs-binding-switcher-pending': '' } : {})}\n >\n {noticeVisible ? <output data-fs-binding-switcher-notice=\"\">{noticeText}</output> : null}\n <Select.Root value={bindingId} onValueChange={handleChange} disabled={pending}>\n <Select.Label>{labelText}</Select.Label>\n <Select.Trigger disabled={pending}>\n <Select.Value>{(value) => options.find((option) => option.id === value)?.label ?? value ?? ''}</Select.Value>\n <Select.Icon>▾</Select.Icon>\n </Select.Trigger>\n <Select.Positioner align=\"start\" sideOffset={4} alignItemWithTrigger={false}>\n <Select.Popup>\n <Select.List>\n {options.map((option) => (\n <Select.Item key={option.id} value={option.id} label={option.label}>\n {option.label}\n </Select.Item>\n ))}\n </Select.List>\n </Select.Popup>\n </Select.Positioner>\n </Select.Root>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/particles/card-summary/card-network.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The one network → mark mapping every card surface shares, so a name marks the same everywhere.
|
|
4
|
+
* Values are base-dialect names only; a network outside it renders by name, never with a wrong mark.
|
|
5
|
+
*/
|
|
6
|
+
export type CardNetworkIconName = 'visa' | 'mastercard' | 'amex' | 'diners' | 'elo-card';
|
|
7
|
+
/** Network key (name lowercased, non-letters removed) → base-dialect icon name. */
|
|
8
|
+
export declare const CARD_NETWORK_ICON_BY_KEY: Readonly<Record<string, CardNetworkIconName>>;
|
|
9
|
+
/**
|
|
10
|
+
* Distinct icon names the map can produce. A store that renders a card mark lists these under
|
|
11
|
+
* `icons.include` in its `foundation.json`: the names come from data, so the compiler cannot see them.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CARD_NETWORK_ICON_NAMES: readonly CardNetworkIconName[];
|
|
14
|
+
/** The base-dialect icon for a network's display name, or `null` when unmapped. */
|
|
15
|
+
export declare function cardNetworkIcon(name: string): CardNetworkIconName | null;
|
|
16
|
+
//#endregion
|
|
17
|
+
//# sourceMappingURL=card-network.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/particles/card-summary/card-network.ts
|
|
2
|
+
/** Network key (name lowercased, non-letters removed) → base-dialect icon name. */
|
|
3
|
+
const CARD_NETWORK_ICON_BY_KEY = Object.freeze({
|
|
4
|
+
visa: "visa",
|
|
5
|
+
mastercard: "mastercard",
|
|
6
|
+
amex: "amex",
|
|
7
|
+
americanexpress: "amex",
|
|
8
|
+
diners: "diners",
|
|
9
|
+
dinersclub: "diners",
|
|
10
|
+
elo: "elo-card"
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Distinct icon names the map can produce. A store that renders a card mark lists these under
|
|
14
|
+
* `icons.include` in its `foundation.json`: the names come from data, so the compiler cannot see them.
|
|
15
|
+
*/
|
|
16
|
+
const CARD_NETWORK_ICON_NAMES = Object.freeze([...new Set(Object.values(CARD_NETWORK_ICON_BY_KEY))]);
|
|
17
|
+
/** The base-dialect icon for a network's display name, or `null` when unmapped. */
|
|
18
|
+
function cardNetworkIcon(name) {
|
|
19
|
+
const key = name.toLowerCase().replaceAll(/[^a-z]/g, "");
|
|
20
|
+
return Object.hasOwn(CARD_NETWORK_ICON_BY_KEY, key) ? CARD_NETWORK_ICON_BY_KEY[key] ?? null : null;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { CARD_NETWORK_ICON_BY_KEY, CARD_NETWORK_ICON_NAMES, cardNetworkIcon };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=card-network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-network.js","names":[],"sources":["../../../src/particles/card-summary/card-network.ts"],"sourcesContent":["/**\n * The one network → mark mapping every card surface shares, so a name marks the same everywhere.\n * Values are base-dialect names only; a network outside it renders by name, never with a wrong mark.\n */\n\nexport type CardNetworkIconName = 'visa' | 'mastercard' | 'amex' | 'diners' | 'elo-card';\n\n/** Network key (name lowercased, non-letters removed) → base-dialect icon name. */\nexport const CARD_NETWORK_ICON_BY_KEY: Readonly<Record<string, CardNetworkIconName>> = Object.freeze({\n visa: 'visa',\n mastercard: 'mastercard',\n amex: 'amex',\n americanexpress: 'amex',\n diners: 'diners',\n dinersclub: 'diners',\n elo: 'elo-card',\n});\n\n/**\n * Distinct icon names the map can produce. A store that renders a card mark lists these under\n * `icons.include` in its `foundation.json`: the names come from data, so the compiler cannot see them.\n */\nexport const CARD_NETWORK_ICON_NAMES: readonly CardNetworkIconName[] = Object.freeze([\n ...new Set(Object.values(CARD_NETWORK_ICON_BY_KEY)),\n]);\n\n/** The base-dialect icon for a network's display name, or `null` when unmapped. */\nexport function cardNetworkIcon(name: string): CardNetworkIconName | null {\n const key = name.toLowerCase().replaceAll(/[^a-z]/g, '');\n // Own keys only: an inherited one (`constructor`) would hand Icon a function.\n return Object.hasOwn(CARD_NETWORK_ICON_BY_KEY, key) ? (CARD_NETWORK_ICON_BY_KEY[key] ?? null) : null;\n}\n"],"mappings":";;AAQA,MAAa,2BAA0E,OAAO,OAAO;CACnG,MAAM;CACN,YAAY;CACZ,MAAM;CACN,iBAAiB;CACjB,QAAQ;CACR,YAAY;CACZ,KAAK;AACP,CAAC;;;;;AAMD,MAAa,0BAA0D,OAAO,OAAO,CACnF,GAAG,IAAI,IAAI,OAAO,OAAO,wBAAwB,CAAC,CACpD,CAAC;;AAGD,SAAgB,gBAAgB,MAA0C;CACxE,MAAM,MAAM,KAAK,YAAY,CAAC,CAAC,WAAW,WAAW,EAAE;CAEvD,OAAO,OAAO,OAAO,0BAA0B,GAAG,IAAK,yBAAyB,QAAQ,OAAQ;AAClG"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ComponentDefinition } from "../../core/dist/define-component.js";
|
|
2
|
+
import "../../core/dist/index.js";
|
|
3
|
+
import { CardNetworkIconName } from "./card-network.js";
|
|
4
|
+
import { ReactNode } from "react";
|
|
5
|
+
//#region src/particles/card-summary/card-summary.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* CardSummary particle (no business coupling — ADR-0001): a saved card's identity — network mark,
|
|
8
|
+
* label or network name, mask, last four digits — as parts the schema arranges. A row that owns
|
|
9
|
+
* card data wraps its children in CardSummaryRoot and declares `card-summary` in its own
|
|
10
|
+
* providesContext; the parts read the card from there. Each part decides from the data, never from
|
|
11
|
+
* which other parts are composed, so any arrangement keeps the network identifiable.
|
|
12
|
+
*/
|
|
13
|
+
export type CardSummaryValue = Readonly<{
|
|
14
|
+
/** The network's display name as given. */
|
|
15
|
+
network: string;
|
|
16
|
+
/** The base-dialect icon for the network, or `null` when unmapped. */
|
|
17
|
+
icon: CardNetworkIconName | null;
|
|
18
|
+
/** The trimmed label, or `null` when absent or blank. */
|
|
19
|
+
label: string | null;
|
|
20
|
+
/** `label ?? network`, or `null` when both are blank. */
|
|
21
|
+
name: string | null;
|
|
22
|
+
/** At most four digits; `''` when none. */
|
|
23
|
+
lastFour: string;
|
|
24
|
+
}>;
|
|
25
|
+
/** The card the nearest CardSummaryRoot provides. Throws outside one. */
|
|
26
|
+
export declare function useCardSummary(): CardSummaryValue;
|
|
27
|
+
export type CardSummaryRootProps = Readonly<{
|
|
28
|
+
/** The network's display name from the platform, e.g. `Visa`. Selects the mark by exact key match. */
|
|
29
|
+
network: string;
|
|
30
|
+
/** The card's last digits. Only the trailing four digit characters ever reach the parts. */
|
|
31
|
+
lastDigits: string;
|
|
32
|
+
/** The shopper's own name for the card. Shown in place of the network name when non-blank. */
|
|
33
|
+
label?: string | null;
|
|
34
|
+
children?: ReactNode;
|
|
35
|
+
}>;
|
|
36
|
+
export type CardSummaryProps = Readonly<{
|
|
37
|
+
className?: string;
|
|
38
|
+
/** The parts, in order. Defaults to Mark, Name, Mask, Digits. */
|
|
39
|
+
children?: ReactNode;
|
|
40
|
+
}>;
|
|
41
|
+
export type CardSummaryPartProps = {
|
|
42
|
+
className?: string;
|
|
43
|
+
};
|
|
44
|
+
export type CardSummaryMarkProps = Readonly<CardSummaryPartProps>;
|
|
45
|
+
export type CardSummaryNameProps = Readonly<CardSummaryPartProps>;
|
|
46
|
+
export type CardSummaryDigitsProps = Readonly<CardSummaryPartProps>;
|
|
47
|
+
export type CardSummaryMaskProps = Readonly<CardSummaryPartProps & {
|
|
48
|
+
/** The masking symbol shown before the digits. Defaults to `••••`; empty renders nothing. */
|
|
49
|
+
mask?: string;
|
|
50
|
+
/** Replaces `mask`, e.g. with an icon. Always hidden from assistive technology. */
|
|
51
|
+
children?: ReactNode;
|
|
52
|
+
}>;
|
|
53
|
+
export declare const CardSummaryDefinition: ComponentDefinition<Readonly<{
|
|
54
|
+
className?: string;
|
|
55
|
+
/** The parts, in order. Defaults to Mark, Name, Mask, Digits. */
|
|
56
|
+
children?: ReactNode;
|
|
57
|
+
}>>;
|
|
58
|
+
export declare const CardSummaryMarkDefinition: ComponentDefinition<Readonly<CardSummaryPartProps>>;
|
|
59
|
+
export declare const CardSummaryNameDefinition: ComponentDefinition<Readonly<CardSummaryPartProps>>;
|
|
60
|
+
export declare const CardSummaryMaskDefinition: ComponentDefinition<Readonly<CardSummaryPartProps & {
|
|
61
|
+
/** The masking symbol shown before the digits. Defaults to `••••`; empty renders nothing. */
|
|
62
|
+
mask?: string;
|
|
63
|
+
/** Replaces `mask`, e.g. with an icon. Always hidden from assistive technology. */
|
|
64
|
+
children?: ReactNode;
|
|
65
|
+
}>>;
|
|
66
|
+
export declare const CardSummaryDigitsDefinition: ComponentDefinition<Readonly<CardSummaryPartProps>>;
|
|
67
|
+
/**
|
|
68
|
+
* Provides one card to the parts, keeping only its last four digits. No definition on purpose: a
|
|
69
|
+
* schema cannot supply the card, so a matter row renders it and declares 'card-summary' itself.
|
|
70
|
+
*/
|
|
71
|
+
export declare function CardSummaryRoot({ network, lastDigits, label, children }: CardSummaryRootProps): import("react/jsx-runtime").JSX.Element;
|
|
72
|
+
/** The wrapper: the composed parts, or Mark, Name, Mask and Digits by default. */
|
|
73
|
+
export declare function CardSummary({ className, children }: CardSummaryProps): import("react/jsx-runtime").JSX.Element;
|
|
74
|
+
/** The network's mark, and the network itself when a label takes the name. */
|
|
75
|
+
export declare function CardSummaryMark({ className }: CardSummaryMarkProps): import("react/jsx-runtime").JSX.Element | null;
|
|
76
|
+
/** The label, or else the network name. Renders nothing when both are blank. */
|
|
77
|
+
export declare function CardSummaryName({ className }: CardSummaryNameProps): import("react/jsx-runtime").JSX.Element | null;
|
|
78
|
+
/** Decoration for the hidden digits. Renders nothing when empty or when there are no digits. */
|
|
79
|
+
export declare function CardSummaryMask({ className, mask, children }: CardSummaryMaskProps): import("react/jsx-runtime").JSX.Element | null;
|
|
80
|
+
/** The last four digits, read as "ending in" them. Renders nothing when there are no digits. */
|
|
81
|
+
export declare function CardSummaryDigits({ className }: CardSummaryDigitsProps): import("react/jsx-runtime").JSX.Element | null;
|
|
82
|
+
//#endregion
|
|
83
|
+
//# sourceMappingURL=card-summary.d.ts.map
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { defineComponent } from "../../core/dist/define-component.js";
|
|
3
|
+
import "../../core/dist/index.js";
|
|
4
|
+
import { useIntl } from "../../sdk/i18n/client.js";
|
|
5
|
+
import { Icon } from "../icon/icon.js";
|
|
6
|
+
import { cardNetworkIcon } from "./card-network.js";
|
|
7
|
+
import { createContext, useContext, useMemo } from "react";
|
|
8
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/particles/card-summary/card-summary.tsx
|
|
10
|
+
const CardSummaryContext = createContext(null);
|
|
11
|
+
/** The card the nearest CardSummaryRoot provides. Throws outside one. */
|
|
12
|
+
function useCardSummary() {
|
|
13
|
+
const ctx = useContext(CardSummaryContext);
|
|
14
|
+
if (!ctx) throw new Error("CardSummary parts must be used inside CardSummaryRoot.");
|
|
15
|
+
return ctx;
|
|
16
|
+
}
|
|
17
|
+
const CardSummaryDefinition = defineComponent({
|
|
18
|
+
name: "CardSummary",
|
|
19
|
+
importPath: "@vtex/faststore/components",
|
|
20
|
+
component: CardSummary,
|
|
21
|
+
requiresContext: "card-summary",
|
|
22
|
+
editor: {
|
|
23
|
+
label: "Card Summary",
|
|
24
|
+
category: "content"
|
|
25
|
+
},
|
|
26
|
+
schema: {},
|
|
27
|
+
guideline: "A saved card's identity: network mark, label or else network name, mask, last four digits, in that order by default. Compose CardSummaryMark / Name / Mask / Digits as children to reorder or drop a part; the reading order follows the composition. The default satisfies the rule that the mark and the digits always show; a custom composition that drops either gives that up. Must be inside a card-summary provider."
|
|
28
|
+
});
|
|
29
|
+
const CardSummaryMarkDefinition = defineComponent({
|
|
30
|
+
name: "CardSummaryMark",
|
|
31
|
+
importPath: "@vtex/faststore/components",
|
|
32
|
+
component: CardSummaryMark,
|
|
33
|
+
requiresContext: "card-summary",
|
|
34
|
+
editor: {
|
|
35
|
+
label: "Card Summary Mark",
|
|
36
|
+
category: "content"
|
|
37
|
+
},
|
|
38
|
+
schema: {},
|
|
39
|
+
guideline: "The card network's mark. When the card has a label, it also carries the network: hidden text beside the mark, or the network name as visible text for a network with no mark. Renders nothing for an unlabelled card on a network with no mark, since the name says it. On an unlabelled card the glyph is decorative and CardSummaryName announces the network, so compose both: Mark without Name leaves screen readers no network. Marks come from data, so the store lists CARD_NETWORK_ICON_NAMES under icons.include. Must be inside a card-summary provider."
|
|
40
|
+
});
|
|
41
|
+
const CardSummaryNameDefinition = defineComponent({
|
|
42
|
+
name: "CardSummaryName",
|
|
43
|
+
importPath: "@vtex/faststore/components",
|
|
44
|
+
component: CardSummaryName,
|
|
45
|
+
requiresContext: "card-summary",
|
|
46
|
+
editor: {
|
|
47
|
+
label: "Card Summary Name",
|
|
48
|
+
category: "content"
|
|
49
|
+
},
|
|
50
|
+
schema: {},
|
|
51
|
+
guideline: "The shopper's label for the card, or else its network name; nothing when both are blank. Read-only. On an unlabelled card it is the only part a screen reader hears the network from. Must be inside a card-summary provider."
|
|
52
|
+
});
|
|
53
|
+
const CardSummaryMaskDefinition = defineComponent({
|
|
54
|
+
name: "CardSummaryMask",
|
|
55
|
+
importPath: "@vtex/faststore/components",
|
|
56
|
+
component: CardSummaryMask,
|
|
57
|
+
requiresContext: "card-summary",
|
|
58
|
+
editor: {
|
|
59
|
+
label: "Card Summary Mask",
|
|
60
|
+
category: "content"
|
|
61
|
+
},
|
|
62
|
+
schema: { mask: {
|
|
63
|
+
type: "string",
|
|
64
|
+
default: "••••",
|
|
65
|
+
label: "Mask"
|
|
66
|
+
} },
|
|
67
|
+
guideline: "Decoration standing for the hidden digits: the mask text (•••• by default), or children such as an icon in its place. Keep children inline. Always hidden from assistive technology; dropping it changes nothing a screen reader hears. Renders nothing when empty or when the card has no digits. Must be inside a card-summary provider."
|
|
68
|
+
});
|
|
69
|
+
const CardSummaryDigitsDefinition = defineComponent({
|
|
70
|
+
name: "CardSummaryDigits",
|
|
71
|
+
importPath: "@vtex/faststore/components",
|
|
72
|
+
component: CardSummaryDigits,
|
|
73
|
+
requiresContext: "card-summary",
|
|
74
|
+
editor: {
|
|
75
|
+
label: "Card Summary Digits",
|
|
76
|
+
category: "content"
|
|
77
|
+
},
|
|
78
|
+
schema: {},
|
|
79
|
+
guideline: "The last four digits, announced to screen readers as \"ending in\" and the digits. Never more than four digits. Renders nothing when the card has no digits. Must be inside a card-summary provider."
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Provides one card to the parts, keeping only its last four digits. No definition on purpose: a
|
|
83
|
+
* schema cannot supply the card, so a matter row renders it and declares 'card-summary' itself.
|
|
84
|
+
*/
|
|
85
|
+
function CardSummaryRoot({ network, lastDigits, label, children }) {
|
|
86
|
+
const value = useMemo(() => {
|
|
87
|
+
const trimmedLabel = label?.trim() || null;
|
|
88
|
+
return {
|
|
89
|
+
network,
|
|
90
|
+
icon: cardNetworkIcon(network),
|
|
91
|
+
label: trimmedLabel,
|
|
92
|
+
name: trimmedLabel ?? (network.trim() ? network : null),
|
|
93
|
+
lastFour: lastDigits.replaceAll(/\D/g, "").slice(-4)
|
|
94
|
+
};
|
|
95
|
+
}, [
|
|
96
|
+
network,
|
|
97
|
+
lastDigits,
|
|
98
|
+
label
|
|
99
|
+
]);
|
|
100
|
+
return /* @__PURE__ */ jsx(CardSummaryContext.Provider, {
|
|
101
|
+
value,
|
|
102
|
+
children
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** The wrapper: the composed parts, or Mark, Name, Mask and Digits by default. */
|
|
106
|
+
function CardSummary({ className, children }) {
|
|
107
|
+
const { icon, label } = useCardSummary();
|
|
108
|
+
return /* @__PURE__ */ jsx("span", {
|
|
109
|
+
className,
|
|
110
|
+
"data-fs-card-summary": "",
|
|
111
|
+
"data-fs-card-summary-network": icon ?? void 0,
|
|
112
|
+
...label ? { "data-fs-card-summary-labeled": "" } : {},
|
|
113
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
114
|
+
/* @__PURE__ */ jsx(CardSummaryMark, {}),
|
|
115
|
+
/* @__PURE__ */ jsx(CardSummaryName, {}),
|
|
116
|
+
/* @__PURE__ */ jsx(CardSummaryMask, {}),
|
|
117
|
+
/* @__PURE__ */ jsx(CardSummaryDigits, {})
|
|
118
|
+
] })
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/** The network's mark, and the network itself when a label takes the name. */
|
|
122
|
+
function CardSummaryMark({ className }) {
|
|
123
|
+
const { network, icon, label } = useCardSummary();
|
|
124
|
+
if (!icon && (!label || !network.trim())) return null;
|
|
125
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
|
|
126
|
+
className,
|
|
127
|
+
"data-fs-card-summary-mark": "",
|
|
128
|
+
children: [
|
|
129
|
+
icon ? /* @__PURE__ */ jsx(Icon, {
|
|
130
|
+
name: icon,
|
|
131
|
+
"data-fs-card-summary-icon": ""
|
|
132
|
+
}) : null,
|
|
133
|
+
label && icon ? /* @__PURE__ */ jsx("span", {
|
|
134
|
+
"data-fs-sr-only": "",
|
|
135
|
+
className: "sr-only",
|
|
136
|
+
children: network
|
|
137
|
+
}) : null,
|
|
138
|
+
label && !icon ? /* @__PURE__ */ jsx("span", {
|
|
139
|
+
"data-fs-card-summary-network-name": "",
|
|
140
|
+
children: network
|
|
141
|
+
}) : null
|
|
142
|
+
]
|
|
143
|
+
}), " "] });
|
|
144
|
+
}
|
|
145
|
+
/** The label, or else the network name. Renders nothing when both are blank. */
|
|
146
|
+
function CardSummaryName({ className }) {
|
|
147
|
+
const { name } = useCardSummary();
|
|
148
|
+
if (!name) return null;
|
|
149
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
150
|
+
className,
|
|
151
|
+
"data-fs-card-summary-name": "",
|
|
152
|
+
children: name
|
|
153
|
+
}), " "] });
|
|
154
|
+
}
|
|
155
|
+
/** Decoration for the hidden digits. Renders nothing when empty or when there are no digits. */
|
|
156
|
+
function CardSummaryMask({ className, mask = "••••", children }) {
|
|
157
|
+
const { lastFour } = useCardSummary();
|
|
158
|
+
const content = children ?? mask;
|
|
159
|
+
if (!lastFour || !content) return null;
|
|
160
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
161
|
+
className,
|
|
162
|
+
"data-fs-card-summary-mask": "",
|
|
163
|
+
"aria-hidden": "true",
|
|
164
|
+
children: content
|
|
165
|
+
}), " "] });
|
|
166
|
+
}
|
|
167
|
+
/** The last four digits, read as "ending in" them. Renders nothing when there are no digits. */
|
|
168
|
+
function CardSummaryDigits({ className }) {
|
|
169
|
+
const { lastFour } = useCardSummary();
|
|
170
|
+
const intl = useIntl();
|
|
171
|
+
if (!lastFour) return null;
|
|
172
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
|
|
173
|
+
className,
|
|
174
|
+
"data-fs-card-summary-digits": "",
|
|
175
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
176
|
+
"aria-hidden": "true",
|
|
177
|
+
children: lastFour
|
|
178
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
179
|
+
"data-fs-sr-only": "",
|
|
180
|
+
className: "sr-only",
|
|
181
|
+
children: intl.formatMessage({ id: "fs/card.ending-in" }, { lastDigits: lastFour })
|
|
182
|
+
})]
|
|
183
|
+
}), " "] });
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
export { CardSummary, CardSummaryDefinition, CardSummaryDigits, CardSummaryDigitsDefinition, CardSummaryMark, CardSummaryMarkDefinition, CardSummaryMask, CardSummaryMaskDefinition, CardSummaryName, CardSummaryNameDefinition, CardSummaryRoot, useCardSummary };
|
|
187
|
+
|
|
188
|
+
//# sourceMappingURL=card-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-summary.js","names":[],"sources":["../../../src/particles/card-summary/card-summary.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport { createContext, type ReactNode, useContext, useMemo } from 'react';\nimport { useIntl } from '../../sdk/i18n/client.js';\nimport { Icon } from '../icon/icon.js';\nimport { type CardNetworkIconName, cardNetworkIcon } from './card-network.js';\n\n/**\n * CardSummary particle (no business coupling — ADR-0001): a saved card's identity — network mark,\n * label or network name, mask, last four digits — as parts the schema arranges. A row that owns\n * card data wraps its children in CardSummaryRoot and declares `card-summary` in its own\n * providesContext; the parts read the card from there. Each part decides from the data, never from\n * which other parts are composed, so any arrangement keeps the network identifiable.\n */\n\nexport type CardSummaryValue = Readonly<{\n /** The network's display name as given. */\n network: string;\n /** The base-dialect icon for the network, or `null` when unmapped. */\n icon: CardNetworkIconName | null;\n /** The trimmed label, or `null` when absent or blank. */\n label: string | null;\n /** `label ?? network`, or `null` when both are blank. */\n name: string | null;\n /** At most four digits; `''` when none. */\n lastFour: string;\n}>;\n\nconst CardSummaryContext = createContext<CardSummaryValue | null>(null);\n\n/** The card the nearest CardSummaryRoot provides. Throws outside one. */\nexport function useCardSummary(): CardSummaryValue {\n const ctx = useContext(CardSummaryContext);\n if (!ctx) throw new Error('CardSummary parts must be used inside CardSummaryRoot.');\n return ctx;\n}\n\nexport type CardSummaryRootProps = Readonly<{\n /** The network's display name from the platform, e.g. `Visa`. Selects the mark by exact key match. */\n network: string;\n /** The card's last digits. Only the trailing four digit characters ever reach the parts. */\n lastDigits: string;\n /** The shopper's own name for the card. Shown in place of the network name when non-blank. */\n label?: string | null;\n children?: ReactNode;\n}>;\n\nexport type CardSummaryProps = Readonly<{\n className?: string;\n /** The parts, in order. Defaults to Mark, Name, Mask, Digits. */\n children?: ReactNode;\n}>;\n\nexport type CardSummaryPartProps = {\n className?: string;\n};\n\nexport type CardSummaryMarkProps = Readonly<CardSummaryPartProps>;\n\nexport type CardSummaryNameProps = Readonly<CardSummaryPartProps>;\n\nexport type CardSummaryDigitsProps = Readonly<CardSummaryPartProps>;\n\nexport type CardSummaryMaskProps = Readonly<\n CardSummaryPartProps & {\n /** The masking symbol shown before the digits. Defaults to `••••`; empty renders nothing. */\n mask?: string;\n /** Replaces `mask`, e.g. with an icon. Always hidden from assistive technology. */\n children?: ReactNode;\n }\n>;\n\nexport const CardSummaryDefinition = defineComponent<CardSummaryProps>({\n name: 'CardSummary',\n importPath: '@vtex/faststore/components',\n component: CardSummary,\n requiresContext: 'card-summary',\n editor: { label: 'Card Summary', category: 'content' },\n schema: {},\n guideline:\n \"A saved card's identity: network mark, label or else network name, mask, last four digits, in that order by default. Compose CardSummaryMark / Name / Mask / Digits as children to reorder or drop a part; the reading order follows the composition. The default satisfies the rule that the mark and the digits always show; a custom composition that drops either gives that up. Must be inside a card-summary provider.\",\n});\n\nexport const CardSummaryMarkDefinition = defineComponent<CardSummaryMarkProps>({\n name: 'CardSummaryMark',\n importPath: '@vtex/faststore/components',\n component: CardSummaryMark,\n requiresContext: 'card-summary',\n editor: { label: 'Card Summary Mark', category: 'content' },\n schema: {},\n guideline:\n \"The card network's mark. When the card has a label, it also carries the network: hidden text beside the mark, or the network name as visible text for a network with no mark. Renders nothing for an unlabelled card on a network with no mark, since the name says it. On an unlabelled card the glyph is decorative and CardSummaryName announces the network, so compose both: Mark without Name leaves screen readers no network. Marks come from data, so the store lists CARD_NETWORK_ICON_NAMES under icons.include. Must be inside a card-summary provider.\",\n});\n\nexport const CardSummaryNameDefinition = defineComponent<CardSummaryNameProps>({\n name: 'CardSummaryName',\n importPath: '@vtex/faststore/components',\n component: CardSummaryName,\n requiresContext: 'card-summary',\n editor: { label: 'Card Summary Name', category: 'content' },\n schema: {},\n guideline:\n \"The shopper's label for the card, or else its network name; nothing when both are blank. Read-only. On an unlabelled card it is the only part a screen reader hears the network from. Must be inside a card-summary provider.\",\n});\n\nexport const CardSummaryMaskDefinition = defineComponent<CardSummaryMaskProps>({\n name: 'CardSummaryMask',\n importPath: '@vtex/faststore/components',\n component: CardSummaryMask,\n requiresContext: 'card-summary',\n editor: { label: 'Card Summary Mask', category: 'content' },\n schema: {\n mask: { type: 'string', default: '••••', label: 'Mask' },\n },\n guideline:\n 'Decoration standing for the hidden digits: the mask text (•••• by default), or children such as an icon in its place. Keep children inline. Always hidden from assistive technology; dropping it changes nothing a screen reader hears. Renders nothing when empty or when the card has no digits. Must be inside a card-summary provider.',\n});\n\nexport const CardSummaryDigitsDefinition = defineComponent<CardSummaryDigitsProps>({\n name: 'CardSummaryDigits',\n importPath: '@vtex/faststore/components',\n component: CardSummaryDigits,\n requiresContext: 'card-summary',\n editor: { label: 'Card Summary Digits', category: 'content' },\n schema: {},\n guideline:\n 'The last four digits, announced to screen readers as \"ending in\" and the digits. Never more than four digits. Renders nothing when the card has no digits. Must be inside a card-summary provider.',\n});\n\n/**\n * Provides one card to the parts, keeping only its last four digits. No definition on purpose: a\n * schema cannot supply the card, so a matter row renders it and declares 'card-summary' itself.\n */\nexport function CardSummaryRoot({ network, lastDigits, label, children }: CardSummaryRootProps) {\n const value = useMemo<CardSummaryValue>(() => {\n const trimmedLabel = label?.trim() || null;\n return {\n network,\n icon: cardNetworkIcon(network),\n label: trimmedLabel,\n name: trimmedLabel ?? (network.trim() ? network : null),\n lastFour: lastDigits.replaceAll(/\\D/g, '').slice(-4),\n };\n }, [network, lastDigits, label]);\n\n return <CardSummaryContext.Provider value={value}>{children}</CardSummaryContext.Provider>;\n}\n\n/** The wrapper: the composed parts, or Mark, Name, Mask and Digits by default. */\nexport function CardSummary({ className, children }: CardSummaryProps) {\n const { icon, label } = useCardSummary();\n return (\n <span\n className={className}\n data-fs-card-summary=\"\"\n data-fs-card-summary-network={icon ?? undefined}\n {...(label ? { 'data-fs-card-summary-labeled': '' } : {})}\n >\n {children ?? (\n <>\n <CardSummaryMark />\n <CardSummaryName />\n <CardSummaryMask />\n <CardSummaryDigits />\n </>\n )}\n </span>\n );\n}\n\n// Each part ends with a space: accessible names concatenate inline siblings with no separator, so\n// without it a screen reader hears \"MastercardCompany card\". A flex container drops it visually.\n\n/** The network's mark, and the network itself when a label takes the name. */\nexport function CardSummaryMark({ className }: CardSummaryMarkProps) {\n const { network, icon, label } = useCardSummary();\n if (!icon && (!label || !network.trim())) return null;\n return (\n <>\n <span className={className} data-fs-card-summary-mark=\"\">\n {icon ? <Icon name={icon} data-fs-card-summary-icon=\"\" /> : null}\n {label && icon ? (\n <span data-fs-sr-only=\"\" className=\"sr-only\">\n {network}\n </span>\n ) : null}\n {label && !icon ? <span data-fs-card-summary-network-name=\"\">{network}</span> : null}\n </span>{' '}\n </>\n );\n}\n\n/** The label, or else the network name. Renders nothing when both are blank. */\nexport function CardSummaryName({ className }: CardSummaryNameProps) {\n const { name } = useCardSummary();\n if (!name) return null;\n return (\n <>\n <span className={className} data-fs-card-summary-name=\"\">\n {name}\n </span>{' '}\n </>\n );\n}\n\n/** Decoration for the hidden digits. Renders nothing when empty or when there are no digits. */\nexport function CardSummaryMask({ className, mask = '••••', children }: CardSummaryMaskProps) {\n const { lastFour } = useCardSummary();\n const content = children ?? mask;\n if (!lastFour || !content) return null;\n return (\n <>\n <span className={className} data-fs-card-summary-mask=\"\" aria-hidden=\"true\">\n {content}\n </span>{' '}\n </>\n );\n}\n\n/** The last four digits, read as \"ending in\" them. Renders nothing when there are no digits. */\nexport function CardSummaryDigits({ className }: CardSummaryDigitsProps) {\n const { lastFour } = useCardSummary();\n const intl = useIntl();\n if (!lastFour) return null;\n return (\n <>\n <span className={className} data-fs-card-summary-digits=\"\">\n <span aria-hidden=\"true\">{lastFour}</span>\n <span data-fs-sr-only=\"\" className=\"sr-only\">\n {intl.formatMessage({ id: 'fs/card.ending-in' }, { lastDigits: lastFour })}\n </span>\n </span>{' '}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -57,7 +57,7 @@ export declare const FooterSocialContent: {
|
|
|
57
57
|
};
|
|
58
58
|
/**
|
|
59
59
|
* The platform glyphs `platform` admits, every one verified to resolve. Exported because a store's
|
|
60
|
-
*
|
|
60
|
+
* foundation has to list them under `icons.include` for a CMS-chosen name to resolve at runtime —
|
|
61
61
|
* one import there instead of five retyped strings. Reading it off the model rather than declaring it
|
|
62
62
|
* beside one makes the two impossible to drift apart.
|
|
63
63
|
*/
|
|
@@ -65,7 +65,7 @@ const FooterSocialContent = defineContentType({
|
|
|
65
65
|
});
|
|
66
66
|
/**
|
|
67
67
|
* The platform glyphs `platform` admits, every one verified to resolve. Exported because a store's
|
|
68
|
-
*
|
|
68
|
+
* foundation has to list them under `icons.include` for a CMS-chosen name to resolve at runtime —
|
|
69
69
|
* one import there instead of five retyped strings. Reading it off the model rather than declaring it
|
|
70
70
|
* beside one makes the two impossible to drift apart.
|
|
71
71
|
*/
|