@hanzo/pay 0.1.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.
@@ -0,0 +1,226 @@
1
+ 'use strict';
2
+
3
+ var chunk64AUOMEL_cjs = require('../chunk-64AUOMEL.cjs');
4
+ var reactNativeSquareInAppPayments = require('react-native-square-in-app-payments');
5
+
6
+ // src/native/theme.ts
7
+ function colour(hex) {
8
+ if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`);
9
+ return {
10
+ r: parseInt(hex.slice(1, 3), 16),
11
+ g: parseInt(hex.slice(3, 5), 16),
12
+ b: parseInt(hex.slice(5, 7), 16),
13
+ a: 1
14
+ };
15
+ }
16
+ function appearance(p, theme) {
17
+ return {
18
+ backgroundColor: colour(p.field),
19
+ textColor: colour(p.text),
20
+ placeholderTextColor: colour(p.placeholder),
21
+ // The caret and the active field's accent — the native equivalent of the
22
+ // focused hairline, and the same value for the same reason.
23
+ tintColor: colour(p.borderFocus),
24
+ messageColor: colour(p.placeholder),
25
+ errorColor: colour(p.error),
26
+ saveButtonTextColor: colour(p.text),
27
+ keyboardAppearance: theme === "dark" ? "Dark" : "Light"
28
+ };
29
+ }
30
+
31
+ // src/native/terminal.ts
32
+ var BRAND = {
33
+ [reactNativeSquareInAppPayments.Brand.VISA]: "VISA",
34
+ [reactNativeSquareInAppPayments.Brand.MASTERCARD]: "MASTERCARD",
35
+ [reactNativeSquareInAppPayments.Brand.AMERICAN_EXPRESS]: "AMERICAN_EXPRESS",
36
+ [reactNativeSquareInAppPayments.Brand.DISCOVER]: "DISCOVER",
37
+ [reactNativeSquareInAppPayments.Brand.DISCOVER_DINERS]: "DISCOVER_DINERS",
38
+ [reactNativeSquareInAppPayments.Brand.JCB]: "JCB",
39
+ [reactNativeSquareInAppPayments.Brand.CHINA_UNION_PAY]: "CHINA_UNION_PAY",
40
+ [reactNativeSquareInAppPayments.Brand.SQUARE_GIFT_CARD]: "SQUARE_GIFT_CARD"
41
+ };
42
+ function token(method, d) {
43
+ if (!d.nonce) throw new Error(`${method} returned no token`);
44
+ return {
45
+ value: d.nonce,
46
+ method,
47
+ card: d.card ? {
48
+ brand: d.card.brand === void 0 ? void 0 : BRAND[d.card.brand],
49
+ last4: d.card.lastFourDigits,
50
+ expMonth: d.card.expirationMonth,
51
+ expYear: d.card.expirationYear
52
+ } : void 0
53
+ };
54
+ }
55
+ var Native = class {
56
+ constructor(config) {
57
+ this.config = config;
58
+ }
59
+ config;
60
+ /**
61
+ * What this DEVICE can pay with.
62
+ *
63
+ * Card and gift entry are always available — they are Square's own sheets and
64
+ * need no wallet, no saved card and no capability beyond the SDK being linked.
65
+ * The two wallets are asked, because both can be missing for reasons no
66
+ * user-agent string would reveal: no card in Wallet, no Play Services, a
67
+ * merchant id the app was not signed for.
68
+ *
69
+ * The tender is unused here. Native availability does not depend on the
70
+ * amount, unlike the web SDK, where the total is bound into the wallet object
71
+ * at construction — the interface carries it for the platform that needs it.
72
+ */
73
+ async offers(_tender) {
74
+ const out = ["card", "gift"];
75
+ if (this.config.appleMerchantId) {
76
+ try {
77
+ if (await reactNativeSquareInAppPayments.SQIPApplePay.canUseApplePay()) out.push("apple_pay");
78
+ } catch {
79
+ }
80
+ }
81
+ try {
82
+ if (await reactNativeSquareInAppPayments.SQIPGooglePay.canUseGooglePay()) out.push("google_pay");
83
+ } catch {
84
+ }
85
+ return out.filter((m) => chunk64AUOMEL_cjs.REACH.native.includes(m));
86
+ }
87
+ collect(method, tender, detail) {
88
+ if (!chunk64AUOMEL_cjs.REACH.native.includes(method)) {
89
+ return Promise.reject(new Error(`${method} is not a rail this SDK has`));
90
+ }
91
+ if (method === "card" || method === "gift") return this.sheet(method, detail);
92
+ if (method === "apple_pay") return this.apple(tender, detail);
93
+ return this.google(tender, detail);
94
+ }
95
+ /**
96
+ * Card and gift entry: one sheet, held open until the charge is known.
97
+ *
98
+ * The promise deliberately stays PENDING while the buyer retries. A declined
99
+ * card returns `{ success: false }`, which keeps Square's sheet up with the
100
+ * message shown and the card still entered — resolving or rejecting here would
101
+ * settle a payment the buyer is still in the middle of making.
102
+ */
103
+ sheet(method, detail) {
104
+ return new Promise((resolve, reject) => {
105
+ const onNonce = async (d) => {
106
+ let t;
107
+ try {
108
+ t = token(method, d);
109
+ } catch (e) {
110
+ return { success: false, errorMessage: message(e) };
111
+ }
112
+ if (detail?.charge) {
113
+ try {
114
+ await detail.charge(t);
115
+ } catch (e) {
116
+ return { success: false, errorMessage: message(e) };
117
+ }
118
+ }
119
+ return { success: true, onCardEntryComplete: () => resolve(t) };
120
+ };
121
+ const onCancel = () => reject(new chunk64AUOMEL_cjs.Cancelled(method));
122
+ if (method === "gift") reactNativeSquareInAppPayments.SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel);
123
+ else reactNativeSquareInAppPayments.SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel);
124
+ });
125
+ }
126
+ apple(tender, detail) {
127
+ return new Promise((resolve, reject) => {
128
+ let settled = null;
129
+ void reactNativeSquareInAppPayments.SQIPApplePay.requestApplePayNonce(
130
+ {
131
+ price: tender.total.amount,
132
+ summaryLabel: tender.label,
133
+ countryCode: tender.country,
134
+ currencyCode: tender.total.currency
135
+ },
136
+ async (d) => {
137
+ let t;
138
+ try {
139
+ t = token("apple_pay", d);
140
+ } catch (e) {
141
+ return { state: reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Failure, errorMessage: message(e) };
142
+ }
143
+ if (detail?.charge) {
144
+ try {
145
+ await detail.charge(t);
146
+ } catch (e) {
147
+ return { state: reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Failure, errorMessage: message(e) };
148
+ }
149
+ }
150
+ settled = t;
151
+ return { state: reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Succeeded };
152
+ },
153
+ (e) => reject(new Error(e.message)),
154
+ // The completion callback is the ONLY place that knows how the sheet
155
+ // ended, so it is the one that settles the promise.
156
+ //
157
+ // Annotated because `requestApplePayNonce` is overloaded and its
158
+ // DEPRECATED signature takes a bare `() => void` here — TypeScript picks
159
+ // that one and infers nothing, so the two arguments this needs would
160
+ // silently be `any`.
161
+ (state, errorMessage) => {
162
+ if (state === reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Succeeded && settled) resolve(settled);
163
+ else if (state === reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Canceled) reject(new chunk64AUOMEL_cjs.Cancelled("apple_pay"));
164
+ else reject(new Error(errorMessage || "Apple Pay could not be completed"));
165
+ }
166
+ );
167
+ });
168
+ }
169
+ google(tender, detail) {
170
+ return new Promise((resolve, reject) => {
171
+ void reactNativeSquareInAppPayments.SQIPGooglePay.requestGooglePayNonce(
172
+ {
173
+ price: tender.total.amount,
174
+ currencyCode: tender.total.currency,
175
+ // FINAL, because this total is what the host will charge. Quoting it
176
+ // as estimated invites Google to show a "price may change" sheet for a
177
+ // price that will not.
178
+ priceStatus: reactNativeSquareInAppPayments.GooglePayPriceStatus.TotalPriceStatusFinal
179
+ },
180
+ (d) => {
181
+ let t;
182
+ try {
183
+ t = token("google_pay", d);
184
+ } catch (e) {
185
+ reject(e);
186
+ return;
187
+ }
188
+ if (detail?.charge) {
189
+ detail.charge(t).then(() => resolve(t), reject);
190
+ return;
191
+ }
192
+ resolve(t);
193
+ },
194
+ (e) => reject(new Error(e.message)),
195
+ () => reject(new chunk64AUOMEL_cjs.Cancelled("google_pay"))
196
+ );
197
+ });
198
+ }
199
+ /** Nothing is held open between payments — every native rail is a sheet per call. */
200
+ async release() {
201
+ }
202
+ };
203
+ function message(e) {
204
+ return e instanceof Error ? e.message : "payment failed";
205
+ }
206
+ async function terminal(config) {
207
+ if (!config.applicationId || !config.locationId) {
208
+ throw new Error("Square is not configured for this build");
209
+ }
210
+ reactNativeSquareInAppPayments.SQIPCore.setSquareApplicationId(config.applicationId);
211
+ reactNativeSquareInAppPayments.SQIPCardEntry.setIOSCardEntryTheme(
212
+ appearance(config.palette ?? chunk64AUOMEL_cjs.PALETTE.dark, config.theme ?? "dark")
213
+ );
214
+ if (config.appleMerchantId) reactNativeSquareInAppPayments.SQIPApplePay.initializeApplePay(config.appleMerchantId);
215
+ reactNativeSquareInAppPayments.SQIPGooglePay.initializeGooglePay(
216
+ config.locationId,
217
+ (config.environment ?? "production").toLowerCase() === "sandbox" ? reactNativeSquareInAppPayments.GooglePayEnvironment.EnvironmentTest : reactNativeSquareInAppPayments.GooglePayEnvironment.EnvironmentProduction
218
+ );
219
+ return new Native(config);
220
+ }
221
+
222
+ exports.appearance = appearance;
223
+ exports.colour = colour;
224
+ exports.terminal = terminal;
225
+ //# sourceMappingURL=index.cjs.map
226
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/native/theme.ts","../../src/native/terminal.ts"],"names":["Brand","SQIPApplePay","SQIPGooglePay","REACH","Cancelled","SQIPCardEntry","ApplePayNonceSuccessState","GooglePayPriceStatus","SQIPCore","PALETTE","GooglePayEnvironment"],"mappings":"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","file":"index.cjs","sourcesContent":["// A `Palette` rendered as the In-App Payments SDK's theme.\n//\n// Same table as the web backend paints the iframe with, so a card field looks\n// the same on a phone as it does in a browser without anyone maintaining two\n// sets of colours. The SDK takes {r,g,b,a} components rather than CSS, which is\n// the entire difference.\n\nimport type { Palette, Theme } from '../palette'\n\n/** The SDK's colour, 0-255 per channel with an optional 0-1 alpha. */\nexport interface Colour {\n r: number\n g: number\n b: number\n a?: number\n}\n\n/**\n * `SQIPCardEntry.setIOSCardEntryTheme`'s argument, as much of it as a palette can\n * answer for. Structurally assignable to the plugin's own `ThemeType`.\n */\nexport interface Appearance {\n backgroundColor?: Colour\n textColor?: Colour\n placeholderTextColor?: Colour\n tintColor?: Colour\n messageColor?: Colour\n errorColor?: Colour\n saveButtonTextColor?: Colour\n keyboardAppearance?: 'Light' | 'Dark'\n}\n\n/** `#rrggbb` -> components. Throws rather than guessing: a silent 0,0,0 is black. */\nexport function colour(hex: string): Colour {\n if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`)\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n a: 1,\n }\n}\n\n/**\n * The native card sheet's appearance for `p`.\n *\n * TWO HONEST GAPS, both properties of the SDK rather than of this mapping:\n *\n * `border` has no counterpart. iOS draws its own field separators and exposes\n * no colour for them, so the palette's hairline is simply unused here. It is\n * not dropped by oversight and must not be mapped onto something else that\n * happens to accept a colour.\n *\n * THIS IS iOS ONLY. The setter is named for the platform it configures, and\n * Android's card entry is themed through native XML styles at build time —\n * there is no runtime channel to it at all. An Android build gets Square's\n * default sheet unless the app ships the corresponding style resource.\n *\n * `keyboardAppearance` is included because it is the one that gets noticed: a\n * light keyboard sliding up under a black sheet is the most visible seam on the\n * screen, and it is a single word to get right.\n */\nexport function appearance(p: Palette, theme: Theme): Appearance {\n return {\n backgroundColor: colour(p.field),\n textColor: colour(p.text),\n placeholderTextColor: colour(p.placeholder),\n // The caret and the active field's accent — the native equivalent of the\n // focused hairline, and the same value for the same reason.\n tintColor: colour(p.borderFocus),\n messageColor: colour(p.placeholder),\n errorColor: colour(p.error),\n saveButtonTextColor: colour(p.text),\n keyboardAppearance: theme === 'dark' ? 'Dark' : 'Light',\n }\n}\n","// Square's In-App Payments SDK behind the same `Terminal` interface the web\n// backend satisfies.\n//\n// The two SDKs are not parallel and this file is where that stops being the\n// host's problem:\n//\n// The web SDK hands back objects you attach and tokenize. This one exposes\n// NAMESPACES OF CALLBACK FUNCTIONS that present native UI — so every rail here\n// is a callback trio (success / failure / cancel) wrapped into one promise.\n//\n// There is nothing to mount. Card entry is a sheet the OS presents, so\n// `mount` is absent rather than a no-op, which is the honest signal to a host\n// that there is no element to position.\n//\n// Card entry is a STATE MACHINE, not a form: the sheet stays open after\n// minting the token and is told, afterwards, whether the charge worked. See\n// `Detail.charge`.\n//\n// Cash App Pay and ACH are absent from `REACH.native` because this SDK has no\n// such rail — not because they are unfinished.\n\nimport {\n SQIPApplePay,\n SQIPCardEntry,\n SQIPCore,\n SQIPGooglePay,\n Brand,\n GooglePayEnvironment,\n GooglePayPriceStatus,\n ApplePayNonceSuccessState,\n type ApplePayNonceSuccessResult,\n type CardDetails,\n type ErrorDetails,\n type NonceSuccessResult,\n} from 'react-native-square-in-app-payments'\n\nimport {\n type Detail,\n type Method,\n type Tender,\n type Terminal,\n type Token,\n Cancelled,\n REACH,\n} from '../terminal'\nimport { type Palette, PALETTE, type Theme } from '../palette'\nimport { appearance } from './theme'\n\nexport interface Config {\n applicationId: string\n locationId: string\n /** `'sandbox'` tokenizes against Square's sandbox. Anything else is production. */\n environment?: string\n /**\n * The Apple merchant id (`merchant.com.example`) from the app's entitlements.\n * Apple Pay is simply not offered without one — there is nothing to fall back\n * to, and a button that cannot open a sheet is worse than no button.\n */\n appleMerchantId?: string\n /** The card sheet's colours. Defaults to @hanzo/design's dark table. */\n palette?: Palette\n /** Chooses the keyboard's own appearance under the sheet. Defaults to dark. */\n theme?: Theme\n}\n\n/** The plugin's numeric brand enum, as the string the web SDK already reports. */\nconst BRAND: Partial<Record<Brand, string>> = {\n [Brand.VISA]: 'VISA',\n [Brand.MASTERCARD]: 'MASTERCARD',\n [Brand.AMERICAN_EXPRESS]: 'AMERICAN_EXPRESS',\n [Brand.DISCOVER]: 'DISCOVER',\n [Brand.DISCOVER_DINERS]: 'DISCOVER_DINERS',\n [Brand.JCB]: 'JCB',\n [Brand.CHINA_UNION_PAY]: 'CHINA_UNION_PAY',\n [Brand.SQUARE_GIFT_CARD]: 'SQUARE_GIFT_CARD',\n}\n\nfunction token(method: Method, d: CardDetails): Token {\n if (!d.nonce) throw new Error(`${method} returned no token`)\n return {\n value: d.nonce,\n method,\n card: d.card\n ? {\n brand: d.card.brand === undefined ? undefined : BRAND[d.card.brand],\n last4: d.card.lastFourDigits,\n expMonth: d.card.expirationMonth,\n expYear: d.card.expirationYear,\n }\n : undefined,\n }\n}\n\nclass Native implements Terminal {\n constructor(private readonly config: Config) {}\n\n /**\n * What this DEVICE can pay with.\n *\n * Card and gift entry are always available — they are Square's own sheets and\n * need no wallet, no saved card and no capability beyond the SDK being linked.\n * The two wallets are asked, because both can be missing for reasons no\n * user-agent string would reveal: no card in Wallet, no Play Services, a\n * merchant id the app was not signed for.\n *\n * The tender is unused here. Native availability does not depend on the\n * amount, unlike the web SDK, where the total is bound into the wallet object\n * at construction — the interface carries it for the platform that needs it.\n */\n async offers(_tender: Tender): Promise<Method[]> {\n const out: Method[] = ['card', 'gift']\n if (this.config.appleMerchantId) {\n try {\n if (await SQIPApplePay.canUseApplePay()) out.push('apple_pay')\n } catch {\n // Not offerable on this device. Say nothing, show nothing.\n }\n }\n try {\n if (await SQIPGooglePay.canUseGooglePay()) out.push('google_pay')\n } catch {\n // Likewise.\n }\n return out.filter((m) => REACH.native.includes(m))\n }\n\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token> {\n if (!REACH.native.includes(method)) {\n return Promise.reject(new Error(`${method} is not a rail this SDK has`))\n }\n if (method === 'card' || method === 'gift') return this.sheet(method, detail)\n if (method === 'apple_pay') return this.apple(tender, detail)\n return this.google(tender, detail)\n }\n\n /**\n * Card and gift entry: one sheet, held open until the charge is known.\n *\n * The promise deliberately stays PENDING while the buyer retries. A declined\n * card returns `{ success: false }`, which keeps Square's sheet up with the\n * message shown and the card still entered — resolving or rejecting here would\n * settle a payment the buyer is still in the middle of making.\n */\n private sheet(method: 'card' | 'gift', detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n const onNonce = async (d: CardDetails): Promise<NonceSuccessResult> => {\n let t: Token\n try {\n t = token(method, d)\n } catch (e) {\n return { success: false, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Stay on the sheet so the buyer can correct the card in place.\n return { success: false, errorMessage: message(e) }\n }\n }\n // `onCardEntryComplete` fires once the sheet has actually closed, so the\n // host's next screen never renders behind a dismissing modal.\n return { success: true, onCardEntryComplete: () => resolve(t) }\n }\n const onCancel = () => reject(new Cancelled(method))\n if (method === 'gift') SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel)\n // `false` collects no postal code: the billing address belongs to the\n // payer and the host's own checkout already owns it, so asking again\n // inside the sheet is a second answer to one question.\n else SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel)\n })\n }\n\n private apple(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n let settled: Token | null = null\n void SQIPApplePay.requestApplePayNonce(\n {\n price: tender.total.amount,\n summaryLabel: tender.label,\n countryCode: tender.country,\n currencyCode: tender.total.currency,\n },\n async (d: CardDetails): Promise<ApplePayNonceSuccessResult> => {\n let t: Token\n try {\n t = token('apple_pay', d)\n } catch (e) {\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Apple's sheet shows its own failure state and then closes; there\n // is no retry-in-place here the way there is for card entry.\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n }\n settled = t\n return { state: ApplePayNonceSuccessState.Succeeded }\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n // The completion callback is the ONLY place that knows how the sheet\n // ended, so it is the one that settles the promise.\n //\n // Annotated because `requestApplePayNonce` is overloaded and its\n // DEPRECATED signature takes a bare `() => void` here — TypeScript picks\n // that one and infers nothing, so the two arguments this needs would\n // silently be `any`.\n (state: ApplePayNonceSuccessState, errorMessage?: string) => {\n if (state === ApplePayNonceSuccessState.Succeeded && settled) resolve(settled)\n else if (state === ApplePayNonceSuccessState.Canceled) reject(new Cancelled('apple_pay'))\n else reject(new Error(errorMessage || 'Apple Pay could not be completed'))\n },\n )\n })\n }\n\n private google(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n void SQIPGooglePay.requestGooglePayNonce(\n {\n price: tender.total.amount,\n currencyCode: tender.total.currency,\n // FINAL, because this total is what the host will charge. Quoting it\n // as estimated invites Google to show a \"price may change\" sheet for a\n // price that will not.\n priceStatus: GooglePayPriceStatus.TotalPriceStatusFinal,\n },\n (d: CardDetails) => {\n let t: Token\n try {\n t = token('google_pay', d)\n } catch (e) {\n reject(e)\n return\n }\n // Google Pay's sheet has already closed by the time this fires, so a\n // charge failure here is the host's to show on its own screen.\n if (detail?.charge) {\n detail.charge(t).then(() => resolve(t), reject)\n return\n }\n resolve(t)\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n () => reject(new Cancelled('google_pay')),\n )\n })\n }\n\n /** Nothing is held open between payments — every native rail is a sheet per call. */\n async release(): Promise<void> {}\n}\n\nfunction message(e: unknown): string {\n return e instanceof Error ? e.message : 'payment failed'\n}\n\n/**\n * A terminal for this device.\n *\n * Configuration is GLOBAL to the SDK — `setSquareApplicationId`,\n * `initializeApplePay` and `initializeGooglePay` set process-wide state rather\n * than returning handles — so this applies it and returns a thin object over it.\n * Two terminals with different application ids cannot coexist; the last one\n * built wins. That is the SDK's shape, not a choice made here.\n */\nexport async function terminal(config: Config): Promise<Terminal> {\n if (!config.applicationId || !config.locationId) {\n throw new Error('Square is not configured for this build')\n }\n SQIPCore.setSquareApplicationId(config.applicationId)\n SQIPCardEntry.setIOSCardEntryTheme(\n appearance(config.palette ?? PALETTE.dark, config.theme ?? 'dark'),\n )\n if (config.appleMerchantId) SQIPApplePay.initializeApplePay(config.appleMerchantId)\n SQIPGooglePay.initializeGooglePay(\n config.locationId,\n (config.environment ?? 'production').toLowerCase() === 'sandbox'\n ? GooglePayEnvironment.EnvironmentTest\n : GooglePayEnvironment.EnvironmentProduction,\n )\n return new Native(config)\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { type Config, terminal } from './terminal';
2
+ export { type Appearance, type Colour, appearance, colour } from './theme';
@@ -0,0 +1,222 @@
1
+ import { PALETTE, REACH, Cancelled } from '../chunk-DXK2QDTX.js';
2
+ import { Brand, SQIPCore, SQIPCardEntry, SQIPApplePay, SQIPGooglePay, GooglePayEnvironment, ApplePayNonceSuccessState, GooglePayPriceStatus } from 'react-native-square-in-app-payments';
3
+
4
+ // src/native/theme.ts
5
+ function colour(hex) {
6
+ if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`);
7
+ return {
8
+ r: parseInt(hex.slice(1, 3), 16),
9
+ g: parseInt(hex.slice(3, 5), 16),
10
+ b: parseInt(hex.slice(5, 7), 16),
11
+ a: 1
12
+ };
13
+ }
14
+ function appearance(p, theme) {
15
+ return {
16
+ backgroundColor: colour(p.field),
17
+ textColor: colour(p.text),
18
+ placeholderTextColor: colour(p.placeholder),
19
+ // The caret and the active field's accent — the native equivalent of the
20
+ // focused hairline, and the same value for the same reason.
21
+ tintColor: colour(p.borderFocus),
22
+ messageColor: colour(p.placeholder),
23
+ errorColor: colour(p.error),
24
+ saveButtonTextColor: colour(p.text),
25
+ keyboardAppearance: theme === "dark" ? "Dark" : "Light"
26
+ };
27
+ }
28
+
29
+ // src/native/terminal.ts
30
+ var BRAND = {
31
+ [Brand.VISA]: "VISA",
32
+ [Brand.MASTERCARD]: "MASTERCARD",
33
+ [Brand.AMERICAN_EXPRESS]: "AMERICAN_EXPRESS",
34
+ [Brand.DISCOVER]: "DISCOVER",
35
+ [Brand.DISCOVER_DINERS]: "DISCOVER_DINERS",
36
+ [Brand.JCB]: "JCB",
37
+ [Brand.CHINA_UNION_PAY]: "CHINA_UNION_PAY",
38
+ [Brand.SQUARE_GIFT_CARD]: "SQUARE_GIFT_CARD"
39
+ };
40
+ function token(method, d) {
41
+ if (!d.nonce) throw new Error(`${method} returned no token`);
42
+ return {
43
+ value: d.nonce,
44
+ method,
45
+ card: d.card ? {
46
+ brand: d.card.brand === void 0 ? void 0 : BRAND[d.card.brand],
47
+ last4: d.card.lastFourDigits,
48
+ expMonth: d.card.expirationMonth,
49
+ expYear: d.card.expirationYear
50
+ } : void 0
51
+ };
52
+ }
53
+ var Native = class {
54
+ constructor(config) {
55
+ this.config = config;
56
+ }
57
+ config;
58
+ /**
59
+ * What this DEVICE can pay with.
60
+ *
61
+ * Card and gift entry are always available — they are Square's own sheets and
62
+ * need no wallet, no saved card and no capability beyond the SDK being linked.
63
+ * The two wallets are asked, because both can be missing for reasons no
64
+ * user-agent string would reveal: no card in Wallet, no Play Services, a
65
+ * merchant id the app was not signed for.
66
+ *
67
+ * The tender is unused here. Native availability does not depend on the
68
+ * amount, unlike the web SDK, where the total is bound into the wallet object
69
+ * at construction — the interface carries it for the platform that needs it.
70
+ */
71
+ async offers(_tender) {
72
+ const out = ["card", "gift"];
73
+ if (this.config.appleMerchantId) {
74
+ try {
75
+ if (await SQIPApplePay.canUseApplePay()) out.push("apple_pay");
76
+ } catch {
77
+ }
78
+ }
79
+ try {
80
+ if (await SQIPGooglePay.canUseGooglePay()) out.push("google_pay");
81
+ } catch {
82
+ }
83
+ return out.filter((m) => REACH.native.includes(m));
84
+ }
85
+ collect(method, tender, detail) {
86
+ if (!REACH.native.includes(method)) {
87
+ return Promise.reject(new Error(`${method} is not a rail this SDK has`));
88
+ }
89
+ if (method === "card" || method === "gift") return this.sheet(method, detail);
90
+ if (method === "apple_pay") return this.apple(tender, detail);
91
+ return this.google(tender, detail);
92
+ }
93
+ /**
94
+ * Card and gift entry: one sheet, held open until the charge is known.
95
+ *
96
+ * The promise deliberately stays PENDING while the buyer retries. A declined
97
+ * card returns `{ success: false }`, which keeps Square's sheet up with the
98
+ * message shown and the card still entered — resolving or rejecting here would
99
+ * settle a payment the buyer is still in the middle of making.
100
+ */
101
+ sheet(method, detail) {
102
+ return new Promise((resolve, reject) => {
103
+ const onNonce = async (d) => {
104
+ let t;
105
+ try {
106
+ t = token(method, d);
107
+ } catch (e) {
108
+ return { success: false, errorMessage: message(e) };
109
+ }
110
+ if (detail?.charge) {
111
+ try {
112
+ await detail.charge(t);
113
+ } catch (e) {
114
+ return { success: false, errorMessage: message(e) };
115
+ }
116
+ }
117
+ return { success: true, onCardEntryComplete: () => resolve(t) };
118
+ };
119
+ const onCancel = () => reject(new Cancelled(method));
120
+ if (method === "gift") SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel);
121
+ else SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel);
122
+ });
123
+ }
124
+ apple(tender, detail) {
125
+ return new Promise((resolve, reject) => {
126
+ let settled = null;
127
+ void SQIPApplePay.requestApplePayNonce(
128
+ {
129
+ price: tender.total.amount,
130
+ summaryLabel: tender.label,
131
+ countryCode: tender.country,
132
+ currencyCode: tender.total.currency
133
+ },
134
+ async (d) => {
135
+ let t;
136
+ try {
137
+ t = token("apple_pay", d);
138
+ } catch (e) {
139
+ return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) };
140
+ }
141
+ if (detail?.charge) {
142
+ try {
143
+ await detail.charge(t);
144
+ } catch (e) {
145
+ return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) };
146
+ }
147
+ }
148
+ settled = t;
149
+ return { state: ApplePayNonceSuccessState.Succeeded };
150
+ },
151
+ (e) => reject(new Error(e.message)),
152
+ // The completion callback is the ONLY place that knows how the sheet
153
+ // ended, so it is the one that settles the promise.
154
+ //
155
+ // Annotated because `requestApplePayNonce` is overloaded and its
156
+ // DEPRECATED signature takes a bare `() => void` here — TypeScript picks
157
+ // that one and infers nothing, so the two arguments this needs would
158
+ // silently be `any`.
159
+ (state, errorMessage) => {
160
+ if (state === ApplePayNonceSuccessState.Succeeded && settled) resolve(settled);
161
+ else if (state === ApplePayNonceSuccessState.Canceled) reject(new Cancelled("apple_pay"));
162
+ else reject(new Error(errorMessage || "Apple Pay could not be completed"));
163
+ }
164
+ );
165
+ });
166
+ }
167
+ google(tender, detail) {
168
+ return new Promise((resolve, reject) => {
169
+ void SQIPGooglePay.requestGooglePayNonce(
170
+ {
171
+ price: tender.total.amount,
172
+ currencyCode: tender.total.currency,
173
+ // FINAL, because this total is what the host will charge. Quoting it
174
+ // as estimated invites Google to show a "price may change" sheet for a
175
+ // price that will not.
176
+ priceStatus: GooglePayPriceStatus.TotalPriceStatusFinal
177
+ },
178
+ (d) => {
179
+ let t;
180
+ try {
181
+ t = token("google_pay", d);
182
+ } catch (e) {
183
+ reject(e);
184
+ return;
185
+ }
186
+ if (detail?.charge) {
187
+ detail.charge(t).then(() => resolve(t), reject);
188
+ return;
189
+ }
190
+ resolve(t);
191
+ },
192
+ (e) => reject(new Error(e.message)),
193
+ () => reject(new Cancelled("google_pay"))
194
+ );
195
+ });
196
+ }
197
+ /** Nothing is held open between payments — every native rail is a sheet per call. */
198
+ async release() {
199
+ }
200
+ };
201
+ function message(e) {
202
+ return e instanceof Error ? e.message : "payment failed";
203
+ }
204
+ async function terminal(config) {
205
+ if (!config.applicationId || !config.locationId) {
206
+ throw new Error("Square is not configured for this build");
207
+ }
208
+ SQIPCore.setSquareApplicationId(config.applicationId);
209
+ SQIPCardEntry.setIOSCardEntryTheme(
210
+ appearance(config.palette ?? PALETTE.dark, config.theme ?? "dark")
211
+ );
212
+ if (config.appleMerchantId) SQIPApplePay.initializeApplePay(config.appleMerchantId);
213
+ SQIPGooglePay.initializeGooglePay(
214
+ config.locationId,
215
+ (config.environment ?? "production").toLowerCase() === "sandbox" ? GooglePayEnvironment.EnvironmentTest : GooglePayEnvironment.EnvironmentProduction
216
+ );
217
+ return new Native(config);
218
+ }
219
+
220
+ export { appearance, colour, terminal };
221
+ //# sourceMappingURL=index.js.map
222
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/native/theme.ts","../../src/native/terminal.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// A `Palette` rendered as the In-App Payments SDK's theme.\n//\n// Same table as the web backend paints the iframe with, so a card field looks\n// the same on a phone as it does in a browser without anyone maintaining two\n// sets of colours. The SDK takes {r,g,b,a} components rather than CSS, which is\n// the entire difference.\n\nimport type { Palette, Theme } from '../palette'\n\n/** The SDK's colour, 0-255 per channel with an optional 0-1 alpha. */\nexport interface Colour {\n r: number\n g: number\n b: number\n a?: number\n}\n\n/**\n * `SQIPCardEntry.setIOSCardEntryTheme`'s argument, as much of it as a palette can\n * answer for. Structurally assignable to the plugin's own `ThemeType`.\n */\nexport interface Appearance {\n backgroundColor?: Colour\n textColor?: Colour\n placeholderTextColor?: Colour\n tintColor?: Colour\n messageColor?: Colour\n errorColor?: Colour\n saveButtonTextColor?: Colour\n keyboardAppearance?: 'Light' | 'Dark'\n}\n\n/** `#rrggbb` -> components. Throws rather than guessing: a silent 0,0,0 is black. */\nexport function colour(hex: string): Colour {\n if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`)\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n a: 1,\n }\n}\n\n/**\n * The native card sheet's appearance for `p`.\n *\n * TWO HONEST GAPS, both properties of the SDK rather than of this mapping:\n *\n * `border` has no counterpart. iOS draws its own field separators and exposes\n * no colour for them, so the palette's hairline is simply unused here. It is\n * not dropped by oversight and must not be mapped onto something else that\n * happens to accept a colour.\n *\n * THIS IS iOS ONLY. The setter is named for the platform it configures, and\n * Android's card entry is themed through native XML styles at build time —\n * there is no runtime channel to it at all. An Android build gets Square's\n * default sheet unless the app ships the corresponding style resource.\n *\n * `keyboardAppearance` is included because it is the one that gets noticed: a\n * light keyboard sliding up under a black sheet is the most visible seam on the\n * screen, and it is a single word to get right.\n */\nexport function appearance(p: Palette, theme: Theme): Appearance {\n return {\n backgroundColor: colour(p.field),\n textColor: colour(p.text),\n placeholderTextColor: colour(p.placeholder),\n // The caret and the active field's accent — the native equivalent of the\n // focused hairline, and the same value for the same reason.\n tintColor: colour(p.borderFocus),\n messageColor: colour(p.placeholder),\n errorColor: colour(p.error),\n saveButtonTextColor: colour(p.text),\n keyboardAppearance: theme === 'dark' ? 'Dark' : 'Light',\n }\n}\n","// Square's In-App Payments SDK behind the same `Terminal` interface the web\n// backend satisfies.\n//\n// The two SDKs are not parallel and this file is where that stops being the\n// host's problem:\n//\n// The web SDK hands back objects you attach and tokenize. This one exposes\n// NAMESPACES OF CALLBACK FUNCTIONS that present native UI — so every rail here\n// is a callback trio (success / failure / cancel) wrapped into one promise.\n//\n// There is nothing to mount. Card entry is a sheet the OS presents, so\n// `mount` is absent rather than a no-op, which is the honest signal to a host\n// that there is no element to position.\n//\n// Card entry is a STATE MACHINE, not a form: the sheet stays open after\n// minting the token and is told, afterwards, whether the charge worked. See\n// `Detail.charge`.\n//\n// Cash App Pay and ACH are absent from `REACH.native` because this SDK has no\n// such rail — not because they are unfinished.\n\nimport {\n SQIPApplePay,\n SQIPCardEntry,\n SQIPCore,\n SQIPGooglePay,\n Brand,\n GooglePayEnvironment,\n GooglePayPriceStatus,\n ApplePayNonceSuccessState,\n type ApplePayNonceSuccessResult,\n type CardDetails,\n type ErrorDetails,\n type NonceSuccessResult,\n} from 'react-native-square-in-app-payments'\n\nimport {\n type Detail,\n type Method,\n type Tender,\n type Terminal,\n type Token,\n Cancelled,\n REACH,\n} from '../terminal'\nimport { type Palette, PALETTE, type Theme } from '../palette'\nimport { appearance } from './theme'\n\nexport interface Config {\n applicationId: string\n locationId: string\n /** `'sandbox'` tokenizes against Square's sandbox. Anything else is production. */\n environment?: string\n /**\n * The Apple merchant id (`merchant.com.example`) from the app's entitlements.\n * Apple Pay is simply not offered without one — there is nothing to fall back\n * to, and a button that cannot open a sheet is worse than no button.\n */\n appleMerchantId?: string\n /** The card sheet's colours. Defaults to @hanzo/design's dark table. */\n palette?: Palette\n /** Chooses the keyboard's own appearance under the sheet. Defaults to dark. */\n theme?: Theme\n}\n\n/** The plugin's numeric brand enum, as the string the web SDK already reports. */\nconst BRAND: Partial<Record<Brand, string>> = {\n [Brand.VISA]: 'VISA',\n [Brand.MASTERCARD]: 'MASTERCARD',\n [Brand.AMERICAN_EXPRESS]: 'AMERICAN_EXPRESS',\n [Brand.DISCOVER]: 'DISCOVER',\n [Brand.DISCOVER_DINERS]: 'DISCOVER_DINERS',\n [Brand.JCB]: 'JCB',\n [Brand.CHINA_UNION_PAY]: 'CHINA_UNION_PAY',\n [Brand.SQUARE_GIFT_CARD]: 'SQUARE_GIFT_CARD',\n}\n\nfunction token(method: Method, d: CardDetails): Token {\n if (!d.nonce) throw new Error(`${method} returned no token`)\n return {\n value: d.nonce,\n method,\n card: d.card\n ? {\n brand: d.card.brand === undefined ? undefined : BRAND[d.card.brand],\n last4: d.card.lastFourDigits,\n expMonth: d.card.expirationMonth,\n expYear: d.card.expirationYear,\n }\n : undefined,\n }\n}\n\nclass Native implements Terminal {\n constructor(private readonly config: Config) {}\n\n /**\n * What this DEVICE can pay with.\n *\n * Card and gift entry are always available — they are Square's own sheets and\n * need no wallet, no saved card and no capability beyond the SDK being linked.\n * The two wallets are asked, because both can be missing for reasons no\n * user-agent string would reveal: no card in Wallet, no Play Services, a\n * merchant id the app was not signed for.\n *\n * The tender is unused here. Native availability does not depend on the\n * amount, unlike the web SDK, where the total is bound into the wallet object\n * at construction — the interface carries it for the platform that needs it.\n */\n async offers(_tender: Tender): Promise<Method[]> {\n const out: Method[] = ['card', 'gift']\n if (this.config.appleMerchantId) {\n try {\n if (await SQIPApplePay.canUseApplePay()) out.push('apple_pay')\n } catch {\n // Not offerable on this device. Say nothing, show nothing.\n }\n }\n try {\n if (await SQIPGooglePay.canUseGooglePay()) out.push('google_pay')\n } catch {\n // Likewise.\n }\n return out.filter((m) => REACH.native.includes(m))\n }\n\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token> {\n if (!REACH.native.includes(method)) {\n return Promise.reject(new Error(`${method} is not a rail this SDK has`))\n }\n if (method === 'card' || method === 'gift') return this.sheet(method, detail)\n if (method === 'apple_pay') return this.apple(tender, detail)\n return this.google(tender, detail)\n }\n\n /**\n * Card and gift entry: one sheet, held open until the charge is known.\n *\n * The promise deliberately stays PENDING while the buyer retries. A declined\n * card returns `{ success: false }`, which keeps Square's sheet up with the\n * message shown and the card still entered — resolving or rejecting here would\n * settle a payment the buyer is still in the middle of making.\n */\n private sheet(method: 'card' | 'gift', detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n const onNonce = async (d: CardDetails): Promise<NonceSuccessResult> => {\n let t: Token\n try {\n t = token(method, d)\n } catch (e) {\n return { success: false, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Stay on the sheet so the buyer can correct the card in place.\n return { success: false, errorMessage: message(e) }\n }\n }\n // `onCardEntryComplete` fires once the sheet has actually closed, so the\n // host's next screen never renders behind a dismissing modal.\n return { success: true, onCardEntryComplete: () => resolve(t) }\n }\n const onCancel = () => reject(new Cancelled(method))\n if (method === 'gift') SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel)\n // `false` collects no postal code: the billing address belongs to the\n // payer and the host's own checkout already owns it, so asking again\n // inside the sheet is a second answer to one question.\n else SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel)\n })\n }\n\n private apple(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n let settled: Token | null = null\n void SQIPApplePay.requestApplePayNonce(\n {\n price: tender.total.amount,\n summaryLabel: tender.label,\n countryCode: tender.country,\n currencyCode: tender.total.currency,\n },\n async (d: CardDetails): Promise<ApplePayNonceSuccessResult> => {\n let t: Token\n try {\n t = token('apple_pay', d)\n } catch (e) {\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Apple's sheet shows its own failure state and then closes; there\n // is no retry-in-place here the way there is for card entry.\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n }\n settled = t\n return { state: ApplePayNonceSuccessState.Succeeded }\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n // The completion callback is the ONLY place that knows how the sheet\n // ended, so it is the one that settles the promise.\n //\n // Annotated because `requestApplePayNonce` is overloaded and its\n // DEPRECATED signature takes a bare `() => void` here — TypeScript picks\n // that one and infers nothing, so the two arguments this needs would\n // silently be `any`.\n (state: ApplePayNonceSuccessState, errorMessage?: string) => {\n if (state === ApplePayNonceSuccessState.Succeeded && settled) resolve(settled)\n else if (state === ApplePayNonceSuccessState.Canceled) reject(new Cancelled('apple_pay'))\n else reject(new Error(errorMessage || 'Apple Pay could not be completed'))\n },\n )\n })\n }\n\n private google(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n void SQIPGooglePay.requestGooglePayNonce(\n {\n price: tender.total.amount,\n currencyCode: tender.total.currency,\n // FINAL, because this total is what the host will charge. Quoting it\n // as estimated invites Google to show a \"price may change\" sheet for a\n // price that will not.\n priceStatus: GooglePayPriceStatus.TotalPriceStatusFinal,\n },\n (d: CardDetails) => {\n let t: Token\n try {\n t = token('google_pay', d)\n } catch (e) {\n reject(e)\n return\n }\n // Google Pay's sheet has already closed by the time this fires, so a\n // charge failure here is the host's to show on its own screen.\n if (detail?.charge) {\n detail.charge(t).then(() => resolve(t), reject)\n return\n }\n resolve(t)\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n () => reject(new Cancelled('google_pay')),\n )\n })\n }\n\n /** Nothing is held open between payments — every native rail is a sheet per call. */\n async release(): Promise<void> {}\n}\n\nfunction message(e: unknown): string {\n return e instanceof Error ? e.message : 'payment failed'\n}\n\n/**\n * A terminal for this device.\n *\n * Configuration is GLOBAL to the SDK — `setSquareApplicationId`,\n * `initializeApplePay` and `initializeGooglePay` set process-wide state rather\n * than returning handles — so this applies it and returns a thin object over it.\n * Two terminals with different application ids cannot coexist; the last one\n * built wins. That is the SDK's shape, not a choice made here.\n */\nexport async function terminal(config: Config): Promise<Terminal> {\n if (!config.applicationId || !config.locationId) {\n throw new Error('Square is not configured for this build')\n }\n SQIPCore.setSquareApplicationId(config.applicationId)\n SQIPCardEntry.setIOSCardEntryTheme(\n appearance(config.palette ?? PALETTE.dark, config.theme ?? 'dark'),\n )\n if (config.appleMerchantId) SQIPApplePay.initializeApplePay(config.appleMerchantId)\n SQIPGooglePay.initializeGooglePay(\n config.locationId,\n (config.environment ?? 'production').toLowerCase() === 'sandbox'\n ? GooglePayEnvironment.EnvironmentTest\n : GooglePayEnvironment.EnvironmentProduction,\n )\n return new Native(config)\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { type Terminal } from '../terminal';
2
+ import { type Palette, type Theme } from '../palette';
3
+ export interface Config {
4
+ applicationId: string;
5
+ locationId: string;
6
+ /** `'sandbox'` tokenizes against Square's sandbox. Anything else is production. */
7
+ environment?: string;
8
+ /**
9
+ * The Apple merchant id (`merchant.com.example`) from the app's entitlements.
10
+ * Apple Pay is simply not offered without one — there is nothing to fall back
11
+ * to, and a button that cannot open a sheet is worse than no button.
12
+ */
13
+ appleMerchantId?: string;
14
+ /** The card sheet's colours. Defaults to @hanzo/design's dark table. */
15
+ palette?: Palette;
16
+ /** Chooses the keyboard's own appearance under the sheet. Defaults to dark. */
17
+ theme?: Theme;
18
+ }
19
+ /**
20
+ * A terminal for this device.
21
+ *
22
+ * Configuration is GLOBAL to the SDK — `setSquareApplicationId`,
23
+ * `initializeApplePay` and `initializeGooglePay` set process-wide state rather
24
+ * than returning handles — so this applies it and returns a thin object over it.
25
+ * Two terminals with different application ids cannot coexist; the last one
26
+ * built wins. That is the SDK's shape, not a choice made here.
27
+ */
28
+ export declare function terminal(config: Config): Promise<Terminal>;
@@ -0,0 +1,44 @@
1
+ import type { Palette, Theme } from '../palette';
2
+ /** The SDK's colour, 0-255 per channel with an optional 0-1 alpha. */
3
+ export interface Colour {
4
+ r: number;
5
+ g: number;
6
+ b: number;
7
+ a?: number;
8
+ }
9
+ /**
10
+ * `SQIPCardEntry.setIOSCardEntryTheme`'s argument, as much of it as a palette can
11
+ * answer for. Structurally assignable to the plugin's own `ThemeType`.
12
+ */
13
+ export interface Appearance {
14
+ backgroundColor?: Colour;
15
+ textColor?: Colour;
16
+ placeholderTextColor?: Colour;
17
+ tintColor?: Colour;
18
+ messageColor?: Colour;
19
+ errorColor?: Colour;
20
+ saveButtonTextColor?: Colour;
21
+ keyboardAppearance?: 'Light' | 'Dark';
22
+ }
23
+ /** `#rrggbb` -> components. Throws rather than guessing: a silent 0,0,0 is black. */
24
+ export declare function colour(hex: string): Colour;
25
+ /**
26
+ * The native card sheet's appearance for `p`.
27
+ *
28
+ * TWO HONEST GAPS, both properties of the SDK rather than of this mapping:
29
+ *
30
+ * `border` has no counterpart. iOS draws its own field separators and exposes
31
+ * no colour for them, so the palette's hairline is simply unused here. It is
32
+ * not dropped by oversight and must not be mapped onto something else that
33
+ * happens to accept a colour.
34
+ *
35
+ * THIS IS iOS ONLY. The setter is named for the platform it configures, and
36
+ * Android's card entry is themed through native XML styles at build time —
37
+ * there is no runtime channel to it at all. An Android build gets Square's
38
+ * default sheet unless the app ships the corresponding style resource.
39
+ *
40
+ * `keyboardAppearance` is included because it is the one that gets noticed: a
41
+ * light keyboard sliding up under a black sheet is the most visible seam on the
42
+ * screen, and it is a single word to get right.
43
+ */
44
+ export declare function appearance(p: Palette, theme: Theme): Appearance;
@@ -0,0 +1,39 @@
1
+ /** The two grounds a checkout can sit on. Dark is the default. */
2
+ export type Theme = 'dark' | 'light';
3
+ export interface Palette {
4
+ /** The field's own ground. */
5
+ field: string;
6
+ /** Hairline at rest. */
7
+ border: string;
8
+ /** Focused hairline. Deliberately >= 3:1 on `field`: it IS the focus indicator. */
9
+ borderFocus: string;
10
+ /** Typed characters. */
11
+ text: string;
12
+ /** Placeholder text. */
13
+ placeholder: string;
14
+ /** Validation text, icon and border. One error hue. */
15
+ error: string;
16
+ }
17
+ export declare const PALETTE: Record<Theme, Palette>;
18
+ /** `#rrggbb`, lowercase. The only form Square accepts on both platforms. */
19
+ export declare const HEX: RegExp;
20
+ /** Relative luminance, WCAG 2.x. */
21
+ export declare function luminance(hex: string): number;
22
+ /** Contrast ratio between two opaque hexes, 1..21. Order does not matter. */
23
+ export declare function ratio(a: string, b: string): number;
24
+ /** One failed contrast pair: what was measured, against what floor. */
25
+ export interface Fault {
26
+ pair: string;
27
+ ratio: number;
28
+ floor: number;
29
+ }
30
+ /**
31
+ * Every contrast pair in a palette that a customer must be able to read, with
32
+ * the WCAG floor each is held to.
33
+ *
34
+ * This is exported rather than kept in a test because a BRAND supplying its own
35
+ * table needs the same check, and the failure it catches is invisible in review:
36
+ * a reviewer looking at a dark mock cannot tell 2.6:1 from 4.4:1, and the focus
37
+ * ring is a WCAG 2.4.11 requirement rather than a preference.
38
+ */
39
+ export declare function legible(p: Palette): Fault[];