Skip to content

Commit fa7e948

Browse files
authored
docs(input): input masking examples (#2993)
1 parent d9ca1bf commit fa7e948

File tree

11 files changed

+431
-2
lines changed

11 files changed

+431
-2
lines changed

docs/api/input.md

+20
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,26 @@ import FilteringData from '@site/static/usage/v7/input/filtering/index.md';
120120

121121
<FilteringData />
122122

123+
## Input Masking
124+
125+
Input masks are expressions that constrain input to support valid input values. Ionic recommends using [Maskito](https://tinkoff.github.io/maskito/getting-started/what-is-maskito) for input masking. Maskito is a lightweight, dependency-free library for masking input fields. It supports a wide range of masks, including phone numbers, credit cards, dates, and more.
126+
127+
To get started with Maskito, install the library:
128+
129+
```bash
130+
npm install @maskito/core @maskito/{angular,react,vue}
131+
```
132+
133+
import Masking from '@site/static/usage/v7/input/mask/index.md';
134+
135+
<Masking />
136+
137+
:::note
138+
139+
Please submit bug reports with Maskito to the [Maskito Github repository](https://github.com/Tinkoff/maskito/issues). For technical support, please use the [Ionic Forum](https://forum.ionicframework.com/) or [Ionic Discord](http://chat.ionicframework.com/).
140+
141+
:::
142+
123143
## Theming
124144

125145
### Colors

src/components/global/Playground/stackblitz.utils.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,15 @@ const openReactEditor = async (code: string, options?: EditorOptions) => {
183183
options.version
184184
);
185185

186+
const package_json = JSON.parse(defaultFiles[4]);
187+
188+
if (options?.dependencies) {
189+
package_json.dependencies = {
190+
...package_json.dependencies,
191+
...options.dependencies,
192+
};
193+
}
194+
186195
const appTsx = 'src/App.tsx';
187196
const files = {
188197
'public/index.html': defaultFiles[6],
@@ -191,7 +200,7 @@ const openReactEditor = async (code: string, options?: EditorOptions) => {
191200
'src/main.tsx': code,
192201
'src/theme/variables.css': defaultFiles[2],
193202
'tsconfig.json': defaultFiles[3],
194-
'package.json': defaultFiles[4],
203+
'package.json': JSON.stringify(package_json, null, 2),
195204
'package-lock.json': defaultFiles[5],
196205
...options?.files,
197206
...options?.dependencies,
@@ -227,6 +236,15 @@ const openVueEditor = async (code: string, options?: EditorOptions) => {
227236
options.version
228237
);
229238

239+
const package_json = JSON.parse(defaultFiles[0]);
240+
241+
if (options?.dependencies) {
242+
package_json.dependencies = {
243+
...package_json.dependencies,
244+
...options.dependencies,
245+
};
246+
}
247+
230248
const mainTs = 'src/main.ts';
231249
const files = {
232250
'src/App.vue': defaultFiles[6],
@@ -236,7 +254,7 @@ const openVueEditor = async (code: string, options?: EditorOptions) => {
236254
'src/theme/variables.css': defaultFiles[3],
237255
'index.html': defaultFiles[2],
238256
'vite.config.ts': defaultFiles[4],
239-
'package.json': defaultFiles[0],
257+
'package.json': JSON.stringify(package_json, null, 2),
240258
'package-lock.json': defaultFiles[1],
241259
'tsconfig.json': defaultFiles[7],
242260
'tsconfig.node.json': defaultFiles[8],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
```ts
2+
import { NgModule } from '@angular/core';
3+
import { FormsModule } from '@angular/forms';
4+
import { BrowserModule } from '@angular/platform-browser';
5+
6+
import { IonicModule } from '@ionic/angular';
7+
8+
import { AppComponent } from './app.component';
9+
import { ExampleComponent } from './example.component';
10+
11+
import { MaskitoModule } from '@maskito/angular';
12+
13+
@NgModule({
14+
imports: [BrowserModule, FormsModule, MaskitoModule, IonicModule.forRoot({})],
15+
declarations: [AppComponent, ExampleComponent],
16+
bootstrap: [AppComponent],
17+
})
18+
export class AppModule {}
19+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
```html
2+
<ion-list>
3+
<ion-item>
4+
<ion-input
5+
label="Card number"
6+
placeholder="0000 0000 0000 0000"
7+
[maskito]="cardMask"
8+
[maskitoElement]="maskPredicate"
9+
></ion-input>
10+
</ion-item>
11+
<ion-item>
12+
<ion-input
13+
label="US phone number"
14+
placeholder="+1 (xxx) xxx-xxxx"
15+
[maskito]="phoneMask"
16+
[maskitoElement]="maskPredicate"
17+
></ion-input>
18+
</ion-item>
19+
</ion-list>
20+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
```ts
2+
import { Component } from '@angular/core';
3+
4+
import { MaskitoOptions, MaskitoElementPredicateAsync } from '@maskito/core';
5+
6+
@Component({
7+
selector: 'app-example',
8+
templateUrl: 'example.component.html',
9+
})
10+
export class ExampleComponent {
11+
readonly phoneMask: MaskitoOptions = {
12+
mask: ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
13+
};
14+
15+
readonly cardMask: MaskitoOptions = {
16+
mask: [
17+
...Array(4).fill(/\d/),
18+
' ',
19+
...Array(4).fill(/\d/),
20+
' ',
21+
...Array(4).fill(/\d/),
22+
' ',
23+
...Array(4).fill(/\d/),
24+
' ',
25+
...Array(4).fill(/\d/),
26+
],
27+
};
28+
29+
readonly maskPredicate: MaskitoElementPredicateAsync = async (el) => (el as HTMLIonInputElement).getInputElement();
30+
}
31+
```

static/usage/v7/input/mask/demo.html

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Input</title>
7+
<link rel="stylesheet" href="../../../common.css" />
8+
<script src="../../../common.js"></script>
9+
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@7/dist/ionic/ionic.esm.js"></script>
10+
<script type="module">
11+
import { Maskito } from 'https://cdn.jsdelivr.net/npm/@maskito/core/index.esm.js';
12+
window.Maskito = Maskito;
13+
</script>
14+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core@7/css/ionic.bundle.css" />
15+
16+
<style>
17+
ion-list {
18+
width: 100%;
19+
}
20+
</style>
21+
</head>
22+
23+
<body>
24+
<ion-app>
25+
<ion-content>
26+
<div class="container">
27+
<ion-list>
28+
<ion-item>
29+
<ion-input id="card" label="Card number" placeholder="0000 0000 0000 0000"></ion-input>
30+
</ion-item>
31+
<ion-item>
32+
<ion-input id="phone" label="US phone number" placeholder="+1 (xxx) xxx-xxxx"></ion-input>
33+
</ion-item>
34+
</ion-list>
35+
</div>
36+
</ion-content>
37+
</ion-app>
38+
<script>
39+
async function initPhoneMask() {
40+
const ionInput = document.querySelector('#phone');
41+
const nativeEl = await ionInput.getInputElement();
42+
43+
new window.Maskito(nativeEl, {
44+
mask: ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
45+
});
46+
}
47+
48+
async function initCardMask() {
49+
const ionInput = document.querySelector('#card');
50+
const nativeEl = await ionInput.getInputElement();
51+
52+
new window.Maskito(nativeEl, {
53+
mask: [
54+
...Array(4).fill(/\d/),
55+
' ',
56+
...Array(4).fill(/\d/),
57+
' ',
58+
...Array(4).fill(/\d/),
59+
' ',
60+
...Array(4).fill(/\d/),
61+
' ',
62+
...Array(4).fill(/\d/),
63+
],
64+
});
65+
}
66+
67+
window.addEventListener('appload', () => {
68+
initCardMask();
69+
initPhoneMask();
70+
});
71+
</script>
72+
</body>
73+
</html>

static/usage/v7/input/mask/index.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Playground from '@site/src/components/global/Playground';
2+
3+
import javascript_index_html from './javascript/index_html.md';
4+
import javascript_index_ts from './javascript/index_ts.md';
5+
6+
import react_main_tsx from './react.md';
7+
8+
import vue_example_vue from './vue.md';
9+
10+
import angular_app_module_ts from './angular/app_module_ts.md';
11+
import angular_example_component_html from './angular/example_component_html.md';
12+
import angular_example_component_ts from './angular/example_component_ts.md';
13+
14+
<Playground
15+
version="7"
16+
code={{
17+
javascript: {
18+
files: {
19+
'index.html': javascript_index_html,
20+
'index.ts': javascript_index_ts,
21+
},
22+
dependencies: {
23+
'@maskito/core': '^0.16.0',
24+
},
25+
},
26+
react: {
27+
files: {
28+
'src/main.tsx': react_main_tsx,
29+
},
30+
dependencies: {
31+
'@maskito/react': '^0.16.0',
32+
'@maskito/core': '^0.16.0',
33+
},
34+
},
35+
vue: {
36+
files: {
37+
'src/components/Example.vue': vue_example_vue,
38+
},
39+
dependencies: {
40+
'@maskito/vue': '^0.16.0',
41+
'@maskito/core': '^0.16.0',
42+
},
43+
},
44+
angular: {
45+
files: {
46+
'src/app/app.module.ts': angular_app_module_ts,
47+
'src/app/example.component.html': angular_example_component_html,
48+
'src/app/example.component.ts': angular_example_component_ts,
49+
},
50+
dependencies: {
51+
'@maskito/angular': '^0.16.0',
52+
'@maskito/core': '^0.16.0',
53+
},
54+
},
55+
}}
56+
src="usage/v7/input/mask/demo.html"
57+
size="300px"
58+
/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
```html
2+
<html>
3+
<head>
4+
<link rel="stylesheet" type="text/css" href="https://cdn.skypack.dev/@ionic/core@7/css/core.css" />
5+
<link rel="stylesheet" type="text/css" href="https://cdn.skypack.dev/@ionic/core@7/css/ionic.bundle.css" />
6+
</head>
7+
8+
<body>
9+
<ion-app>
10+
<ion-content class="ion-padding">
11+
<ion-list>
12+
<ion-item>
13+
<ion-input id="card" label="Card number" placeholder="0000 0000 0000 0000"></ion-input>
14+
</ion-item>
15+
<ion-item>
16+
<ion-input id="phone" label="US phone number" placeholder="+1 (xxx) xxx-xxxx"></ion-input>
17+
</ion-item>
18+
</ion-list>
19+
</ion-content>
20+
21+
<script>
22+
async function initPhoneMask() {
23+
const ionInput = document.querySelector('#phone');
24+
const nativeEl = await ionInput.getInputElement();
25+
26+
new window.Maskito(nativeEl, {
27+
mask: ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
28+
});
29+
}
30+
31+
async function initCardMask() {
32+
const ionInput = document.querySelector('#card');
33+
const nativeEl = await ionInput.getInputElement();
34+
35+
new window.Maskito(nativeEl, {
36+
mask: [
37+
...Array(4).fill(/\d/),
38+
' ',
39+
...Array(4).fill(/\d/),
40+
' ',
41+
...Array(4).fill(/\d/),
42+
' ',
43+
...Array(4).fill(/\d/),
44+
' ',
45+
...Array(4).fill(/\d/),
46+
],
47+
});
48+
}
49+
50+
window.addEventListener('appload', () => {
51+
initCardMask();
52+
initPhoneMask();
53+
});
54+
</script>
55+
</ion-app>
56+
</body>
57+
</html>
58+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
```ts
2+
import { defineCustomElements } from '@ionic/core/loader';
3+
4+
import { Maskito } from '@maskito/core';
5+
6+
/* Core CSS required for Ionic components to work properly */
7+
import '@ionic/core/css/core.css';
8+
9+
/* Basic CSS for apps built with Ionic */
10+
import '@ionic/core/css/normalize.css';
11+
import '@ionic/core/css/structure.css';
12+
import '@ionic/core/css/typography.css';
13+
14+
/* Optional CSS utils that can be commented out */
15+
import '@ionic/core/css/padding.css';
16+
import '@ionic/core/css/float-elements.css';
17+
import '@ionic/core/css/text-alignment.css';
18+
import '@ionic/core/css/text-transformation.css';
19+
import '@ionic/core/css/flex-utils.css';
20+
import '@ionic/core/css/display.css';
21+
22+
/* Theme variables */
23+
import './theme/variables.css';
24+
25+
defineCustomElements();
26+
27+
(window as any).Maskito = Maskito;
28+
```

0 commit comments

Comments
 (0)