@ozura/elements 1.0.1 → 1.0.2-next.9

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.
@@ -821,13 +821,26 @@ function validateBilling(billing) {
821
821
  return { valid: errors.length === 0, errors, normalized };
822
822
  }
823
823
 
824
+ /**
825
+ * Shared postMessage protocol constants.
826
+ *
827
+ * PROTOCOL_VERSION must be incremented any time a breaking change is made to
828
+ * the postMessage message shape (new required fields, renamed types, removed
829
+ * fields, changed semantics). The SDK reads this value from OZ_FRAME_READY
830
+ * messages and warns when the frame and SDK are out of sync.
831
+ *
832
+ * Non-breaking additions (new optional fields, new message types that old
833
+ * frames can safely ignore) do NOT require a version bump.
834
+ */
835
+ const PROTOCOL_VERSION = 1;
836
+
824
837
  function isCardMetadata(v) {
825
838
  return !!v && typeof v === 'object' && typeof v.last4 === 'string';
826
839
  }
827
840
  function isBankAccountMetadata(v) {
828
841
  return !!v && typeof v === 'object' && typeof v.last4 === 'string';
829
842
  }
830
- const DEFAULT_FRAME_BASE_URL = "https://elements.ozura.com";
843
+ const DEFAULT_FRAME_BASE_URL = "https://lively-hill-097170c0f.4.azurestaticapps.net";
831
844
  /**
832
845
  * The main entry point for OzElements. Creates and manages iframe-based
833
846
  * card input elements that keep raw card data isolated from the merchant page.
@@ -1393,6 +1406,11 @@ class OzVault {
1393
1406
  // the previous session and justCompleted never fires, breaking auto-advance.
1394
1407
  if (msg.type === 'OZ_FRAME_READY') {
1395
1408
  this.completionState.set(frameId, false);
1409
+ if (msg.__ozVersion !== PROTOCOL_VERSION) {
1410
+ console.warn(`[OzVault] Protocol version mismatch on element frame "${frameId}" — ` +
1411
+ `SDK expects v${PROTOCOL_VERSION}, frame reported v${typeof msg.__ozVersion === 'number' ? msg.__ozVersion : '(none)'}. ` +
1412
+ 'Deploy the matching frame assets to elements.ozura.com and purge the Azure CDN cache.');
1413
+ }
1396
1414
  }
1397
1415
  // Intercept OZ_CHANGE before forwarding — handle auto-advance and CVV sync
1398
1416
  if (msg.type === 'OZ_CHANGE') {
@@ -1438,6 +1456,12 @@ class OzVault {
1438
1456
  var _a, _b, _c;
1439
1457
  switch (msg.type) {
1440
1458
  case 'OZ_FRAME_READY':
1459
+ if (msg.__ozVersion !== PROTOCOL_VERSION) {
1460
+ console.warn(`[OzVault] Protocol version mismatch — SDK expects v${PROTOCOL_VERSION}, ` +
1461
+ `tokenizer frame reported v${typeof msg.__ozVersion === 'number' ? msg.__ozVersion : '(none)'}. ` +
1462
+ 'This usually means the deployed frame files are stale. ' +
1463
+ 'Deploy the matching frame assets to elements.ozura.com and purge the Azure CDN cache.');
1464
+ }
1441
1465
  this.tokenizerReady = true;
1442
1466
  if (this.loadErrorTimeoutId != null) {
1443
1467
  clearTimeout(this.loadErrorTimeoutId);
@@ -1471,13 +1495,8 @@ class OzVault {
1471
1495
  pending.reject(new OzError('Vault returned a token result without a cvcSession — possible vault misconfiguration or API change.', undefined, 'server'));
1472
1496
  break;
1473
1497
  }
1474
- if (!card) {
1475
- pending.reject(new OzError('Vault returned a token result without card metadata possible vault API change.', undefined, 'server'));
1476
- break;
1477
- }
1478
- pending.resolve(Object.assign({ token,
1479
- cvcSession,
1480
- card }, (pending.billing ? { billing: pending.billing } : {})));
1498
+ pending.resolve(Object.assign(Object.assign({ token,
1499
+ cvcSession }, (card ? { card } : {})), (pending.billing ? { billing: pending.billing } : {})));
1481
1500
  // Increment the per-key success counter and proactively refresh once
1482
1501
  // the budget is exhausted so the next createToken() call uses a fresh
1483
1502
  // key without waiting for a vault rejection.
@@ -1843,9 +1862,25 @@ function OzElements({ fetchWaxKey, pubKey, frameBaseUrl, fonts, onLoadError, loa
1843
1862
  // proactive, or visibility-change proactive). Without this the React
1844
1863
  // counter accumulates across key refreshes and diverges from the vault's
1845
1864
  // internal _tokenizeSuccessCount, which resets to 0 on every refresh.
1865
+ //
1866
+ // The reset is deferred via Promise.resolve().then() rather than being
1867
+ // called synchronously. In the proactive-refresh case (budget exhausted
1868
+ // after a successful tokenization), the vault's message handler calls
1869
+ // onWaxRefresh synchronously before the Promise microtask that resumes
1870
+ // the awaiting createToken() wrapper (and its notifyTokenize() call).
1871
+ // A synchronous setTokenizeCount(0) would therefore fire BEFORE
1872
+ // notifyTokenize's setTokenizeCount(n => n + 1), causing React to batch
1873
+ // them as: reset to 0, then +1 = 1 — a persistent off-by-one.
1874
+ // Deferring by one microtask flips the order: notifyTokenize fires first
1875
+ // (increment), then the deferred reset fires (set 0), so the final
1876
+ // batched result is 0 — correct for a just-exhausted key.
1877
+ // In the reactive-refresh case the deferred reset still fires well before
1878
+ // the retry tokenization completes (a full fetchWaxKey + tokenize round-
1879
+ // trip separates them), so the count correctly resets to 0 then rises to
1880
+ // 1 after the retry notifyTokenize fires.
1846
1881
  onWaxRefresh: () => {
1847
1882
  var _a;
1848
- setTokenizeCount(0);
1883
+ Promise.resolve().then(() => setTokenizeCount(0));
1849
1884
  (_a = onWaxRefreshRef.current) === null || _a === void 0 ? void 0 : _a.call(onWaxRefreshRef);
1850
1885
  } }), (onReadyRef.current ? { onReady: () => { var _a; return (_a = onReadyRef.current) === null || _a === void 0 ? void 0 : _a.call(onReadyRef); } } : {})), (maxTokenizeCalls !== undefined ? { maxTokenizeCalls } : {})), abortController.signal).then(v => {
1851
1886
  if (cancelled) {
@@ -2009,6 +2044,71 @@ const OzCardNumber = (props) => jsxRuntime.jsx(OzFieldBase, Object.assign({ type
2009
2044
  const OzExpiry = (props) => jsxRuntime.jsx(OzFieldBase, Object.assign({ type: "expirationDate", variant: "card" }, props));
2010
2045
  /** Renders a PCI-isolated CVV input inside an Ozura iframe. */
2011
2046
  const OzCvv = (props) => jsxRuntime.jsx(OzFieldBase, Object.assign({ type: "cvv", variant: "card" }, props));
2047
+ // ─── Shared composite-component hook ─────────────────────────────────────────
2048
+ /**
2049
+ * Shared plumbing for OzCard and OzBankCard.
2050
+ *
2051
+ * Manages:
2052
+ * - Callback refs (onChange, onReady, onFocus, onBlur) kept in sync on every render
2053
+ * - Vault-change detection: resets `readyFieldTypes` and `onReadyFiredRef` when the
2054
+ * vault instance is replaced (e.g. after fetchWaxKey changes or the provider remounts)
2055
+ * - Per-field ready tracking: creates one stable handler per named field; fires the
2056
+ * `onReady` callback once all `fieldNames.length` fields have reported ready
2057
+ * - Error state
2058
+ * - Layout helpers: `gapStr`, `resolvedLabelStyle`, `renderLabel`
2059
+ *
2060
+ * @internal — not exported; used only by OzCard and OzBankCard.
2061
+ */
2062
+ function useCardBase({ vault, fieldNames, onChange, onReady, onFocus, onBlur, gap = 8, labelStyle, labelClassName, }) {
2063
+ const totalFields = fieldNames.length;
2064
+ const readyFieldTypes = react.useRef(new Set());
2065
+ const onReadyFiredRef = react.useRef(false);
2066
+ const vaultRef = react.useRef(vault);
2067
+ const onChangeRef = react.useRef(onChange);
2068
+ const onReadyRef = react.useRef(onReady);
2069
+ const onFocusRef = react.useRef(onFocus);
2070
+ const onBlurRef = react.useRef(onBlur);
2071
+ react.useEffect(() => { onChangeRef.current = onChange; }, [onChange]);
2072
+ react.useEffect(() => { onReadyRef.current = onReady; }, [onReady]);
2073
+ react.useEffect(() => { onFocusRef.current = onFocus; }, [onFocus]);
2074
+ react.useEffect(() => { onBlurRef.current = onBlur; }, [onBlur]);
2075
+ react.useEffect(() => {
2076
+ if (vault !== vaultRef.current) {
2077
+ vaultRef.current = vault;
2078
+ readyFieldTypes.current = new Set();
2079
+ onReadyFiredRef.current = false;
2080
+ }
2081
+ return () => {
2082
+ readyFieldTypes.current = new Set();
2083
+ onReadyFiredRef.current = false;
2084
+ };
2085
+ }, [vault]);
2086
+ // One stable handler per named field — recreated only when total field count changes.
2087
+ // Field names are static (card = 3 fields, bank = 2 fields) so `totalFields` alone
2088
+ // is a sufficient dependency; a JSON dep would create a new map on every render.
2089
+ // CONTRACT: `fieldNames` must be a static literal — callers must not pass a dynamic
2090
+ // array that changes length without also changing field count.
2091
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2092
+ const readyHandlers = react.useMemo(() => {
2093
+ const handlers = {};
2094
+ for (const name of fieldNames) {
2095
+ handlers[name] = () => {
2096
+ var _a;
2097
+ readyFieldTypes.current.add(name);
2098
+ if (readyFieldTypes.current.size >= totalFields && !onReadyFiredRef.current) {
2099
+ onReadyFiredRef.current = true;
2100
+ (_a = onReadyRef.current) === null || _a === void 0 ? void 0 : _a.call(onReadyRef);
2101
+ }
2102
+ };
2103
+ }
2104
+ return handlers;
2105
+ }, [totalFields]); // totalFields captures fieldNames.length; field names are static
2106
+ const [error, setError] = react.useState();
2107
+ const gapStr = typeof gap === 'string' ? gap : `${gap}px`;
2108
+ const resolvedLabelStyle = react.useMemo(() => (labelStyle ? Object.assign(Object.assign({}, DEFAULT_LABEL_STYLE), labelStyle) : DEFAULT_LABEL_STYLE), [labelStyle]);
2109
+ const renderLabel = react.useCallback((text) => renderFieldLabel(text, labelClassName, resolvedLabelStyle), [labelClassName, resolvedLabelStyle]);
2110
+ return { onChangeRef, onFocusRef, onBlurRef, readyHandlers, error, setError, gapStr, resolvedLabelStyle, renderLabel };
2111
+ }
2012
2112
  const DEFAULT_ERROR_STYLE = {
2013
2113
  color: '#dc2626',
2014
2114
  fontSize: 13,
@@ -2051,62 +2151,22 @@ function mergeStyles(base, override) {
2051
2151
  function OzCard({ style, styles, classNames, labels, labelStyle, labelClassName, layout = 'default', gap = 8, hideErrors = false, errorStyle, errorClassName, renderError, onChange, onReady, onFocus, onBlur, disabled, className, placeholders, }) {
2052
2152
  var _a, _b, _c;
2053
2153
  const { vault } = react.useContext(OzContext);
2154
+ const { onChangeRef, onFocusRef, onBlurRef, readyHandlers, error, setError, gapStr, renderLabel, } = useCardBase({
2155
+ vault,
2156
+ fieldNames: ['cardNumber', 'expiry', 'cvv'],
2157
+ onChange,
2158
+ onReady,
2159
+ onFocus,
2160
+ onBlur,
2161
+ gap,
2162
+ labelStyle,
2163
+ labelClassName,
2164
+ });
2054
2165
  const fieldState = react.useRef({
2055
2166
  cardNumber: null,
2056
2167
  expiry: null,
2057
2168
  cvv: null,
2058
2169
  });
2059
- const readyFieldTypes = react.useRef(new Set());
2060
- const onReadyFiredRef = react.useRef(false);
2061
- const vaultRef = react.useRef(vault);
2062
- const onChangeRef = react.useRef(onChange);
2063
- const onReadyRef = react.useRef(onReady);
2064
- const onFocusRef = react.useRef(onFocus);
2065
- const onBlurRef = react.useRef(onBlur);
2066
- react.useEffect(() => { onChangeRef.current = onChange; }, [onChange]);
2067
- react.useEffect(() => { onReadyRef.current = onReady; }, [onReady]);
2068
- react.useEffect(() => { onFocusRef.current = onFocus; }, [onFocus]);
2069
- react.useEffect(() => { onBlurRef.current = onBlur; }, [onBlur]);
2070
- // When the vault is recreated (e.g. appearance/fonts props change on OzElements),
2071
- // context readyCount is reset but this ref is not. Reset so onReady fires once when all 3 are ready.
2072
- // The cleanup resets readyFieldTypes when the component unmounts (covers React StrictMode double-invoke
2073
- // and SPA scenarios where the parent re-mounts this component).
2074
- react.useEffect(() => {
2075
- if (vault !== vaultRef.current) {
2076
- vaultRef.current = vault;
2077
- readyFieldTypes.current = new Set();
2078
- onReadyFiredRef.current = false;
2079
- }
2080
- return () => {
2081
- readyFieldTypes.current = new Set();
2082
- onReadyFiredRef.current = false;
2083
- };
2084
- }, [vault]);
2085
- const [error, setError] = react.useState();
2086
- const handleCardNumberReady = react.useCallback(() => {
2087
- var _a;
2088
- readyFieldTypes.current.add('cardNumber');
2089
- if (readyFieldTypes.current.size >= 3 && !onReadyFiredRef.current) {
2090
- onReadyFiredRef.current = true;
2091
- (_a = onReadyRef.current) === null || _a === void 0 ? void 0 : _a.call(onReadyRef);
2092
- }
2093
- }, []);
2094
- const handleExpiryReady = react.useCallback(() => {
2095
- var _a;
2096
- readyFieldTypes.current.add('expiry');
2097
- if (readyFieldTypes.current.size >= 3 && !onReadyFiredRef.current) {
2098
- onReadyFiredRef.current = true;
2099
- (_a = onReadyRef.current) === null || _a === void 0 ? void 0 : _a.call(onReadyRef);
2100
- }
2101
- }, []);
2102
- const handleCvvReady = react.useCallback(() => {
2103
- var _a;
2104
- readyFieldTypes.current.add('cvv');
2105
- if (readyFieldTypes.current.size >= 3 && !onReadyFiredRef.current) {
2106
- onReadyFiredRef.current = true;
2107
- (_a = onReadyRef.current) === null || _a === void 0 ? void 0 : _a.call(onReadyRef);
2108
- }
2109
- }, []);
2110
2170
  const emitChange = react.useCallback(() => {
2111
2171
  var _a;
2112
2172
  const { cardNumber, expiry, cvv } = fieldState.current;
@@ -2121,20 +2181,16 @@ function OzCard({ style, styles, classNames, labels, labelStyle, labelClassName,
2121
2181
  error: err,
2122
2182
  fields: Object.assign({}, fieldState.current),
2123
2183
  });
2124
- }, []);
2125
- const gapStr = typeof gap === 'string' ? gap : `${gap}px`;
2126
- const resolvedLabelStyle = labelStyle
2127
- ? Object.assign(Object.assign({}, DEFAULT_LABEL_STYLE), labelStyle) : DEFAULT_LABEL_STYLE;
2128
- const renderLabel = (text) => renderFieldLabel(text, labelClassName, resolvedLabelStyle);
2184
+ }, [setError, onChangeRef]);
2129
2185
  const showError = !hideErrors && error;
2130
2186
  const errorNode = showError
2131
2187
  ? renderError
2132
2188
  ? renderError(error)
2133
2189
  : (jsxRuntime.jsx("div", { role: "alert", className: errorClassName, style: errorStyle ? Object.assign(Object.assign({}, DEFAULT_ERROR_STYLE), errorStyle) : DEFAULT_ERROR_STYLE, children: error }))
2134
2190
  : null;
2135
- const cardNumberField = (jsxRuntime.jsxs("div", { children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.cardNumber), jsxRuntime.jsx(OzCardNumber, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.cardNumber), className: classNames === null || classNames === void 0 ? void 0 : classNames.cardNumber, placeholder: (_a = placeholders === null || placeholders === void 0 ? void 0 : placeholders.cardNumber) !== null && _a !== void 0 ? _a : 'Card number', disabled: disabled, onChange: (e) => { fieldState.current.cardNumber = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'cardNumber'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'cardNumber'); }, onReady: handleCardNumberReady })] }));
2136
- const expiryField = (jsxRuntime.jsxs("div", { style: layout === 'default' ? { flex: 1 } : undefined, children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.expiry), jsxRuntime.jsx(OzExpiry, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.expiry), className: classNames === null || classNames === void 0 ? void 0 : classNames.expiry, placeholder: (_b = placeholders === null || placeholders === void 0 ? void 0 : placeholders.expiry) !== null && _b !== void 0 ? _b : 'MM / YY', disabled: disabled, onChange: (e) => { fieldState.current.expiry = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'expiry'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'expiry'); }, onReady: handleExpiryReady })] }));
2137
- const cvvField = (jsxRuntime.jsxs("div", { style: layout === 'default' ? { flex: 1 } : undefined, children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.cvv), jsxRuntime.jsx(OzCvv, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.cvv), className: classNames === null || classNames === void 0 ? void 0 : classNames.cvv, placeholder: (_c = placeholders === null || placeholders === void 0 ? void 0 : placeholders.cvv) !== null && _c !== void 0 ? _c : 'CVV', disabled: disabled, onChange: (e) => { fieldState.current.cvv = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'cvv'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'cvv'); }, onReady: handleCvvReady })] }));
2191
+ const cardNumberField = (jsxRuntime.jsxs("div", { children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.cardNumber), jsxRuntime.jsx(OzCardNumber, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.cardNumber), className: classNames === null || classNames === void 0 ? void 0 : classNames.cardNumber, placeholder: (_a = placeholders === null || placeholders === void 0 ? void 0 : placeholders.cardNumber) !== null && _a !== void 0 ? _a : 'Card number', disabled: disabled, onChange: (e) => { fieldState.current.cardNumber = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'cardNumber'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'cardNumber'); }, onReady: readyHandlers['cardNumber'] })] }));
2192
+ const expiryField = (jsxRuntime.jsxs("div", { style: layout === 'default' ? { flex: 1 } : undefined, children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.expiry), jsxRuntime.jsx(OzExpiry, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.expiry), className: classNames === null || classNames === void 0 ? void 0 : classNames.expiry, placeholder: (_b = placeholders === null || placeholders === void 0 ? void 0 : placeholders.expiry) !== null && _b !== void 0 ? _b : 'MM / YY', disabled: disabled, onChange: (e) => { fieldState.current.expiry = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'expiry'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'expiry'); }, onReady: readyHandlers['expiry'] })] }));
2193
+ const cvvField = (jsxRuntime.jsxs("div", { style: layout === 'default' ? { flex: 1 } : undefined, children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.cvv), jsxRuntime.jsx(OzCvv, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.cvv), className: classNames === null || classNames === void 0 ? void 0 : classNames.cvv, placeholder: (_c = placeholders === null || placeholders === void 0 ? void 0 : placeholders.cvv) !== null && _c !== void 0 ? _c : 'CVV', disabled: disabled, onChange: (e) => { fieldState.current.cvv = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'cvv'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'cvv'); }, onReady: readyHandlers['cvv'] })] }));
2138
2194
  if (layout === 'rows') {
2139
2195
  return (jsxRuntime.jsxs("div", { className: className, style: { width: '100%', display: 'flex', flexDirection: 'column', gap: gapStr }, children: [cardNumberField, expiryField, cvvField, errorNode] }));
2140
2196
  }
@@ -2155,49 +2211,21 @@ const OzBankRoutingNumber = (props) => jsxRuntime.jsx(OzFieldBase, Object.assign
2155
2211
  function OzBankCard({ style, styles, classNames, labels, labelStyle, labelClassName, gap = 8, hideErrors = false, errorStyle, errorClassName, renderError, onChange, onReady, onFocus, onBlur, disabled, className, placeholders, }) {
2156
2212
  var _a, _b;
2157
2213
  const { vault } = react.useContext(OzContext);
2214
+ const { onChangeRef, onFocusRef, onBlurRef, readyHandlers, error, setError, gapStr, renderLabel, } = useCardBase({
2215
+ vault,
2216
+ fieldNames: ['accountNumber', 'routingNumber'],
2217
+ onChange,
2218
+ onReady,
2219
+ onFocus,
2220
+ onBlur,
2221
+ gap,
2222
+ labelStyle,
2223
+ labelClassName,
2224
+ });
2158
2225
  const fieldState = react.useRef({
2159
2226
  accountNumber: null,
2160
2227
  routingNumber: null,
2161
2228
  });
2162
- const readyFieldTypes = react.useRef(new Set());
2163
- const onReadyFiredRef = react.useRef(false);
2164
- const vaultRef = react.useRef(vault);
2165
- const onChangeRef = react.useRef(onChange);
2166
- const onReadyRef = react.useRef(onReady);
2167
- const onFocusRef = react.useRef(onFocus);
2168
- const onBlurRef = react.useRef(onBlur);
2169
- react.useEffect(() => { onChangeRef.current = onChange; }, [onChange]);
2170
- react.useEffect(() => { onReadyRef.current = onReady; }, [onReady]);
2171
- react.useEffect(() => { onFocusRef.current = onFocus; }, [onFocus]);
2172
- react.useEffect(() => { onBlurRef.current = onBlur; }, [onBlur]);
2173
- react.useEffect(() => {
2174
- if (vault !== vaultRef.current) {
2175
- vaultRef.current = vault;
2176
- readyFieldTypes.current = new Set();
2177
- onReadyFiredRef.current = false;
2178
- }
2179
- return () => {
2180
- readyFieldTypes.current = new Set();
2181
- onReadyFiredRef.current = false;
2182
- };
2183
- }, [vault]);
2184
- const [error, setError] = react.useState();
2185
- const handleAccountReady = react.useCallback(() => {
2186
- var _a;
2187
- readyFieldTypes.current.add('accountNumber');
2188
- if (readyFieldTypes.current.size >= 2 && !onReadyFiredRef.current) {
2189
- onReadyFiredRef.current = true;
2190
- (_a = onReadyRef.current) === null || _a === void 0 ? void 0 : _a.call(onReadyRef);
2191
- }
2192
- }, []);
2193
- const handleRoutingReady = react.useCallback(() => {
2194
- var _a;
2195
- readyFieldTypes.current.add('routingNumber');
2196
- if (readyFieldTypes.current.size >= 2 && !onReadyFiredRef.current) {
2197
- onReadyFiredRef.current = true;
2198
- (_a = onReadyRef.current) === null || _a === void 0 ? void 0 : _a.call(onReadyRef);
2199
- }
2200
- }, []);
2201
2229
  const emitChange = react.useCallback(() => {
2202
2230
  var _a;
2203
2231
  const { accountNumber, routingNumber } = fieldState.current;
@@ -2210,18 +2238,14 @@ function OzBankCard({ style, styles, classNames, labels, labelStyle, labelClassN
2210
2238
  error: err,
2211
2239
  fields: Object.assign({}, fieldState.current),
2212
2240
  });
2213
- }, []);
2214
- const gapStr = typeof gap === 'string' ? gap : `${gap}px`;
2215
- const resolvedLabelStyle = labelStyle
2216
- ? Object.assign(Object.assign({}, DEFAULT_LABEL_STYLE), labelStyle) : DEFAULT_LABEL_STYLE;
2217
- const renderLabel = (text) => renderFieldLabel(text, labelClassName, resolvedLabelStyle);
2241
+ }, [setError, onChangeRef]);
2218
2242
  const showError = !hideErrors && error;
2219
2243
  const errorNode = showError
2220
2244
  ? renderError
2221
2245
  ? renderError(error)
2222
2246
  : (jsxRuntime.jsx("div", { role: "alert", className: errorClassName, style: errorStyle ? Object.assign(Object.assign({}, DEFAULT_ERROR_STYLE), errorStyle) : DEFAULT_ERROR_STYLE, children: error }))
2223
2247
  : null;
2224
- return (jsxRuntime.jsxs("div", { className: className, style: { width: '100%', display: 'flex', flexDirection: 'column', gap: gapStr }, children: [jsxRuntime.jsxs("div", { children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.accountNumber), jsxRuntime.jsx(OzBankAccountNumber, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.accountNumber), className: classNames === null || classNames === void 0 ? void 0 : classNames.accountNumber, placeholder: (_a = placeholders === null || placeholders === void 0 ? void 0 : placeholders.accountNumber) !== null && _a !== void 0 ? _a : 'Account number', disabled: disabled, onChange: (e) => { fieldState.current.accountNumber = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'accountNumber'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'accountNumber'); }, onReady: handleAccountReady })] }), jsxRuntime.jsxs("div", { children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.routingNumber), jsxRuntime.jsx(OzBankRoutingNumber, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.routingNumber), className: classNames === null || classNames === void 0 ? void 0 : classNames.routingNumber, placeholder: (_b = placeholders === null || placeholders === void 0 ? void 0 : placeholders.routingNumber) !== null && _b !== void 0 ? _b : 'Routing number', disabled: disabled, onChange: (e) => { fieldState.current.routingNumber = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'routingNumber'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'routingNumber'); }, onReady: handleRoutingReady })] }), errorNode] }));
2248
+ return (jsxRuntime.jsxs("div", { className: className, style: { width: '100%', display: 'flex', flexDirection: 'column', gap: gapStr }, children: [jsxRuntime.jsxs("div", { children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.accountNumber), jsxRuntime.jsx(OzBankAccountNumber, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.accountNumber), className: classNames === null || classNames === void 0 ? void 0 : classNames.accountNumber, placeholder: (_a = placeholders === null || placeholders === void 0 ? void 0 : placeholders.accountNumber) !== null && _a !== void 0 ? _a : 'Account number', disabled: disabled, onChange: (e) => { fieldState.current.accountNumber = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'accountNumber'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'accountNumber'); }, onReady: readyHandlers['accountNumber'] })] }), jsxRuntime.jsxs("div", { children: [renderLabel(labels === null || labels === void 0 ? void 0 : labels.routingNumber), jsxRuntime.jsx(OzBankRoutingNumber, { style: mergeStyles(style, styles === null || styles === void 0 ? void 0 : styles.routingNumber), className: classNames === null || classNames === void 0 ? void 0 : classNames.routingNumber, placeholder: (_b = placeholders === null || placeholders === void 0 ? void 0 : placeholders.routingNumber) !== null && _b !== void 0 ? _b : 'Routing number', disabled: disabled, onChange: (e) => { fieldState.current.routingNumber = e; emitChange(); }, onFocus: () => { var _a; return (_a = onFocusRef.current) === null || _a === void 0 ? void 0 : _a.call(onFocusRef, 'routingNumber'); }, onBlur: () => { var _a; return (_a = onBlurRef.current) === null || _a === void 0 ? void 0 : _a.call(onBlurRef, 'routingNumber'); }, onReady: readyHandlers['routingNumber'] })] }), errorNode] }));
2225
2249
  }
2226
2250
 
2227
2251
  exports.OzBankAccountNumber = OzBankAccountNumber;