@descope/web-components-ui 1.0.73 → 1.0.75

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. package/dist/index.esm.js +2425 -622
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/umd/447.js +1 -1
  4. package/dist/umd/744.js +1 -1
  5. package/dist/umd/878.js +1 -0
  6. package/dist/umd/descope-combo-box-index-js.js +1 -1
  7. package/dist/umd/descope-logo-index-js.js +1 -1
  8. package/dist/umd/descope-passcode-descope-passcode-internal-index-js.js +1 -1
  9. package/dist/umd/descope-passcode-index-js.js +1 -1
  10. package/dist/umd/descope-phone-field-descope-phone-field-internal-index-js.js +1 -0
  11. package/dist/umd/descope-phone-field-index-js.js +1 -0
  12. package/dist/umd/descope-text-field-index-js.js +1 -1
  13. package/dist/umd/index.js +1 -1
  14. package/package.json +1 -1
  15. package/src/components/descope-combo-box/ComboBox.js +85 -50
  16. package/src/components/descope-logo/Logo.js +1 -1
  17. package/src/components/descope-passcode/Passcode.js +2 -5
  18. package/src/components/descope-phone-field/CountryCodes.js +1212 -0
  19. package/src/components/descope-phone-field/PhoneField.js +179 -0
  20. package/src/components/descope-phone-field/descope-phone-field-internal/PhoneFieldInternal.js +213 -0
  21. package/src/components/descope-phone-field/descope-phone-field-internal/index.js +6 -0
  22. package/src/components/descope-phone-field/helpers.js +23 -0
  23. package/src/components/descope-phone-field/index.js +9 -0
  24. package/src/components/descope-text-field/TextField.js +31 -3
  25. package/src/components/descope-text-field/textFieldMappings.js +4 -1
  26. package/src/index.js +1 -0
  27. package/src/mixins/inputValidationMixin.js +21 -2
  28. package/src/mixins/portalMixin.js +8 -3
  29. package/src/theme/components/comboBox.js +39 -9
  30. package/src/theme/components/index.js +3 -1
  31. package/src/theme/components/phoneField.js +74 -0
  32. package/src/theme/components/textField.js +2 -2
@@ -0,0 +1,179 @@
1
+ import { componentName as descopeInternalComponentName } from './descope-phone-field-internal/PhoneFieldInternal';
2
+ import { forwardAttrs, getComponentName } from '../../helpers/componentHelpers';
3
+ import { compose } from '../../helpers';
4
+ import {
5
+ createProxy,
6
+ createStyleMixin,
7
+ draggableMixin,
8
+ proxyInputMixin
9
+ } from '../../mixins';
10
+
11
+ import TextField from '../descope-text-field/TextField';
12
+ import ComboBox from '../descope-combo-box/ComboBox';
13
+
14
+ const textVars = TextField.cssVarList;
15
+ const comboVars = ComboBox.cssVarList;
16
+
17
+ export const componentName = getComponentName('phone-field');
18
+
19
+ const customMixin = (superclass) =>
20
+ class PhoneFieldClass extends superclass {
21
+ constructor() {
22
+ super();
23
+ }
24
+
25
+ init() {
26
+ super.init?.();
27
+
28
+ const template = document.createElement('template');
29
+
30
+ template.innerHTML = `
31
+ <${descopeInternalComponentName}
32
+ tabindex="-1"
33
+ slot="input"
34
+ ></${descopeInternalComponentName}>
35
+ `;
36
+
37
+ this.baseElement.appendChild(template.content.cloneNode(true));
38
+
39
+ this.inputElement = this.shadowRoot.querySelector(descopeInternalComponentName);
40
+
41
+ forwardAttrs(this.shadowRoot.host, this.inputElement, {
42
+ includeAttrs: [
43
+ 'size',
44
+ 'bordered',
45
+ 'invalid',
46
+ 'minlength',
47
+ 'maxlength',
48
+ 'default-code',
49
+ 'country-input-placeholder',
50
+ 'phone-input-placeholder',
51
+ ]
52
+ });
53
+ }
54
+ };
55
+
56
+ const {
57
+ inputWrapper,
58
+ countryCodeInput,
59
+ phoneInput,
60
+ label,
61
+ requiredIndicator,
62
+ separator
63
+ } = {
64
+ inputWrapper: { selector: '::part(input-field)' },
65
+ phoneInput: { selector: () => 'descope-text-field' },
66
+ countryCodeInput: { selector: () => 'descope-combo-box' },
67
+ label: { selector: '> label' },
68
+ requiredIndicator: { selector: '[required]::part(required-indicator)::after' },
69
+ separator: { selector: 'descope-phone-field-internal .separator' }
70
+ };
71
+
72
+ const PhoneField = compose(
73
+ createStyleMixin({
74
+ mappings: {
75
+ componentWidth: { selector: () => ':host', property: 'width' },
76
+
77
+ wrapperBorderStyle: [
78
+ { ...inputWrapper, property: 'border-style' },
79
+ { ...separator, property: 'border-left-style' }
80
+ ],
81
+ wrapperBorderWidth: [
82
+ { ...inputWrapper, property: 'border-width' },
83
+ { ...separator, property: 'border-left-width' }
84
+ ],
85
+ wrapperBorderColor: [
86
+ { ...inputWrapper, property: 'border-color' },
87
+ { ...separator, property: 'border-left-color' }
88
+ ],
89
+ wrapperBorderRadius: { ...inputWrapper, property: 'border-radius' },
90
+
91
+ inputHeight: { ...inputWrapper, property: 'height' },
92
+
93
+ countryCodeInputWidth: { ...countryCodeInput, property: comboVars.width },
94
+ countryCodeDropdownWidth: {
95
+ ...countryCodeInput,
96
+ property: '--vaadin-combo-box-overlay-width'
97
+ },
98
+
99
+ phoneInputWidth: { ...phoneInput, property: 'width' },
100
+
101
+ color: [label, requiredIndicator],
102
+
103
+ placeholderColor: {
104
+ ...phoneInput,
105
+ property: textVars.placeholderColor
106
+ },
107
+
108
+ overlayItemBackgroundColor: {
109
+ selector: 'descope-combo-box',
110
+ property: comboVars.overlayItemBackgroundColor
111
+ },
112
+ },
113
+ }),
114
+ draggableMixin,
115
+ proxyInputMixin,
116
+ customMixin,
117
+ )(
118
+ createProxy({
119
+ slots: [],
120
+ wrappedEleName: 'vaadin-text-field',
121
+ style: () => `
122
+ :host {
123
+ --vaadin-field-default-width: auto;
124
+ display: inline-block;
125
+ }
126
+ div {
127
+ display: inline-flex;
128
+ }
129
+ vaadin-text-field {
130
+ padding: 0;
131
+ width: 100%;
132
+ height: 100%;
133
+ }
134
+ vaadin-text-field::part(input-field) {
135
+ padding: 0;
136
+ min-height: 0;
137
+ background: transparent;
138
+ overflow: hidden;
139
+ }
140
+ descope-phone-field-internal {
141
+ -webkit-mask-image: none;
142
+ padding: 0;
143
+ min-height: 0;
144
+ width: 100%;
145
+ height: 100%;
146
+ }
147
+ descope-phone-field-internal > div {
148
+ width: 100%;
149
+ height: 100%;
150
+ }
151
+ descope-phone-field-internal .separator {
152
+ flex: 0;
153
+ border: none;
154
+ }
155
+ descope-combo-box {
156
+ flex-shrink: 0;
157
+ height: 100%;
158
+ ${comboVars.borderWidth}: 0;
159
+ }
160
+ descope-text-field {
161
+ flex-grow: 1;
162
+ min-height: 0;
163
+ height: 100%;
164
+ ${textVars.borderWidth}: 0;
165
+ ${textVars.borderRadius}: 0;
166
+ }
167
+ vaadin-text-field[required]::part(required-indicator)::after {
168
+ content: "*";
169
+ }
170
+ vaadin-text-field[readonly] > input:placeholder-shown {
171
+ opacity: 1;
172
+ }
173
+ `,
174
+ excludeAttrsSync: ['tabindex'],
175
+ componentName
176
+ })
177
+ );
178
+
179
+ export default PhoneField;
@@ -0,0 +1,213 @@
1
+ import { createBaseInputClass } from '../../../baseClasses/createBaseInputClass';
2
+ import { getComponentName } from '../../../helpers/componentHelpers';
3
+ import { createDispatchEvent } from '../../../helpers/mixinsHelpers';
4
+ import CountryCodes from '../CountryCodes';
5
+ import { comboBoxItem } from '../helpers';
6
+
7
+ export const componentName = getComponentName('phone-field-internal');
8
+
9
+ const commonAttrs = [
10
+ 'disabled',
11
+ 'size',
12
+ 'bordered',
13
+ 'invalid',
14
+ ];
15
+ const countryAttrs = ['country-input-placeholder', 'default-code'];
16
+ const phoneAttrs = ['phone-input-placeholder', 'maxlength'];
17
+ const mapAttrs = {
18
+ 'country-input-placeholder': 'placeholder',
19
+ 'phone-input-placeholder': 'placeholder',
20
+ }
21
+
22
+ const inputRelatedAttrs = [].concat(commonAttrs, countryAttrs, phoneAttrs);
23
+
24
+ const BaseInputClass = createBaseInputClass({ componentName, baseSelector: 'div' });
25
+
26
+ class PhoneFieldInternal extends BaseInputClass {
27
+ static get observedAttributes() {
28
+ return [].concat(
29
+ BaseInputClass.observedAttributes || [],
30
+ inputRelatedAttrs,
31
+ );
32
+ }
33
+
34
+ #dispatchBlur = createDispatchEvent.bind(this, 'blur');
35
+ #dispatchFocus = createDispatchEvent.bind(this, 'focus');
36
+
37
+ constructor() {
38
+ super();
39
+
40
+ this.innerHTML = `
41
+ <div>
42
+ <descope-combo-box
43
+ item-label-path="data-name"
44
+ item-value-path="data-id"
45
+ >
46
+ ${CountryCodes.map(item => comboBoxItem(item)).join('')}
47
+ </descope-combo-box>
48
+ <div class="separator"></div>
49
+ <descope-text-field type="tel"></descope-text-field>
50
+ </div>`;
51
+
52
+ this.countryCodeInput = this.querySelector('descope-combo-box');
53
+ this.phoneNumberInput = this.querySelector('descope-text-field');
54
+ this.inputs = [
55
+ this.countryCodeInput,
56
+ this.phoneNumberInput
57
+ ];
58
+ }
59
+
60
+ get value() {
61
+ return this.inputs.map(({ value }) => value).join('-');
62
+ }
63
+
64
+ set value(val) {
65
+ const [countryCode = '', phoneNumber = ''] = val.split('-');
66
+ this.countryCodeInput.value = countryCode;
67
+ this.phoneNumberInput.value = phoneNumber;
68
+ }
69
+
70
+ get phoneNumberValue() {
71
+ return this.phoneNumberInput.value;
72
+ }
73
+
74
+ get countryCodeValue() {
75
+ return this.countryCodeInput.shadowRoot.querySelector('input').value;
76
+ }
77
+
78
+ get minLength() {
79
+ return parseInt(this.getAttribute('minlength'), 10) || 0;
80
+ }
81
+
82
+ getValidity() {
83
+ const hasCode = this.countryCodeInput.value;
84
+ const hasPhone = this.phoneNumberInput.value;
85
+ const emptyValue = !hasCode || !hasPhone;
86
+ const hasMinPhoneLength = this.phoneNumberInput.value.length && this.phoneNumberInput.value.length < this.minLength;
87
+
88
+ if (this.isRequired && emptyValue) {
89
+ return { valueMissing: true };
90
+ }
91
+ if (hasMinPhoneLength) {
92
+ return { tooShort: true };
93
+ }
94
+ if ((hasCode && !hasPhone) || (!hasCode && hasPhone)) {
95
+ return { valueMissing: true };
96
+ }
97
+ return {}
98
+ };
99
+
100
+ init() {
101
+ super.init();
102
+ this.initInputs();
103
+ this.setComboBoxDescriptor();
104
+ }
105
+
106
+ handleDefaultCountryCode(countryCode) {
107
+ if (!this.countryCodeInput.value) {
108
+ const countryData = this.countryCodeInput.items.find(c => c['data-id'] === countryCode)?.['data-name'];
109
+
110
+ // When replacing the input component (inserting internal component into text-field) -
111
+ // Vaadin resets the input's value. We use setTimeout in order to make sure this happens
112
+ // after the reset.
113
+ if (countryData) {
114
+ setTimeout(() => this.countryCodeInput.value = countryData);
115
+ }
116
+ }
117
+ }
118
+
119
+ // We want to override Vaadin's Combo Box value setter. This is needed since Vaadin couples between the
120
+ // field that it searches the value, and the finaly display value of the input. We want to search ALL
121
+ // the values (so we made a field with all the values), but display ONLY the dial code, so we added
122
+ // this setter, which does that.
123
+ setComboBoxDescriptor() {
124
+ const comboBox = this.countryCodeInput;
125
+ const input = comboBox.shadowRoot.querySelector('input');
126
+ const valueDescriptor = Object.getOwnPropertyDescriptor(
127
+ input.constructor.prototype,
128
+ 'value'
129
+ );
130
+ Object.defineProperties(input, {
131
+ value: {
132
+ ...valueDescriptor,
133
+ set(val) {
134
+ if (!comboBox.items?.length) {
135
+ return;
136
+ }
137
+
138
+ const [_code, dialCode] = val.split(' ');
139
+
140
+ if (val === this.value) {
141
+ return;
142
+ }
143
+
144
+ valueDescriptor.set.call(this, dialCode || '');
145
+ }
146
+ }
147
+ });
148
+ }
149
+
150
+ initInputs() {
151
+ let prevVal = this.value
152
+ let blurTimerId
153
+
154
+ // Sanitize phone input value to filter everything but digits
155
+ this.phoneNumberInput.addEventListener('input', (e) => {
156
+ const telDigitsRegExp = /^\d$/;
157
+ const sanitizedInput = e.target.value
158
+ .split('')
159
+ .filter(char => telDigitsRegExp.test(char))
160
+ .join('');
161
+ e.target.value = sanitizedInput;
162
+ });
163
+
164
+ this.inputs.forEach(input => {
165
+ input.addEventListener('blur', (e) => {
166
+ e.stopImmediatePropagation();
167
+ blurTimerId = setTimeout(() => {
168
+ blurTimerId = null
169
+ this.#dispatchBlur()
170
+ });
171
+ })
172
+
173
+ input.addEventListener('focus', (e) => {
174
+ e.stopImmediatePropagation();
175
+ clearTimeout(blurTimerId)
176
+ if (!blurTimerId) {
177
+ this.#dispatchFocus()
178
+ }
179
+ })
180
+
181
+ input.addEventListener('input', (e) => {
182
+ if (prevVal === this.value) {
183
+ e.stopImmediatePropagation();
184
+ }
185
+ });
186
+ });
187
+ }
188
+
189
+ attributeChangedCallback(attrName, oldValue, newValue) {
190
+ super.attributeChangedCallback(attrName, oldValue, newValue);
191
+
192
+ if (oldValue !== newValue) {
193
+ if (attrName === 'default-code' && newValue) {
194
+ this.handleDefaultCountryCode(newValue);
195
+ }
196
+ else if (inputRelatedAttrs.includes(attrName)) {
197
+ const attr = mapAttrs[attrName] || attrName;
198
+
199
+ if (commonAttrs.includes(attrName)) {
200
+ this.inputs.forEach(input => input.setAttribute(attr, newValue));
201
+ }
202
+ else if (countryAttrs.includes(attrName)) {
203
+ this.countryCodeInput.setAttribute(attr, newValue);
204
+ }
205
+ else if (phoneAttrs.includes(attrName)) {
206
+ this.phoneNumberInput.setAttribute(attr, newValue);
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+
213
+ export default PhoneFieldInternal;
@@ -0,0 +1,6 @@
1
+ import '../../descope-combo-box';
2
+ import '../../descope-text-field';
3
+
4
+ import PhoneFieldInternal, { componentName } from './PhoneFieldInternal';
5
+
6
+ customElements.define(componentName, PhoneFieldInternal);
@@ -0,0 +1,23 @@
1
+ // We use JSDelivr in order to fetch the images as image file from this library (svg-country-flags)
2
+ // This reduces our bundle size, and we use it as a static remote resource.
3
+ export const getCountryFlag = (code) =>
4
+ `https://cdn.jsdelivr.net/npm/svg-country-flags@1.2.10/svg/${code.toLowerCase()}.svg`;
5
+
6
+ export const comboBoxItem = ({ code, dialCode, name: country }) => (`
7
+ <div
8
+ style="display:flex; flex-direction: column;"
9
+ data-id="${code}"
10
+ data-name="${code} ${dialCode} ${country}"
11
+ >
12
+ <div>
13
+ <span>
14
+ <img src="${getCountryFlag(code)}" width="20"/>
15
+ </span>
16
+ <span>${country}</span>
17
+ </div>
18
+ <div>
19
+ <span>${code}</span>
20
+ <span>${dialCode}</span>
21
+ </div>
22
+ </div>
23
+ `);
@@ -0,0 +1,9 @@
1
+ import './descope-phone-field-internal';
2
+ import '../descope-combo-box';
3
+ import '../descope-text-field';
4
+
5
+ import PhoneField, { componentName } from './PhoneField';
6
+
7
+ customElements.define(componentName, PhoneField);
8
+
9
+ export { PhoneField };
@@ -13,13 +13,36 @@ export const componentName = getComponentName('text-field');
13
13
 
14
14
  let overrides = ``;
15
15
 
16
+ const observedAttrs = ['type'];
17
+
18
+ const customMixin = (superclass) =>
19
+ class TextFieldClass extends superclass {
20
+ static get observedAttributes() {
21
+ return observedAttrs.concat(superclass.observedAttributes || []);
22
+ }
23
+
24
+ attributeChangedCallback(attrName, oldVal, newVal) {
25
+ super.attributeChangeCallback?.(attrName, oldVal, newVal);
26
+
27
+ // Vaadin doesn't allow to change the input type attribute.
28
+ // We need the ability to do that, so we're overriding their
29
+ // behavior with their private API.
30
+ // When receiving a `type` attribute, we use their private API
31
+ // to set it on the input.
32
+ if (attrName === 'type') {
33
+ this.baseElement._setType(newVal);
34
+ }
35
+ }
36
+ }
37
+
16
38
  const TextField = compose(
17
39
  createStyleMixin({
18
40
  mappings: textFieldMappings
19
41
  }),
20
42
  draggableMixin,
21
43
  proxyInputMixin,
22
- componentNameValidationMixin
44
+ componentNameValidationMixin,
45
+ customMixin
23
46
  )(
24
47
  createProxy({
25
48
  slots: ['prefix', 'suffix'],
@@ -33,14 +56,20 @@ const TextField = compose(
33
56
  overrides = `
34
57
  :host {
35
58
  display: inline-block;
59
+ --vaadin-field-default-width: auto;
36
60
  }
37
-
38
61
  vaadin-text-field {
39
62
  margin: 0;
40
63
  padding: 0;
64
+ width: 100%;
65
+ height: 100%;
66
+ }
67
+ vaadin-text-field input {
68
+ min-height: 0;
41
69
  }
42
70
  vaadin-text-field::part(input-field) {
43
71
  overflow: hidden;
72
+ padding: 0;
44
73
  }
45
74
  vaadin-text-field[readonly] > input:placeholder-shown {
46
75
  opacity: 1;
@@ -55,7 +84,6 @@ overrides = `
55
84
  }
56
85
  vaadin-text-field > label,
57
86
  vaadin-text-field::part(input-field) {
58
- cursor: pointer;
59
87
  color: var(${TextField.cssVarList.color});
60
88
  }
61
89
  vaadin-text-field::part(input-field):focus {
@@ -24,7 +24,10 @@ export default {
24
24
  ],
25
25
  borderRadius: { selector: selectors.input },
26
26
  boxShadow: { selector: selectors.input },
27
- fontSize: {},
27
+
28
+ // we apply font-size also on the host so we can set its width with em
29
+ fontSize: [{}, { selector: selectors.host }],
30
+
28
31
  height: { selector: selectors.input },
29
32
  padding: { selector: selectors.input },
30
33
  outline: { selector: selectors.input },
package/src/index.js CHANGED
@@ -16,6 +16,7 @@ import './components/descope-text';
16
16
  import './components/descope-text-area';
17
17
  import './components/descope-text-field';
18
18
  import './components/descope-image';
19
+ import './components/descope-phone-field';
19
20
 
20
21
  export {
21
22
  globalsThemeToStyle,
@@ -5,7 +5,9 @@ const observedAttributes = [
5
5
 
6
6
  const errorAttributes = {
7
7
  valueMissing: 'data-errormessage-value-missing',
8
- patternMismatch: 'data-errormessage-pattern-mismatch'
8
+ patternMismatch: 'data-errormessage-pattern-mismatch',
9
+ tooShort: 'data-errormessage-pattern-mismatch-too-short',
10
+ tooLong: 'data-errormessage-pattern-mismatch-too-long',
9
11
  }
10
12
  export const inputValidationMixin = (superclass) => class InputValidationMixinClass extends superclass {
11
13
  static get observedAttributes() {
@@ -35,6 +37,14 @@ export const inputValidationMixin = (superclass) => class InputValidationMixinCl
35
37
  return 'Please match the requested format.'
36
38
  }
37
39
 
40
+ get defaultErrorMsgTooShort() {
41
+ return `Minimum length is ${this.getAttribute('minlength')}.`
42
+ }
43
+
44
+ get defaultErrorMsgTooLong() {
45
+ return `Maximum length is ${this.getAttribute('maxlength')}. `
46
+ }
47
+
38
48
  getErrorMessage(flags) {
39
49
  switch (true) {
40
50
  case flags.valueMissing:
@@ -43,6 +53,12 @@ export const inputValidationMixin = (superclass) => class InputValidationMixinCl
43
53
  case flags.patternMismatch || flags.typeMismatch:
44
54
  return this.getAttribute(errorAttributes.patternMismatch) ||
45
55
  this.defaultErrorMsgPatternMismatch
56
+ case flags.tooShort:
57
+ return this.getAttribute(errorAttributes.tooShort) ||
58
+ this.defaultErrorMsgTooShort
59
+ case flags.tooLong:
60
+ return this.getAttribute(errorAttributes.tooLong) ||
61
+ this.defaultErrorMsgTooLong
46
62
  case flags.customError:
47
63
  return this.validationMessage
48
64
  default:
@@ -110,6 +126,9 @@ export const inputValidationMixin = (superclass) => class InputValidationMixinCl
110
126
  this.addEventListener('invalid', (e) => e.stopPropagation())
111
127
  this.addEventListener('input', this.#setValidity)
112
128
 
113
- this.#setValidity();
129
+ // The attribute sync takes time, so getValidity returns valid,
130
+ // even when it shouldn't. This way allows all attributes to sync
131
+ // after render, before checking the validity.
132
+ setTimeout(() => this.#setValidity());
114
133
  }
115
134
  }
@@ -15,7 +15,12 @@ const sanitizeSelector = (selector) => selector.replace(/[^\w\s]/gi, '');
15
15
 
16
16
  const getDomNode = (maybeDomNode) => maybeDomNode.host || maybeDomNode;
17
17
 
18
- export const portalMixin = ({ name, selector, mappings = {} }) => (superclass) => {
18
+ export const portalMixin = ({
19
+ name,
20
+ selector,
21
+ mappings = {},
22
+ forward: { attributes = [], include = true } = {}
23
+ }) => (superclass) => {
19
24
  const eleDisplayName = name || sanitizeSelector(selector)
20
25
 
21
26
  const BaseClass = createStyleMixin({
@@ -58,9 +63,9 @@ export const portalMixin = ({ name, selector, mappings = {} }) => (superclass) =
58
63
 
59
64
  init() {
60
65
  super.init?.();
61
- forwardAttrs(this, this.#portalEle, { excludeAttrs: ['hover'] })
66
+ forwardAttrs(this, this.#portalEle, { [include ? 'includeAttrs' : 'excludeAttrs']: attributes })
62
67
 
63
68
  this.#handleHoverAttribute();
64
69
  }
65
70
  }
66
- }
71
+ }
@@ -1,6 +1,5 @@
1
1
  import globals from '../globals';
2
2
  import ComboBox from '../../components/descope-combo-box/ComboBox';
3
- import { textField } from './textField';
4
3
  import { getThemeRefs } from '../../helpers/themeHelpers';
5
4
 
6
5
  const globalRefs = getThemeRefs(globals);
@@ -8,18 +7,49 @@ const globalRefs = getThemeRefs(globals);
8
7
  const vars = ComboBox.cssVarList;
9
8
 
10
9
  export const comboBox = {
11
- ...textField(ComboBox.cssVarList),
10
+ [vars.borderColor]: globalRefs.colors.surface.main,
11
+ [vars.borderWidth]: '1px',
12
+ [vars.borderStyle]: 'solid',
13
+ [vars.cursor]: 'pointer',
14
+ [vars.padding]: '0',
15
+ [vars.placeholderColor]: globalRefs.colors.surface.main,
16
+ [vars.toggleColor]: globalRefs.colors.surface.contrast,
17
+ [vars.toggleCursor]: 'pointer',
12
18
  size: {
13
19
  xs: {
14
- [vars.width]: '30px'
20
+ [vars.height]: '14px',
21
+ [vars.fontSize]: '8px',
22
+ [vars.padding]: `0 ${globalRefs.spacing.xs}`
23
+ },
24
+ sm: {
25
+ [vars.height]: '20px',
26
+ [vars.fontSize]: '10px',
27
+ [vars.padding]: `0 ${globalRefs.spacing.sm}`
28
+ },
29
+ md: {
30
+ [vars.height]: '30px',
31
+ [vars.fontSize]: '14px',
32
+ [vars.padding]: `0 ${globalRefs.spacing.md}`
33
+ },
34
+ lg: {
35
+ [vars.height]: '40px',
36
+ [vars.fontSize]: '20px',
37
+ [vars.padding]: `0 ${globalRefs.spacing.lg}`
38
+ },
39
+ xl: {
40
+ [vars.height]: '50px',
41
+ [vars.fontSize]: '25px',
42
+ [vars.padding]: `0 ${globalRefs.spacing.xl}`
15
43
  }
16
44
  },
17
- [vars.borderColor]: 'green',
18
- [vars.borderWidth]: '0',
19
- [vars.cursor]: 'pointer',
20
- [vars.padding]: '0',
21
- // [vars.overlayBackground]: 'blue',
22
- // [vars.overlayBorder]: '3px solid red',
45
+ _invalid: {
46
+ [vars.borderColor]: globalRefs.colors.error.main,
47
+ [vars.placeholderColor]: globalRefs.colors.error.light,
48
+ [vars.toggleColor]: globalRefs.colors.error.main,
49
+ },
50
+ // [vars.overlayCursor]: 'pointer',
51
+ // [vars.overlayBackground]: globalRefs.colors.surface.light,
52
+ // [vars.overlayBorder]: `2px solid red`,
23
53
  };
24
54
 
25
55
  export default comboBox;
@@ -15,6 +15,7 @@ import passcode from './passcode';
15
15
  import { loaderRadial, loaderLinear } from './loader';
16
16
  import comboBox from './comboBox';
17
17
  import image from './image';
18
+ import phoneField from './phoneField';
18
19
 
19
20
  export default {
20
21
  button,
@@ -34,5 +35,6 @@ export default {
34
35
  loaderRadial,
35
36
  loaderLinear,
36
37
  comboBox,
37
- image
38
+ image,
39
+ phoneField
38
40
  };