diff --git a/__tests__/components/__snapshots__/components.test.js.snap b/__tests__/components/__snapshots__/components.test.js.snap
index ad718fd..a38540f 100644
--- a/__tests__/components/__snapshots__/components.test.js.snap
+++ b/__tests__/components/__snapshots__/components.test.js.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`test Collect And Reveal Elements Components test CardHolderNameElement component 1`] = `
+exports[`test Collect Elements Components test CardHolderNameElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test CardNumberElement component 1`] = `
+exports[`test Collect Elements Components test CardNumberElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test CvvElement component 1`] = `
+exports[`test Collect Elements Components test CvvElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test ExpirationDateElement component 1`] = `
+exports[`test Collect Elements Components test ExpirationDateElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test ExpirationMonthElement component 1`] = `
+exports[`test Collect Elements Components test ExpirationMonthElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test ExpirationYearElement component 1`] = `
+exports[`test Collect Elements Components test ExpirationYearElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test InputFieldElement component 1`] = `
+exports[`test Collect Elements Components test InputFieldElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test PinElement component 1`] = `
+exports[`test Collect Elements Components test PinElement component 1`] = `
`;
-exports[`test Collect And Reveal Elements Components test RevealElement component 1`] = `
+exports[`test Collect Elements Components test Reveal Elements Components renders correctly with the handler & snapshot 1`] = `
Array [
,
,
]
`;
-exports[`test Collect And Reveal Elements Components test skyflow provider 1`] = `
+exports[`test Collect Elements Components test RevealElement component rendering 1`] = `
+Array [
+
+ Card Number
+ ,
+
+ XXXX XXXX XXXX XXXX
+ ,
+ ,
+]
+`;
+
+exports[`test Collect Elements Components test skyflow provider 1`] = `
- Provider Childern
+ Provider Children
`;
diff --git a/__tests__/components/components.test.js b/__tests__/components/components.test.js
index aa2fb49..94cd182 100644
--- a/__tests__/components/components.test.js
+++ b/__tests__/components/components.test.js
@@ -21,6 +21,7 @@ import { Text } from 'react-native';
import SkyflowError from '../../src/utils/skyflow-error';
import SKYFLOW_ERROR_CODE from '../../src/utils/skyflow-error-code';
import { ContainerType, ElementType } from '../../src/utils/constants';
+import { act } from 'react-test-renderer';
const testSkyflowClient = new Skyflow({
vaultID: '1234',
@@ -37,7 +38,7 @@ const changeTrigger = jest.fn();
const foucsTrigger = jest.fn();
const blurTrigger = jest.fn();
-describe('test Collect And Reveal Elements Components', () => {
+describe('test Collect Elements Components', () => {
let collectContainer;
beforeEach(() => {
jest.clearAllMocks();
@@ -558,11 +559,112 @@ describe('test Collect And Reveal Elements Components', () => {
}
});
- it('test RevealElement component', () => {
+ describe('test Reveal Elements Components', () => {
+ it('renders correctly with the handler & snapshot', () => {
+ const revealSetMethodMock = jest.fn();
+ const revealContainer = new RevealContainer(testSkyflowClient);
+ jest.spyOn(revealContainer, 'create').mockImplementation(() => ({
+ setMethods: revealSetMethodMock,
+ }));
+
+ const revealElement = render(
+
+ );
+
+ expect(revealElement).toMatchSnapshot();
+ expect(revealSetMethodMock).toBeCalledTimes(1);
+
+ // render without alttext
+ const revealElement2 = render(
+
+ );
+ try {
+ render();
+ } catch (err) {
+ expect(err).toEqual(
+ new SkyflowError(
+ SKYFLOW_ERROR_CODE.CONTAINER_OBJECT_IS_REQUIRED,
+ ['Reveal', 'useRevealContainer()'],
+ true
+ )
+ );
+ }
+ });
+
+ it('renders formatted value when format is provided', () => {
+ const revealSetMethodMock = jest.fn();
+ const revealContainer = new RevealContainer(testSkyflowClient);
+ jest.spyOn(revealContainer, 'create').mockImplementation(() => ({
+ setMethods: revealSetMethodMock,
+ }));
+
+ const format = 'XXXX XXXX XXXX XXXX';
+ const altText = '4111111111111111';
+
+ render(
+
+ );
+
+ // Should format altText using format
+ expect(screen.getByTestId('reveal-format').props.children).toBe(
+ '4111 1111 1111 1111'
+ );
+ });
+
+ it('renders formatted value when format and translation are provided', () => {
+ const revealSetMethodMock = jest.fn();
+ const revealContainer = new RevealContainer(testSkyflowClient);
+ jest.spyOn(revealContainer, 'create').mockImplementation(() => ({
+ setMethods: revealSetMethodMock,
+ }));
+
+ const format = 'XX-XX-XX-YYZ-ZZX';
+ const translation = { X: '[0-9]', Y: '[A-Z]' };
+ const altText = '123456AB7';
+
+ render(
+
+ );
+
+ // Should format altText using format and translation
+ expect(
+ screen.getByTestId('reveal-format-translation').props.children
+ ).toBe('12-34-56-ABZ-ZZ7');
+ });
+ });
+
+ it('test RevealElement component rendering', () => {
const revealSetMethodMock = jest.fn();
+ const revealSetTokenMock = jest.fn();
const revealContainer = new RevealContainer(testSkyflowClient);
+
jest.spyOn(revealContainer, 'create').mockImplementation(() => ({
setMethods: revealSetMethodMock,
+ setToken: revealSetTokenMock,
}));
const revealElement = render(
@@ -577,14 +679,15 @@ describe('test Collect And Reveal Elements Components', () => {
expect(revealElement).toMatchSnapshot();
expect(revealSetMethodMock).toBeCalledTimes(1);
- // render without alttext
- const revealElement2 = render(
+ render(
);
+ expect(screen.getByText('test_token_no_alt')).toBeTruthy();
+
try {
render();
} catch (err) {
@@ -598,6 +701,40 @@ describe('test Collect And Reveal Elements Components', () => {
}
});
+ it('test RevealElement setToken via ref updates UI and internal element', () => {
+ const revealSetMethodMock = jest.fn();
+ const revealSetTokenMock = jest.fn();
+ const revealContainer = new RevealContainer(testSkyflowClient);
+
+ jest.spyOn(revealContainer, 'create').mockImplementation(() => ({
+ setMethods: revealSetMethodMock,
+ setToken: revealSetTokenMock,
+ }));
+
+ const ref = React.createRef();
+ const initialToken = 'initial_token_123';
+ const newToken = 'updated_token_456';
+
+ const { getByText } = render(
+
+ );
+
+ expect(getByText(initialToken)).toBeTruthy();
+
+ act(() => {
+ ref.current.setToken(newToken);
+ });
+
+ expect(revealSetTokenMock).toHaveBeenCalledWith(newToken);
+
+ expect(getByText(newToken)).toBeTruthy();
+ });
+
it('test skyflow provider', () => {
const testSkyflowConfig = {
vaultID: '1234',
@@ -607,7 +744,7 @@ describe('test Collect And Reveal Elements Components', () => {
const providerElement = render(
- Provider Childern
+ Provider Children
);
expect(providerElement).toMatchSnapshot();
diff --git a/__tests__/core-utils/element-validations.test.js b/__tests__/core-utils/element-validations.test.js
index b9960f6..9f46068 100644
--- a/__tests__/core-utils/element-validations.test.js
+++ b/__tests__/core-utils/element-validations.test.js
@@ -8,6 +8,7 @@ import {
validatePin,
validateRevealElementRecords,
validateGetInput,
+ validateExpiryDate,
} from '../../src/core-utils/element-validations';
import SKYFLOW_ERROR_CODE from '../../src/utils/skyflow-error-code';
import { parameterizedString } from '../../src/utils/logs-helper';
@@ -186,6 +187,41 @@ describe('test validatePin function', () => {
});
});
+describe('test validateExpiryDate function with various format', () => {
+ it('should return true for current month/year', () => {
+ const today = new Date();
+ const month = (today.getMonth() + 1).toString().padStart(2, '0');
+ const year = today.getFullYear();
+ expect(validateExpiryDate(`${month}/${year}`, 'MM/YYYY')).toBe(true);
+ expect(validateExpiryDate(`${year}/${month}`, 'YYYY/MM')).toBe(true);
+
+ const yearTwoDigit = year % 100;
+ expect(validateExpiryDate(`${month}/${yearTwoDigit}`, 'MM/YY')).toBe(true);
+ expect(validateExpiryDate(`${yearTwoDigit}/${month}`, 'YY/MM')).toBe(true);
+ });
+
+ it('should return true for valid future date', () => {
+ expect(validateExpiryDate('07/2074', 'MM/YYYY')).toBe(true);
+ expect(validateExpiryDate('2074/04', 'YYYY/MM')).toBe(true);
+ expect(validateExpiryDate('01/35', 'MM/YY')).toBe(true);
+ expect(validateExpiryDate('35/04', 'YY/MM')).toBe(true);
+ });
+
+ it('should return false for expired dates', () => {
+ expect(validateExpiryDate('01/2020', 'MM/YYYY')).toBe(false);
+ expect(validateExpiryDate('2000/04', 'YYYY/MM')).toBe(false);
+ expect(validateExpiryDate('04/20', 'MM/YY')).toBe(false);
+ expect(validateExpiryDate('20/04', 'YY/MM')).toBe(false);
+ });
+
+ it('should return false for invalid month for expired date', () => {
+ expect(validateExpiryDate('15/2040', 'MM/YYYY')).toBe(false);
+ expect(validateExpiryDate('2040/16', 'YYYY/MM')).toBe(false);
+ expect(validateExpiryDate('14/20', 'MM/YY')).toBe(false);
+ expect(validateExpiryDate('40/14', 'YY/MM')).toBe(false);
+ });
+});
+
describe('test validateRevealElementRecords', () => {
it('should throw error when invalid redaction type is passed', (done) => {
try {
diff --git a/__tests__/core/RevealContainer.test.js b/__tests__/core/RevealContainer.test.js
index a126ee6..9fb5530 100644
--- a/__tests__/core/RevealContainer.test.js
+++ b/__tests__/core/RevealContainer.test.js
@@ -146,4 +146,56 @@ describe('test RevealConatiner Class', () => {
}
});
});
+
+ it('test reveal method uses updated token when setToken is called', (done) => {
+ const initialToken = 'initial_token';
+ const updatedToken = 'updated_token';
+
+ const revealElement = revealContainer.create({
+ token: initialToken,
+ });
+
+ const revealSuccessValue = {
+ records: [
+ {
+ token: updatedToken,
+ value: 'revealed_value',
+ },
+ ],
+ };
+
+ const fetchSpy = jest
+ .spyOn(revealUtils, 'fetchRecordsByTokenId')
+ .mockResolvedValue(revealSuccessValue);
+
+ const setValueMock = jest.fn();
+ const setErrorMock = jest.fn();
+ revealElement.setMethods(setValueMock, setErrorMock);
+
+ revealElement.setToken(updatedToken);
+
+ revealContainer
+ .reveal()
+ .then((res) => {
+ try {
+ expect(fetchSpy).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.arrayContaining([
+ expect.objectContaining({
+ token: updatedToken,
+ elementId: revealElement.elementId,
+ }),
+ ])
+ );
+
+ expect(res).toEqual({ success: [{ token: updatedToken }] });
+ done();
+ } catch (assertionError) {
+ done(assertionError);
+ }
+ })
+ .catch((err) => {
+ done(err);
+ });
+ });
});
diff --git a/__tests__/core/collectElement.test.js b/__tests__/core/collectElement.test.js
index 185c480..f3a176b 100644
--- a/__tests__/core/collectElement.test.js
+++ b/__tests__/core/collectElement.test.js
@@ -257,7 +257,11 @@ describe('test Collect Element class', () => {
new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_COLUMN_IN_COLLECT, [], true)
);
- collecteElement = new CollectElement({ table: 'cards', column: 'test', skyflowID: '' }, {}, context);
+ collecteElement = new CollectElement(
+ { table: 'cards', column: 'test', skyflowID: '' },
+ {},
+ context
+ );
expect(isValid).toThrow(
new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_SKYFLOW_ID_COLLECT, [], true)
);
@@ -515,6 +519,122 @@ describe('test Collect Element class', () => {
);
cardNumberElement.onDropdownSelect(CardType.DISCOVER);
cardNumberElement.onChangeElement('', true);
- expect(cardNumberElement.getClientState().selectedCardScheme).toEqual('DISCOVER');
- })
-});
\ No newline at end of file
+ expect(cardNumberElement.getClientState().selectedCardScheme).toEqual(
+ 'DISCOVER'
+ );
+ });
+
+ it('test format option in card number element', () => {
+ const formatTestCases = [
+ // Test different valid formats for the card number
+ {
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ input: '4111111111111111',
+ expected: '4111-1111-1111-1111',
+ },
+ {
+ format: 'XXXX XXXX XXXX XXXX',
+ input: '4111111111111111',
+ expected: '4111 1111 1111 1111',
+ },
+ // Test partial input
+ {
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ input: '411111',
+ expected: '4111-11',
+ },
+ {
+ format: 'XXXX XXXX XXXX XXXX',
+ input: '411111',
+ expected: '4111 11',
+ },
+ // Test for invalid format, It will fallback to default format
+ {
+ format: ' xxxx-xxxx-xxxx ',
+ input: ' 4111111111111111 ',
+ expected: '4111 1111 1111 1111',
+ },
+ ];
+
+ formatTestCases.forEach((testCase) => {
+ const collectElement = new CollectElement(
+ {
+ table: 'cards',
+ column: 'card_number',
+ type: ElementType.CARD_NUMBER,
+ containerType: ContainerType.COLLECT,
+ },
+ {
+ format: testCase.format,
+ },
+ context
+ );
+
+ collectElement.onChangeElement(testCase.input);
+ expect(collectElement.getInternalState().value).toBe(testCase.expected);
+ });
+ });
+
+ it('test format option in input field element', () => {
+ const formatTestCases = [
+ {
+ format: 'XX-XX-XX',
+ input: '123456',
+ expected: '12-34-56',
+ },
+ {
+ format: 'XXX XXX',
+ input: '123456',
+ expected: '123 456',
+ },
+ {
+ format: 'XX/XX/XX',
+ input: '123456',
+ expected: '12/34/56',
+ },
+ // Test partial input
+ {
+ format: 'XX-XX-XX',
+ input: '1234',
+ expected: '12-34',
+ },
+ // Test with special characters
+ {
+ format: 'XX@XX#XX',
+ input: '123456',
+ expected: '12@34#56',
+ },
+ // Test input longer than format
+ {
+ format: 'XX-XX',
+ input: '123456',
+ expected: '12-34',
+ },
+ // Test input with leading, trailing spaces & small format
+ {
+ format: ' xx-xx-xxx ',
+ input: ' 1234567 ',
+ expected: ' xx-xx-xxx ',
+ },
+ ];
+
+ formatTestCases.forEach((testCase) => {
+ const collectElement = new CollectElement(
+ {
+ table: 'table',
+ column: 'column',
+ type: ElementType.INPUT_FIELD,
+ containerType: ContainerType.COLLECT,
+ },
+ {
+ format: testCase.format,
+ },
+ context
+ );
+
+ collectElement.onChangeElement(testCase.input);
+ expect(collectElement.getInternalState().value).toBe(testCase.expected);
+ expect(collectElement.getInternalState().isValid).toBe(true);
+ });
+ });
+});
diff --git a/__tests__/utils/helper.test.js b/__tests__/utils/helper.test.js
index c1a2a36..708ad0f 100644
--- a/__tests__/utils/helper.test.js
+++ b/__tests__/utils/helper.test.js
@@ -16,6 +16,7 @@ import {
getYearAndMonthBasedOnFormat,
getMetaObject,
getDeviceModel,
+ formatInputFieldValue,
} from '../../src/utils/helpers';
import {
CardType,
@@ -218,6 +219,16 @@ describe('test getReturnValue function', () => {
).toBe('4111111111111111');
});
+ it('should return unformatted value for card number element', () => {
+ expect(
+ getReturnValue('4111 1111 1111 1111', true, ElementType.CARD_NUMBER)
+ ).toBe('4111111111111111');
+
+ expect(
+ getReturnValue('4111-1111-1111-1111', true, ElementType.CARD_NUMBER)
+ ).toBe('4111111111111111');
+ });
+
it('should return non string value when return value is true', () => {
expect(getReturnValue(1000, true, ElementType.INPUT_FIELD)).toBe(1000);
});
@@ -300,4 +311,223 @@ describe('test getYearAndMonthBasedOnFormat function', () => {
year: '2032',
});
});
+
+ it('should format expiration date options correctly', () => {
+ const validFormats = ['MM/YY', 'MM/YYYY', 'YYYY/MM', 'YY/MM'];
+ validFormats.forEach((format) => {
+ const result = formatCollectElementOptions(
+ ElementType.EXPIRATION_DATE,
+ { format },
+ LogLevel.WARN
+ );
+ expect(result).toEqual({
+ format,
+ required: false,
+ });
+ });
+ });
+
+ it('should use default format for invalid expiration date format', () => {
+ const result = formatCollectElementOptions(
+ ElementType.EXPIRATION_DATE,
+ { format: 'INVALID' },
+ LogLevel.WARN
+ );
+ expect(result).toEqual({
+ format: DEFAULT_EXPIRATION_DATE_FORMAT,
+ required: false,
+ });
+ expect(printLog).toBeCalled();
+ });
+
+ it('should format expiration year options correctly', () => {
+ const validFormats = ['YY', 'YYYY'];
+ validFormats.forEach((format) => {
+ const result = formatCollectElementOptions(
+ ElementType.EXPIRATION_YEAR,
+ { format },
+ LogLevel.WARN
+ );
+ expect(result).toEqual({
+ format,
+ required: false,
+ });
+ });
+ });
+
+ it('should use default format for invalid expiration year format', () => {
+ const result = formatCollectElementOptions(
+ ElementType.EXPIRATION_YEAR,
+ { format: 'INVALID' },
+ LogLevel.WARN
+ );
+ expect(result).toEqual({
+ format: DEFAULT_EXPIRATION_YEAR_FORMAT,
+ required: false,
+ });
+ expect(printLog).toBeCalled();
+ });
+});
+
+describe('test formatCardNumber with different formats', () => {
+ const testCases = [
+ {
+ input: '4111111111111111',
+ type: CardType.VISA,
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ expected: '4111-1111-1111-1111',
+ },
+ {
+ input: '378282246310005',
+ type: CardType.AMEX,
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ expected: '3782-822463-10005',
+ },
+ {
+ input: '6011111111111117',
+ type: CardType.DISCOVER,
+ format: 'XXXX XXXX XXXX XXXX',
+ expected: '6011 1111 1111 1117',
+ },
+ // Test partial inputs
+ {
+ input: '411111',
+ type: CardType.VISA,
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ expected: '4111-11',
+ },
+ // Test empty input
+ {
+ input: '',
+ type: CardType.DEFAULT,
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ expected: '',
+ },
+ ];
+
+ testCases.forEach((testCase) => {
+ it(`should format ${testCase.type} card number correctly with format ${testCase.format}`, () => {
+ expect(
+ formatCardNumber(testCase.input, testCase.type, testCase.format)
+ ).toBe(testCase.expected);
+ });
+ });
+});
+
+describe('test formatInputFieldValue with different formats', () => {
+ const testCases = [
+ {
+ input: '123456',
+ format: 'XX-XX-XX',
+ expected: '12-34-56',
+ },
+ {
+ input: '123456',
+ format: 'XXX XXX',
+ expected: '123 456',
+ },
+ {
+ input: '12345',
+ format: 'XX/XX/X',
+ expected: '12/34/5',
+ },
+ {
+ input: '1567C89',
+ format: 'XX/XYX/X',
+ translation: { X: '[5-9]', Y: '[A-C]' },
+ expected: '56/7C8/9',
+ },
+ // Combination of constants and dynamic inputs
+ {
+ input: '1234121234',
+ format: '+91 XXXX-XX-XXXX',
+ expected: '+91 1234-12-1234',
+ },
+ {
+ input: 'B5678978C7QAB97',
+ format: '91 YXX-XZX-XXY-XZYXX',
+ translation: { X: '[5-9]', Y: '[A-C]' },
+ expected: '91 B56-7Z8-97C-7ZA97',
+ },
+ // Test with special characters in format
+ {
+ input: '123456',
+ format: 'XX@XX#XX',
+ expected: '12@34#56',
+ },
+ // Test partial input
+ {
+ input: '123',
+ format: 'XX-XX-XX',
+ expected: '12-3',
+ },
+ // Test input longer than format
+ {
+ input: '1234567',
+ format: 'XX-XX',
+ expected: '12-34',
+ },
+ // Test empty input
+ {
+ input: '',
+ format: 'XX-XX',
+ expected: '',
+ },
+ // Test with no format
+ {
+ input: '123456',
+ format: '',
+ expected: '123456',
+ },
+ ];
+
+ testCases.forEach((testCase) => {
+ const translation = testCase.translation || {
+ X: '[0-9]',
+ };
+ it(`should format input '${testCase.input}' with format '${
+ testCase.format
+ }' & translation '${JSON.stringify(translation)}' correctly`, () => {
+ expect(
+ formatInputFieldValue(
+ testCase.input,
+ testCase.format,
+ testCase?.translation
+ )
+ ).toBe(testCase.expected);
+ });
+ });
+});
+
+describe('test formatCollectElementOptions for different element types', () => {
+ it('should format card number options correctly', () => {
+ const options = {
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ required: true,
+ };
+ const result = formatCollectElementOptions(
+ ElementType.CARD_NUMBER,
+ options,
+ LogLevel.WARN
+ );
+ expect(result).toEqual({
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ required: true,
+ });
+ });
+
+ it('should preserve other options while formatting', () => {
+ const options = {
+ format: 'XXXX-XXXX-XXXX-XXXX',
+ required: true,
+ enableCardIcon: true,
+ customOption: 'value',
+ };
+ const result = formatCollectElementOptions(
+ ElementType.CARD_NUMBER,
+ options,
+ LogLevel.WARN
+ );
+ expect(result).toEqual(options);
+ });
});
diff --git a/example/metro.config.js b/example/metro.config.js
index b5c0064..a41e637 100644
--- a/example/metro.config.js
+++ b/example/metro.config.js
@@ -17,10 +17,14 @@ module.exports = {
// So we block them at the root, and alias them to the versions in example's node_modules
resolver: {
blacklistRE: exclusionList(
- modules.map(
- (m) =>
- new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
- )
+ modules
+ .map(
+ (m) =>
+ new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
+ )
+ .concat([
+ new RegExp(`^${escape(path.join(root, 'lib', 'package.json'))}$`),
+ ])
),
extraNodeModules: modules.reduce((acc, name) => {
diff --git a/example/package.json b/example/package.json
index c0c7860..97db816 100644
--- a/example/package.json
+++ b/example/package.json
@@ -14,6 +14,11 @@
"react": "18.2.0",
"react-native": "^0.71.19"
},
+ "resolutions": {
+ "@babel/runtime": "^7.26.10",
+ "@babel/helpers": "^7.26.10",
+ "brace-expansion": "^1.1.12"
+ },
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/runtime": "^7.12.5",
diff --git a/example/src/App.tsx b/example/src/App.tsx
index 1bff8d3..380fe4c 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -77,4 +77,4 @@ const App = () => {
);
};
-export default App;
+export default App;
\ No newline at end of file
diff --git a/example/src/ElementView.tsx b/example/src/ElementView.tsx
index 362202d..2e1a7f0 100644
--- a/example/src/ElementView.tsx
+++ b/example/src/ElementView.tsx
@@ -35,4 +35,4 @@ const styles = StyleSheet.create({
},
});
-export default ElementView;
+export default ElementView;
\ No newline at end of file
diff --git a/example/src/RevealElements.tsx b/example/src/RevealElements.tsx
index 694ed4c..0cd6cab 100644
--- a/example/src/RevealElements.tsx
+++ b/example/src/RevealElements.tsx
@@ -161,4 +161,4 @@ const buttonStyles = StyleSheet.create({
margin: 10,
},
});
-export default RevealElements;
+export default RevealElements;
\ No newline at end of file
diff --git a/example/yarn.lock b/example/yarn.lock
index 6dc241b..1ce7df6 100644
--- a/example/yarn.lock
+++ b/example/yarn.lock
@@ -19,6 +19,15 @@
js-tokens "^4.0.0"
picocolors "^1.0.0"
+"@babel/code-frame@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
+ integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.27.1"
+ js-tokens "^4.0.0"
+ picocolors "^1.1.1"
+
"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02"
@@ -182,11 +191,21 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
+"@babel/helper-string-parser@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
+ integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
+
"@babel/helper-validator-identifier@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
+"@babel/helper-validator-identifier@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
+ integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
+
"@babel/helper-validator-option@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72"
@@ -201,13 +220,13 @@
"@babel/traverse" "^7.25.9"
"@babel/types" "^7.25.9"
-"@babel/helpers@^7.26.0":
- version "7.26.0"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4"
- integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==
+"@babel/helpers@^7.26.0", "@babel/helpers@^7.26.10":
+ version "7.27.6"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c"
+ integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==
dependencies:
- "@babel/template" "^7.25.9"
- "@babel/types" "^7.26.0"
+ "@babel/template" "^7.27.2"
+ "@babel/types" "^7.27.6"
"@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.20.0", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3":
version "7.26.3"
@@ -216,6 +235,13 @@
dependencies:
"@babel/types" "^7.26.3"
+"@babel/parser@^7.27.2":
+ version "7.28.0"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e"
+ integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==
+ dependencies:
+ "@babel/types" "^7.28.0"
+
"@babel/plugin-proposal-async-generator-functions@^7.0.0":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326"
@@ -633,12 +659,10 @@
pirates "^4.0.6"
source-map-support "^0.5.16"
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4":
- version "7.26.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
- integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
- dependencies:
- regenerator-runtime "^0.14.0"
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.26.10", "@babel/runtime@^7.8.4":
+ version "7.27.6"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6"
+ integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==
"@babel/template@^7.0.0", "@babel/template@^7.25.9":
version "7.25.9"
@@ -649,6 +673,15 @@
"@babel/parser" "^7.25.9"
"@babel/types" "^7.25.9"
+"@babel/template@^7.27.2":
+ version "7.27.2"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
+ integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==
+ dependencies:
+ "@babel/code-frame" "^7.27.1"
+ "@babel/parser" "^7.27.2"
+ "@babel/types" "^7.27.1"
+
"@babel/traverse@^7.20.0", "@babel/traverse@^7.25.9":
version "7.26.4"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd"
@@ -670,6 +703,14 @@
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
+"@babel/types@^7.27.1", "@babel/types@^7.27.6", "@babel/types@^7.28.0":
+ version "7.28.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.0.tgz#2fd0159a6dc7353933920c43136335a9b264d950"
+ integrity sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==
+ dependencies:
+ "@babel/helper-string-parser" "^7.27.1"
+ "@babel/helper-validator-identifier" "^7.27.1"
+
"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
@@ -1282,21 +1323,14 @@ bl@^4.1.0:
inherits "^2.0.4"
readable-stream "^3.4.0"
-brace-expansion@^1.1.7:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
- integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+brace-expansion@^1.1.12, brace-expansion@^1.1.7, brace-expansion@^2.0.1:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
+ integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
-brace-expansion@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
- integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
- dependencies:
- balanced-match "^1.0.0"
-
braces@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
@@ -3059,7 +3093,7 @@ path-scurry@^1.6.1:
lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
-picocolors@^1.0.0, picocolors@^1.1.0:
+picocolors@^1.0.0, picocolors@^1.1.0, picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
@@ -3321,11 +3355,6 @@ regenerator-runtime@^0.13.2:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
-regenerator-runtime@^0.14.0:
- version "0.14.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
- integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
-
regenerator-transform@^0.15.2:
version "0.15.2"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4"
diff --git a/package.json b/package.json
index 03d5000..235391a 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,17 @@
{
"name": "skyflow-react-native",
- "version": "1.9.0",
+ "version": "1.9.0-dev.28f5536",
"description": "Skyflow React Native SDK",
"main": "lib/commonjs/index",
"module": "lib/module/index",
- "types": "lib/typescript/index.d.ts",
+ "types": "lib/typescript/src/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./lib/typescript/src/index.d.ts",
+ "import": "./lib/module/index.js",
+ "require": "./lib/commonjs/index.js"
+ }
+ },
"react-native": "src/index",
"source": "src/index",
"files": [
@@ -29,7 +36,7 @@
"prepare": "bob build",
"example": "yarn --cwd example",
"bootstrap": "yarn example && yarn && yarn example pods",
- "build": "bob build"
+ "build": "bob build && cp -r assets lib/ && cp package.json lib/"
},
"keywords": [
"react-native",
@@ -64,7 +71,10 @@
"typescript": "^4.5.2"
},
"resolutions": {
- "@types/react": "17.0.21"
+ "@types/react": "17.0.21",
+ "@babel/runtime": "^7.26.10",
+ "@babel/helpers": "^7.26.10",
+ "brace-expansion": "^1.1.12"
},
"peerDependencies": {
"react": "^17.0.2 || ^18.0.0",
diff --git a/src/components/CardHolderNameElement/index.tsx b/src/components/CardHolderNameElement/index.tsx
index e9ec317..8bd1307 100644
--- a/src/components/CardHolderNameElement/index.tsx
+++ b/src/components/CardHolderNameElement/index.tsx
@@ -49,6 +49,7 @@ const CardHolderNameElement: React.FC = ({ container, optio
ref={textInputRef}
value={elementValue}
placeholder={rest.placeholder}
+ testID={rest?.testID}
onChangeText={(text) => {
element?.onChangeElement(text)
setElementValue(element.getInternalState().value)
@@ -75,7 +76,7 @@ const CardHolderNameElement: React.FC = ({ container, optio
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
diff --git a/src/components/CardNumberElement/index.tsx b/src/components/CardNumberElement/index.tsx
index de3b8b3..0817f0e 100644
--- a/src/components/CardNumberElement/index.tsx
+++ b/src/components/CardNumberElement/index.tsx
@@ -5,11 +5,12 @@ import React, { useEffect, useRef } from "react";
import { Image, Text, TextInput, View } from "react-native";
import type CollectElement from "../../core/CollectElement";
import { CARD_ENCODED_ICONS, CARD_NUMBER_MASK, CardType, CardTypeValues, DEFAULT_CARD_INPUT_MAX_LENGTH } from "../../core/constants";
-import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType, CARD_NUMBER_ELEMENT_DEFAULT_STYLE, CARD_ICON_DEFAULT_STYLE, IListItem } from "../../utils/constants";
+import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType, CARD_NUMBER_ELEMENT_DEFAULT_STYLE, CARD_ICON_DEFAULT_STYLE, IListItem, CollectElementOptions } from "../../utils/constants";
import SkyflowError from "../../utils/skyflow-error";
import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code";
import uuid from 'react-native-uuid';
import Dropdown from "../../core/Dropdown";
+import { formatCollectElementOptions } from "../../utils/helpers";
const CardNumberElement: React.FC = ({ container, options, ...rest }) => {
@@ -33,7 +34,8 @@ const CardNumberElement: React.FC = ({ container, options,
useEffect(() => {
if (container) {
- const element: CollectElement = container.create({ ...rest, type: ElementType.CARD_NUMBER, containerType: container.type }, mergedOptions);
+ const elementOptions: CollectElementOptions = formatCollectElementOptions(ElementType.CARD_NUMBER, options, container.getContext().logLevel);
+ const element: CollectElement = container.create({ ...rest, type: ElementType.CARD_NUMBER, containerType: container.type }, {...mergedOptions , ...elementOptions});
setElement(element);
if (container.type === ContainerType.COLLECT)
element.setMethods(setErrorText, { setInputStyles: setInputStyles, setLabelStyles: setLabelStyles });
@@ -109,6 +111,7 @@ const CardNumberElement: React.FC = ({ container, options,
ref={textInputRef}
value={elementValue}
placeholder={rest.placeholder}
+ testID={rest?.testID}
onChangeText={(text) => {
element?.onChangeElement(text)
setElementValue(element.getInternalState().value)
@@ -141,7 +144,7 @@ const CardNumberElement: React.FC = ({ container, options,
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
}
diff --git a/src/components/CvvElement/index.tsx b/src/components/CvvElement/index.tsx
index dddbe8d..5754c7a 100644
--- a/src/components/CvvElement/index.tsx
+++ b/src/components/CvvElement/index.tsx
@@ -49,6 +49,7 @@ const CvvElement: React.FC = ({ container, options = { requ
ref={textInputRef}
value={elementValue}
placeholder={rest.placeholder}
+ testID={rest?.testID}
onChangeText={(text) => {
element?.onChangeElement(text);
setElementValue(element.getInternalState().value)
@@ -76,7 +77,7 @@ const CvvElement: React.FC = ({ container, options = { requ
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
}
diff --git a/src/components/ExpirationDateElement/index.tsx b/src/components/ExpirationDateElement/index.tsx
index 04cd240..af9c071 100644
--- a/src/components/ExpirationDateElement/index.tsx
+++ b/src/components/ExpirationDateElement/index.tsx
@@ -54,6 +54,7 @@ const ExpirationDateElement: React.FC = ({ container, optio
ref={textInputRef}
value={elementValue}
placeholder={rest.placeholder}
+ testID={rest?.testID}
onChangeText={(text) => {
element?.onChangeElement(text);
setElementValue(element.getInternalState().value)
@@ -84,7 +85,7 @@ const ExpirationDateElement: React.FC = ({ container, optio
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
}
diff --git a/src/components/ExpirationMonthElement/index.tsx b/src/components/ExpirationMonthElement/index.tsx
index 8092770..6e61fe7 100644
--- a/src/components/ExpirationMonthElement/index.tsx
+++ b/src/components/ExpirationMonthElement/index.tsx
@@ -49,6 +49,7 @@ const ExpirationMonthElement: React.FC = ({ container, opti
ref={textInputRef}
value={elementValue}
placeholder={rest.placeholder}
+ testID={rest?.testID}
onChangeText={(text) => {
element?.onChangeElement(text);
setElementValue(element.getInternalState().value)
@@ -79,7 +80,7 @@ const ExpirationMonthElement: React.FC = ({ container, opti
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
}
diff --git a/src/components/ExpirationYearElement/index.tsx b/src/components/ExpirationYearElement/index.tsx
index c21439e..adba727 100644
--- a/src/components/ExpirationYearElement/index.tsx
+++ b/src/components/ExpirationYearElement/index.tsx
@@ -55,6 +55,7 @@ const ExpirationYearElement: React.FC = ({ container, optio
ref={textInputRef}
value={elementValue}
placeholder={rest.placeholder}
+ testID={rest?.testID}
onChangeText={(text) => {
element?.onChangeElement(text);
setElementValue(element.getInternalState().value)
@@ -85,7 +86,7 @@ const ExpirationYearElement: React.FC = ({ container, optio
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
}
diff --git a/src/components/InputFieldElement/index.tsx b/src/components/InputFieldElement/index.tsx
index 0825173..8fd6177 100644
--- a/src/components/InputFieldElement/index.tsx
+++ b/src/components/InputFieldElement/index.tsx
@@ -4,7 +4,7 @@
import React, { useEffect, useRef } from "react";
import { Text, TextInput, View } from "react-native";
import type CollectElement from "../../core/CollectElement";
-import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType } from "../../utils/constants";
+import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType, CollectElementOptions } from "../../utils/constants";
import SkyflowError from "../../utils/skyflow-error";
import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code";
import uuid from 'react-native-uuid';
@@ -48,9 +48,11 @@ const InputFieldElement: React.FC = ({ container, options =
)
}
{
element?.onChangeElement(text);
setElementValue(element.getInternalState().value)
@@ -76,7 +78,7 @@ const InputFieldElement: React.FC = ({ container, options =
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
}
diff --git a/src/components/PinElement/index.tsx b/src/components/PinElement/index.tsx
index 6bab3dc..79576a6 100644
--- a/src/components/PinElement/index.tsx
+++ b/src/components/PinElement/index.tsx
@@ -49,6 +49,7 @@ const PinElement: React.FC = ({ container, options = { requ
ref={textInputRef}
value={elementValue}
placeholder={rest.placeholder}
+ testID={rest?.testID}
onChangeText={(text) => {
element?.onChangeElement(text)
setElementValue(element.getInternalState().value)
@@ -76,7 +77,7 @@ const PinElement: React.FC = ({ container, options = { requ
{
container && container?.type === ContainerType.COLLECT
&&
- {errorText}
+ {errorText}
}
);
}
diff --git a/src/components/RevealElement/index.tsx b/src/components/RevealElement/index.tsx
index d08872a..49bef9c 100644
--- a/src/components/RevealElement/index.tsx
+++ b/src/components/RevealElement/index.tsx
@@ -1,19 +1,29 @@
/*
Copyright (c) 2022 Skyflow, Inc.
*/
-import React, { useEffect } from "react";
+import React, { useEffect, useImperativeHandle, forwardRef } from "react";
import { Text } from "react-native";
import RevealSkyflowElement from "../../core/RevealSkyflowElement";
-import { RevealElementProps } from "../../utils/constants"
+import { RevealElementProps, SkyflowRevealElementRef } from "../../utils/constants"
import SkyflowError from "../../utils/skyflow-error";
import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code";
+import { formatInputFieldValue } from "../../utils/helpers";
+import { DEFAULT_INPUT_FIELD_TRANSLATION } from "../../core/constants";
-
-const RevealElement: React.FC = ({ container, label, ...rest }) => {
- const [element, setElement] = React.useState(undefined);
+const RevealElement = forwardRef((props, ref) => {
+ const { container, label, format, translation, ...rest } = props;
+
+ const [element, setElement] = React.useState(undefined);
const [errorText, setErrorText] = React.useState('');
const [value, setValue] = React.useState(rest?.altText || rest.token);
+ const formattedValue = React.useMemo(() => {
+ if (!format) return value;
+ const valueTranslation = translation ?? DEFAULT_INPUT_FIELD_TRANSLATION;
+ const formattedText = formatInputFieldValue(value, format, valueTranslation);
+ return formattedText ? formattedText : value;
+ }, [value, format, translation]);
+
useEffect(() => {
if (container) {
const revealElement = container.create(rest);
@@ -25,12 +35,37 @@ const RevealElement: React.FC = ({ container, label, ...rest
}, []);
- return <>
- {label}
- {value}
- {errorText}
- >
+ useImperativeHandle(ref, () => ({
+ setToken: (newToken: string) => {
+ if (element) {
+ element.setToken(newToken);
+ setValue(newToken);
+ } else {
+ throw new SkyflowError(SKYFLOW_ERROR_CODE.ELEMENT_NOT_FOUND, ['RevealElement'], true);
+ }
+ }
+ }), [element]);
+
+ return (
+ <>
+ {label}
+
+ {formattedValue}
+
+
+ {errorText}
+
+ >
+ );
+});
-}
+RevealElement.displayName = 'RevealElement';
export default RevealElement;
\ No newline at end of file
diff --git a/src/core-utils/collect/index.ts b/src/core-utils/collect/index.ts
index 5d2cc3d..e022dc8 100644
--- a/src/core-utils/collect/index.ts
+++ b/src/core-utils/collect/index.ts
@@ -7,7 +7,7 @@ import _ from 'lodash';
import Skyflow from '../../core/Skyflow';
import SkyflowError from '../../utils/skyflow-error';
import SKYFLOW_ERROR_CODE from '../../utils/skyflow-error-code';
-import { IInsertRecord, IInsertResponse } from '../../../src/utils/constants';
+import { ElementType, IInsertRecord, IInsertResponse } from '../../utils/constants';
import omit from 'lodash/omit';
const set = require('set-value');
@@ -184,6 +184,12 @@ export const constructElementsInsertReq = (req: any, options: any) => {
return { records };
};
+export function getElementValueToInsert(element: CollectElement) {
+ return element.getClientState().elementType === ElementType.CARD_NUMBER
+ ? element.getUnformattedValue()
+ : element.getInternalState().value;
+}
+
export const tokenize = (
skyflowClient: Skyflow,
elementList: CollectElement[],
diff --git a/src/core-utils/element-validations/index.ts b/src/core-utils/element-validations/index.ts
index b9491bf..9f20042 100644
--- a/src/core-utils/element-validations/index.ts
+++ b/src/core-utils/element-validations/index.ts
@@ -58,13 +58,20 @@ export const validateExpiryDate = (date: string, format: string) => {
if (date.trim().length === 0) return true;
if (!date.includes('/')) return false;
const { month, year } = getYearAndMonthBasedOnFormat(date, format);
- const expiryDate = new Date(`${year}-${month}-01`);
+
+ if (month < 1 || month > 12) return false;
+
+ const expiryDate = new Date(Number(year), Number(month) - 1, 1);
const today = new Date();
+ today.setDate(1);
+ today.setHours(0, 0, 0, 0);
const maxDate = new Date();
maxDate.setFullYear(today.getFullYear() + 50);
+ maxDate.setDate(1);
+ maxDate.setHours(0, 0, 0, 0);
- return expiryDate > today && expiryDate <= maxDate;
+ return expiryDate >= today && expiryDate <= maxDate;
};
export const validateCreditCardNumber = (cardNumber: string) => {
diff --git a/src/core/CollectElement/index.ts b/src/core/CollectElement/index.ts
index 68f79bf..13bf271 100644
--- a/src/core/CollectElement/index.ts
+++ b/src/core/CollectElement/index.ts
@@ -32,6 +32,7 @@ import {
appendZeroToOne,
detectCardType,
formatCardNumber,
+ formatInputFieldValue,
formatExpirationDate,
formatExpirationMonthValue,
getReturnValue,
@@ -136,6 +137,10 @@ class CollectElement extends SkyflowElement {
return this.#state;
}
+ getUnformattedValue() {
+ return this.#state.value.trim().replace(/[\s-]/g, '');
+ }
+
getElementInput() {
return this.#elementInput;
}
@@ -186,7 +191,10 @@ class CollectElement extends SkyflowElement {
break;
case ElementType.CARD_NUMBER:
this.#cardType = detectCardType(value);
- this.updateElement(formatCardNumber(value, this.#cardType));
+ this.updateElement(formatCardNumber(value, this.#cardType, this.#options.format));
+ break;
+ case ElementType.INPUT_FIELD:
+ this.updateElement(formatInputFieldValue(value, this.#options.format, this.#options.translation));
break;
default:
this.updateElement(value);
diff --git a/src/core/RevealContainer/index.ts b/src/core/RevealContainer/index.ts
index 35552ae..bd20cc4 100644
--- a/src/core/RevealContainer/index.ts
+++ b/src/core/RevealContainer/index.ts
@@ -70,7 +70,22 @@ class RevealContainer extends Container {
try {
validateInitConfig(this.#skyflowClient.getSkyflowConfig());
validateRevealElementRecords(this.#revealRecords);
- fetchRecordsByTokenId(this.#skyflowClient, this.#tokensList).then(
+
+ const freshTokensList = this.#tokensList.map((record) => {
+ const elementInstance = this.#elementList.find(
+ (e) => e.elementId === record.elementId
+ );
+
+ if (elementInstance) {
+ return {
+ ...record,
+ token: elementInstance.getToken(),
+ };
+ }
+ return record;
+ });
+
+ fetchRecordsByTokenId(this.#skyflowClient, freshTokensList).then(
(resolvedResult) => {
const formattedResult = formatRecordsForIframe(resolvedResult);
this.setRevealValuesInElements(formattedResult);
diff --git a/src/core/RevealSkyflowElement/index.ts b/src/core/RevealSkyflowElement/index.ts
index bd4986c..c56e984 100644
--- a/src/core/RevealSkyflowElement/index.ts
+++ b/src/core/RevealSkyflowElement/index.ts
@@ -27,6 +27,10 @@ class RevealSkyflowElement extends SkyflowElement {
this.#setErrorText(REVEAL_ELEMENT_ERROR_TEXT);
}
+ setToken(newToken: string) {
+ this.#token = newToken;
+ }
+
getToken() {
return this.#token;
}
diff --git a/src/core/constants/index.ts b/src/core/constants/index.ts
index 0924bcd..3be2ea7 100644
--- a/src/core/constants/index.ts
+++ b/src/core/constants/index.ts
@@ -40,6 +40,7 @@ export const DEFAULT_EXPIRATION_YEAR_FORMAT = 'YY';
export const FOUR_DIGIT_YEAR_FORMAT = 'YYYY';
export const DEFAULT_EXPIRATION_DATE_FORMAT = 'MM/YY';
+export const DEFAULT_CARD_NUMBER_FORMAT = 'XXXX XXXX XXXX XXXX';
export const MONTH_FORMAT = 'MM';
@@ -163,9 +164,12 @@ export const DEFAULT_CARD_INPUT_MAX_LENGTH = 23;
export const REVEAL_ELEMENT_ERROR_TEXT = 'Invalid Token';
-export const DEFAULT_COLLECT_ELEMENT_ERROR_TEXT = 'Invalid Value';
+export const DEFAULT_COLLECT_ELEMENT_ERROR_TEXT = 'Invalid value';
export const DEFAULT_VALIDATION_ERROR_TEXT = 'Validation Failed';
+export const DEFAULT_INPUT_FIELD_TRANSLATION: Record = {
+ 'X': '[0-9]',
+};
export const ALLOWED_EXPIRY_YEAR_FORMATS = [
DEFAULT_EXPIRATION_YEAR_FORMAT,
@@ -178,6 +182,10 @@ export const ALLOWED_EXPIRY_DATE_FORMATS = [
'YY/MM',
'MM/YYYY',
];
+export const ALLOWED_CARD_NUMBER_FORMATS = [
+ DEFAULT_CARD_NUMBER_FORMAT,
+ 'XXXX-XXXX-XXXX-XXXX',
+]
export const DEFAULT_COLLECT_ELEMENT_REQUIRED_TEXT = 'Field is required';
diff --git a/src/index.ts b/src/index.ts
index d5c72ef..009b7dc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -9,6 +9,7 @@ export {
LogLevel,
ValidationRuleType,
RedactionType,
+ SkyflowRevealElementRef,
} from './utils/constants';
export { CardType } from './core/constants'
export { default as useCollectContainer } from './hooks/useCollectContainer';
diff --git a/src/utils/constants/index.ts b/src/utils/constants/index.ts
index 97bc0b5..2fb25c8 100644
--- a/src/utils/constants/index.ts
+++ b/src/utils/constants/index.ts
@@ -3,7 +3,7 @@
*/
import type CollectContainer from '../../core/CollectContainer';
import RevealContainer from '../../core/RevealContainer';
-import { CardType } from '../../../src/core/constants';
+import { CardType } from '../../core/constants';
export interface IConfig {
vaultID: string;
@@ -55,6 +55,7 @@ export interface CollectElementProps {
errorTextStyles?: StylesBaseVariant;
containerMethods?: Record;
skyflowID?: string;
+ testID?: string;
}
export enum ElementType {
@@ -108,12 +109,16 @@ export interface RevealElementInput {
export interface RevealElementProps {
token: string;
container: RevealContainer;
+ format?: string
+ translation?: Record;
label?: string;
altText?: string;
inputStyles?: StylesBaseVariant;
labelStyles?: StylesBaseVariant;
errorTextStyles?: StylesBaseVariant;
redaction?: RedactionType;
+ testID?: string;
+ id?: string;
}
export enum MessageType {
@@ -133,6 +138,10 @@ export interface IRevealResponseType {
errors?: Record[];
}
+export interface SkyflowRevealElementRef {
+ setToken: (newToken: string) => void;
+}
+
export enum ValidationRuleType {
REGEX_MATCH_RULE = 'REGEX_MATCH_RULE',
LENGTH_MATCH_RULE = 'LENGTH_MATCH_RULE',
diff --git a/src/utils/helpers/index.ts b/src/utils/helpers/index.ts
index 8c523de..face546 100644
--- a/src/utils/helpers/index.ts
+++ b/src/utils/helpers/index.ts
@@ -12,6 +12,9 @@ import {
DEFAULT_EXPIRATION_DATE_FORMAT,
ALLOWED_EXPIRY_DATE_FORMATS,
ALLOWED_EXPIRY_YEAR_FORMATS,
+ ALLOWED_CARD_NUMBER_FORMATS,
+ DEFAULT_CARD_NUMBER_FORMAT,
+ DEFAULT_INPUT_FIELD_TRANSLATION,
} from '../../core/constants';
import { ElementType, MessageType } from '../constants';
import logs from '../logs';
@@ -141,8 +144,81 @@ export const detectCardType = (cardNumber: string) => {
return detectedType;
};
-export const formatCardNumber = (cardNumber, type) => {
- return applyMask(cardNumber, CARD_NUMBER_MASK[type]);
+export const formatCardNumber = (
+ cardNumber: string,
+ type: string | number,
+ format = DEFAULT_CARD_NUMBER_FORMAT
+) => {
+ if (!cardNumber || cardNumber.length === 0) return '';
+ const isvalidFormat = isValidCardNumberFormat(
+ format
+ );
+
+ if (!isvalidFormat) {
+ format = DEFAULT_CARD_NUMBER_FORMAT;
+ };
+
+ const mask = CARD_NUMBER_MASK[type] || CARD_NUMBER_MASK[CardType.DEFAULT];
+ const maskedValue = applyMask(cardNumber, mask);
+ const separator = format.includes('-') ? '-' : ' ';
+ const formattedValue = maskedValue.replace(/[\s-]+/g, separator).trim();
+
+ return formattedValue;
+};
+
+export const formatInputFieldValue = (
+ input: string,
+ format: string,
+ translation: Record = DEFAULT_INPUT_FIELD_TRANSLATION
+): string => {
+ if (!format || format.length === 0) return input;
+ if (!input || input.length === 0) return '';
+
+ const inputArray = Array.from(input);
+ const formatArray = Array.from(format);
+ let formattedOutput = '';
+ let formatIndex = 0;
+
+ for (let inputIndex = 0; inputIndex < inputArray.length; inputIndex++) {
+ const inputChar = inputArray[inputIndex];
+
+ if (formatIndex < formatArray.length) {
+ const currentFormatChar = formatArray[formatIndex];
+
+ if (translation[currentFormatChar]) {
+ const regex = new RegExp(translation[currentFormatChar]);
+ if (regex.test(inputChar)) {
+ formattedOutput += inputChar;
+ formatIndex++;
+ }
+ } else {
+ if (inputChar === currentFormatChar) {
+ formattedOutput += inputChar;
+ formatIndex++;
+ } else {
+ for (let scanIndex = formatIndex; scanIndex < formatArray.length; scanIndex++) {
+ const nextFormatChar = formatArray[scanIndex];
+
+ if (translation[nextFormatChar]) {
+ const regex = new RegExp(translation[nextFormatChar]);
+ if (regex.test(inputChar)) {
+ formattedOutput += inputChar;
+ formatIndex = scanIndex + 1;
+ }
+ break;
+ } else {
+ formattedOutput += nextFormatChar;
+ formatIndex = scanIndex + 1;
+ }
+ }
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ return formattedOutput;
};
export const getReturnValue = (
@@ -153,7 +229,7 @@ export const getReturnValue = (
) => {
if (typeof value === 'string') {
if (elementType === ElementType.CARD_NUMBER) {
- value = value && value.replace(/\s/g, '');
+ value = value && value.replace(/[\s-]/g, '');
if (!doesReturnValue) {
const threshold =
cardType !== CardType.DEFAULT && cardType === CardType.AMEX ? 6 : 8;
@@ -204,6 +280,13 @@ export const isValidExpiryYearFormat = (format: string): boolean => {
return false;
};
+export const isValidCardNumberFormat = (format: string): boolean => {
+ if (format) {
+ return ALLOWED_CARD_NUMBER_FORMATS.includes(format);
+ }
+ return false;
+};
+
export const formatCollectElementOptions = (
elementType: ElementType,
options,
@@ -259,6 +342,27 @@ export const formatCollectElementOptions = (
? formattedOptions.format.toUpperCase()
: DEFAULT_EXPIRATION_YEAR_FORMAT,
};
+ } else if (elementType === ElementType.CARD_NUMBER) {
+ let isvalidFormat = false;
+ if (formattedOptions.format) {
+ isvalidFormat = isValidCardNumberFormat(
+ formattedOptions.format.toUpperCase()
+ );
+ if (!isvalidFormat) {
+ printLog(
+ parameterizedString(
+ logs.warnLogs.INVALID_CARD_NUMBER_FORMAT,
+ ALLOWED_CARD_NUMBER_FORMATS.toString()
+ ),
+ MessageType.WARN,
+ logLevel
+ );
+ }
+ }
+ formattedOptions = {
+ ...formattedOptions,
+ format: isvalidFormat ? formattedOptions.format : DEFAULT_CARD_NUMBER_FORMAT,
+ };
}
return formattedOptions;
};
diff --git a/src/utils/logs/index.ts b/src/utils/logs/index.ts
index fb6a125..00f1cf5 100644
--- a/src/utils/logs/index.ts
+++ b/src/utils/logs/index.ts
@@ -133,6 +133,8 @@ const logs = {
`Skyflow ${SDK_NAME_VERSION} initialization failed - SkyflowProvider config is missing. `,
CONTAINER_OBJECT_IS_REQUIRED:
`${SDK_NAME_VERSION} cannot create %s1 element without container object, create a container using %s2 hook.`,
+ ELEMENT_NOT_FOUND:
+ `${SDK_NAME_VERSION} %s1 not found. The specified element does not exist in the container.`,
INVALID_UPSERT_OPTION_TYPE:
`${SDK_NAME_VERSION} Validation error. Invalid \'upsert\' key in insert options. Specify a value of type array instead`,
EMPTY_UPSERT_OPTIONS_ARRAY:
@@ -226,6 +228,8 @@ const logs = {
'EXPIRATION_DATE format must be in one of %s1, the format is set to default MM/YY',
INVALID_EXPIRATION_YEAR_FORMAT:
'EXPIRATION_YEAR format must be in one of %s1, the format is set to default YY',
+ INVALID_CARD_NUMBER_FORMAT:
+ `CARD_NUMBER format must be in one of %s1, the format is set to default XXXX XXXX XXXX XXXX`,
},
};
diff --git a/src/utils/skyflow-error-code/index.ts b/src/utils/skyflow-error-code/index.ts
index 14e93eb..333351f 100644
--- a/src/utils/skyflow-error-code/index.ts
+++ b/src/utils/skyflow-error-code/index.ts
@@ -190,6 +190,10 @@ const SKYFLOW_ERROR_CODE = {
code: 400,
description: logs.errorLogs.CONTAINER_OBJECT_IS_REQUIRED,
},
+ ELEMENT_NOT_FOUND: {
+ code: 400,
+ description: logs.errorLogs.ELEMENT_NOT_FOUND,
+ },
INVALID_UPSERT_OPTION_TYPE: {
code: 400,
description: logs.errorLogs.INVALID_UPSERT_OPTION_TYPE,
diff --git a/yarn.lock b/yarn.lock
index 21546bc..50752c4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -24,6 +24,15 @@
js-tokens "^4.0.0"
picocolors "^1.0.0"
+"@babel/code-frame@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
+ integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.27.1"
+ js-tokens "^4.0.0"
+ picocolors "^1.1.1"
+
"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9", "@babel/compat-data@^7.26.0":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02"
@@ -196,11 +205,21 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
+"@babel/helper-string-parser@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
+ integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
+
"@babel/helper-validator-identifier@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
+"@babel/helper-validator-identifier@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
+ integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
+
"@babel/helper-validator-option@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72"
@@ -215,13 +234,13 @@
"@babel/traverse" "^7.25.9"
"@babel/types" "^7.25.9"
-"@babel/helpers@^7.26.0":
- version "7.26.0"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4"
- integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==
+"@babel/helpers@^7.26.0", "@babel/helpers@^7.26.10":
+ version "7.27.6"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c"
+ integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==
dependencies:
- "@babel/template" "^7.25.9"
- "@babel/types" "^7.26.0"
+ "@babel/template" "^7.27.2"
+ "@babel/types" "^7.27.6"
"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3":
version "7.26.3"
@@ -230,6 +249,13 @@
dependencies:
"@babel/types" "^7.26.3"
+"@babel/parser@^7.27.2":
+ version "7.28.0"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e"
+ integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==
+ dependencies:
+ "@babel/types" "^7.28.0"
+
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe"
@@ -1082,12 +1108,10 @@
pirates "^4.0.6"
source-map-support "^0.5.16"
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.8.4":
- version "7.26.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
- integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
- dependencies:
- regenerator-runtime "^0.14.0"
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.26.10", "@babel/runtime@^7.8.4":
+ version "7.27.6"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6"
+ integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==
"@babel/template@^7.0.0", "@babel/template@^7.25.9", "@babel/template@^7.3.3":
version "7.25.9"
@@ -1098,6 +1122,15 @@
"@babel/parser" "^7.25.9"
"@babel/types" "^7.25.9"
+"@babel/template@^7.27.2":
+ version "7.27.2"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
+ integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==
+ dependencies:
+ "@babel/code-frame" "^7.27.1"
+ "@babel/parser" "^7.27.2"
+ "@babel/types" "^7.27.1"
+
"@babel/traverse@^7.20.0", "@babel/traverse@^7.25.9", "@babel/traverse@^7.7.2":
version "7.26.4"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd"
@@ -1119,6 +1152,14 @@
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
+"@babel/types@^7.27.1", "@babel/types@^7.27.6", "@babel/types@^7.28.0":
+ version "7.28.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.0.tgz#2fd0159a6dc7353933920c43136335a9b264d950"
+ integrity sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==
+ dependencies:
+ "@babel/helper-string-parser" "^7.27.1"
+ "@babel/helper-validator-identifier" "^7.27.1"
+
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -2112,7 +2153,16 @@
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@17.0.21", "@types/react@~17.0.21":
+"@types/react@*", "@types/react@17.0.21":
+ version "17.0.21"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.21.tgz#069c43177cd419afaab5ce26bb4e9056549f7ea6"
+ integrity sha512-GzzXCpOthOjXvrAUFQwU/svyxu658cwu00Q9ugujS4qc1zXgLFaO0kS2SLOaMWLt2Jik781yuHCWB7UcYdGAeQ==
+ dependencies:
+ "@types/prop-types" "*"
+ "@types/scheduler" "*"
+ csstype "^3.0.2"
+
+"@types/react@~17.0.21":
version "17.0.83"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.83.tgz#b477c56387b74279281149dcf5ba2a1e2216d131"
integrity sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==
@@ -2121,6 +2171,11 @@
"@types/scheduler" "^0.16"
csstype "^3.0.2"
+"@types/scheduler@*":
+ version "0.26.0"
+ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.26.0.tgz#2b7183b9bbb622d130b23bedf06899b7fec7eed5"
+ integrity sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==
+
"@types/scheduler@^0.16":
version "0.16.8"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
@@ -2678,21 +2733,14 @@ bl@^4.1.0:
inherits "^2.0.4"
readable-stream "^3.4.0"
-brace-expansion@^1.1.7:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
- integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+brace-expansion@^1.1.12, brace-expansion@^1.1.7, brace-expansion@^2.0.1:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
+ integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
-brace-expansion@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
- integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
- dependencies:
- balanced-match "^1.0.0"
-
braces@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
@@ -6285,7 +6333,7 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-picocolors@^1.0.0, picocolors@^1.1.0:
+picocolors@^1.0.0, picocolors@^1.1.0, picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
@@ -6667,11 +6715,6 @@ regenerator-runtime@^0.13.2:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
-regenerator-runtime@^0.14.0:
- version "0.14.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
- integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
-
regenerator-transform@^0.15.2:
version "0.15.2"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4"