@descope/web-components-ui 1.0.73 → 1.0.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  };