@gait-financial/react 0.1.11 → 0.1.12
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/dist/index.cjs +137 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +137 -94
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -87,6 +87,54 @@ if (typeof window !== "undefined" && typeof customElements !== "undefined") {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// src/components/GaitButton.tsx
|
|
90
|
+
function setAttributes(el, props) {
|
|
91
|
+
const {
|
|
92
|
+
"data-id": dataId,
|
|
93
|
+
disabled,
|
|
94
|
+
size,
|
|
95
|
+
style,
|
|
96
|
+
items,
|
|
97
|
+
priceBreakdown,
|
|
98
|
+
totalCost,
|
|
99
|
+
customer,
|
|
100
|
+
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
|
+
}
|
|
90
138
|
var GaitButton = (0, import_react.forwardRef)(function GaitButton2({
|
|
91
139
|
"data-id": dataId,
|
|
92
140
|
disabled,
|
|
@@ -108,8 +156,25 @@ var GaitButton = (0, import_react.forwardRef)(function GaitButton2({
|
|
|
108
156
|
id,
|
|
109
157
|
...rest
|
|
110
158
|
}, ref) {
|
|
159
|
+
const containerRef = (0, import_react.useRef)(null);
|
|
111
160
|
const elementRef = (0, import_react.useRef)(null);
|
|
112
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 = {
|
|
171
|
+
onClick,
|
|
172
|
+
onLoaded,
|
|
173
|
+
onDataProcessed,
|
|
174
|
+
onSplitFeedback,
|
|
175
|
+
onMerchantIdError,
|
|
176
|
+
onConfirm
|
|
177
|
+
};
|
|
113
178
|
(0, import_react.useImperativeHandle)(ref, () => elementRef.current, []);
|
|
114
179
|
(0, import_react.useEffect)(() => {
|
|
115
180
|
if (typeof customElements !== "undefined" && customElements.get("gait-button")) {
|
|
@@ -119,95 +184,51 @@ var GaitButton = (0, import_react.forwardRef)(function GaitButton2({
|
|
|
119
184
|
defineCustomElements().then(() => setIsReady(true)).catch(() => setIsReady(false));
|
|
120
185
|
}, []);
|
|
121
186
|
(0, import_react.useEffect)(() => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
el.setAttribute(
|
|
145
|
-
"price-breakdown",
|
|
146
|
-
typeof priceBreakdown === "string" ? priceBreakdown : JSON.stringify(priceBreakdown)
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
if (totalCost !== void 0) {
|
|
150
|
-
el.setAttribute("total-cost", String(totalCost));
|
|
151
|
-
}
|
|
152
|
-
if (customer !== void 0) {
|
|
153
|
-
el.setAttribute(
|
|
154
|
-
"customer",
|
|
155
|
-
typeof customer === "string" ? customer : JSON.stringify(customer)
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
if (webhook !== void 0) {
|
|
159
|
-
el.setAttribute(
|
|
160
|
-
"webhook",
|
|
161
|
-
typeof webhook === "string" ? webhook : JSON.stringify(webhook)
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
if (merchantStoreUrl !== void 0) {
|
|
165
|
-
el.setAttribute("merchant-store-url", merchantStoreUrl);
|
|
166
|
-
}
|
|
167
|
-
}, [
|
|
168
|
-
dataId,
|
|
169
|
-
disabled,
|
|
170
|
-
size,
|
|
171
|
-
style,
|
|
172
|
-
items,
|
|
173
|
-
priceBreakdown,
|
|
174
|
-
totalCost,
|
|
175
|
-
customer,
|
|
176
|
-
webhook,
|
|
177
|
-
merchantStoreUrl
|
|
178
|
-
]);
|
|
179
|
-
(0, import_react.useEffect)(() => {
|
|
180
|
-
const el = elementRef.current;
|
|
181
|
-
if (!el) return;
|
|
187
|
+
if (!isReady || !containerRef.current || typeof document === "undefined")
|
|
188
|
+
return;
|
|
189
|
+
const container = containerRef.current;
|
|
190
|
+
const el = document.createElement("gait-button");
|
|
191
|
+
setAttributes(el, {
|
|
192
|
+
"data-id": dataId,
|
|
193
|
+
disabled,
|
|
194
|
+
size,
|
|
195
|
+
style,
|
|
196
|
+
items,
|
|
197
|
+
priceBreakdown,
|
|
198
|
+
totalCost,
|
|
199
|
+
customer,
|
|
200
|
+
webhook,
|
|
201
|
+
merchantStoreUrl
|
|
202
|
+
});
|
|
203
|
+
if (className) el.className = className;
|
|
204
|
+
if (id) el.id = id;
|
|
205
|
+
Object.entries(rest).forEach(([k, v]) => {
|
|
206
|
+
if (v != null && typeof v !== "function") el.setAttribute(k, String(v));
|
|
207
|
+
});
|
|
208
|
+
const cbs = callbackRef.current;
|
|
182
209
|
const handleClick = (e) => {
|
|
183
|
-
if (onClick && e instanceof CustomEvent && e.detail)
|
|
184
|
-
onClick(e.detail);
|
|
185
|
-
}
|
|
210
|
+
if (cbs.onClick && e instanceof CustomEvent && e.detail)
|
|
211
|
+
cbs.onClick(e.detail);
|
|
186
212
|
};
|
|
187
213
|
const handleLoaded = (e) => {
|
|
188
|
-
if (onLoaded && e instanceof CustomEvent && e.detail)
|
|
189
|
-
onLoaded(e.detail);
|
|
190
|
-
}
|
|
214
|
+
if (cbs.onLoaded && e instanceof CustomEvent && e.detail)
|
|
215
|
+
cbs.onLoaded(e.detail);
|
|
191
216
|
};
|
|
192
217
|
const handleDataProcessed = (e) => {
|
|
193
|
-
if (onDataProcessed && e instanceof CustomEvent && e.detail)
|
|
194
|
-
onDataProcessed(e.detail);
|
|
195
|
-
}
|
|
218
|
+
if (cbs.onDataProcessed && e instanceof CustomEvent && e.detail)
|
|
219
|
+
cbs.onDataProcessed(e.detail);
|
|
196
220
|
};
|
|
197
221
|
const handleSplitFeedback = (e) => {
|
|
198
|
-
if (onSplitFeedback && e instanceof CustomEvent && e.detail)
|
|
199
|
-
onSplitFeedback(e.detail);
|
|
200
|
-
}
|
|
222
|
+
if (cbs.onSplitFeedback && e instanceof CustomEvent && e.detail)
|
|
223
|
+
cbs.onSplitFeedback(e.detail);
|
|
201
224
|
};
|
|
202
225
|
const handleMerchantIdError = (e) => {
|
|
203
|
-
if (onMerchantIdError && e instanceof CustomEvent && e.detail)
|
|
204
|
-
onMerchantIdError(e.detail);
|
|
205
|
-
}
|
|
226
|
+
if (cbs.onMerchantIdError && e instanceof CustomEvent && e.detail)
|
|
227
|
+
cbs.onMerchantIdError(e.detail);
|
|
206
228
|
};
|
|
207
229
|
const handleConfirm = (e) => {
|
|
208
|
-
if (onConfirm && e instanceof CustomEvent && e.detail)
|
|
209
|
-
onConfirm(e.detail);
|
|
210
|
-
}
|
|
230
|
+
if (cbs.onConfirm && e instanceof CustomEvent && e.detail)
|
|
231
|
+
cbs.onConfirm(e.detail);
|
|
211
232
|
};
|
|
212
233
|
el.addEventListener("gait-click", handleClick);
|
|
213
234
|
el.addEventListener("gait-loaded", handleLoaded);
|
|
@@ -215,6 +236,8 @@ var GaitButton = (0, import_react.forwardRef)(function GaitButton2({
|
|
|
215
236
|
el.addEventListener("gait-split-feedback", handleSplitFeedback);
|
|
216
237
|
el.addEventListener("gait-merchant-id-error", handleMerchantIdError);
|
|
217
238
|
el.addEventListener("gait-confirm", handleConfirm);
|
|
239
|
+
elementRef.current = el;
|
|
240
|
+
container.appendChild(el);
|
|
218
241
|
return () => {
|
|
219
242
|
el.removeEventListener("gait-click", handleClick);
|
|
220
243
|
el.removeEventListener("gait-loaded", handleLoaded);
|
|
@@ -222,25 +245,45 @@ var GaitButton = (0, import_react.forwardRef)(function GaitButton2({
|
|
|
222
245
|
el.removeEventListener("gait-split-feedback", handleSplitFeedback);
|
|
223
246
|
el.removeEventListener("gait-merchant-id-error", handleMerchantIdError);
|
|
224
247
|
el.removeEventListener("gait-confirm", handleConfirm);
|
|
248
|
+
container.removeChild(el);
|
|
249
|
+
elementRef.current = null;
|
|
225
250
|
};
|
|
251
|
+
}, [isReady]);
|
|
252
|
+
(0, import_react.useEffect)(() => {
|
|
253
|
+
const el = elementRef.current;
|
|
254
|
+
if (!el) return;
|
|
255
|
+
setAttributes(el, {
|
|
256
|
+
"data-id": dataId,
|
|
257
|
+
disabled,
|
|
258
|
+
size,
|
|
259
|
+
style,
|
|
260
|
+
items,
|
|
261
|
+
priceBreakdown,
|
|
262
|
+
totalCost,
|
|
263
|
+
customer,
|
|
264
|
+
webhook,
|
|
265
|
+
merchantStoreUrl
|
|
266
|
+
});
|
|
267
|
+
if (className) el.className = className;
|
|
268
|
+
else el.removeAttribute("class");
|
|
269
|
+
if (id) el.id = id;
|
|
270
|
+
else el.removeAttribute("id");
|
|
226
271
|
}, [
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
272
|
+
dataId,
|
|
273
|
+
disabled,
|
|
274
|
+
size,
|
|
275
|
+
style,
|
|
276
|
+
items,
|
|
277
|
+
priceBreakdown,
|
|
278
|
+
totalCost,
|
|
279
|
+
customer,
|
|
280
|
+
webhook,
|
|
281
|
+
merchantStoreUrl,
|
|
282
|
+
className,
|
|
283
|
+
id
|
|
233
284
|
]);
|
|
234
|
-
if (!isReady)
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
const elementProps = {
|
|
238
|
-
ref: elementRef
|
|
239
|
-
};
|
|
240
|
-
if (className) elementProps.className = className;
|
|
241
|
-
if (id) elementProps.id = id;
|
|
242
|
-
Object.assign(elementProps, rest);
|
|
243
|
-
return import_react.default.createElement("gait-button", elementProps);
|
|
285
|
+
if (!isReady) return null;
|
|
286
|
+
return import_react.default.createElement("div", { ref: containerRef });
|
|
244
287
|
});
|
|
245
288
|
GaitButton.displayName = "GaitButton";
|
|
246
289
|
// Annotate the CommonJS export names for ESM import in node:
|
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 * Maps React props to element attributes (WC uses attributes as source of truth).\n * Uses ref + useEffect for binding - no direct JSX attribute spread to avoid React's\n * string coercion of booleans/objects.\n * Waits for WC registration before rendering to avoid invisible element (race condition).\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\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 elementRef = useRef<HTMLElement>(null);\n const [isReady, setIsReady] = useState(false);\n\n useImperativeHandle(ref, () => elementRef.current as HTMLElement, []);\n\n // Wait for WC to be registered before rendering (avoids invisible element)\n useEffect(() => {\n if (typeof customElements !== 'undefined' && customElements.get('gait-button')) {\n setIsReady(true);\n return;\n }\n defineCustomElements().then(() => setIsReady(true)).catch(() => setIsReady(false));\n }, []);\n\n // Sync props to element attributes via ref (WC reads attributes) - must run every render (hooks order)\n useEffect(() => {\n const el = elementRef.current;\n if (!el) return;\n\n if (dataId !== undefined) el.setAttribute('data-id', dataId);\n if (size !== undefined) el.setAttribute('size', size);\n\n if (disabled) {\n el.setAttribute('disabled', '');\n } else {\n el.removeAttribute('disabled');\n }\n\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\n if (items !== undefined) {\n el.setAttribute(\n 'items',\n typeof items === 'string' ? items : JSON.stringify(items)\n );\n }\n\n if (priceBreakdown !== undefined) {\n el.setAttribute(\n 'price-breakdown',\n typeof priceBreakdown === 'string'\n ? priceBreakdown\n : JSON.stringify(priceBreakdown)\n );\n }\n\n if (totalCost !== undefined) {\n el.setAttribute('total-cost', String(totalCost));\n }\n\n if (customer !== undefined) {\n el.setAttribute(\n 'customer',\n typeof customer === 'string' ? customer : JSON.stringify(customer)\n );\n }\n\n if (webhook !== undefined) {\n el.setAttribute(\n 'webhook',\n typeof webhook === 'string' ? webhook : JSON.stringify(webhook)\n );\n }\n\n if (merchantStoreUrl !== undefined) {\n el.setAttribute('merchant-store-url', merchantStoreUrl);\n }\n }, [\n dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n ]);\n\n // Event listeners\n useEffect(() => {\n const el = elementRef.current;\n if (!el) return;\n\n const handleClick = (e: Event) => {\n if (onClick && e instanceof CustomEvent && e.detail) {\n onClick(e.detail as GaitClickDetail);\n }\n };\n const handleLoaded = (e: Event) => {\n if (onLoaded && e instanceof CustomEvent && e.detail) {\n onLoaded(e.detail as GaitLoadedDetail);\n }\n };\n const handleDataProcessed = (e: Event) => {\n if (onDataProcessed && e instanceof CustomEvent && e.detail) {\n onDataProcessed(e.detail as GaitDataProcessedDetail);\n }\n };\n const handleSplitFeedback = (e: Event) => {\n if (onSplitFeedback && e instanceof CustomEvent && e.detail) {\n onSplitFeedback(e.detail as GaitSplitFeedbackDetail);\n }\n };\n const handleMerchantIdError = (e: Event) => {\n if (onMerchantIdError && e instanceof CustomEvent && e.detail) {\n onMerchantIdError(e.detail as GaitMerchantIdErrorDetail);\n }\n };\n const handleConfirm = (e: Event) => {\n if (onConfirm && e instanceof CustomEvent && e.detail) {\n onConfirm(e.detail as GaitConfirmDetail);\n }\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 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 };\n }, [\n onClick,\n onLoaded,\n onDataProcessed,\n onSplitFeedback,\n onMerchantIdError,\n onConfirm,\n ]);\n\n // Conditional render AFTER all hooks - required by Rules of Hooks\n if (!isReady) {\n return null;\n }\n\n // Only pass ref, className, id - React assigns props as properties, which throws\n // \"readonly property\" on custom elements. All other attrs set via setAttribute in useEffect.\n const elementProps: Record<string, unknown> = {\n ref: elementRef,\n };\n if (className) elementProps.className = className;\n if (id) elementProps.id = id;\n Object.assign(elementProps, rest);\n\n return React.createElement('gait-button', elementProps);\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUA,mBAMO;;;AChBP;AAWA,IAAI,cAAoC;AAUxC,eAAsB,qBACpB,WACe;AACf,MAAI,OAAO,WAAW,eAAe,OAAO,mBAAmB,aAAa;AAC1E;AAAA,EACF;AACA,MAAI,eAAe,IAAI,aAAa,GAAG;AACrC;AAAA,EACF;AACA,MAAI,aAAa;AACf,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,CAAC,QACf,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,WAAO,MAAM;AACb,WAAO,SAAS,MAAM,QAAQ;AAC9B,WAAO,UAAU,MAAM,OAAO;AAC9B,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC,CAAC;AAEH,iBAAe,YAAY;AACzB,UAAM,cAAc,GAAG,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS,EAAE;AAElF,QAAI,WAAW;AACb,YAAM,QAAQ,SAAS;AACvB;AAAA,IACF;AAGA,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,kBAAkB,YAAY,GAAG,EAAE;AACvD,YAAM,QAAQ,GAAG;AACjB;AAAA,IACF,QAAQ;AAAA,IAER;AAGA,QAAI;AACF,YAAM,QAAQ,WAAW;AACzB;AAAA,IACF,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG;AACH,SAAO;AACT;AAGA,IAAI,OAAO,WAAW,eAAe,OAAO,mBAAmB,aAAa;AAC1E,OAAK,qBAAqB;AAC5B;;;ADTA,IAAM,iBAAa,yBAAyC,SAASA,YACnE;AAAA,EACE,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GACA,KACA;AACA,QAAM,iBAAa,qBAAoB,IAAI;AAC3C,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAE5C,wCAAoB,KAAK,MAAM,WAAW,SAAwB,CAAC,CAAC;AAGpE,8BAAU,MAAM;AACd,QAAI,OAAO,mBAAmB,eAAe,eAAe,IAAI,aAAa,GAAG;AAC9E,iBAAW,IAAI;AACf;AAAA,IACF;AACA,yBAAqB,EAAE,KAAK,MAAM,WAAW,IAAI,CAAC,EAAE,MAAM,MAAM,WAAW,KAAK,CAAC;AAAA,EACnF,GAAG,CAAC,CAAC;AAGL,8BAAU,MAAM;AACd,UAAM,KAAK,WAAW;AACtB,QAAI,CAAC,GAAI;AAET,QAAI,WAAW,OAAW,IAAG,aAAa,WAAW,MAAM;AAC3D,QAAI,SAAS,OAAW,IAAG,aAAa,QAAQ,IAAI;AAEpD,QAAI,UAAU;AACZ,SAAG,aAAa,YAAY,EAAE;AAAA,IAChC,OAAO;AACL,SAAG,gBAAgB,UAAU;AAAA,IAC/B;AAEA,QAAI,UAAU,QAAW;AACvB,YAAM,WACJ,OAAO,UAAU,WACb,QACA,OAAO,QAAQ,KAAK,EACjB;AAAA,QACC,CAAC,CAAC,GAAG,CAAC,MACJ,GAAG,EAAE,QAAQ,YAAY,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC;AAAA,MACvD,EACC,KAAK,IAAI;AAClB,SAAG,aAAa,SAAS,QAAQ;AAAA,IACnC;AAEA,QAAI,UAAU,QAAW;AACvB,SAAG;AAAA,QACD;AAAA,QACA,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AAAA,MAC1D;AAAA,IACF;AAEA,QAAI,mBAAmB,QAAW;AAChC,SAAG;AAAA,QACD;AAAA,QACA,OAAO,mBAAmB,WACtB,iBACA,KAAK,UAAU,cAAc;AAAA,MACnC;AAAA,IACF;AAEA,QAAI,cAAc,QAAW;AAC3B,SAAG,aAAa,cAAc,OAAO,SAAS,CAAC;AAAA,IACjD;AAEA,QAAI,aAAa,QAAW;AAC1B,SAAG;AAAA,QACD;AAAA,QACA,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,QAAQ;AAAA,MACnE;AAAA,IACF;AAEA,QAAI,YAAY,QAAW;AACzB,SAAG;AAAA,QACD;AAAA,QACA,OAAO,YAAY,WAAW,UAAU,KAAK,UAAU,OAAO;AAAA,MAChE;AAAA,IACF;AAEA,QAAI,qBAAqB,QAAW;AAClC,SAAG,aAAa,sBAAsB,gBAAgB;AAAA,IACxD;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,8BAAU,MAAM;AACd,UAAM,KAAK,WAAW;AACtB,QAAI,CAAC,GAAI;AAET,UAAM,cAAc,CAAC,MAAa;AAChC,UAAI,WAAW,aAAa,eAAe,EAAE,QAAQ;AACnD,gBAAQ,EAAE,MAAyB;AAAA,MACrC;AAAA,IACF;AACA,UAAM,eAAe,CAAC,MAAa;AACjC,UAAI,YAAY,aAAa,eAAe,EAAE,QAAQ;AACpD,iBAAS,EAAE,MAA0B;AAAA,MACvC;AAAA,IACF;AACA,UAAM,sBAAsB,CAAC,MAAa;AACxC,UAAI,mBAAmB,aAAa,eAAe,EAAE,QAAQ;AAC3D,wBAAgB,EAAE,MAAiC;AAAA,MACrD;AAAA,IACF;AACA,UAAM,sBAAsB,CAAC,MAAa;AACxC,UAAI,mBAAmB,aAAa,eAAe,EAAE,QAAQ;AAC3D,wBAAgB,EAAE,MAAiC;AAAA,MACrD;AAAA,IACF;AACA,UAAM,wBAAwB,CAAC,MAAa;AAC1C,UAAI,qBAAqB,aAAa,eAAe,EAAE,QAAQ;AAC7D,0BAAkB,EAAE,MAAmC;AAAA,MACzD;AAAA,IACF;AACA,UAAM,gBAAgB,CAAC,MAAa;AAClC,UAAI,aAAa,aAAa,eAAe,EAAE,QAAQ;AACrD,kBAAU,EAAE,MAA2B;AAAA,MACzC;AAAA,IACF;AAEA,OAAG,iBAAiB,cAAc,WAA4B;AAC9D,OAAG,iBAAiB,eAAe,YAA6B;AAChE,OAAG,iBAAiB,uBAAuB,mBAAoC;AAC/E,OAAG,iBAAiB,uBAAuB,mBAAoC;AAC/E,OAAG,iBAAiB,0BAA0B,qBAAsC;AACpF,OAAG,iBAAiB,gBAAgB,aAA8B;AAElE,WAAO,MAAM;AACX,SAAG,oBAAoB,cAAc,WAA4B;AACjE,SAAG,oBAAoB,eAAe,YAA6B;AACnE,SAAG,oBAAoB,uBAAuB,mBAAoC;AAClF,SAAG,oBAAoB,uBAAuB,mBAAoC;AAClF,SAAG,oBAAoB,0BAA0B,qBAAsC;AACvF,SAAG,oBAAoB,gBAAgB,aAA8B;AAAA,IACvE;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAIA,QAAM,eAAwC;AAAA,IAC5C,KAAK;AAAA,EACP;AACA,MAAI,UAAW,cAAa,YAAY;AACxC,MAAI,GAAI,cAAa,KAAK;AAC1B,SAAO,OAAO,cAAc,IAAI;AAEhC,SAAO,aAAAC,QAAM,cAAc,eAAe,YAAY;AACxD,CAAC;AAED,WAAW,cAAc;","names":["GaitButton","React"]}
|
|
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"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -70,10 +70,9 @@ interface GaitConfirmDetail {
|
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* React wrapper for GaitButton Web Component
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* Waits for WC registration before rendering to avoid invisible element (race condition).
|
|
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.
|
|
77
76
|
*/
|
|
78
77
|
|
|
79
78
|
interface GaitButtonProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'style'> {
|
package/dist/index.d.ts
CHANGED
|
@@ -70,10 +70,9 @@ interface GaitConfirmDetail {
|
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* React wrapper for GaitButton Web Component
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* Waits for WC registration before rendering to avoid invisible element (race condition).
|
|
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.
|
|
77
76
|
*/
|
|
78
77
|
|
|
79
78
|
interface GaitButtonProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'style'> {
|
package/dist/index.js
CHANGED
|
@@ -57,6 +57,54 @@ if (typeof window !== "undefined" && typeof customElements !== "undefined") {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// src/components/GaitButton.tsx
|
|
60
|
+
function setAttributes(el, props) {
|
|
61
|
+
const {
|
|
62
|
+
"data-id": dataId,
|
|
63
|
+
disabled,
|
|
64
|
+
size,
|
|
65
|
+
style,
|
|
66
|
+
items,
|
|
67
|
+
priceBreakdown,
|
|
68
|
+
totalCost,
|
|
69
|
+
customer,
|
|
70
|
+
webhook,
|
|
71
|
+
merchantStoreUrl
|
|
72
|
+
} = props;
|
|
73
|
+
if (dataId !== void 0) el.setAttribute("data-id", dataId);
|
|
74
|
+
if (size !== void 0) el.setAttribute("size", size);
|
|
75
|
+
if (disabled) el.setAttribute("disabled", "");
|
|
76
|
+
else el.removeAttribute("disabled");
|
|
77
|
+
if (style !== void 0) {
|
|
78
|
+
const styleStr = typeof style === "string" ? style : Object.entries(style).map(
|
|
79
|
+
([k, v]) => `${k.replace(/([A-Z])/g, "-$1").toLowerCase()}: ${v}`
|
|
80
|
+
).join("; ");
|
|
81
|
+
el.setAttribute("style", styleStr);
|
|
82
|
+
}
|
|
83
|
+
if (items !== void 0)
|
|
84
|
+
el.setAttribute(
|
|
85
|
+
"items",
|
|
86
|
+
typeof items === "string" ? items : JSON.stringify(items)
|
|
87
|
+
);
|
|
88
|
+
if (priceBreakdown !== void 0)
|
|
89
|
+
el.setAttribute(
|
|
90
|
+
"price-breakdown",
|
|
91
|
+
typeof priceBreakdown === "string" ? priceBreakdown : JSON.stringify(priceBreakdown)
|
|
92
|
+
);
|
|
93
|
+
if (totalCost !== void 0)
|
|
94
|
+
el.setAttribute("total-cost", String(totalCost));
|
|
95
|
+
if (customer !== void 0)
|
|
96
|
+
el.setAttribute(
|
|
97
|
+
"customer",
|
|
98
|
+
typeof customer === "string" ? customer : JSON.stringify(customer)
|
|
99
|
+
);
|
|
100
|
+
if (webhook !== void 0)
|
|
101
|
+
el.setAttribute(
|
|
102
|
+
"webhook",
|
|
103
|
+
typeof webhook === "string" ? webhook : JSON.stringify(webhook)
|
|
104
|
+
);
|
|
105
|
+
if (merchantStoreUrl !== void 0)
|
|
106
|
+
el.setAttribute("merchant-store-url", merchantStoreUrl);
|
|
107
|
+
}
|
|
60
108
|
var GaitButton = forwardRef(function GaitButton2({
|
|
61
109
|
"data-id": dataId,
|
|
62
110
|
disabled,
|
|
@@ -78,8 +126,25 @@ var GaitButton = forwardRef(function GaitButton2({
|
|
|
78
126
|
id,
|
|
79
127
|
...rest
|
|
80
128
|
}, ref) {
|
|
129
|
+
const containerRef = useRef(null);
|
|
81
130
|
const elementRef = useRef(null);
|
|
82
131
|
const [isReady, setIsReady] = useState(false);
|
|
132
|
+
const callbackRef = useRef({
|
|
133
|
+
onClick,
|
|
134
|
+
onLoaded,
|
|
135
|
+
onDataProcessed,
|
|
136
|
+
onSplitFeedback,
|
|
137
|
+
onMerchantIdError,
|
|
138
|
+
onConfirm
|
|
139
|
+
});
|
|
140
|
+
callbackRef.current = {
|
|
141
|
+
onClick,
|
|
142
|
+
onLoaded,
|
|
143
|
+
onDataProcessed,
|
|
144
|
+
onSplitFeedback,
|
|
145
|
+
onMerchantIdError,
|
|
146
|
+
onConfirm
|
|
147
|
+
};
|
|
83
148
|
useImperativeHandle(ref, () => elementRef.current, []);
|
|
84
149
|
useEffect(() => {
|
|
85
150
|
if (typeof customElements !== "undefined" && customElements.get("gait-button")) {
|
|
@@ -89,95 +154,51 @@ var GaitButton = forwardRef(function GaitButton2({
|
|
|
89
154
|
defineCustomElements().then(() => setIsReady(true)).catch(() => setIsReady(false));
|
|
90
155
|
}, []);
|
|
91
156
|
useEffect(() => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
el.setAttribute(
|
|
115
|
-
"price-breakdown",
|
|
116
|
-
typeof priceBreakdown === "string" ? priceBreakdown : JSON.stringify(priceBreakdown)
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
if (totalCost !== void 0) {
|
|
120
|
-
el.setAttribute("total-cost", String(totalCost));
|
|
121
|
-
}
|
|
122
|
-
if (customer !== void 0) {
|
|
123
|
-
el.setAttribute(
|
|
124
|
-
"customer",
|
|
125
|
-
typeof customer === "string" ? customer : JSON.stringify(customer)
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
if (webhook !== void 0) {
|
|
129
|
-
el.setAttribute(
|
|
130
|
-
"webhook",
|
|
131
|
-
typeof webhook === "string" ? webhook : JSON.stringify(webhook)
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
if (merchantStoreUrl !== void 0) {
|
|
135
|
-
el.setAttribute("merchant-store-url", merchantStoreUrl);
|
|
136
|
-
}
|
|
137
|
-
}, [
|
|
138
|
-
dataId,
|
|
139
|
-
disabled,
|
|
140
|
-
size,
|
|
141
|
-
style,
|
|
142
|
-
items,
|
|
143
|
-
priceBreakdown,
|
|
144
|
-
totalCost,
|
|
145
|
-
customer,
|
|
146
|
-
webhook,
|
|
147
|
-
merchantStoreUrl
|
|
148
|
-
]);
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
const el = elementRef.current;
|
|
151
|
-
if (!el) return;
|
|
157
|
+
if (!isReady || !containerRef.current || typeof document === "undefined")
|
|
158
|
+
return;
|
|
159
|
+
const container = containerRef.current;
|
|
160
|
+
const el = document.createElement("gait-button");
|
|
161
|
+
setAttributes(el, {
|
|
162
|
+
"data-id": dataId,
|
|
163
|
+
disabled,
|
|
164
|
+
size,
|
|
165
|
+
style,
|
|
166
|
+
items,
|
|
167
|
+
priceBreakdown,
|
|
168
|
+
totalCost,
|
|
169
|
+
customer,
|
|
170
|
+
webhook,
|
|
171
|
+
merchantStoreUrl
|
|
172
|
+
});
|
|
173
|
+
if (className) el.className = className;
|
|
174
|
+
if (id) el.id = id;
|
|
175
|
+
Object.entries(rest).forEach(([k, v]) => {
|
|
176
|
+
if (v != null && typeof v !== "function") el.setAttribute(k, String(v));
|
|
177
|
+
});
|
|
178
|
+
const cbs = callbackRef.current;
|
|
152
179
|
const handleClick = (e) => {
|
|
153
|
-
if (onClick && e instanceof CustomEvent && e.detail)
|
|
154
|
-
onClick(e.detail);
|
|
155
|
-
}
|
|
180
|
+
if (cbs.onClick && e instanceof CustomEvent && e.detail)
|
|
181
|
+
cbs.onClick(e.detail);
|
|
156
182
|
};
|
|
157
183
|
const handleLoaded = (e) => {
|
|
158
|
-
if (onLoaded && e instanceof CustomEvent && e.detail)
|
|
159
|
-
onLoaded(e.detail);
|
|
160
|
-
}
|
|
184
|
+
if (cbs.onLoaded && e instanceof CustomEvent && e.detail)
|
|
185
|
+
cbs.onLoaded(e.detail);
|
|
161
186
|
};
|
|
162
187
|
const handleDataProcessed = (e) => {
|
|
163
|
-
if (onDataProcessed && e instanceof CustomEvent && e.detail)
|
|
164
|
-
onDataProcessed(e.detail);
|
|
165
|
-
}
|
|
188
|
+
if (cbs.onDataProcessed && e instanceof CustomEvent && e.detail)
|
|
189
|
+
cbs.onDataProcessed(e.detail);
|
|
166
190
|
};
|
|
167
191
|
const handleSplitFeedback = (e) => {
|
|
168
|
-
if (onSplitFeedback && e instanceof CustomEvent && e.detail)
|
|
169
|
-
onSplitFeedback(e.detail);
|
|
170
|
-
}
|
|
192
|
+
if (cbs.onSplitFeedback && e instanceof CustomEvent && e.detail)
|
|
193
|
+
cbs.onSplitFeedback(e.detail);
|
|
171
194
|
};
|
|
172
195
|
const handleMerchantIdError = (e) => {
|
|
173
|
-
if (onMerchantIdError && e instanceof CustomEvent && e.detail)
|
|
174
|
-
onMerchantIdError(e.detail);
|
|
175
|
-
}
|
|
196
|
+
if (cbs.onMerchantIdError && e instanceof CustomEvent && e.detail)
|
|
197
|
+
cbs.onMerchantIdError(e.detail);
|
|
176
198
|
};
|
|
177
199
|
const handleConfirm = (e) => {
|
|
178
|
-
if (onConfirm && e instanceof CustomEvent && e.detail)
|
|
179
|
-
onConfirm(e.detail);
|
|
180
|
-
}
|
|
200
|
+
if (cbs.onConfirm && e instanceof CustomEvent && e.detail)
|
|
201
|
+
cbs.onConfirm(e.detail);
|
|
181
202
|
};
|
|
182
203
|
el.addEventListener("gait-click", handleClick);
|
|
183
204
|
el.addEventListener("gait-loaded", handleLoaded);
|
|
@@ -185,6 +206,8 @@ var GaitButton = forwardRef(function GaitButton2({
|
|
|
185
206
|
el.addEventListener("gait-split-feedback", handleSplitFeedback);
|
|
186
207
|
el.addEventListener("gait-merchant-id-error", handleMerchantIdError);
|
|
187
208
|
el.addEventListener("gait-confirm", handleConfirm);
|
|
209
|
+
elementRef.current = el;
|
|
210
|
+
container.appendChild(el);
|
|
188
211
|
return () => {
|
|
189
212
|
el.removeEventListener("gait-click", handleClick);
|
|
190
213
|
el.removeEventListener("gait-loaded", handleLoaded);
|
|
@@ -192,25 +215,45 @@ var GaitButton = forwardRef(function GaitButton2({
|
|
|
192
215
|
el.removeEventListener("gait-split-feedback", handleSplitFeedback);
|
|
193
216
|
el.removeEventListener("gait-merchant-id-error", handleMerchantIdError);
|
|
194
217
|
el.removeEventListener("gait-confirm", handleConfirm);
|
|
218
|
+
container.removeChild(el);
|
|
219
|
+
elementRef.current = null;
|
|
195
220
|
};
|
|
221
|
+
}, [isReady]);
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
const el = elementRef.current;
|
|
224
|
+
if (!el) return;
|
|
225
|
+
setAttributes(el, {
|
|
226
|
+
"data-id": dataId,
|
|
227
|
+
disabled,
|
|
228
|
+
size,
|
|
229
|
+
style,
|
|
230
|
+
items,
|
|
231
|
+
priceBreakdown,
|
|
232
|
+
totalCost,
|
|
233
|
+
customer,
|
|
234
|
+
webhook,
|
|
235
|
+
merchantStoreUrl
|
|
236
|
+
});
|
|
237
|
+
if (className) el.className = className;
|
|
238
|
+
else el.removeAttribute("class");
|
|
239
|
+
if (id) el.id = id;
|
|
240
|
+
else el.removeAttribute("id");
|
|
196
241
|
}, [
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
242
|
+
dataId,
|
|
243
|
+
disabled,
|
|
244
|
+
size,
|
|
245
|
+
style,
|
|
246
|
+
items,
|
|
247
|
+
priceBreakdown,
|
|
248
|
+
totalCost,
|
|
249
|
+
customer,
|
|
250
|
+
webhook,
|
|
251
|
+
merchantStoreUrl,
|
|
252
|
+
className,
|
|
253
|
+
id
|
|
203
254
|
]);
|
|
204
|
-
if (!isReady)
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
const elementProps = {
|
|
208
|
-
ref: elementRef
|
|
209
|
-
};
|
|
210
|
-
if (className) elementProps.className = className;
|
|
211
|
-
if (id) elementProps.id = id;
|
|
212
|
-
Object.assign(elementProps, rest);
|
|
213
|
-
return React.createElement("gait-button", elementProps);
|
|
255
|
+
if (!isReady) return null;
|
|
256
|
+
return React.createElement("div", { ref: containerRef });
|
|
214
257
|
});
|
|
215
258
|
GaitButton.displayName = "GaitButton";
|
|
216
259
|
export {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/GaitButton.tsx","../src/register.ts"],"sourcesContent":["'use client';\n\n/**\n * React wrapper for GaitButton Web Component\n * Maps React props to element attributes (WC uses attributes as source of truth).\n * Uses ref + useEffect for binding - no direct JSX attribute spread to avoid React's\n * string coercion of booleans/objects.\n * Waits for WC registration before rendering to avoid invisible element (race condition).\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\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 elementRef = useRef<HTMLElement>(null);\n const [isReady, setIsReady] = useState(false);\n\n useImperativeHandle(ref, () => elementRef.current as HTMLElement, []);\n\n // Wait for WC to be registered before rendering (avoids invisible element)\n useEffect(() => {\n if (typeof customElements !== 'undefined' && customElements.get('gait-button')) {\n setIsReady(true);\n return;\n }\n defineCustomElements().then(() => setIsReady(true)).catch(() => setIsReady(false));\n }, []);\n\n // Sync props to element attributes via ref (WC reads attributes) - must run every render (hooks order)\n useEffect(() => {\n const el = elementRef.current;\n if (!el) return;\n\n if (dataId !== undefined) el.setAttribute('data-id', dataId);\n if (size !== undefined) el.setAttribute('size', size);\n\n if (disabled) {\n el.setAttribute('disabled', '');\n } else {\n el.removeAttribute('disabled');\n }\n\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\n if (items !== undefined) {\n el.setAttribute(\n 'items',\n typeof items === 'string' ? items : JSON.stringify(items)\n );\n }\n\n if (priceBreakdown !== undefined) {\n el.setAttribute(\n 'price-breakdown',\n typeof priceBreakdown === 'string'\n ? priceBreakdown\n : JSON.stringify(priceBreakdown)\n );\n }\n\n if (totalCost !== undefined) {\n el.setAttribute('total-cost', String(totalCost));\n }\n\n if (customer !== undefined) {\n el.setAttribute(\n 'customer',\n typeof customer === 'string' ? customer : JSON.stringify(customer)\n );\n }\n\n if (webhook !== undefined) {\n el.setAttribute(\n 'webhook',\n typeof webhook === 'string' ? webhook : JSON.stringify(webhook)\n );\n }\n\n if (merchantStoreUrl !== undefined) {\n el.setAttribute('merchant-store-url', merchantStoreUrl);\n }\n }, [\n dataId,\n disabled,\n size,\n style,\n items,\n priceBreakdown,\n totalCost,\n customer,\n webhook,\n merchantStoreUrl,\n ]);\n\n // Event listeners\n useEffect(() => {\n const el = elementRef.current;\n if (!el) return;\n\n const handleClick = (e: Event) => {\n if (onClick && e instanceof CustomEvent && e.detail) {\n onClick(e.detail as GaitClickDetail);\n }\n };\n const handleLoaded = (e: Event) => {\n if (onLoaded && e instanceof CustomEvent && e.detail) {\n onLoaded(e.detail as GaitLoadedDetail);\n }\n };\n const handleDataProcessed = (e: Event) => {\n if (onDataProcessed && e instanceof CustomEvent && e.detail) {\n onDataProcessed(e.detail as GaitDataProcessedDetail);\n }\n };\n const handleSplitFeedback = (e: Event) => {\n if (onSplitFeedback && e instanceof CustomEvent && e.detail) {\n onSplitFeedback(e.detail as GaitSplitFeedbackDetail);\n }\n };\n const handleMerchantIdError = (e: Event) => {\n if (onMerchantIdError && e instanceof CustomEvent && e.detail) {\n onMerchantIdError(e.detail as GaitMerchantIdErrorDetail);\n }\n };\n const handleConfirm = (e: Event) => {\n if (onConfirm && e instanceof CustomEvent && e.detail) {\n onConfirm(e.detail as GaitConfirmDetail);\n }\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 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 };\n }, [\n onClick,\n onLoaded,\n onDataProcessed,\n onSplitFeedback,\n onMerchantIdError,\n onConfirm,\n ]);\n\n // Conditional render AFTER all hooks - required by Rules of Hooks\n if (!isReady) {\n return null;\n }\n\n // Only pass ref, className, id - React assigns props as properties, which throws\n // \"readonly property\" on custom elements. All other attrs set via setAttribute in useEffect.\n const elementProps: Record<string, unknown> = {\n ref: elementRef,\n };\n if (className) elementProps.className = className;\n if (id) elementProps.id = id;\n Object.assign(elementProps, rest);\n\n return React.createElement('gait-button', elementProps);\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/GaitButton.tsx","../src/register.ts"],"sourcesContent":["'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"]}
|