@descope/web-components-ui 1.0.64 → 1.0.66
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.
- package/dist/cjs/index.cjs.js +6 -4
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/index.esm.js +706 -464
- package/dist/index.esm.js.map +1 -1
- package/dist/umd/233.js +5 -1
- package/dist/umd/314.js +283 -0
- package/dist/umd/314.js.LICENSE.txt +27 -0
- package/dist/umd/541.js +744 -0
- package/dist/umd/541.js.LICENSE.txt +21 -0
- package/dist/umd/725.js +37 -1
- package/dist/umd/786.js +1 -1
- package/dist/umd/824.js +229 -0
- package/dist/umd/{54.js.LICENSE.txt → 824.js.LICENSE.txt} +0 -6
- package/dist/umd/840.js +9 -9
- package/dist/umd/860.js +1 -0
- package/dist/umd/descope-button-index-js.js +1 -1
- package/dist/umd/descope-checkbox-index-js.js +1 -1
- package/dist/umd/descope-combo-box-index-js.js +1 -0
- package/dist/umd/descope-container-index-js.js +1 -1
- package/dist/umd/descope-date-picker-index-js.js +1 -1
- package/dist/umd/descope-divider-index-js.js +1 -1
- package/dist/umd/descope-email-field-index-js.js +1 -1
- package/dist/umd/descope-link-index-js.js +1 -1
- package/dist/umd/descope-loader-linear-index-js.js +1 -1
- package/dist/umd/descope-loader-radial-index-js.js +1 -1
- package/dist/umd/descope-logo-index-js.js +1 -1
- package/dist/umd/descope-number-field-index-js.js +1 -1
- package/dist/umd/descope-passcode-descope-passcode-internal-index-js.js +1 -1
- package/dist/umd/descope-passcode-index-js.js +1 -1
- package/dist/umd/descope-password-field-index-js.js +1 -1
- package/dist/umd/descope-switch-toggle-index-js.js +1 -1
- package/dist/umd/descope-text-area-index-js.js +1 -1
- package/dist/umd/descope-text-field-index-js.js +1 -1
- package/dist/umd/descope-text-index-js.js +1 -1
- package/dist/umd/index.js +1 -1
- package/package.json +2 -1
- package/src/components/descope-combo-box/ComboBox.js +111 -0
- package/src/components/descope-combo-box/index.js +6 -0
- package/src/components/descope-passcode/Passcode.js +1 -0
- package/src/components/descope-passcode/descope-passcode-internal/PasscodeInternal.js +9 -5
- package/src/constants.js +3 -1
- package/src/helpers/componentHelpers.js +55 -36
- package/src/helpers/index.js +2 -1
- package/src/helpers/themeHelpers/index.js +3 -3
- package/src/mixins/createStyleMixin/index.js +116 -90
- package/src/mixins/index.js +1 -0
- package/src/mixins/inputMixin.js +12 -7
- package/src/mixins/portalMixin.js +62 -0
- package/src/mixins/proxyInputMixin.js +23 -22
- package/src/theme/components/comboBox.js +32 -0
- package/src/theme/components/index.js +3 -1
- package/dist/umd/54.js +0 -971
- package/dist/umd/666.js +0 -37
- /package/dist/umd/{666.js.LICENSE.txt → 725.js.LICENSE.txt} +0 -0
@@ -1,109 +1,135 @@
|
|
1
|
-
import { CSS_SELECTOR_SPECIFIER_MULTIPLY } from '../../constants';
|
1
|
+
import { BASE_THEME_SECTION, CSS_SELECTOR_SPECIFIER_MULTIPLY } from '../../constants';
|
2
2
|
import { kebabCaseJoin } from '../../helpers';
|
3
|
-
import { getCssVarName } from '../../helpers/componentHelpers';
|
3
|
+
import { getCssVarName, observeAttributes } from '../../helpers/componentHelpers';
|
4
4
|
import { componentsThemeManager } from '../../helpers/themeHelpers/componentsThemeManager';
|
5
5
|
import { createStyle, createCssVarsList, createClassSelectorSpecifier } from './helpers';
|
6
6
|
|
7
|
-
|
8
|
-
({ mappings = {} }) =>
|
9
|
-
(superclass) => {
|
10
|
-
const styleAttributes = Object.keys(mappings).map((key) =>
|
11
|
-
kebabCaseJoin('st', key)
|
12
|
-
);
|
13
|
-
return class CustomStyleMixinClass extends superclass {
|
14
|
-
static get observedAttributes() {
|
15
|
-
const superAttrs = superclass.observedAttributes || [];
|
16
|
-
return [...superAttrs, ...styleAttributes];
|
17
|
-
}
|
7
|
+
const STYLE_OVERRIDE_ATTR_PREFIX = 'st'
|
18
8
|
|
19
|
-
|
20
|
-
|
9
|
+
|
10
|
+
export const createStyleMixin =
|
11
|
+
({ mappings = {} }) => (superclass) =>
|
12
|
+
class CustomStyleMixinClass extends superclass {
|
13
|
+
static get cssVarList() {
|
14
|
+
return {
|
15
|
+
...superclass.cssVarList,
|
16
|
+
...createCssVarsList(superclass.componentName, {
|
21
17
|
...mappings,
|
22
|
-
})
|
18
|
+
})
|
19
|
+
};
|
20
|
+
}
|
21
|
+
|
22
|
+
#overrideStyleEle;
|
23
|
+
#themeStyleEle;
|
24
|
+
#disconnectThemeManager
|
25
|
+
#componentNameSuffix
|
26
|
+
#themeSection
|
27
|
+
#rootElement
|
28
|
+
#baseSelector
|
29
|
+
#styleAttributes
|
30
|
+
|
31
|
+
// we are using this mixin also for portalMixin
|
32
|
+
// so we should be able to inject styles to other DOM elements
|
33
|
+
// this is why we need to support these overrides
|
34
|
+
constructor({
|
35
|
+
getRootElement,
|
36
|
+
componentNameSuffix = '',
|
37
|
+
themeSection = BASE_THEME_SECTION,
|
38
|
+
baseSelector
|
39
|
+
} = {}) {
|
40
|
+
super();
|
41
|
+
this.#componentNameSuffix = componentNameSuffix
|
42
|
+
this.#themeSection = themeSection
|
43
|
+
this.#rootElement = getRootElement?.(this) || this.shadowRoot
|
44
|
+
this.#baseSelector = baseSelector ?? this.baseSelector
|
45
|
+
|
46
|
+
this.#styleAttributes = Object.keys(mappings).map((key) =>
|
47
|
+
kebabCaseJoin(STYLE_OVERRIDE_ATTR_PREFIX, componentNameSuffix, key)
|
48
|
+
);
|
49
|
+
}
|
50
|
+
|
51
|
+
get componentTheme() {
|
52
|
+
return componentsThemeManager.currentTheme?.[superclass.componentName] || ''
|
53
|
+
}
|
54
|
+
|
55
|
+
#onComponentThemeChange() {
|
56
|
+
this.#themeStyleEle.innerHTML = this.componentTheme[this.#themeSection]
|
57
|
+
}
|
58
|
+
|
59
|
+
#createComponentTheme() {
|
60
|
+
this.#themeStyleEle = document.createElement('style');
|
61
|
+
this.#themeStyleEle.id = 'style-mixin-theme';
|
62
|
+
this.#rootElement.prepend(this.#themeStyleEle);
|
63
|
+
this.#disconnectThemeManager = componentsThemeManager.onCurrentThemeChange(this.#onComponentThemeChange.bind(this))
|
64
|
+
this.#onComponentThemeChange()
|
65
|
+
}
|
66
|
+
|
67
|
+
#createAttrOverrideStyle() {
|
68
|
+
this.#overrideStyleEle = document.createElement('style');
|
69
|
+
this.#overrideStyleEle.id = 'style-mixin-overrides';
|
70
|
+
|
71
|
+
const classSpecifier = createClassSelectorSpecifier(superclass.componentName, CSS_SELECTOR_SPECIFIER_MULTIPLY);
|
72
|
+
|
73
|
+
this.#overrideStyleEle.innerText = `:host(${classSpecifier}) {}`;
|
74
|
+
this.#rootElement.append(this.#overrideStyleEle);
|
75
|
+
}
|
76
|
+
|
77
|
+
#setAttrOverrideStyle(attrName, value) {
|
78
|
+
const style = this.#overrideStyleEle?.sheet?.cssRules[0].style;
|
79
|
+
if (!style) return;
|
80
|
+
|
81
|
+
const varName = getCssVarName(
|
82
|
+
superclass.componentName,
|
83
|
+
attrName.replace(new RegExp(`^${STYLE_OVERRIDE_ATTR_PREFIX}-`), '')
|
84
|
+
);
|
85
|
+
|
86
|
+
if (value) style?.setProperty(varName, value);
|
87
|
+
else style?.removeProperty(varName);
|
88
|
+
}
|
89
|
+
|
90
|
+
#updateOverrideStyle(attrs = []) {
|
91
|
+
for (const attr of attrs) {
|
92
|
+
if (this.#styleAttributes.includes(attr)) {
|
93
|
+
this.#setAttrOverrideStyle(attr, this.getAttribute(attr));
|
94
|
+
}
|
23
95
|
}
|
24
96
|
|
25
|
-
|
26
|
-
|
27
|
-
|
97
|
+
// we are rewriting the style back to the style tag
|
98
|
+
this.#overrideStyleEle.innerHTML = this.#overrideStyleEle?.sheet?.cssRules[0].cssText
|
99
|
+
}
|
100
|
+
|
101
|
+
#createComponentStyle() {
|
102
|
+
const themeStyle = document.createElement('style');
|
103
|
+
themeStyle.id = 'style-mixin-mappings'
|
104
|
+
themeStyle.innerHTML = createStyle(
|
105
|
+
kebabCaseJoin(superclass.componentName, this.#componentNameSuffix),
|
106
|
+
this.#baseSelector,
|
107
|
+
mappings
|
108
|
+
);
|
109
|
+
this.#rootElement.prepend(themeStyle);
|
110
|
+
}
|
111
|
+
|
112
|
+
#addClassName(className) {
|
113
|
+
(this.#rootElement.classList || this.#rootElement.host.classList).add(className)
|
114
|
+
}
|
28
115
|
|
29
|
-
|
30
|
-
|
116
|
+
connectedCallback() {
|
117
|
+
super.connectedCallback?.();
|
118
|
+
if (this.shadowRoot.isConnected) {
|
31
119
|
|
32
|
-
this
|
120
|
+
this.#addClassName(superclass.componentName)
|
33
121
|
|
34
122
|
this.#createComponentStyle();
|
35
123
|
this.#createComponentTheme();
|
36
124
|
this.#createAttrOverrideStyle();
|
37
|
-
}
|
38
|
-
|
39
|
-
get componentTheme() {
|
40
|
-
return componentsThemeManager.currentTheme?.[superclass.componentName] || ''
|
41
|
-
}
|
42
|
-
|
43
|
-
onComponentThemeChange() {
|
44
|
-
this.#themeStyleEle.innerHTML = this.componentTheme.theme
|
45
|
-
}
|
46
|
-
|
47
|
-
#createComponentTheme() {
|
48
|
-
this.#themeStyleEle = document.createElement('style');
|
49
|
-
this.#themeStyleEle.id = 'style-mixin-component-theme';
|
50
|
-
this.shadowRoot.prepend(this.#themeStyleEle);
|
51
|
-
this.#disconnectThemeManager = componentsThemeManager.onCurrentThemeChange(this.onComponentThemeChange.bind(this))
|
52
|
-
this.onComponentThemeChange()
|
53
|
-
}
|
54
125
|
|
55
|
-
|
56
|
-
this.#
|
57
|
-
this.#overrideStyleEle.id = 'style-mixin-overrides';
|
126
|
+
// this is instead attributeChangedCallback because we cannot use static methods in this case
|
127
|
+
observeAttributes(this, this.#updateOverrideStyle.bind(this), {})
|
58
128
|
|
59
|
-
const classSpecifier = createClassSelectorSpecifier(superclass.componentName, CSS_SELECTOR_SPECIFIER_MULTIPLY);
|
60
|
-
this.#overrideStyleEle.innerText = `:host(${classSpecifier}) {}`;
|
61
|
-
this.shadowRoot.append(this.#overrideStyleEle);
|
62
129
|
}
|
130
|
+
}
|
63
131
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
superclass.componentName,
|
68
|
-
attrName.replace(/^st-/, '')
|
69
|
-
);
|
70
|
-
|
71
|
-
if (value) style?.setProperty(varName, value);
|
72
|
-
else style?.removeProperty(varName);
|
73
|
-
}
|
74
|
-
|
75
|
-
#createComponentStyle() {
|
76
|
-
const themeStyle = document.createElement('style');
|
77
|
-
themeStyle.id = 'style-mixin-component';
|
78
|
-
themeStyle.innerHTML = createStyle(
|
79
|
-
superclass.componentName,
|
80
|
-
this.baseSelector,
|
81
|
-
mappings
|
82
|
-
);
|
83
|
-
this.shadowRoot.prepend(themeStyle);
|
84
|
-
}
|
85
|
-
|
86
|
-
attributeChangedCallback(attrName, oldValue, newValue) {
|
87
|
-
super.attributeChangedCallback?.(attrName, oldValue, newValue);
|
88
|
-
|
89
|
-
if (styleAttributes.includes(attrName)) {
|
90
|
-
this.#updateAttrOverrideStyle(attrName, newValue);
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
connectedCallback() {
|
95
|
-
super.connectedCallback?.();
|
96
|
-
if (this.shadowRoot.isConnected) {
|
97
|
-
Array.from(this.attributes).forEach((attr) => {
|
98
|
-
if (styleAttributes.includes(attr.nodeName)) {
|
99
|
-
this.#updateAttrOverrideStyle(attr.nodeName, attr.value);
|
100
|
-
}
|
101
|
-
});
|
102
|
-
}
|
103
|
-
}
|
104
|
-
|
105
|
-
disconnectedCallback() {
|
106
|
-
this.#disconnectThemeManager?.();
|
107
|
-
}
|
108
|
-
};
|
132
|
+
disconnectedCallback() {
|
133
|
+
this.#disconnectThemeManager?.();
|
134
|
+
}
|
109
135
|
};
|
package/src/mixins/index.js
CHANGED
@@ -5,3 +5,4 @@ export { proxyInputMixin } from './proxyInputMixin';
|
|
5
5
|
export { componentNameValidationMixin } from './componentNameValidationMixin';
|
6
6
|
export { hoverableMixin } from './hoverableMixin';
|
7
7
|
export { inputMixin } from './inputMixin'
|
8
|
+
export { portalMixin } from './portalMixin'
|
package/src/mixins/inputMixin.js
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
const upperFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1)
|
1
|
+
import { upperFirst } from "../helpers";
|
3
2
|
|
4
3
|
const events = [
|
5
4
|
'change',
|
@@ -68,7 +67,13 @@ export const inputMixin = (superclass) => class InputMixinClass extends supercla
|
|
68
67
|
}
|
69
68
|
}
|
70
69
|
|
70
|
+
get isReadOnly() {
|
71
|
+
return this.getAttribute('readonly') !== 'false'
|
72
|
+
}
|
73
|
+
|
71
74
|
setValidity() {
|
75
|
+
if (this.isReadOnly) return;
|
76
|
+
|
72
77
|
const validity = this.getValidity()
|
73
78
|
this.#internals.setValidity(validity, this.getErrorMessage(validity))
|
74
79
|
}
|
@@ -94,8 +99,8 @@ export const inputMixin = (superclass) => class InputMixinClass extends supercla
|
|
94
99
|
}
|
95
100
|
|
96
101
|
setCustomValidity(errorMessage) {
|
97
|
-
if(errorMessage){
|
98
|
-
this.#internals.setValidity({customError: true}, errorMessage)
|
102
|
+
if (errorMessage) {
|
103
|
+
this.#internals.setValidity({ customError: true }, errorMessage)
|
99
104
|
} else {
|
100
105
|
this.#internals.setValidity({})
|
101
106
|
this.setValidity()
|
@@ -148,9 +153,9 @@ export const inputMixin = (superclass) => class InputMixinClass extends supercla
|
|
148
153
|
}
|
149
154
|
}
|
150
155
|
|
151
|
-
handleDispatchValidationEvents(){
|
152
|
-
if(this.checkValidity()) {
|
153
|
-
this.dispatchValid()
|
156
|
+
handleDispatchValidationEvents() {
|
157
|
+
if (this.checkValidity()) {
|
158
|
+
this.dispatchValid()
|
154
159
|
} else {
|
155
160
|
this.dispatchInvalid()
|
156
161
|
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import { PORTAL_THEME_PREFIX } from "../constants";
|
2
|
+
import { upperFirst } from "../helpers";
|
3
|
+
import { forwardAttrs } from "../helpers/componentHelpers";
|
4
|
+
import { createStyleMixin } from "./createStyleMixin";
|
5
|
+
import { createCssVarsList } from "./createStyleMixin/helpers";
|
6
|
+
|
7
|
+
const sanitizeSelector = (selector) => selector.replace(/[^\w\s]/gi, '');
|
8
|
+
|
9
|
+
const appendSuffixToKeys = (obj, suffix) => Object.keys(obj).reduce((acc, key) =>
|
10
|
+
Object.assign(acc, { [suffix + upperFirst(key)]: obj[key] }), {})
|
11
|
+
|
12
|
+
const getDomNode = (maybeDomNode) => maybeDomNode.host || maybeDomNode;
|
13
|
+
|
14
|
+
export const portalMixin = ({ name, selector, mappings = {} }) => (superclass) => {
|
15
|
+
const eleDisplayName = name || sanitizeSelector(selector)
|
16
|
+
|
17
|
+
const BaseClass = createStyleMixin({
|
18
|
+
mappings
|
19
|
+
})(superclass)
|
20
|
+
|
21
|
+
return class PortalMixinClass extends BaseClass {
|
22
|
+
static get cssVarList() {
|
23
|
+
return {
|
24
|
+
...BaseClass.cssVarList,
|
25
|
+
...createCssVarsList(superclass.componentName, appendSuffixToKeys(mappings, eleDisplayName))
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
#portalEle
|
30
|
+
|
31
|
+
constructor() {
|
32
|
+
// we cannot use "this" before calling "super"
|
33
|
+
const getRootElement = (that) => {
|
34
|
+
const baseEle = that.shadowRoot.querySelector(that.baseSelector)
|
35
|
+
const portal = baseEle.shadowRoot.querySelector(selector)
|
36
|
+
|
37
|
+
return portal.shadowRoot || portal
|
38
|
+
};
|
39
|
+
|
40
|
+
super({
|
41
|
+
getRootElement,
|
42
|
+
componentNameSuffix: eleDisplayName,
|
43
|
+
themeSection: PORTAL_THEME_PREFIX + eleDisplayName,
|
44
|
+
baseSelector: ':host'
|
45
|
+
})
|
46
|
+
|
47
|
+
this.#portalEle = getDomNode(getRootElement(this))
|
48
|
+
}
|
49
|
+
|
50
|
+
#handleHoverAttribute() {
|
51
|
+
this.#portalEle.onmouseenter = (e) => { e.target.setAttribute('hover', 'true') }
|
52
|
+
this.#portalEle.onmouseleave = (e) => { e.target.removeAttribute('hover') }
|
53
|
+
}
|
54
|
+
|
55
|
+
connectedCallback() {
|
56
|
+
super.connectedCallback?.();
|
57
|
+
forwardAttrs(this, this.#portalEle, { excludeAttrs: ['hover'] })
|
58
|
+
|
59
|
+
this.#handleHoverAttribute();
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
@@ -41,28 +41,6 @@ export const proxyInputMixin = (superclass) =>
|
|
41
41
|
|
42
42
|
this.#inputElement = super.inputElement
|
43
43
|
|
44
|
-
// this is our way to identify that the form was submitted
|
45
|
-
// in this case, we want the input to be in error state if it's not valid
|
46
|
-
this.addEventListener('focus', (e) => {
|
47
|
-
if (e.relatedTarget?.form) {
|
48
|
-
if (!this.checkValidity()) {
|
49
|
-
this.setAttribute('invalid', 'true');
|
50
|
-
}
|
51
|
-
|
52
|
-
if (this.hasAttribute('invalid')) {
|
53
|
-
this.reportValidityOnInternalInput()
|
54
|
-
}
|
55
|
-
}
|
56
|
-
})
|
57
|
-
|
58
|
-
this.addEventListener('invalid', () => {
|
59
|
-
this.setInternalInputErrorMessage()
|
60
|
-
this.setAttribute('error-message', this.validationMessage)
|
61
|
-
})
|
62
|
-
|
63
|
-
this.addEventListener('valid', () => {
|
64
|
-
this.removeAttribute('invalid')
|
65
|
-
})
|
66
44
|
}
|
67
45
|
|
68
46
|
get inputElement() {
|
@@ -118,6 +96,29 @@ export const proxyInputMixin = (superclass) =>
|
|
118
96
|
connectedCallback() {
|
119
97
|
this.baseEle = this.shadowRoot.querySelector(this.baseSelector);
|
120
98
|
|
99
|
+
// this is our way to identify that the form was submitted
|
100
|
+
// in this case, we want the input to be in error state if it's not valid
|
101
|
+
this.addEventListener('focus', (e) => {
|
102
|
+
if (e.relatedTarget?.form) {
|
103
|
+
if (!this.checkValidity()) {
|
104
|
+
this.setAttribute('invalid', 'true');
|
105
|
+
}
|
106
|
+
|
107
|
+
if (this.hasAttribute('invalid')) {
|
108
|
+
this.reportValidityOnInternalInput()
|
109
|
+
}
|
110
|
+
}
|
111
|
+
})
|
112
|
+
|
113
|
+
this.addEventListener('invalid', () => {
|
114
|
+
this.setInternalInputErrorMessage()
|
115
|
+
this.setAttribute('error-message', this.validationMessage)
|
116
|
+
})
|
117
|
+
|
118
|
+
this.addEventListener('valid', () => {
|
119
|
+
this.removeAttribute('invalid')
|
120
|
+
})
|
121
|
+
|
121
122
|
super.connectedCallback?.();
|
122
123
|
|
123
124
|
this.inputElement.addEventListener('input', () => {
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import globals from '../globals';
|
2
|
+
import ComboBox from '../../components/descope-combo-box/ComboBox';
|
3
|
+
import { textField } from './textField';
|
4
|
+
import { getThemeRefs } from '../../helpers/themeHelpers';
|
5
|
+
|
6
|
+
const globalRefs = getThemeRefs(globals);
|
7
|
+
|
8
|
+
const vars = ComboBox.cssVarList;
|
9
|
+
|
10
|
+
export const comboBox = {
|
11
|
+
...textField(ComboBox.cssVarList),
|
12
|
+
size: {
|
13
|
+
xs: {
|
14
|
+
[vars.width]: '30px'
|
15
|
+
}
|
16
|
+
},
|
17
|
+
[vars.borderColor]: 'green',
|
18
|
+
[vars.borderWidth]: '0',
|
19
|
+
[vars.cursor]: 'pointer',
|
20
|
+
[vars.padding]: '0',
|
21
|
+
|
22
|
+
'@overlay': {
|
23
|
+
[vars.overlayBackgroundColor] : 'red',
|
24
|
+
[vars.overlayBorder]: '3px solid blue',
|
25
|
+
|
26
|
+
_hover: {
|
27
|
+
[vars.overlayBackgroundColor] : 'blue',
|
28
|
+
}
|
29
|
+
}
|
30
|
+
};
|
31
|
+
|
32
|
+
export default comboBox;
|
@@ -13,6 +13,7 @@ import link from './link';
|
|
13
13
|
import divider from './divider';
|
14
14
|
import passcode from './passcode';
|
15
15
|
import { loaderRadial, loaderLinear } from './loader';
|
16
|
+
import comboBox from './comboBox';
|
16
17
|
|
17
18
|
export default {
|
18
19
|
button,
|
@@ -30,5 +31,6 @@ export default {
|
|
30
31
|
divider,
|
31
32
|
passcode,
|
32
33
|
loaderRadial,
|
33
|
-
loaderLinear
|
34
|
+
loaderLinear,
|
35
|
+
comboBox
|
34
36
|
};
|