@gait-financial/react 0.1.12 → 0.1.15
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/README.md +25 -84
- package/dist/index.cjs +70 -191
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -23
- package/dist/index.d.ts +0 -23
- package/dist/index.js +71 -198
- package/dist/index.js.map +1 -1
- package/dist/register.cjs +17 -34
- package/dist/register.cjs.map +1 -1
- package/dist/register.d.cts +2 -16
- package/dist/register.d.ts +2 -16
- package/dist/register.js +17 -34
- package/dist/register.js.map +1 -1
- package/dist/wc/button.js +102 -1769
- package/package.json +1 -1
- package/wc/button.js +102 -1769
package/README.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# @gait-financial/react
|
|
2
2
|
|
|
3
|
-
React
|
|
3
|
+
React wrapper for Gait Web Components. Use `<GaitButton>` with `data-id` and optional props for checkout/split payment.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
5
|
+
## Install
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
npm install @gait-financial/react
|
|
@@ -12,103 +10,46 @@ npm install @gait-financial/react
|
|
|
12
10
|
|
|
13
11
|
## Setup
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Import the registration module once (e.g. in `_app.tsx`, `layout.tsx`, or your root component):
|
|
13
|
+
**1. Register once** (e.g. in your root or layout):
|
|
18
14
|
|
|
19
15
|
```tsx
|
|
20
16
|
import '@gait-financial/react/register';
|
|
21
17
|
```
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
**Alternative:** Load the Web Component via script tag and skip the register import:
|
|
26
|
-
|
|
27
|
-
```html
|
|
28
|
-
<script src="https://cdn.usegait.com/button.js"></script>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### 2. Use the Components
|
|
19
|
+
**2. Use the component:**
|
|
32
20
|
|
|
33
21
|
```tsx
|
|
34
22
|
import { GaitButton } from '@gait-financial/react';
|
|
35
23
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
onClick={(detail) => console.log('Clicked', detail)}
|
|
42
|
-
onSplitFeedback={(detail) => {
|
|
43
|
-
if (detail.success) console.log('Split sent!');
|
|
44
|
-
else console.error('Failed', detail.error);
|
|
45
|
-
}}
|
|
46
|
-
/>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
24
|
+
<GaitButton
|
|
25
|
+
data-id="your-checkout-id"
|
|
26
|
+
totalCost={99.99}
|
|
27
|
+
onSplitFeedback={(d) => console.log(d.success ? 'OK' : d.error)}
|
|
28
|
+
/>
|
|
49
29
|
```
|
|
50
30
|
|
|
51
|
-
## GaitButton Props
|
|
52
|
-
|
|
53
|
-
| Prop | Type | Description |
|
|
54
|
-
|------|------|-------------|
|
|
55
|
-
| `data-id` | `string` | Checkout/data identity (required for payments) |
|
|
56
|
-
| `disabled` | `boolean` | Disable the button |
|
|
57
|
-
| `size` | `'small' \| 'medium' \| 'large'` | Button size |
|
|
58
|
-
| `style` | `string \| React.CSSProperties` | Inline styles |
|
|
59
|
-
| `items` | `GaitButtonItem[] \| string` | Cart items for split payment modal |
|
|
60
|
-
| `priceBreakdown` | `GaitPriceBreakdownItem[] \| string` | Price breakdown |
|
|
61
|
-
| `totalCost` | `number \| string` | Total cost |
|
|
62
|
-
| `customer` | `GaitCustomer \| string` | Customer info for split payment |
|
|
63
|
-
| `webhook` | `GaitWebhook \| string` | Webhook config for split callbacks |
|
|
64
|
-
| `merchantStoreUrl` | `string` | Merchant store URL |
|
|
65
|
-
| `onClick` | `(detail) => void` | Button clicked |
|
|
66
|
-
| `onLoaded` | `(detail) => void` | Component loaded |
|
|
67
|
-
| `onDataProcessed` | `(detail) => void` | Data processed |
|
|
68
|
-
| `onSplitFeedback` | `(detail) => void` | Split payment API result |
|
|
69
|
-
| `onMerchantIdError` | `(detail) => void` | Merchant ID lookup failed |
|
|
70
|
-
| `onConfirm` | `(detail) => void` | Pay remaining confirmed |
|
|
71
|
-
|
|
72
|
-
The button label is always **"Gait"** (with icon). Brand color is fixed to **#4147BF**; split-option styling uses **#F3F2FF**.
|
|
73
|
-
|
|
74
31
|
## Vite
|
|
75
32
|
|
|
76
|
-
|
|
33
|
+
Add to `vite.config.ts` so the web component script loads:
|
|
77
34
|
|
|
78
35
|
```ts
|
|
79
|
-
|
|
80
|
-
optimizeDeps: {
|
|
81
|
-
exclude: ['@gait-financial/react'],
|
|
82
|
-
},
|
|
83
|
-
// ...
|
|
84
|
-
});
|
|
36
|
+
optimizeDeps: { exclude: ['@gait-financial/react'] },
|
|
85
37
|
```
|
|
86
38
|
|
|
87
|
-
##
|
|
88
|
-
|
|
89
|
-
The package uses `"use client"` directives. Import and use in Client Components:
|
|
90
|
-
|
|
91
|
-
```tsx
|
|
92
|
-
'use client';
|
|
93
|
-
|
|
94
|
-
import '@gait-financial/react/register';
|
|
95
|
-
import { GaitButton } from '@gait-financial/react';
|
|
96
|
-
|
|
97
|
-
export default function CheckoutPage() {
|
|
98
|
-
return <GaitButton data-id="your-checkout-id" />;
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Architecture
|
|
103
|
-
|
|
104
|
-
This package is a thin wrapper. The Web Component implementation is the source of truth. The structure allows adding other framework packages (e.g. `@gait/vue`, `@gait/svelte`) later without refactoring the core.
|
|
39
|
+
## Builds (from repo root)
|
|
105
40
|
|
|
106
|
-
|
|
41
|
+
- **Production:** `npm run publish:react` — builds WC + React package, publishes to `latest`
|
|
42
|
+
- **Staging:** `npm run publish:react:staging` — builds with `.env.staging`, publishes with tag `staging`
|
|
43
|
+
From `packages/react`: `npm run publish:staging`
|
|
107
44
|
|
|
108
|
-
|
|
45
|
+
## Props
|
|
109
46
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
47
|
+
| Prop | Description |
|
|
48
|
+
|------|-------------|
|
|
49
|
+
| `data-id` | Checkout identity (required for payments) |
|
|
50
|
+
| `totalCost` | Total amount |
|
|
51
|
+
| `items` | Cart items for split payment |
|
|
52
|
+
| `customer` | `{ email, name? }` |
|
|
53
|
+
| `webhook` | `{ url, body? }` for split callbacks |
|
|
54
|
+
| `disabled`, `size`, `style` | Button options |
|
|
55
|
+
| `onClick`, `onLoaded`, `onDataProcessed`, `onSplitFeedback`, `onMerchantIdError`, `onConfirm` | Event callbacks |
|
package/dist/index.cjs
CHANGED
|
@@ -41,45 +41,28 @@ var import_react = __toESM(require("react"), 1);
|
|
|
41
41
|
// src/register.ts
|
|
42
42
|
var import_meta = {};
|
|
43
43
|
var loadPromise = null;
|
|
44
|
-
|
|
45
|
-
if (typeof window === "undefined" || typeof customElements === "undefined")
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
44
|
+
function defineCustomElements(scriptUrl) {
|
|
45
|
+
if (typeof window === "undefined" || typeof customElements === "undefined") return Promise.resolve();
|
|
46
|
+
if (customElements.get("gait-button")) return Promise.resolve();
|
|
47
|
+
if (loadPromise) return loadPromise;
|
|
48
|
+
loadPromise = new Promise((resolve, reject) => {
|
|
49
|
+
let src;
|
|
50
|
+
if (scriptUrl) src = scriptUrl;
|
|
51
|
+
else {
|
|
52
|
+
try {
|
|
53
|
+
src = new URL("./wc/button.js", import_meta.url).href;
|
|
54
|
+
} catch {
|
|
55
|
+
reject(new Error('[@gait-financial/react] Could not resolve script. With Vite, add optimizeDeps: { exclude: ["@gait-financial/react"] } to vite.config.'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
55
59
|
const script = document.createElement("script");
|
|
56
60
|
script.async = true;
|
|
57
|
-
script.src =
|
|
61
|
+
script.src = src;
|
|
58
62
|
script.onload = () => resolve();
|
|
59
|
-
script.onerror = () => reject();
|
|
63
|
+
script.onerror = () => reject(new Error("[@gait-financial/react] Failed to load web component."));
|
|
60
64
|
document.head.appendChild(script);
|
|
61
65
|
});
|
|
62
|
-
loadPromise = (async () => {
|
|
63
|
-
const fallbackUrl = `${typeof window !== "undefined" ? window.location.origin : ""}/node_modules/@gait-financial/react/dist/wc/button.js`;
|
|
64
|
-
if (scriptUrl) {
|
|
65
|
-
await tryLoad(scriptUrl);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
try {
|
|
69
|
-
const url = new URL("./wc/button.js", import_meta.url).href;
|
|
70
|
-
await tryLoad(url);
|
|
71
|
-
return;
|
|
72
|
-
} catch {
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
await tryLoad(fallbackUrl);
|
|
76
|
-
return;
|
|
77
|
-
} catch {
|
|
78
|
-
throw new Error(
|
|
79
|
-
'[@gait-financial/react] Failed to load web component script. If using Vite, add optimizeDeps: { exclude: ["@gait-financial/react"] } to vite.config.'
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
})();
|
|
83
66
|
return loadPromise;
|
|
84
67
|
}
|
|
85
68
|
if (typeof window !== "undefined" && typeof customElements !== "undefined") {
|
|
@@ -87,7 +70,31 @@ if (typeof window !== "undefined" && typeof customElements !== "undefined") {
|
|
|
87
70
|
}
|
|
88
71
|
|
|
89
72
|
// src/components/GaitButton.tsx
|
|
90
|
-
|
|
73
|
+
var EVENT_HANDLERS = [
|
|
74
|
+
{ event: "gait-click", key: "onClick" },
|
|
75
|
+
{ event: "gait-loaded", key: "onLoaded" },
|
|
76
|
+
{ event: "gait-data-processed", key: "onDataProcessed" },
|
|
77
|
+
{ event: "gait-split-feedback", key: "onSplitFeedback" },
|
|
78
|
+
{ event: "gait-merchant-id-error", key: "onMerchantIdError" },
|
|
79
|
+
{ event: "gait-confirm", key: "onConfirm" }
|
|
80
|
+
];
|
|
81
|
+
function applyAttributes(el, props) {
|
|
82
|
+
const { "data-id": dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl } = props;
|
|
83
|
+
if (dataId !== void 0) el.setAttribute("data-id", dataId);
|
|
84
|
+
if (size !== void 0) el.setAttribute("size", size);
|
|
85
|
+
disabled ? el.setAttribute("disabled", "") : el.removeAttribute("disabled");
|
|
86
|
+
if (style !== void 0) {
|
|
87
|
+
const s = typeof style === "string" ? style : Object.entries(style).map(([k, v]) => `${k.replace(/([A-Z])/g, "-$1").toLowerCase()}: ${v}`).join("; ");
|
|
88
|
+
el.setAttribute("style", s);
|
|
89
|
+
}
|
|
90
|
+
if (items !== void 0) el.setAttribute("items", typeof items === "string" ? items : JSON.stringify(items));
|
|
91
|
+
if (priceBreakdown !== void 0) el.setAttribute("price-breakdown", typeof priceBreakdown === "string" ? priceBreakdown : JSON.stringify(priceBreakdown));
|
|
92
|
+
if (totalCost !== void 0) el.setAttribute("total-cost", String(totalCost));
|
|
93
|
+
if (customer !== void 0) el.setAttribute("customer", typeof customer === "string" ? customer : JSON.stringify(customer));
|
|
94
|
+
if (webhook !== void 0) el.setAttribute("webhook", typeof webhook === "string" ? webhook : JSON.stringify(webhook));
|
|
95
|
+
if (merchantStoreUrl !== void 0) el.setAttribute("merchant-store-url", merchantStoreUrl);
|
|
96
|
+
}
|
|
97
|
+
var GaitButton = (0, import_react.forwardRef)(function GaitButton2(props, ref) {
|
|
91
98
|
const {
|
|
92
99
|
"data-id": dataId,
|
|
93
100
|
disabled,
|
|
@@ -98,191 +105,63 @@ function setAttributes(el, props) {
|
|
|
98
105
|
totalCost,
|
|
99
106
|
customer,
|
|
100
107
|
webhook,
|
|
101
|
-
merchantStoreUrl
|
|
102
|
-
} = props;
|
|
103
|
-
if (dataId !== void 0) el.setAttribute("data-id", dataId);
|
|
104
|
-
if (size !== void 0) el.setAttribute("size", size);
|
|
105
|
-
if (disabled) el.setAttribute("disabled", "");
|
|
106
|
-
else el.removeAttribute("disabled");
|
|
107
|
-
if (style !== void 0) {
|
|
108
|
-
const styleStr = typeof style === "string" ? style : Object.entries(style).map(
|
|
109
|
-
([k, v]) => `${k.replace(/([A-Z])/g, "-$1").toLowerCase()}: ${v}`
|
|
110
|
-
).join("; ");
|
|
111
|
-
el.setAttribute("style", styleStr);
|
|
112
|
-
}
|
|
113
|
-
if (items !== void 0)
|
|
114
|
-
el.setAttribute(
|
|
115
|
-
"items",
|
|
116
|
-
typeof items === "string" ? items : JSON.stringify(items)
|
|
117
|
-
);
|
|
118
|
-
if (priceBreakdown !== void 0)
|
|
119
|
-
el.setAttribute(
|
|
120
|
-
"price-breakdown",
|
|
121
|
-
typeof priceBreakdown === "string" ? priceBreakdown : JSON.stringify(priceBreakdown)
|
|
122
|
-
);
|
|
123
|
-
if (totalCost !== void 0)
|
|
124
|
-
el.setAttribute("total-cost", String(totalCost));
|
|
125
|
-
if (customer !== void 0)
|
|
126
|
-
el.setAttribute(
|
|
127
|
-
"customer",
|
|
128
|
-
typeof customer === "string" ? customer : JSON.stringify(customer)
|
|
129
|
-
);
|
|
130
|
-
if (webhook !== void 0)
|
|
131
|
-
el.setAttribute(
|
|
132
|
-
"webhook",
|
|
133
|
-
typeof webhook === "string" ? webhook : JSON.stringify(webhook)
|
|
134
|
-
);
|
|
135
|
-
if (merchantStoreUrl !== void 0)
|
|
136
|
-
el.setAttribute("merchant-store-url", merchantStoreUrl);
|
|
137
|
-
}
|
|
138
|
-
var GaitButton = (0, import_react.forwardRef)(function GaitButton2({
|
|
139
|
-
"data-id": dataId,
|
|
140
|
-
disabled,
|
|
141
|
-
size,
|
|
142
|
-
style,
|
|
143
|
-
items,
|
|
144
|
-
priceBreakdown,
|
|
145
|
-
totalCost,
|
|
146
|
-
customer,
|
|
147
|
-
webhook,
|
|
148
|
-
merchantStoreUrl,
|
|
149
|
-
onClick,
|
|
150
|
-
onLoaded,
|
|
151
|
-
onDataProcessed,
|
|
152
|
-
onSplitFeedback,
|
|
153
|
-
onMerchantIdError,
|
|
154
|
-
onConfirm,
|
|
155
|
-
className,
|
|
156
|
-
id,
|
|
157
|
-
...rest
|
|
158
|
-
}, ref) {
|
|
159
|
-
const containerRef = (0, import_react.useRef)(null);
|
|
160
|
-
const elementRef = (0, import_react.useRef)(null);
|
|
161
|
-
const [isReady, setIsReady] = (0, import_react.useState)(false);
|
|
162
|
-
const callbackRef = (0, import_react.useRef)({
|
|
163
|
-
onClick,
|
|
164
|
-
onLoaded,
|
|
165
|
-
onDataProcessed,
|
|
166
|
-
onSplitFeedback,
|
|
167
|
-
onMerchantIdError,
|
|
168
|
-
onConfirm
|
|
169
|
-
});
|
|
170
|
-
callbackRef.current = {
|
|
108
|
+
merchantStoreUrl,
|
|
171
109
|
onClick,
|
|
172
110
|
onLoaded,
|
|
173
111
|
onDataProcessed,
|
|
174
112
|
onSplitFeedback,
|
|
175
113
|
onMerchantIdError,
|
|
176
|
-
onConfirm
|
|
177
|
-
|
|
114
|
+
onConfirm,
|
|
115
|
+
className,
|
|
116
|
+
id
|
|
117
|
+
} = props;
|
|
118
|
+
const containerRef = (0, import_react.useRef)(null);
|
|
119
|
+
const elementRef = (0, import_react.useRef)(null);
|
|
120
|
+
const [ready, setReady] = (0, import_react.useState)(false);
|
|
121
|
+
const callbacksRef = (0, import_react.useRef)({ onClick, onLoaded, onDataProcessed, onSplitFeedback, onMerchantIdError, onConfirm });
|
|
122
|
+
callbacksRef.current = { onClick, onLoaded, onDataProcessed, onSplitFeedback, onMerchantIdError, onConfirm };
|
|
178
123
|
(0, import_react.useImperativeHandle)(ref, () => elementRef.current, []);
|
|
179
124
|
(0, import_react.useEffect)(() => {
|
|
180
125
|
if (typeof customElements !== "undefined" && customElements.get("gait-button")) {
|
|
181
|
-
|
|
126
|
+
setReady(true);
|
|
182
127
|
return;
|
|
183
128
|
}
|
|
184
|
-
defineCustomElements().then(() =>
|
|
129
|
+
defineCustomElements().then(() => setReady(true), () => setReady(false));
|
|
185
130
|
}, []);
|
|
186
131
|
(0, import_react.useEffect)(() => {
|
|
187
|
-
if (!
|
|
188
|
-
return;
|
|
132
|
+
if (!ready || !containerRef.current) return;
|
|
189
133
|
const container = containerRef.current;
|
|
190
134
|
const el = document.createElement("gait-button");
|
|
191
|
-
|
|
192
|
-
"data-id": dataId,
|
|
193
|
-
disabled,
|
|
194
|
-
size,
|
|
195
|
-
style,
|
|
196
|
-
items,
|
|
197
|
-
priceBreakdown,
|
|
198
|
-
totalCost,
|
|
199
|
-
customer,
|
|
200
|
-
webhook,
|
|
201
|
-
merchantStoreUrl
|
|
202
|
-
});
|
|
135
|
+
applyAttributes(el, { "data-id": dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl });
|
|
203
136
|
if (className) el.className = className;
|
|
204
137
|
if (id) el.id = id;
|
|
205
|
-
|
|
206
|
-
|
|
138
|
+
const listeners = [];
|
|
139
|
+
EVENT_HANDLERS.forEach(({ event, key }) => {
|
|
140
|
+
const handler = (e) => {
|
|
141
|
+
const cb = callbacksRef.current[key];
|
|
142
|
+
if (cb && e instanceof CustomEvent && e.detail) cb(e.detail);
|
|
143
|
+
};
|
|
144
|
+
el.addEventListener(event, handler);
|
|
145
|
+
listeners.push(() => el.removeEventListener(event, handler));
|
|
207
146
|
});
|
|
208
|
-
const cbs = callbackRef.current;
|
|
209
|
-
const handleClick = (e) => {
|
|
210
|
-
if (cbs.onClick && e instanceof CustomEvent && e.detail)
|
|
211
|
-
cbs.onClick(e.detail);
|
|
212
|
-
};
|
|
213
|
-
const handleLoaded = (e) => {
|
|
214
|
-
if (cbs.onLoaded && e instanceof CustomEvent && e.detail)
|
|
215
|
-
cbs.onLoaded(e.detail);
|
|
216
|
-
};
|
|
217
|
-
const handleDataProcessed = (e) => {
|
|
218
|
-
if (cbs.onDataProcessed && e instanceof CustomEvent && e.detail)
|
|
219
|
-
cbs.onDataProcessed(e.detail);
|
|
220
|
-
};
|
|
221
|
-
const handleSplitFeedback = (e) => {
|
|
222
|
-
if (cbs.onSplitFeedback && e instanceof CustomEvent && e.detail)
|
|
223
|
-
cbs.onSplitFeedback(e.detail);
|
|
224
|
-
};
|
|
225
|
-
const handleMerchantIdError = (e) => {
|
|
226
|
-
if (cbs.onMerchantIdError && e instanceof CustomEvent && e.detail)
|
|
227
|
-
cbs.onMerchantIdError(e.detail);
|
|
228
|
-
};
|
|
229
|
-
const handleConfirm = (e) => {
|
|
230
|
-
if (cbs.onConfirm && e instanceof CustomEvent && e.detail)
|
|
231
|
-
cbs.onConfirm(e.detail);
|
|
232
|
-
};
|
|
233
|
-
el.addEventListener("gait-click", handleClick);
|
|
234
|
-
el.addEventListener("gait-loaded", handleLoaded);
|
|
235
|
-
el.addEventListener("gait-data-processed", handleDataProcessed);
|
|
236
|
-
el.addEventListener("gait-split-feedback", handleSplitFeedback);
|
|
237
|
-
el.addEventListener("gait-merchant-id-error", handleMerchantIdError);
|
|
238
|
-
el.addEventListener("gait-confirm", handleConfirm);
|
|
239
147
|
elementRef.current = el;
|
|
240
148
|
container.appendChild(el);
|
|
241
149
|
return () => {
|
|
242
|
-
|
|
243
|
-
el.
|
|
244
|
-
el.removeEventListener("gait-data-processed", handleDataProcessed);
|
|
245
|
-
el.removeEventListener("gait-split-feedback", handleSplitFeedback);
|
|
246
|
-
el.removeEventListener("gait-merchant-id-error", handleMerchantIdError);
|
|
247
|
-
el.removeEventListener("gait-confirm", handleConfirm);
|
|
248
|
-
container.removeChild(el);
|
|
150
|
+
listeners.forEach((off) => off());
|
|
151
|
+
if (el.parentNode) el.parentNode.removeChild(el);
|
|
249
152
|
elementRef.current = null;
|
|
250
153
|
};
|
|
251
|
-
}, [
|
|
154
|
+
}, [ready]);
|
|
252
155
|
(0, import_react.useEffect)(() => {
|
|
253
156
|
const el = elementRef.current;
|
|
254
157
|
if (!el) return;
|
|
255
|
-
|
|
256
|
-
"data-id": dataId,
|
|
257
|
-
disabled,
|
|
258
|
-
size,
|
|
259
|
-
style,
|
|
260
|
-
items,
|
|
261
|
-
priceBreakdown,
|
|
262
|
-
totalCost,
|
|
263
|
-
customer,
|
|
264
|
-
webhook,
|
|
265
|
-
merchantStoreUrl
|
|
266
|
-
});
|
|
158
|
+
applyAttributes(el, { "data-id": dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl });
|
|
267
159
|
if (className) el.className = className;
|
|
268
160
|
else el.removeAttribute("class");
|
|
269
161
|
if (id) el.id = id;
|
|
270
162
|
else el.removeAttribute("id");
|
|
271
|
-
}, [
|
|
272
|
-
|
|
273
|
-
disabled,
|
|
274
|
-
size,
|
|
275
|
-
style,
|
|
276
|
-
items,
|
|
277
|
-
priceBreakdown,
|
|
278
|
-
totalCost,
|
|
279
|
-
customer,
|
|
280
|
-
webhook,
|
|
281
|
-
merchantStoreUrl,
|
|
282
|
-
className,
|
|
283
|
-
id
|
|
284
|
-
]);
|
|
285
|
-
if (!isReady) return null;
|
|
163
|
+
}, [dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl, className, id]);
|
|
164
|
+
if (!ready) return null;
|
|
286
165
|
return import_react.default.createElement("div", { ref: containerRef });
|
|
287
166
|
});
|
|
288
167
|
GaitButton.displayName = "GaitButton";
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/GaitButton.tsx","../src/register.ts"],"sourcesContent":["'use client';\n\n/**\n * @gait-financial/react - React wrappers for Gait Web Components\n *\n * Usage:\n * 1. Register the Web Component (run once, e.g. in _app.tsx or layout):\n * import '@gait-financial/react/register';\n *\n * 2. Use the React components:\n * import { GaitButton } from '@gait-financial/react';\n */\n\nexport { GaitButton } from './components/GaitButton';\nexport type { GaitButtonProps } from './components/GaitButton';\n\nexport type {\n ButtonSize,\n GaitButtonItem,\n GaitPriceBreakdownItem,\n GaitCustomer,\n GaitWebhook,\n GaitClickDetail,\n GaitLoadedDetail,\n GaitDataProcessedDetail,\n GaitSplitFeedbackDetail,\n GaitMerchantIdErrorDetail,\n GaitConfirmDetail,\n} from './types';\n","'use client';\n\n/**\n * React wrapper for GaitButton Web Component\n * Creates the element imperatively with attributes set BEFORE appending,\n * so connectedCallback sees data-id and other attrs immediately.\n * Avoids React's prop handling which causes \"readonly property\" errors.\n */\n\nimport React, {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { defineCustomElements } from '../register';\nimport type {\n GaitButtonItem,\n GaitPriceBreakdownItem,\n GaitCustomer,\n GaitWebhook,\n GaitClickDetail,\n GaitLoadedDetail,\n GaitDataProcessedDetail,\n GaitSplitFeedbackDetail,\n GaitMerchantIdErrorDetail,\n GaitConfirmDetail,\n} from '../types';\n\nexport interface GaitButtonProps\n extends Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'style'> {\n /** Checkout/data identity (required for payment flow) */\n 'data-id'?: string;\n /** Disable the button */\n disabled?: boolean;\n /** Button size */\n size?: 'small' | 'medium' | 'large';\n /** Inline styles - string (for WC) or React.CSSProperties */\n style?: React.CSSProperties | string;\n /** Cart/order items for split payment modal */\n items?: GaitButtonItem[] | string;\n /** Price breakdown items */\n priceBreakdown?: GaitPriceBreakdownItem[] | string;\n /** Total cost */\n totalCost?: number | string;\n /** Customer info for split payment */\n customer?: GaitCustomer | string;\n /** Webhook config for split payment callbacks */\n webhook?: GaitWebhook | string;\n /** Merchant store URL (defaults to window.location.origin) */\n merchantStoreUrl?: string;\n\n /** Button clicked */\n onClick?: (detail: GaitClickDetail) => void;\n /** Component loaded/rendered */\n onLoaded?: (detail: GaitLoadedDetail) => void;\n /** Data processed (e.g. checkoutId resolved) */\n onDataProcessed?: (detail: GaitDataProcessedDetail) => void;\n /** Split payment API feedback (success/failure) */\n onSplitFeedback?: (detail: GaitSplitFeedbackDetail) => void;\n /** Merchant ID lookup failed */\n onMerchantIdError?: (detail: GaitMerchantIdErrorDetail) => void;\n /** Pay remaining confirmed */\n onConfirm?: (detail: GaitConfirmDetail) => void;\n}\n\nfunction setAttributes(\n el: HTMLElement,\n props: Pick<\n GaitButtonProps,\n | 'data-id'\n | 'disabled'\n | 'size'\n | 'style'\n | 'items'\n | 'priceBreakdown'\n | 'totalCost'\n | 'customer'\n | 'webhook'\n | 'merchantStoreUrl'\n >\n) {\n const {\n 'data-id': dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n } = props;\n\n if (dataId !== undefined) el.setAttribute('data-id', dataId);\n if (size !== undefined) el.setAttribute('size', size);\n if (disabled) el.setAttribute('disabled', '');\n else el.removeAttribute('disabled');\n if (style !== undefined) {\n const styleStr =\n typeof style === 'string'\n ? style\n : Object.entries(style)\n .map(\n ([k, v]) =>\n `${k.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${v}`\n )\n .join('; ');\n el.setAttribute('style', styleStr);\n }\n if (items !== undefined)\n el.setAttribute(\n 'items',\n typeof items === 'string' ? items : JSON.stringify(items)\n );\n if (priceBreakdown !== undefined)\n el.setAttribute(\n 'price-breakdown',\n typeof priceBreakdown === 'string'\n ? priceBreakdown\n : JSON.stringify(priceBreakdown)\n );\n if (totalCost !== undefined)\n el.setAttribute('total-cost', String(totalCost));\n if (customer !== undefined)\n el.setAttribute(\n 'customer',\n typeof customer === 'string' ? customer : JSON.stringify(customer)\n );\n if (webhook !== undefined)\n el.setAttribute(\n 'webhook',\n typeof webhook === 'string' ? webhook : JSON.stringify(webhook)\n );\n if (merchantStoreUrl !== undefined)\n el.setAttribute('merchant-store-url', merchantStoreUrl);\n}\n\nconst GaitButton = forwardRef<HTMLElement, GaitButtonProps>(function GaitButton(\n {\n 'data-id': dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n onClick,\n onLoaded,\n onDataProcessed,\n onSplitFeedback,\n onMerchantIdError,\n onConfirm,\n className,\n id,\n ...rest\n },\n ref\n) {\n const containerRef = useRef<HTMLDivElement>(null);\n const elementRef = useRef<HTMLElement | null>(null);\n const [isReady, setIsReady] = useState(false);\n\n const callbackRef = useRef({\n onClick,\n onLoaded,\n onDataProcessed,\n onSplitFeedback,\n onMerchantIdError,\n onConfirm,\n });\n callbackRef.current = {\n onClick,\n onLoaded,\n onDataProcessed,\n onSplitFeedback,\n onMerchantIdError,\n onConfirm,\n };\n\n useImperativeHandle(ref, () => elementRef.current as HTMLElement, []);\n\n // Wait for WC registration\n useEffect(() => {\n if (\n typeof customElements !== 'undefined' &&\n customElements.get('gait-button')\n ) {\n setIsReady(true);\n return;\n }\n defineCustomElements()\n .then(() => setIsReady(true))\n .catch(() => setIsReady(false));\n }, []);\n\n // Create gait-button imperatively with attrs BEFORE append (so connectedCallback sees data-id)\n useEffect(() => {\n if (!isReady || !containerRef.current || typeof document === 'undefined')\n return;\n\n const container = containerRef.current;\n const el = document.createElement('gait-button') as HTMLElement;\n\n // Set attributes BEFORE appending - connectedCallback fires on append and will see them\n setAttributes(el, {\n 'data-id': dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n });\n\n if (className) el.className = className;\n if (id) el.id = id;\n Object.entries(rest).forEach(([k, v]) => {\n if (v != null && typeof v !== 'function') el.setAttribute(k, String(v));\n });\n\n const cbs = callbackRef.current;\n const handleClick = (e: Event) => {\n if (cbs.onClick && e instanceof CustomEvent && e.detail)\n cbs.onClick(e.detail as GaitClickDetail);\n };\n const handleLoaded = (e: Event) => {\n if (cbs.onLoaded && e instanceof CustomEvent && e.detail)\n cbs.onLoaded(e.detail as GaitLoadedDetail);\n };\n const handleDataProcessed = (e: Event) => {\n if (cbs.onDataProcessed && e instanceof CustomEvent && e.detail)\n cbs.onDataProcessed(e.detail as GaitDataProcessedDetail);\n };\n const handleSplitFeedback = (e: Event) => {\n if (cbs.onSplitFeedback && e instanceof CustomEvent && e.detail)\n cbs.onSplitFeedback(e.detail as GaitSplitFeedbackDetail);\n };\n const handleMerchantIdError = (e: Event) => {\n if (cbs.onMerchantIdError && e instanceof CustomEvent && e.detail)\n cbs.onMerchantIdError(e.detail as GaitMerchantIdErrorDetail);\n };\n const handleConfirm = (e: Event) => {\n if (cbs.onConfirm && e instanceof CustomEvent && e.detail)\n cbs.onConfirm(e.detail as GaitConfirmDetail);\n };\n\n el.addEventListener('gait-click', handleClick as EventListener);\n el.addEventListener('gait-loaded', handleLoaded as EventListener);\n el.addEventListener('gait-data-processed', handleDataProcessed as EventListener);\n el.addEventListener('gait-split-feedback', handleSplitFeedback as EventListener);\n el.addEventListener('gait-merchant-id-error', handleMerchantIdError as EventListener);\n el.addEventListener('gait-confirm', handleConfirm as EventListener);\n\n elementRef.current = el;\n container.appendChild(el);\n\n return () => {\n el.removeEventListener('gait-click', handleClick as EventListener);\n el.removeEventListener('gait-loaded', handleLoaded as EventListener);\n el.removeEventListener('gait-data-processed', handleDataProcessed as EventListener);\n el.removeEventListener('gait-split-feedback', handleSplitFeedback as EventListener);\n el.removeEventListener('gait-merchant-id-error', handleMerchantIdError as EventListener);\n el.removeEventListener('gait-confirm', handleConfirm as EventListener);\n container.removeChild(el);\n elementRef.current = null;\n };\n }, [isReady]); // Only run when isReady changes - create once\n\n // Update attributes when props change\n useEffect(() => {\n const el = elementRef.current;\n if (!el) return;\n\n setAttributes(el, {\n 'data-id': dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n });\n\n if (className) el.className = className;\n else el.removeAttribute('class');\n if (id) el.id = id;\n else el.removeAttribute('id');\n }, [\n dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n className,\n id,\n ]);\n\n if (!isReady) return null;\n\n return React.createElement('div', { ref: containerRef });\n});\n\nGaitButton.displayName = 'GaitButton';\n\nexport { GaitButton };\n","/**\n * Registers Gait Web Components in the browser.\n * Safe to call in SSR environments - no-op when window/customElements unavailable.\n *\n * Usage:\n * import '@gait-financial/react/register'; // Side-effect: registers when in browser\n * // or\n * import { defineCustomElements } from '@gait-financial/react/register';\n * await defineCustomElements(); // Optional: load from custom URL\n */\n\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Loads and registers Gait Web Components.\n * In browser: loads the WC script if not already registered.\n * In SSR: no-op.\n * Deduplicated: multiple calls return the same promise.\n *\n * @param scriptUrl - Optional URL to the button.js script. If omitted, uses the bundled script.\n */\nexport async function defineCustomElements(\n scriptUrl?: string\n): Promise<void> {\n if (typeof window === 'undefined' || typeof customElements === 'undefined') {\n return;\n }\n if (customElements.get('gait-button')) {\n return;\n }\n if (loadPromise) {\n return loadPromise;\n }\n\n const tryLoad = (url: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.async = true;\n script.src = url;\n script.onload = () => resolve();\n script.onerror = () => reject();\n document.head.appendChild(script);\n });\n\n loadPromise = (async () => {\n const fallbackUrl = `${typeof window !== 'undefined' ? window.location.origin : ''}/node_modules/@gait-financial/react/dist/wc/button.js`;\n\n if (scriptUrl) {\n await tryLoad(scriptUrl);\n return;\n }\n\n // Try relative to module first (works when not pre-bundled)\n try {\n const url = new URL('./wc/button.js', import.meta.url).href;\n await tryLoad(url);\n return;\n } catch {\n // ignore\n }\n\n // Fallback: direct path (works when Vite pre-bundles and breaks import.meta.url)\n try {\n await tryLoad(fallbackUrl);\n return;\n } catch {\n throw new Error(\n '[@gait-financial/react] Failed to load web component script. If using Vite, add optimizeDeps: { exclude: [\"@gait-financial/react\"] } to vite.config.'\n );\n }\n })();\n return loadPromise;\n}\n\n// Side-effect: auto-register when imported in browser (SSR-safe)\nif (typeof window !== 'undefined' && typeof customElements !== 'undefined') {\n void defineCustomElements();\n}\n"],"mappings":"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","names":["GaitButton","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/GaitButton.tsx","../src/register.ts"],"sourcesContent":["'use client';\n\nexport { GaitButton } from './components/GaitButton';\nexport type { GaitButtonProps } from './components/GaitButton';\nexport type {\n ButtonSize,\n GaitButtonItem,\n GaitPriceBreakdownItem,\n GaitCustomer,\n GaitWebhook,\n GaitClickDetail,\n GaitLoadedDetail,\n GaitDataProcessedDetail,\n GaitSplitFeedbackDetail,\n GaitMerchantIdErrorDetail,\n GaitConfirmDetail,\n} from './types';\n","'use client';\n\nimport React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';\nimport { defineCustomElements } from '../register';\nimport type {\n GaitButtonItem,\n GaitPriceBreakdownItem,\n GaitCustomer,\n GaitWebhook,\n GaitClickDetail,\n GaitLoadedDetail,\n GaitDataProcessedDetail,\n GaitSplitFeedbackDetail,\n GaitMerchantIdErrorDetail,\n GaitConfirmDetail,\n} from '../types';\n\nexport interface GaitButtonProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'style'> {\n 'data-id'?: string;\n disabled?: boolean;\n size?: 'small' | 'medium' | 'large';\n style?: React.CSSProperties | string;\n items?: GaitButtonItem[] | string;\n priceBreakdown?: GaitPriceBreakdownItem[] | string;\n totalCost?: number | string;\n customer?: GaitCustomer | string;\n webhook?: GaitWebhook | string;\n merchantStoreUrl?: string;\n onClick?: (detail: GaitClickDetail) => void;\n onLoaded?: (detail: GaitLoadedDetail) => void;\n onDataProcessed?: (detail: GaitDataProcessedDetail) => void;\n onSplitFeedback?: (detail: GaitSplitFeedbackDetail) => void;\n onMerchantIdError?: (detail: GaitMerchantIdErrorDetail) => void;\n onConfirm?: (detail: GaitConfirmDetail) => void;\n}\n\nconst EVENT_HANDLERS: Array<{ event: string; key: keyof Pick<GaitButtonProps, 'onClick' | 'onLoaded' | 'onDataProcessed' | 'onSplitFeedback' | 'onMerchantIdError' | 'onConfirm'> }> = [\n { event: 'gait-click', key: 'onClick' },\n { event: 'gait-loaded', key: 'onLoaded' },\n { event: 'gait-data-processed', key: 'onDataProcessed' },\n { event: 'gait-split-feedback', key: 'onSplitFeedback' },\n { event: 'gait-merchant-id-error', key: 'onMerchantIdError' },\n { event: 'gait-confirm', key: 'onConfirm' },\n];\n\nfunction applyAttributes(\n el: HTMLElement,\n props: Pick<GaitButtonProps, 'data-id' | 'disabled' | 'size' | 'style' | 'items' | 'priceBreakdown' | 'totalCost' | 'customer' | 'webhook' | 'merchantStoreUrl'>\n) {\n const { 'data-id': dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl } = props;\n if (dataId !== undefined) el.setAttribute('data-id', dataId);\n if (size !== undefined) el.setAttribute('size', size);\n disabled ? el.setAttribute('disabled', '') : el.removeAttribute('disabled');\n if (style !== undefined) {\n const s = typeof style === 'string' ? style : Object.entries(style).map(([k, v]) => `${k.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${v}`).join('; ');\n el.setAttribute('style', s);\n }\n if (items !== undefined) el.setAttribute('items', typeof items === 'string' ? items : JSON.stringify(items));\n if (priceBreakdown !== undefined) el.setAttribute('price-breakdown', typeof priceBreakdown === 'string' ? priceBreakdown : JSON.stringify(priceBreakdown));\n if (totalCost !== undefined) el.setAttribute('total-cost', String(totalCost));\n if (customer !== undefined) el.setAttribute('customer', typeof customer === 'string' ? customer : JSON.stringify(customer));\n if (webhook !== undefined) el.setAttribute('webhook', typeof webhook === 'string' ? webhook : JSON.stringify(webhook));\n if (merchantStoreUrl !== undefined) el.setAttribute('merchant-store-url', merchantStoreUrl);\n}\n\nconst GaitButton = forwardRef<HTMLElement, GaitButtonProps>(function GaitButton(props, ref) {\n const {\n 'data-id': dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n onClick,\n onLoaded,\n onDataProcessed,\n onSplitFeedback,\n onMerchantIdError,\n onConfirm,\n className,\n id,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const elementRef = useRef<HTMLElement | null>(null);\n const [ready, setReady] = useState(false);\n const callbacksRef = useRef({ onClick, onLoaded, onDataProcessed, onSplitFeedback, onMerchantIdError, onConfirm });\n callbacksRef.current = { onClick, onLoaded, onDataProcessed, onSplitFeedback, onMerchantIdError, onConfirm };\n\n useImperativeHandle(ref, () => elementRef.current as HTMLElement, []);\n\n useEffect(() => {\n if (typeof customElements !== 'undefined' && customElements.get('gait-button')) {\n setReady(true);\n return;\n }\n defineCustomElements().then(() => setReady(true), () => setReady(false));\n }, []);\n\n useEffect(() => {\n if (!ready || !containerRef.current) return;\n\n const container = containerRef.current;\n const el = document.createElement('gait-button') as HTMLElement;\n\n applyAttributes(el, { 'data-id': dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl });\n if (className) el.className = className;\n if (id) el.id = id;\n\n const listeners: Array<() => void> = [];\n EVENT_HANDLERS.forEach(({ event, key }) => {\n const handler = (e: Event) => {\n const cb = callbacksRef.current[key];\n if (cb && e instanceof CustomEvent && e.detail) cb(e.detail as never);\n };\n el.addEventListener(event, handler as EventListener);\n listeners.push(() => el.removeEventListener(event, handler as EventListener));\n });\n\n elementRef.current = el;\n container.appendChild(el);\n\n return () => {\n listeners.forEach((off) => off());\n if (el.parentNode) el.parentNode.removeChild(el);\n elementRef.current = null;\n };\n }, [ready]);\n\n useEffect(() => {\n const el = elementRef.current;\n if (!el) return;\n applyAttributes(el, { 'data-id': dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl });\n if (className) el.className = className;\n else el.removeAttribute('class');\n if (id) el.id = id;\n else el.removeAttribute('id');\n }, [dataId, disabled, size, style, items, priceBreakdown, totalCost, customer, webhook, merchantStoreUrl, className, id]);\n\n if (!ready) return null;\n return React.createElement('div', { ref: containerRef });\n});\n\nGaitButton.displayName = 'GaitButton';\nexport { GaitButton };\n","/**\n * Loads and registers Gait Web Components. Safe for SSR (no-op when no window).\n * Import once: import '@gait-financial/react/register';\n */\n\nlet loadPromise: Promise<void> | null = null;\n\nexport function defineCustomElements(scriptUrl?: string): Promise<void> {\n if (typeof window === 'undefined' || typeof customElements === 'undefined') return Promise.resolve();\n if (customElements.get('gait-button')) return Promise.resolve();\n if (loadPromise) return loadPromise;\n\n loadPromise = new Promise((resolve, reject) => {\n let src: string;\n if (scriptUrl) src = scriptUrl;\n else {\n try {\n src = new URL('./wc/button.js', import.meta.url).href;\n } catch {\n reject(new Error('[@gait-financial/react] Could not resolve script. With Vite, add optimizeDeps: { exclude: [\"@gait-financial/react\"] } to vite.config.'));\n return;\n }\n }\n const script = document.createElement('script');\n script.async = true;\n script.src = src;\n script.onload = () => resolve();\n script.onerror = () => reject(new Error('[@gait-financial/react] Failed to load web component.'));\n document.head.appendChild(script);\n });\n return loadPromise;\n}\n\nif (typeof window !== 'undefined' && typeof customElements !== 'undefined') {\n void defineCustomElements();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAoF;;;ACFpF;AAKA,IAAI,cAAoC;AAEjC,SAAS,qBAAqB,WAAmC;AACtE,MAAI,OAAO,WAAW,eAAe,OAAO,mBAAmB,YAAa,QAAO,QAAQ,QAAQ;AACnG,MAAI,eAAe,IAAI,aAAa,EAAG,QAAO,QAAQ,QAAQ;AAC9D,MAAI,YAAa,QAAO;AAExB,gBAAc,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC7C,QAAI;AACJ,QAAI,UAAW,OAAM;AAAA,SAChB;AACH,UAAI;AACF,cAAM,IAAI,IAAI,kBAAkB,YAAY,GAAG,EAAE;AAAA,MACnD,QAAQ;AACN,eAAO,IAAI,MAAM,uIAAuI,CAAC;AACzJ;AAAA,MACF;AAAA,IACF;AACA,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,WAAO,MAAM;AACb,WAAO,SAAS,MAAM,QAAQ;AAC9B,WAAO,UAAU,MAAM,OAAO,IAAI,MAAM,uDAAuD,CAAC;AAChG,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC,CAAC;AACD,SAAO;AACT;AAEA,IAAI,OAAO,WAAW,eAAe,OAAO,mBAAmB,aAAa;AAC1E,OAAK,qBAAqB;AAC5B;;;ADCA,IAAM,iBAAiL;AAAA,EACrL,EAAE,OAAO,cAAc,KAAK,UAAU;AAAA,EACtC,EAAE,OAAO,eAAe,KAAK,WAAW;AAAA,EACxC,EAAE,OAAO,uBAAuB,KAAK,kBAAkB;AAAA,EACvD,EAAE,OAAO,uBAAuB,KAAK,kBAAkB;AAAA,EACvD,EAAE,OAAO,0BAA0B,KAAK,oBAAoB;AAAA,EAC5D,EAAE,OAAO,gBAAgB,KAAK,YAAY;AAC5C;AAEA,SAAS,gBACP,IACA,OACA;AACA,QAAM,EAAE,WAAW,QAAQ,UAAU,MAAM,OAAO,OAAO,gBAAgB,WAAW,UAAU,SAAS,iBAAiB,IAAI;AAC5H,MAAI,WAAW,OAAW,IAAG,aAAa,WAAW,MAAM;AAC3D,MAAI,SAAS,OAAW,IAAG,aAAa,QAAQ,IAAI;AACpD,aAAW,GAAG,aAAa,YAAY,EAAE,IAAI,GAAG,gBAAgB,UAAU;AAC1E,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI,OAAO,UAAU,WAAW,QAAQ,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,QAAQ,YAAY,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI;AACpJ,OAAG,aAAa,SAAS,CAAC;AAAA,EAC5B;AACA,MAAI,UAAU,OAAW,IAAG,aAAa,SAAS,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK,CAAC;AAC3G,MAAI,mBAAmB,OAAW,IAAG,aAAa,mBAAmB,OAAO,mBAAmB,WAAW,iBAAiB,KAAK,UAAU,cAAc,CAAC;AACzJ,MAAI,cAAc,OAAW,IAAG,aAAa,cAAc,OAAO,SAAS,CAAC;AAC5E,MAAI,aAAa,OAAW,IAAG,aAAa,YAAY,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,QAAQ,CAAC;AAC1H,MAAI,YAAY,OAAW,IAAG,aAAa,WAAW,OAAO,YAAY,WAAW,UAAU,KAAK,UAAU,OAAO,CAAC;AACrH,MAAI,qBAAqB,OAAW,IAAG,aAAa,sBAAsB,gBAAgB;AAC5F;AAEA,IAAM,iBAAa,yBAAyC,SAASA,YAAW,OAAO,KAAK;AAC1F,QAAM;AAAA,IACJ,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,mBAAe,qBAAuB,IAAI;AAChD,QAAM,iBAAa,qBAA2B,IAAI;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,KAAK;AACxC,QAAM,mBAAe,qBAAO,EAAE,SAAS,UAAU,iBAAiB,iBAAiB,mBAAmB,UAAU,CAAC;AACjH,eAAa,UAAU,EAAE,SAAS,UAAU,iBAAiB,iBAAiB,mBAAmB,UAAU;AAE3G,wCAAoB,KAAK,MAAM,WAAW,SAAwB,CAAC,CAAC;AAEpE,8BAAU,MAAM;AACd,QAAI,OAAO,mBAAmB,eAAe,eAAe,IAAI,aAAa,GAAG;AAC9E,eAAS,IAAI;AACb;AAAA,IACF;AACA,yBAAqB,EAAE,KAAK,MAAM,SAAS,IAAI,GAAG,MAAM,SAAS,KAAK,CAAC;AAAA,EACzE,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,aAAa,QAAS;AAErC,UAAM,YAAY,aAAa;AAC/B,UAAM,KAAK,SAAS,cAAc,aAAa;AAE/C,oBAAgB,IAAI,EAAE,WAAW,QAAQ,UAAU,MAAM,OAAO,OAAO,gBAAgB,WAAW,UAAU,SAAS,iBAAiB,CAAC;AACvI,QAAI,UAAW,IAAG,YAAY;AAC9B,QAAI,GAAI,IAAG,KAAK;AAEhB,UAAM,YAA+B,CAAC;AACtC,mBAAe,QAAQ,CAAC,EAAE,OAAO,IAAI,MAAM;AACzC,YAAM,UAAU,CAAC,MAAa;AAC5B,cAAM,KAAK,aAAa,QAAQ,GAAG;AACnC,YAAI,MAAM,aAAa,eAAe,EAAE,OAAQ,IAAG,EAAE,MAAe;AAAA,MACtE;AACA,SAAG,iBAAiB,OAAO,OAAwB;AACnD,gBAAU,KAAK,MAAM,GAAG,oBAAoB,OAAO,OAAwB,CAAC;AAAA,IAC9E,CAAC;AAED,eAAW,UAAU;AACrB,cAAU,YAAY,EAAE;AAExB,WAAO,MAAM;AACX,gBAAU,QAAQ,CAAC,QAAQ,IAAI,CAAC;AAChC,UAAI,GAAG,WAAY,IAAG,WAAW,YAAY,EAAE;AAC/C,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,8BAAU,MAAM;AACd,UAAM,KAAK,WAAW;AACtB,QAAI,CAAC,GAAI;AACT,oBAAgB,IAAI,EAAE,WAAW,QAAQ,UAAU,MAAM,OAAO,OAAO,gBAAgB,WAAW,UAAU,SAAS,iBAAiB,CAAC;AACvI,QAAI,UAAW,IAAG,YAAY;AAAA,QACzB,IAAG,gBAAgB,OAAO;AAC/B,QAAI,GAAI,IAAG,KAAK;AAAA,QACX,IAAG,gBAAgB,IAAI;AAAA,EAC9B,GAAG,CAAC,QAAQ,UAAU,MAAM,OAAO,OAAO,gBAAgB,WAAW,UAAU,SAAS,kBAAkB,WAAW,EAAE,CAAC;AAExH,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,aAAAC,QAAM,cAAc,OAAO,EAAE,KAAK,aAAa,CAAC;AACzD,CAAC;AAED,WAAW,cAAc;","names":["GaitButton","React"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -68,45 +68,22 @@ interface GaitConfirmDetail {
|
|
|
68
68
|
paymentId: string;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
/**
|
|
72
|
-
* React wrapper for GaitButton Web Component
|
|
73
|
-
* Creates the element imperatively with attributes set BEFORE appending,
|
|
74
|
-
* so connectedCallback sees data-id and other attrs immediately.
|
|
75
|
-
* Avoids React's prop handling which causes "readonly property" errors.
|
|
76
|
-
*/
|
|
77
|
-
|
|
78
71
|
interface GaitButtonProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'style'> {
|
|
79
|
-
/** Checkout/data identity (required for payment flow) */
|
|
80
72
|
'data-id'?: string;
|
|
81
|
-
/** Disable the button */
|
|
82
73
|
disabled?: boolean;
|
|
83
|
-
/** Button size */
|
|
84
74
|
size?: 'small' | 'medium' | 'large';
|
|
85
|
-
/** Inline styles - string (for WC) or React.CSSProperties */
|
|
86
75
|
style?: React.CSSProperties | string;
|
|
87
|
-
/** Cart/order items for split payment modal */
|
|
88
76
|
items?: GaitButtonItem[] | string;
|
|
89
|
-
/** Price breakdown items */
|
|
90
77
|
priceBreakdown?: GaitPriceBreakdownItem[] | string;
|
|
91
|
-
/** Total cost */
|
|
92
78
|
totalCost?: number | string;
|
|
93
|
-
/** Customer info for split payment */
|
|
94
79
|
customer?: GaitCustomer | string;
|
|
95
|
-
/** Webhook config for split payment callbacks */
|
|
96
80
|
webhook?: GaitWebhook | string;
|
|
97
|
-
/** Merchant store URL (defaults to window.location.origin) */
|
|
98
81
|
merchantStoreUrl?: string;
|
|
99
|
-
/** Button clicked */
|
|
100
82
|
onClick?: (detail: GaitClickDetail) => void;
|
|
101
|
-
/** Component loaded/rendered */
|
|
102
83
|
onLoaded?: (detail: GaitLoadedDetail) => void;
|
|
103
|
-
/** Data processed (e.g. checkoutId resolved) */
|
|
104
84
|
onDataProcessed?: (detail: GaitDataProcessedDetail) => void;
|
|
105
|
-
/** Split payment API feedback (success/failure) */
|
|
106
85
|
onSplitFeedback?: (detail: GaitSplitFeedbackDetail) => void;
|
|
107
|
-
/** Merchant ID lookup failed */
|
|
108
86
|
onMerchantIdError?: (detail: GaitMerchantIdErrorDetail) => void;
|
|
109
|
-
/** Pay remaining confirmed */
|
|
110
87
|
onConfirm?: (detail: GaitConfirmDetail) => void;
|
|
111
88
|
}
|
|
112
89
|
declare const GaitButton: React.ForwardRefExoticComponent<GaitButtonProps & React.RefAttributes<HTMLElement>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -68,45 +68,22 @@ interface GaitConfirmDetail {
|
|
|
68
68
|
paymentId: string;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
/**
|
|
72
|
-
* React wrapper for GaitButton Web Component
|
|
73
|
-
* Creates the element imperatively with attributes set BEFORE appending,
|
|
74
|
-
* so connectedCallback sees data-id and other attrs immediately.
|
|
75
|
-
* Avoids React's prop handling which causes "readonly property" errors.
|
|
76
|
-
*/
|
|
77
|
-
|
|
78
71
|
interface GaitButtonProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'style'> {
|
|
79
|
-
/** Checkout/data identity (required for payment flow) */
|
|
80
72
|
'data-id'?: string;
|
|
81
|
-
/** Disable the button */
|
|
82
73
|
disabled?: boolean;
|
|
83
|
-
/** Button size */
|
|
84
74
|
size?: 'small' | 'medium' | 'large';
|
|
85
|
-
/** Inline styles - string (for WC) or React.CSSProperties */
|
|
86
75
|
style?: React.CSSProperties | string;
|
|
87
|
-
/** Cart/order items for split payment modal */
|
|
88
76
|
items?: GaitButtonItem[] | string;
|
|
89
|
-
/** Price breakdown items */
|
|
90
77
|
priceBreakdown?: GaitPriceBreakdownItem[] | string;
|
|
91
|
-
/** Total cost */
|
|
92
78
|
totalCost?: number | string;
|
|
93
|
-
/** Customer info for split payment */
|
|
94
79
|
customer?: GaitCustomer | string;
|
|
95
|
-
/** Webhook config for split payment callbacks */
|
|
96
80
|
webhook?: GaitWebhook | string;
|
|
97
|
-
/** Merchant store URL (defaults to window.location.origin) */
|
|
98
81
|
merchantStoreUrl?: string;
|
|
99
|
-
/** Button clicked */
|
|
100
82
|
onClick?: (detail: GaitClickDetail) => void;
|
|
101
|
-
/** Component loaded/rendered */
|
|
102
83
|
onLoaded?: (detail: GaitLoadedDetail) => void;
|
|
103
|
-
/** Data processed (e.g. checkoutId resolved) */
|
|
104
84
|
onDataProcessed?: (detail: GaitDataProcessedDetail) => void;
|
|
105
|
-
/** Split payment API feedback (success/failure) */
|
|
106
85
|
onSplitFeedback?: (detail: GaitSplitFeedbackDetail) => void;
|
|
107
|
-
/** Merchant ID lookup failed */
|
|
108
86
|
onMerchantIdError?: (detail: GaitMerchantIdErrorDetail) => void;
|
|
109
|
-
/** Pay remaining confirmed */
|
|
110
87
|
onConfirm?: (detail: GaitConfirmDetail) => void;
|
|
111
88
|
}
|
|
112
89
|
declare const GaitButton: React.ForwardRefExoticComponent<GaitButtonProps & React.RefAttributes<HTMLElement>>;
|