Skip to content

Commit 6190d0c

Browse files
committed
fix(input-otp): update colors and valid/invalid states design
1 parent a7d14f2 commit 6190d0c

File tree

5 files changed

+106
-86
lines changed

5 files changed

+106
-86
lines changed

core/api.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,12 +812,18 @@ ion-input-otp,css-prop,--border-radius,ios
812812
ion-input-otp,css-prop,--border-radius,md
813813
ion-input-otp,css-prop,--border-width,ios
814814
ion-input-otp,css-prop,--border-width,md
815+
ion-input-otp,css-prop,--border-width-focused,ios
816+
ion-input-otp,css-prop,--border-width-focused,md
815817
ion-input-otp,css-prop,--color,ios
816818
ion-input-otp,css-prop,--color,md
817819
ion-input-otp,css-prop,--height,ios
818820
ion-input-otp,css-prop,--height,md
821+
ion-input-otp,css-prop,--highlight-color-focused,ios
822+
ion-input-otp,css-prop,--highlight-color-focused,md
819823
ion-input-otp,css-prop,--highlight-color-invalid,ios
820824
ion-input-otp,css-prop,--highlight-color-invalid,md
825+
ion-input-otp,css-prop,--highlight-color-valid,ios
826+
ion-input-otp,css-prop,--highlight-color-valid,md
821827
ion-input-otp,css-prop,--margin-bottom,ios
822828
ion-input-otp,css-prop,--margin-bottom,md
823829
ion-input-otp,css-prop,--margin-end,ios

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

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*
1313
* @prop --border-width: Border width of the input boxes
1414
* @prop --border-color: Border color of the input boxes
15+
* @prop --border-width-focused: Border width when focused
1516
* @prop --border-color-focused: Border color when focused
1617
*
1718
* @prop --color: Text color of the input
@@ -35,7 +36,9 @@
3536
* @prop --separator-height: Height of the separator between boxes
3637
* @prop --separator-border-radius: Border radius of the separator between boxes
3738
*
38-
* @prop --highlight-color-invalid: Color used for the invalid state
39+
* @prop --highlight-color-focused: The color of the highlight on the input when focused
40+
* @prop --highlight-color-valid: The color of the highlight on the input when valid
41+
* @prop --highlight-color-invalid: The color of the highlight on the input when invalid
3942
*/
4043
--margin-top: 0;
4144
--margin-end: 0;
@@ -51,11 +54,24 @@
5154
--separator-border-radius: 999px;
5255
--separator-color: #{$background-color-step-150};
5356
--background-focused: var(--background);
54-
--border-color-focused: #{ion-color(primary, base, 0.4)};
57+
--border-width-focused: 2px;
58+
--border-color-focused: var(--highlight-color);
59+
--highlight-color-focused: #{ion-color(primary, base, 0.4)};
60+
--highlight-color-valid: #{ion-color(success, base)};
5561
--highlight-color-invalid: #{ion-color(danger, base)};
5662

63+
/**
64+
* This is a private API that is used to switch
65+
* out the highlight color based on the state
66+
* of the component without having to write
67+
* different selectors for different fill variants.
68+
*/
69+
--highlight-color: var(--highlight-color-focused);
70+
5771
display: block;
5872
position: relative;
73+
74+
font-size: dynamic-font(14px);
5975
}
6076

6177
.input-otp-group {
@@ -102,7 +118,7 @@
102118
.input-otp-description {
103119
color: $text-color-step-400;
104120

105-
font-size: 12px;
121+
font-size: dynamic-font(12px);
106122
font-weight: 500;
107123

108124
line-height: 20px;
@@ -127,8 +143,6 @@
127143
:host(.input-otp-size-small) {
128144
--width: 40px;
129145
--height: 40px;
130-
131-
font-size: 0.875em;
132146
}
133147

134148
:host(.input-otp-size-small) .input-otp-group {
@@ -138,15 +152,11 @@
138152
:host(.input-otp-size-medium) {
139153
--width: 48px;
140154
--height: 48px;
141-
142-
font-size: 1em;
143155
}
144156

145157
:host(.input-otp-size-large) {
146158
--width: 56px;
147159
--height: 56px;
148-
149-
font-size: 1.125em;
150160
}
151161

152162
:host(.input-otp-size-medium) .input-otp-group,
@@ -179,7 +189,7 @@
179189

180190
:host(.input-otp-fill-solid) {
181191
--border-color: #{$background-color-step-50};
182-
--background: var(--border-color);
192+
--background: #{$background-color-step-50};
183193
}
184194

185195
// States
@@ -188,6 +198,8 @@
188198
:host(.input-otp-fill-outline.input-otp-disabled) {
189199
--background: #{$background-color-step-50};
190200
--border-color: #{$background-color-step-100};
201+
202+
color: #{$text-color-step-650};
191203
}
192204

193205
:host(.input-otp-disabled),
@@ -196,19 +208,14 @@
196208
}
197209

198210
:host(.has-focus) .native-input:focus {
199-
border-width: 2px;
211+
border-width: var(--border-width-focused);
200212
border-color: var(--border-color-focused);
201213

202214
outline: none;
203215

204216
background: var(--background-focused);
205217
}
206218

207-
:host(.ion-invalid) .native-input,
208-
:host(.ion-invalid.has-focus) .native-input {
209-
border-color: var(--highlight-color-invalid);
210-
}
211-
212219
:host(.input-otp-fill-outline.input-otp-readonly) {
213220
--background: #{$background-color-step-50};
214221
}
@@ -218,34 +225,62 @@
218225
--border-color: #{$background-color-step-100};
219226
}
220227

228+
// Input Highlight
229+
// ----------------------------------------------------------------
230+
231+
:host(.ion-touched.ion-invalid) {
232+
--highlight-color: var(--highlight-color-invalid);
233+
}
234+
235+
/**
236+
* The component highlight is only shown
237+
* on focus, so we can safely set the valid
238+
* color state when valid. If we
239+
* set it when .has-focus is present then
240+
* the highlight color would change
241+
* from the valid color to the component's
242+
* color during the transition after the
243+
* component loses focus.
244+
*/
245+
:host(.ion-valid) {
246+
--highlight-color: var(--highlight-color-valid);
247+
}
248+
249+
:host(.has-focus.ion-valid),
250+
:host(.ion-touched.ion-invalid) {
251+
--border-color: var(--highlight-color);
252+
}
253+
221254
// Colors
222255
// --------------------------------------------------
223256

224257
:host(.input-otp-fill-outline.ion-color) .native-input {
225-
border-color: current-color(base, 0.3);
258+
border-color: #{current-color(base, 0.3)};
226259
}
227260

228-
:host(.input-otp-fill-outline.ion-color.has-focus) .native-input:focus {
229-
border-color: current-color(base, 0.4);
261+
// Focused
262+
:host(.input-otp-fill-outline.ion-color.has-focus) .native-input:focus,
263+
:host(.input-otp-fill-solid.ion-color.has-focus) .native-input:focus {
264+
border-color: #{current-color(base, 0.4)};
230265
}
231266

232-
:host(.input-otp-fill-solid.ion-color) .native-input {
233-
border-color: transparent;
234-
235-
background: current-color(base, 0.08);
267+
// Invalid
268+
:host(.input-otp-fill-outline.ion-color.ion-invalid) .native-input,
269+
:host(.input-otp-fill-solid.ion-color.ion-invalid) .native-input,
270+
:host(.input-otp-fill-outline.ion-color.has-focus.ion-invalid) .native-input,
271+
:host(.input-otp-fill-solid.ion-color.has-focus.ion-invalid) .native-input {
272+
border-color: #{ion-color(danger, base)};
236273
}
237274

238-
:host(.input-otp-fill-solid.ion-color.has-focus) .native-input:focus {
239-
border-color: current-color(base, 0.4);
275+
// Valid
276+
:host(.input-otp-fill-outline.ion-color.ion-valid) .native-input,
277+
:host(.input-otp-fill-solid.ion-color.ion-valid) .native-input,
278+
:host(.input-otp-fill-outline.ion-color.has-focus.ion-valid) .native-input,
279+
:host(.input-otp-fill-solid.ion-color.has-focus.ion-valid) .native-input {
280+
border-color: #{ion-color(success, base)};
240281
}
241282

242283
// Outline & Disabled
243284
:host(.input-otp-fill-outline.input-otp-disabled.ion-color) .native-input {
244-
border-color: current-color(base, 0.1);
245-
}
246-
247-
// Solid & Disabled/Readonly
248-
:host(.input-otp-fill-solid.input-otp-disabled.ion-color) .native-input,
249-
:host(.input-otp-fill-solid.input-otp-readonly.ion-color) .native-input {
250-
background: current-color(base, 0.16);
285+
border-color: #{current-color(base, 0.1)};
251286
}

core/src/components/input-otp/test/basic/index.html

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,12 @@ <h2>Readonly</h2>
7676
</div>
7777

7878
<div class="grid-item">
79-
<h2>Invalid</h2>
80-
<ion-input-otp class="ion-invalid">Description</ion-input-otp>
81-
<ion-input-otp fill="solid" class="ion-invalid">Description</ion-input-otp>
82-
83-
<h2>Methods</h2>
84-
<ion-input-otp id="inputOtpMethods" value="1234">Description</ion-input-otp>
85-
<div style="display: flex; justify-content: center">
86-
<button id="reset">Reset</button>
87-
<button id="focus">Focus</button>
88-
<button id="focus-third">Focus Third</button>
89-
<button id="focus-and-reset">Focus and Reset</button>
90-
</div>
79+
<h2>Invalid / Touched</h2>
80+
<ion-input-otp class="ion-invalid ion-touched">Description</ion-input-otp>
81+
<ion-input-otp fill="solid" class="ion-invalid ion-touched">Description</ion-input-otp>
82+
<h2>Valid / Focused</h2>
83+
<ion-input-otp class="ion-valid has-focus">Description</ion-input-otp>
84+
<ion-input-otp fill="solid" class="ion-valid has-focus">Description</ion-input-otp>
9185
</div>
9286
</div>
9387
</ion-content>
@@ -125,23 +119,6 @@ <h2>Methods</h2>
125119
document.addEventListener('ionBlur', (ev) => {
126120
console.log('ionBlur', ev);
127121
});
128-
129-
document.getElementById('reset').addEventListener('click', () => {
130-
inputOtpMethods.reset();
131-
});
132-
133-
document.getElementById('focus').addEventListener('click', () => {
134-
inputOtpMethods.setFocus();
135-
});
136-
137-
document.getElementById('focus-third').addEventListener('click', () => {
138-
inputOtpMethods.setFocus(2);
139-
});
140-
141-
document.getElementById('focus-and-reset').addEventListener('click', () => {
142-
inputOtpMethods.setFocus();
143-
inputOtpMethods.reset();
144-
});
145122
</script>
146123
</ion-app>
147124
</body>

core/src/components/input-otp/test/color/index.html

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,24 @@ <h2>Solid Colors</h2>
6565

6666
<div class="grid-item">
6767
<h2>Disabled</h2>
68-
<ion-input-otp value="12" color="primary" disabled>Outline</ion-input-otp>
69-
<ion-input-otp value="12" color="warning" disabled>Outline</ion-input-otp>
70-
<ion-input-otp value="12" color="danger" disabled>Outline</ion-input-otp>
71-
<ion-input-otp value="12" color="primary" fill="solid" disabled>Solid</ion-input-otp>
72-
<ion-input-otp value="12" color="warning" fill="solid" disabled>Solid</ion-input-otp>
73-
<ion-input-otp value="12" color="danger" fill="solid" disabled>Solid</ion-input-otp>
68+
<ion-input-otp value="12" color="tertiary" disabled>Outline</ion-input-otp>
69+
<ion-input-otp value="12" color="tertiary" fill="solid" disabled>Solid</ion-input-otp>
70+
71+
<h2>Readonly</h2>
72+
<ion-input-otp value="12" color="tertiary" readonly>Outline</ion-input-otp>
73+
<ion-input-otp value="12" color="tertiary" fill="solid" readonly>Solid</ion-input-otp>
7474
</div>
7575

7676
<div class="grid-item">
77-
<h2>Readonly</h2>
78-
<ion-input-otp value="12" color="primary" readonly>Outline</ion-input-otp>
79-
<ion-input-otp value="12" color="warning" readonly>Outline</ion-input-otp>
80-
<ion-input-otp value="12" color="danger" readonly>Outline</ion-input-otp>
81-
<ion-input-otp value="12" color="primary" fill="solid" readonly>Solid</ion-input-otp>
82-
<ion-input-otp value="12" color="warning" fill="solid" readonly>Solid</ion-input-otp>
83-
<ion-input-otp value="12" color="danger" fill="solid" readonly>Solid</ion-input-otp>
77+
<h2>Invalid / Touched</h2>
78+
<ion-input-otp value="12" color="tertiary" class="ion-invalid ion-touched">Outline</ion-input-otp>
79+
<ion-input-otp value="12" color="tertiary" fill="solid" class="ion-invalid ion-touched"
80+
>Solid</ion-input-otp
81+
>
82+
83+
<h2>Valid / Focused</h2>
84+
<ion-input-otp value="12" color="tertiary" class="ion-valid has-focus">Outline</ion-input-otp>
85+
<ion-input-otp value="12" color="tertiary" fill="solid" class="ion-valid has-focus">Solid</ion-input-otp>
8486
</div>
8587
</div>
8688
</ion-content>

core/src/components/input-otp/test/size/index.html

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,26 @@
3939
<div class="grid">
4040
<div class="grid-item">
4141
<h2>Small</h2>
42-
<ion-input-otp size="small">Description</ion-input-otp>
43-
<ion-input-otp size="small" separators="all">Description</ion-input-otp>
44-
<ion-input-otp size="small" fill="solid">Description</ion-input-otp>
45-
<ion-input-otp size="small" fill="solid" separators="all">Description</ion-input-otp>
42+
<ion-input-otp value="12" size="small">Description</ion-input-otp>
43+
<ion-input-otp value="12" size="small" separators="all">Description</ion-input-otp>
44+
<ion-input-otp value="12" size="small" fill="solid">Description</ion-input-otp>
45+
<ion-input-otp value="12" size="small" fill="solid" separators="all">Description</ion-input-otp>
4646
</div>
4747

4848
<div class="grid-item">
4949
<h2>Medium</h2>
50-
<ion-input-otp size="medium">Description</ion-input-otp>
51-
<ion-input-otp size="medium" separators="all">Description</ion-input-otp>
52-
<ion-input-otp size="medium" fill="solid">Description</ion-input-otp>
53-
<ion-input-otp size="medium" fill="solid" separators="all">Description</ion-input-otp>
50+
<ion-input-otp value="12" size="medium">Description</ion-input-otp>
51+
<ion-input-otp value="12" size="medium" separators="all">Description</ion-input-otp>
52+
<ion-input-otp value="12" size="medium" fill="solid">Description</ion-input-otp>
53+
<ion-input-otp value="12" size="medium" fill="solid" separators="all">Description</ion-input-otp>
5454
</div>
5555

5656
<div class="grid-item">
5757
<h2>Large</h2>
58-
<ion-input-otp size="large">Description</ion-input-otp>
59-
<ion-input-otp size="large" separators="all">Description</ion-input-otp>
60-
<ion-input-otp size="large" fill="solid">Description</ion-input-otp>
61-
<ion-input-otp size="large" fill="solid" separators="all">Description</ion-input-otp>
58+
<ion-input-otp value="12" size="large">Description</ion-input-otp>
59+
<ion-input-otp value="12" size="large" separators="all">Description</ion-input-otp>
60+
<ion-input-otp value="12" size="large" fill="solid">Description</ion-input-otp>
61+
<ion-input-otp value="12" size="large" fill="solid" separators="all">Description</ion-input-otp>
6262
</div>
6363
</div>
6464
</ion-content>

0 commit comments

Comments
 (0)