Skip to content

Commit 2a9c274

Browse files
committed
fix(input-otp): allow characters outside of latin when type is text
1 parent eb7f838 commit 2a9c274

File tree

3 files changed

+187
-6
lines changed

3 files changed

+187
-6
lines changed

core/src/components.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,7 +1347,7 @@ export namespace Components {
13471347
*/
13481348
"length": number;
13491349
/**
1350-
* A regex pattern string for allowed characters. Defaults based on type. For numbers (type="number"): "[0-9]" For text (type="text"): "[a-zA-Z0-9]"
1350+
* A regex pattern string for allowed characters. Defaults based on type. For numbers (type="number"): "[0-9]" For text (type="text"): "[\\p{L}\\p{N}]"
13511351
*/
13521352
"pattern"?: string;
13531353
/**
@@ -6315,7 +6315,7 @@ declare namespace LocalJSX {
63156315
*/
63166316
"onIonInput"?: (event: IonInputOtpCustomEvent<InputOtpInputEventDetail>) => void;
63176317
/**
6318-
* A regex pattern string for allowed characters. Defaults based on type. For numbers (type="number"): "[0-9]" For text (type="text"): "[a-zA-Z0-9]"
6318+
* A regex pattern string for allowed characters. Defaults based on type. For numbers (type="number"): "[0-9]" For text (type="text"): "[\\p{L}\\p{N}]"
63196319
*/
63206320
"pattern"?: string;
63216321
/**

core/src/components/input-otp/input-otp.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class InputOTP implements ComponentInterface {
8989
* A regex pattern string for allowed characters. Defaults based on type.
9090
*
9191
* For numbers (type="number"): "[0-9]"
92-
* For text (type="text"): "[a-zA-Z0-9]"
92+
* For text (type="text"): "[\\p{L}\\p{N}]"
9393
*/
9494
@Prop() pattern?: string;
9595

@@ -306,7 +306,7 @@ export class InputOTP implements ComponentInterface {
306306
* Otherwise, use the default regex pattern based on type
307307
*/
308308
private get validKeyPattern(): RegExp {
309-
return new RegExp(`^${this.getPattern()}$`);
309+
return new RegExp(`^${this.getPattern()}$`, 'u');
310310
}
311311

312312
/**
@@ -318,7 +318,7 @@ export class InputOTP implements ComponentInterface {
318318
if (pattern) {
319319
return pattern;
320320
}
321-
return type === 'number' ? '[0-9]' : '[a-zA-Z0-9]';
321+
return type === 'number' ? '[0-9]' : '[\\p{L}\\p{N}]';
322322
}
323323

324324
/**

core/src/components/input-otp/test/basic/input-otp.e2e.ts

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ configs({ modes: ['ios'] }).forEach(({ title, config }) => {
7474
await verifyInputValues(inputOtp, ['2', '4', '6', '8']);
7575
});
7676

77-
test('should accept text and numbers when type is set to text', async ({ page }) => {
77+
test('should accept Latin characters when type is text', async ({ page }) => {
7878
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
7979

8080
const inputOtp = page.locator('ion-input-otp');
@@ -87,6 +87,102 @@ configs({ modes: ['ios'] }).forEach(({ title, config }) => {
8787
await verifyInputValues(inputOtp, ['A', '2', 'B', '5']);
8888
});
8989

90+
test('should accept accented Latin characters when type is text', async ({ page }) => {
91+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
92+
93+
const inputOtp = page.locator('ion-input-otp');
94+
const firstInput = page.locator('ion-input-otp input').first();
95+
await firstInput.focus();
96+
97+
await page.keyboard.type('áéíó');
98+
99+
await verifyInputValues(inputOtp, ['á', 'é', 'í', 'ó']);
100+
});
101+
102+
test('should accept Cyrillic characters when type is text', async ({ page }) => {
103+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
104+
105+
const inputOtp = page.locator('ion-input-otp');
106+
const firstInput = page.locator('ion-input-otp input').first();
107+
await firstInput.focus();
108+
109+
await page.keyboard.type('АбвГ');
110+
111+
await verifyInputValues(inputOtp, ['А', 'б', 'в', 'Г']);
112+
});
113+
114+
test('should accept Chinese characters when type is text', async ({ page }) => {
115+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
116+
117+
const inputOtp = page.locator('ion-input-otp');
118+
const firstInput = page.locator('ion-input-otp input').first();
119+
await firstInput.focus();
120+
121+
await page.keyboard.type('中国北京');
122+
123+
await verifyInputValues(inputOtp, ['中', '国', '北', '京']);
124+
});
125+
126+
test('should accept Japanese characters when type is text', async ({ page }) => {
127+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
128+
129+
const inputOtp = page.locator('ion-input-otp');
130+
const firstInput = page.locator('ion-input-otp input').first();
131+
await firstInput.focus();
132+
133+
await page.keyboard.type('ひらがな');
134+
135+
await verifyInputValues(inputOtp, ['ひ', 'ら', 'が', 'な']);
136+
});
137+
138+
test('should accept Korean characters when type is text', async ({ page }) => {
139+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
140+
141+
const inputOtp = page.locator('ion-input-otp');
142+
const firstInput = page.locator('ion-input-otp input').first();
143+
await firstInput.focus();
144+
145+
await page.keyboard.type('안녕하세');
146+
147+
await verifyInputValues(inputOtp, ['안', '녕', '하', '세']);
148+
});
149+
150+
test('should accept Arabic characters when type is text', async ({ page }) => {
151+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
152+
153+
const inputOtp = page.locator('ion-input-otp');
154+
const firstInput = page.locator('ion-input-otp input').first();
155+
await firstInput.focus();
156+
157+
await page.keyboard.type('أبجد');
158+
159+
await verifyInputValues(inputOtp, ['أ', 'ب', 'ج', 'د']);
160+
});
161+
162+
test('should accept mixed language characters when type is text', async ({ page }) => {
163+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
164+
165+
const inputOtp = page.locator('ion-input-otp');
166+
const firstInput = page.locator('ion-input-otp input').first();
167+
await firstInput.focus();
168+
169+
await page.keyboard.type('A漢字Б');
170+
171+
await verifyInputValues(inputOtp, ['A', '漢', '字', 'Б']);
172+
});
173+
174+
test('should reject special characters when type is text', async ({ page }) => {
175+
await page.setContent(`<ion-input-otp type="text">Description</ion-input-otp>`, config);
176+
177+
const inputOtp = page.locator('ion-input-otp');
178+
const firstInput = page.locator('ion-input-otp input').first();
179+
await firstInput.focus();
180+
181+
await page.keyboard.type('!@#$%^&*()-,:;./?+');
182+
183+
await verifyInputValues(inputOtp, ['', '', '', '']);
184+
});
185+
90186
test('should accept custom pattern of lowercase and uppercase letters when pattern is set', async ({ page }) => {
91187
await page.setContent(`<ion-input-otp type="text" pattern="[a-fA-F]">Description</ion-input-otp>`, config);
92188

@@ -112,6 +208,91 @@ configs({ modes: ['ios'] }).forEach(({ title, config }) => {
112208

113209
await verifyInputValues(inputOtp, ['D', 'E', 'F', 'G']);
114210
});
211+
212+
test('should accept custom pattern of all characters when pattern is set', async ({ page }) => {
213+
await page.setContent(`<ion-input-otp type="text" pattern=".">Description</ion-input-otp>`, config);
214+
215+
const inputOtp = page.locator('ion-input-otp');
216+
217+
const firstInput = page.locator('ion-input-otp input').first();
218+
await firstInput.focus();
219+
220+
await page.keyboard.type('*#.!');
221+
222+
await verifyInputValues(inputOtp, ['*', '#', '.', '!']);
223+
});
224+
225+
test('should accept only Latin characters and numbers when pattern is set', async ({ page }) => {
226+
await page.setContent(`<ion-input-otp type="text" pattern="[A-Za-z0-9]">Description</ion-input-otp>`, config);
227+
228+
const inputOtp = page.locator('ion-input-otp');
229+
const firstInput = page.locator('ion-input-otp input').first();
230+
await firstInput.focus();
231+
232+
await page.keyboard.type('Ab中国北京12');
233+
234+
await verifyInputValues(inputOtp, ['A', 'b', '1', '2']);
235+
});
236+
237+
test('should accept only Cyrillic characters when pattern is set', async ({ page }) => {
238+
await page.setContent(`<ion-input-otp type="text" pattern="[А-Яа-я]">Description</ion-input-otp>`, config);
239+
240+
const inputOtp = page.locator('ion-input-otp');
241+
const firstInput = page.locator('ion-input-otp input').first();
242+
await firstInput.focus();
243+
244+
await page.keyboard.type('АбABC123вГ');
245+
246+
await verifyInputValues(inputOtp, ['А', 'б', 'в', 'Г']);
247+
});
248+
249+
test('should accept only Chinese characters when pattern is set', async ({ page }) => {
250+
await page.setContent(`<ion-input-otp type="text" pattern="[\\u4e00-\\u9fff]">Description</ion-input-otp>`, config);
251+
252+
const inputOtp = page.locator('ion-input-otp');
253+
const firstInput = page.locator('ion-input-otp input').first();
254+
await firstInput.focus();
255+
256+
await page.keyboard.type('中国ABC123北京');
257+
258+
await verifyInputValues(inputOtp, ['中', '国', '北', '京']);
259+
});
260+
261+
test('should accept only Japanese characters when pattern is set', async ({ page }) => {
262+
await page.setContent(`<ion-input-otp type="text" pattern="[\\u3040-\\u309F\\u30A0-\\u30FF]">Description</ion-input-otp>`, config);
263+
264+
const inputOtp = page.locator('ion-input-otp');
265+
const firstInput = page.locator('ion-input-otp input').first();
266+
await firstInput.focus();
267+
268+
await page.keyboard.type('ひらABC123がな');
269+
270+
await verifyInputValues(inputOtp, ['ひ', 'ら', 'が', 'な']);
271+
});
272+
273+
test('should accept only Korean characters when pattern is set', async ({ page }) => {
274+
await page.setContent(`<ion-input-otp type="text" pattern="[\\uAC00-\\uD7AF\\u1100-\\u11FF]">Description</ion-input-otp>`, config);
275+
276+
const inputOtp = page.locator('ion-input-otp');
277+
const firstInput = page.locator('ion-input-otp input').first();
278+
await firstInput.focus();
279+
280+
await page.keyboard.type('안녕ABC123하세');
281+
282+
await verifyInputValues(inputOtp, ['안', '녕', '하', '세']);
283+
});
284+
285+
test('should accept only Arabic characters when pattern is set', async ({ page }) => {
286+
await page.setContent(`<ion-input-otp type="text" pattern="[\\u0600-\\u06FF]">Description</ion-input-otp>`, config);
287+
288+
const inputOtp = page.locator('ion-input-otp');
289+
const firstInput = page.locator('ion-input-otp input').first();
290+
await firstInput.focus();
291+
292+
await page.keyboard.type('أبجد123');
293+
294+
await verifyInputValues(inputOtp, ['أ', 'ب', 'ج', 'د']);
295+
});
115296
});
116297

117298
test.describe(title('input-otp: input functionality'), () => {

0 commit comments

Comments
 (0)