@salesforcedevs/dx-components 1.3.178 → 1.3.180
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/lwc.config.json +4 -0
- package/package.json +2 -2
- package/src/modules/dx/alert/alert.css +108 -0
- package/src/modules/dx/alert/alert.html +36 -0
- package/src/modules/dx/alert/alert.ts +137 -0
- package/src/modules/dx/button/button.css +4 -1
- package/src/modules/dx/button/button.ts +18 -2
- package/src/modules/dx/cardStep/cardStep.css +128 -0
- package/src/modules/dx/cardStep/cardStep.html +31 -0
- package/src/modules/dx/cardStep/cardStep.ts +55 -0
- package/src/modules/dx/cardStep/mockProps.ts +60 -0
- package/src/modules/dx/checkbox/checkbox.ts +26 -2
- package/src/modules/dx/featuresListHeader/featuresListHeader.css +6 -1
- package/src/modules/dx/featuresListHeader/featuresListHeader.html +3 -1
- package/src/modules/dx/featuresListHeader/featuresListHeader.ts +14 -1
- package/src/modules/dx/input/input.css +4 -0
- package/src/modules/dx/input/input.html +1 -0
- package/src/modules/dx/input/input.ts +56 -7
- package/src/modules/dx/scrollManager/scrollManager.ts +1 -0
- package/src/modules/dx/sectionBanner/sectionBanner.css +47 -1
- package/src/modules/dx/sectionBanner/sectionBanner.html +19 -5
- package/src/modules/dx/sectionBanner/sectionBanner.ts +96 -3
- package/src/modules/dx/select/select.ts +28 -5
- package/src/modules/dx/stepSequence/stepSequence.css +0 -4
- package/src/modules/dx/stepSequence/stepSequence.html +2 -1
- package/src/modules/dx/stepSequence/stepSequence.ts +139 -34
- package/src/modules/dxBaseElements/lightningElementWithState/lightningElementWithState.ts +93 -0
- package/src/modules/dxUtils/css/css.ts +4 -1
- package/src/modules/dxUtils/list/list.ts +11 -0
- package/src/modules/dxUtils/lwc/lwc.ts +15 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import cx from "classnames";
|
|
3
|
+
import { reflectBooleanAttribute } from "dxUtils/lwc";
|
|
3
4
|
|
|
4
5
|
export default class Checkbox extends LightningElement {
|
|
5
6
|
@api disabled: boolean = false;
|
|
6
7
|
@api errorMessage?: string = "Please check this box if you want to proceed";
|
|
7
8
|
@api label?: string;
|
|
8
|
-
@api name: string | null = null;
|
|
9
|
-
@api required: boolean = false;
|
|
10
9
|
@api type: "checkbox" | "radio" = "checkbox";
|
|
11
10
|
@api value!: string;
|
|
12
11
|
|
|
13
12
|
private _checked: boolean = false;
|
|
13
|
+
private _required: boolean = false;
|
|
14
|
+
private _name: string | null = null;
|
|
14
15
|
|
|
15
16
|
@api
|
|
16
17
|
get checked(): boolean {
|
|
@@ -20,6 +21,24 @@ export default class Checkbox extends LightningElement {
|
|
|
20
21
|
this._checked = value;
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
@api
|
|
25
|
+
get name(): string | null {
|
|
26
|
+
return this._name;
|
|
27
|
+
}
|
|
28
|
+
set name(value: string | null) {
|
|
29
|
+
this._name = value;
|
|
30
|
+
this.setAttribute("name", value); // reflect to HTML
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@api
|
|
34
|
+
get required(): boolean {
|
|
35
|
+
return this._required;
|
|
36
|
+
}
|
|
37
|
+
set required(value: boolean) {
|
|
38
|
+
this._required = value;
|
|
39
|
+
reflectBooleanAttribute(this, "required", value);
|
|
40
|
+
}
|
|
41
|
+
|
|
23
42
|
private showValidity = false;
|
|
24
43
|
|
|
25
44
|
private get valid(): boolean {
|
|
@@ -40,6 +59,11 @@ export default class Checkbox extends LightningElement {
|
|
|
40
59
|
return this.valid;
|
|
41
60
|
}
|
|
42
61
|
|
|
62
|
+
@api
|
|
63
|
+
checkValidity(): boolean {
|
|
64
|
+
return this.valid;
|
|
65
|
+
}
|
|
66
|
+
|
|
43
67
|
private onChange(e: InputEvent) {
|
|
44
68
|
this._checked = ((e.currentTarget as HTMLInputElement) || {}).checked;
|
|
45
69
|
this.dispatchEvent(
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
flex-direction: column;
|
|
15
15
|
justify-content: center;
|
|
16
16
|
align-items: flex-start;
|
|
17
|
-
padding: var(--dx-g-spacing-
|
|
17
|
+
padding: var(--dx-g-spacing-2xl) 0 var(--dx-g-spacing-3xl) 0;
|
|
18
18
|
min-height: 460px;
|
|
19
19
|
text-align: left;
|
|
20
20
|
background-position: center;
|
|
@@ -62,6 +62,11 @@ dx-button {
|
|
|
62
62
|
margin-top: var(--dx-g-spacing-smd);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
img.desktop {
|
|
66
|
+
padding-left: 20px;
|
|
67
|
+
max-width: 50%; /* assumes desktop images are high-res */
|
|
68
|
+
}
|
|
69
|
+
|
|
65
70
|
img.mobile {
|
|
66
71
|
display: none;
|
|
67
72
|
}
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
<div class="container" style={style}>
|
|
3
3
|
<div class={textStyle}>
|
|
4
4
|
<h1 class="heading dx-text-display-2">
|
|
5
|
-
<dx-formatted-rich-text
|
|
5
|
+
<dx-formatted-rich-text
|
|
6
|
+
value={displayTitle}
|
|
7
|
+
></dx-formatted-rich-text>
|
|
6
8
|
</h1>
|
|
7
9
|
<span if:true={subtitle} class="dx-text-display-5">{subtitle}</span>
|
|
8
10
|
<div class="features-list">
|
|
@@ -2,8 +2,10 @@ import { LightningElement, api } from "lwc";
|
|
|
2
2
|
import cx from "classnames";
|
|
3
3
|
import { track } from "dxUtils/analytics";
|
|
4
4
|
import { toJson } from "dxUtils/normalizers";
|
|
5
|
+
import { toDxColor } from "dxUtils/css";
|
|
5
6
|
|
|
6
7
|
export default class FeaturesListHeader extends LightningElement {
|
|
8
|
+
private _displayTitle: string | null = null;
|
|
7
9
|
@api title!: string;
|
|
8
10
|
@api subtitle?: string;
|
|
9
11
|
@api ctaLabel!: string;
|
|
@@ -25,10 +27,21 @@ export default class FeaturesListHeader extends LightningElement {
|
|
|
25
27
|
this._featuresList = toJson(value);
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
// For use when displayed title will have embed HTML, i.e., is "rich text"
|
|
31
|
+
@api
|
|
32
|
+
get displayTitle() {
|
|
33
|
+
return typeof this._displayTitle === "string"
|
|
34
|
+
? this._displayTitle
|
|
35
|
+
: this.title;
|
|
36
|
+
}
|
|
37
|
+
set displayTitle(value: string | null) {
|
|
38
|
+
this._displayTitle = value;
|
|
39
|
+
}
|
|
40
|
+
|
|
28
41
|
private get style() {
|
|
29
42
|
return cx(
|
|
30
43
|
this.backgroundColor &&
|
|
31
|
-
`background-color:
|
|
44
|
+
`background-color: ${toDxColor(this.backgroundColor)};`
|
|
32
45
|
);
|
|
33
46
|
}
|
|
34
47
|
|
|
@@ -87,6 +87,10 @@ input {
|
|
|
87
87
|
text-overflow: ellipsis;
|
|
88
88
|
transition: var(--dx-g-transition-hue-1x);
|
|
89
89
|
outline: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* Show the default system disabled background if disabled; otherwise show container background */
|
|
93
|
+
input:not([disabled]) {
|
|
90
94
|
background: none;
|
|
91
95
|
}
|
|
92
96
|
|
|
@@ -2,7 +2,7 @@ import { LightningElement, api } from "lwc";
|
|
|
2
2
|
import cx from "classnames";
|
|
3
3
|
import { IconSize, IconSymbol } from "typings/custom";
|
|
4
4
|
import { isMac } from "dxUtils/devices";
|
|
5
|
-
import { setContainerInnerHtml } from "dxUtils/lwc";
|
|
5
|
+
import { reflectBooleanAttribute, setContainerInnerHtml } from "dxUtils/lwc";
|
|
6
6
|
import { isValidEmail } from "./validators";
|
|
7
7
|
|
|
8
8
|
type ValidatorMap = {
|
|
@@ -24,7 +24,6 @@ export default class Input extends LightningElement {
|
|
|
24
24
|
@api ariaLabel!: string;
|
|
25
25
|
@api autocomplete: string | null = null;
|
|
26
26
|
@api clearable: boolean = false;
|
|
27
|
-
@api disabled: boolean = false;
|
|
28
27
|
@api iconSize: IconSize = "medium";
|
|
29
28
|
@api iconSymbol: IconSymbol | null = null;
|
|
30
29
|
@api label?: string;
|
|
@@ -32,9 +31,8 @@ export default class Input extends LightningElement {
|
|
|
32
31
|
@api loading: boolean = false;
|
|
33
32
|
@api missingErrorMessage: string = "Complete this field";
|
|
34
33
|
@api formatErrorMessage?: string;
|
|
35
|
-
@api name?: string;
|
|
36
34
|
@api placeholder!: string;
|
|
37
|
-
@api
|
|
35
|
+
@api readOnly: boolean = false;
|
|
38
36
|
@api role: string | null = null;
|
|
39
37
|
@api shortcutKey: string | null = null;
|
|
40
38
|
@api size: "small" | "large" | "override" = "small";
|
|
@@ -50,6 +48,41 @@ export default class Input extends LightningElement {
|
|
|
50
48
|
this._value = value || "";
|
|
51
49
|
}
|
|
52
50
|
|
|
51
|
+
@api
|
|
52
|
+
get disabled() {
|
|
53
|
+
return this._disabled;
|
|
54
|
+
}
|
|
55
|
+
set disabled(value: boolean) {
|
|
56
|
+
this._disabled = value;
|
|
57
|
+
reflectBooleanAttribute(
|
|
58
|
+
this as unknown as LightningElement,
|
|
59
|
+
"disabled",
|
|
60
|
+
value
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@api
|
|
65
|
+
get name() {
|
|
66
|
+
return this._name;
|
|
67
|
+
}
|
|
68
|
+
set name(name: string | undefined) {
|
|
69
|
+
this._name = name;
|
|
70
|
+
this.setAttribute("name", name); // reflect to HTML
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@api
|
|
74
|
+
get required(): boolean {
|
|
75
|
+
return this._required;
|
|
76
|
+
}
|
|
77
|
+
set required(value: boolean) {
|
|
78
|
+
this._required = value;
|
|
79
|
+
reflectBooleanAttribute(
|
|
80
|
+
this as unknown as LightningElement,
|
|
81
|
+
"required",
|
|
82
|
+
value
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
53
86
|
@api
|
|
54
87
|
get errorMessage() {
|
|
55
88
|
return this._errorMessage;
|
|
@@ -67,7 +100,7 @@ export default class Input extends LightningElement {
|
|
|
67
100
|
|
|
68
101
|
@api
|
|
69
102
|
reportValidity(): boolean {
|
|
70
|
-
if (this.
|
|
103
|
+
if (this.isRequiredButEmpty) {
|
|
71
104
|
this._errorMessage = this.missingErrorMessage;
|
|
72
105
|
return false;
|
|
73
106
|
}
|
|
@@ -83,10 +116,26 @@ export default class Input extends LightningElement {
|
|
|
83
116
|
return true;
|
|
84
117
|
}
|
|
85
118
|
|
|
119
|
+
@api checkValidity(): boolean {
|
|
120
|
+
if (this.isRequiredButEmpty) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const typeValidator = typeValidatorMap[this.type];
|
|
125
|
+
if (typeValidator && !typeValidator.validator(this.value)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
|
|
86
132
|
private _errorMessage: string = "";
|
|
87
133
|
private focused: boolean = false;
|
|
88
134
|
private input: HTMLInputElement | null = null;
|
|
89
135
|
private _value: string | null = null;
|
|
136
|
+
private _disabled: boolean = false;
|
|
137
|
+
private _name?: string;
|
|
138
|
+
private _required: boolean = false;
|
|
90
139
|
private _loading: boolean = false;
|
|
91
140
|
private isMac: boolean = false;
|
|
92
141
|
|
|
@@ -109,7 +158,7 @@ export default class Input extends LightningElement {
|
|
|
109
158
|
private get inputInvalid() {
|
|
110
159
|
const typeValidator = typeValidatorMap[this.type];
|
|
111
160
|
return (
|
|
112
|
-
this.
|
|
161
|
+
this.isRequiredButEmpty &&
|
|
113
162
|
typeValidator &&
|
|
114
163
|
!typeValidator.validator(this.value)
|
|
115
164
|
);
|
|
@@ -153,7 +202,7 @@ export default class Input extends LightningElement {
|
|
|
153
202
|
return `${this.commandKey}-${this.shortcutKey} is the search shortcut`;
|
|
154
203
|
}
|
|
155
204
|
|
|
156
|
-
private get
|
|
205
|
+
private get isRequiredButEmpty() {
|
|
157
206
|
return this.required && (!this.value || !this.value.trim());
|
|
158
207
|
}
|
|
159
208
|
|
|
@@ -166,6 +166,7 @@ export default class ScrollManager extends LightningElement {
|
|
|
166
166
|
saveScroll = throttle(100, () => {
|
|
167
167
|
window.history.replaceState(
|
|
168
168
|
{
|
|
169
|
+
...window.history.state,
|
|
169
170
|
scroll: {
|
|
170
171
|
value: document.body.scrollTop,
|
|
171
172
|
docSize: document.body.scrollHeight
|
|
@@ -6,12 +6,14 @@
|
|
|
6
6
|
--padding-top: var(--dx-g-spacing-4xl);
|
|
7
7
|
--margin-top: 80px;
|
|
8
8
|
--dx-c-section-banner-content-align: flex-end;
|
|
9
|
+
--dx-c-section-banner-image-transform: none;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
.container {
|
|
12
13
|
position: relative;
|
|
13
14
|
display: flex;
|
|
14
15
|
justify-content: space-between;
|
|
16
|
+
overflow-x: hidden;
|
|
15
17
|
padding-top: var(--padding-top);
|
|
16
18
|
padding-left: var(--dx-g-page-padding-horizontal);
|
|
17
19
|
}
|
|
@@ -46,8 +48,23 @@
|
|
|
46
48
|
margin-top: var(--dx-g-spacing-md);
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
.
|
|
51
|
+
.quote-attribution {
|
|
50
52
|
margin-top: var(--dx-g-spacing-md);
|
|
53
|
+
position: relative;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.quote-attribution-character {
|
|
57
|
+
display: inline-block;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.quote-attribution-text {
|
|
61
|
+
left: 24px;
|
|
62
|
+
position: absolute;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.quote-attribution-subtext {
|
|
66
|
+
left: 24px;
|
|
67
|
+
position: relative;
|
|
51
68
|
}
|
|
52
69
|
|
|
53
70
|
.image {
|
|
@@ -97,3 +114,32 @@
|
|
|
97
114
|
margin: 0 var(--dx-g-page-padding-horizontal) var(--dx-g-spacing-3xl) 0;
|
|
98
115
|
}
|
|
99
116
|
}
|
|
117
|
+
|
|
118
|
+
@media screen and (max-width: 480px) {
|
|
119
|
+
.content-body-container {
|
|
120
|
+
display: block;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.quote-content p {
|
|
124
|
+
font-size: var(--dx-g-text-lg);
|
|
125
|
+
line-height: 28px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.quote-content p.quote-attribution {
|
|
129
|
+
font-size: var(--dx-g-text-md);
|
|
130
|
+
letter-spacing: unset;
|
|
131
|
+
line-height: 24px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.quote-attribution-text {
|
|
135
|
+
left: 20px;
|
|
136
|
+
position: absolute;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.quote-attribution-subtext {
|
|
140
|
+
font-size: 12px;
|
|
141
|
+
left: 20px;
|
|
142
|
+
line-height: 20px;
|
|
143
|
+
position: relative;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -14,14 +14,28 @@
|
|
|
14
14
|
<img if:true={hasQuote} src={quoteGraphicSrc} alt="" />
|
|
15
15
|
<div class={quoteContentStyle}>
|
|
16
16
|
<p class={contentBodyStyle}>{body}</p>
|
|
17
|
-
<p
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
<p
|
|
18
|
+
if:true={quoteAttributionText}
|
|
19
|
+
class={quoteAttributionStyle}
|
|
20
|
+
>
|
|
21
|
+
<span class="quote-attribution-character">—</span>
|
|
22
|
+
<span class="quote-attribution-text">
|
|
23
|
+
<dx-formatted-rich-text
|
|
24
|
+
value={quoteAttributionText}
|
|
25
|
+
></dx-formatted-rich-text>
|
|
26
|
+
</span>
|
|
27
|
+
<span
|
|
28
|
+
if:true={quoteAttributionSubtext}
|
|
29
|
+
class={quoteAttributionSubtextStyle}
|
|
30
|
+
>
|
|
31
|
+
<dx-formatted-rich-text
|
|
32
|
+
value={quoteAttributionSubtext}
|
|
33
|
+
></dx-formatted-rich-text>
|
|
34
|
+
</span>
|
|
21
35
|
</p>
|
|
22
36
|
</div>
|
|
23
37
|
</div>
|
|
24
38
|
</div>
|
|
25
|
-
<img class="image" src={imgSrc} alt={imgAlt} />
|
|
39
|
+
<img class="image" src={imgSrc} alt={imgAlt} part="banner-image" />
|
|
26
40
|
</div>
|
|
27
41
|
</template>
|
|
@@ -1,18 +1,76 @@
|
|
|
1
1
|
import { api, LightningElement } from "lwc";
|
|
2
2
|
import cx from "classnames";
|
|
3
|
+
import debounce from "debounce";
|
|
4
|
+
import { toJson } from "dxUtils/normalizers";
|
|
3
5
|
import { toDxColor } from "dxUtils/css";
|
|
4
6
|
|
|
5
7
|
export default class SectionBanner extends LightningElement {
|
|
8
|
+
private _images?: {
|
|
9
|
+
desktop: {
|
|
10
|
+
alt: string;
|
|
11
|
+
src: string;
|
|
12
|
+
};
|
|
13
|
+
mobile: {
|
|
14
|
+
alt: string;
|
|
15
|
+
src: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
private _quoteAttribution?: {
|
|
19
|
+
desktop: {
|
|
20
|
+
text: string;
|
|
21
|
+
subtext?: string;
|
|
22
|
+
};
|
|
23
|
+
mobile: {
|
|
24
|
+
text: string;
|
|
25
|
+
subtext?: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
6
28
|
@api title!: string;
|
|
7
29
|
@api body!: string;
|
|
8
|
-
@api footNote?: string;
|
|
9
|
-
@api imgSrc!: string;
|
|
10
|
-
@api imgAlt!: string;
|
|
11
30
|
@api hideTopGraphic = false;
|
|
12
31
|
@api backgroundColor = "indigo-vibrant-20";
|
|
13
32
|
@api hasQuote = false;
|
|
14
33
|
@api quoteGraphicSrc?: string;
|
|
15
34
|
|
|
35
|
+
private isMobile = false;
|
|
36
|
+
private mediaQueryList?: MediaQueryList;
|
|
37
|
+
|
|
38
|
+
@api
|
|
39
|
+
get images() {
|
|
40
|
+
return this._images;
|
|
41
|
+
}
|
|
42
|
+
set images(value) {
|
|
43
|
+
this._images = value && toJson(value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@api
|
|
47
|
+
get quoteAttribution() {
|
|
48
|
+
return this._quoteAttribution;
|
|
49
|
+
}
|
|
50
|
+
set quoteAttribution(value) {
|
|
51
|
+
this._quoteAttribution = value && toJson(value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get environment() {
|
|
55
|
+
return this.isMobile ? "mobile" : "desktop";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get imgSrc() {
|
|
59
|
+
return this.images?.[this.environment]?.src || "";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get imgAlt() {
|
|
63
|
+
return this.images?.[this.environment]?.alt || "";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get quoteAttributionText() {
|
|
67
|
+
return this.quoteAttribution?.[this.environment]?.text || "";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get quoteAttributionSubtext() {
|
|
71
|
+
return this.quoteAttribution?.[this.environment]?.subtext || "";
|
|
72
|
+
}
|
|
73
|
+
|
|
16
74
|
get containerStyle() {
|
|
17
75
|
return cx("container", !this.hideTopGraphic && "top-margin");
|
|
18
76
|
}
|
|
@@ -21,6 +79,19 @@ export default class SectionBanner extends LightningElement {
|
|
|
21
79
|
return cx(this.hasQuote && "quote-content");
|
|
22
80
|
}
|
|
23
81
|
|
|
82
|
+
get quoteAttributionStyle() {
|
|
83
|
+
return cx("quote-attribution", {
|
|
84
|
+
"dx-text-display-7": !this.isMobile,
|
|
85
|
+
"dx-text-display-8": this.isMobile
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get quoteAttributionSubtextStyle() {
|
|
90
|
+
return cx("quote-attribution-subtext", {
|
|
91
|
+
"is-mobile": this.isMobile
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
24
95
|
get contentBodyStyle() {
|
|
25
96
|
return cx(this.title ? "content-body" : "dx-text-display-6");
|
|
26
97
|
}
|
|
@@ -32,4 +103,26 @@ export default class SectionBanner extends LightningElement {
|
|
|
32
103
|
|
|
33
104
|
return `${backgroundColor}`;
|
|
34
105
|
}
|
|
106
|
+
|
|
107
|
+
private handleMediaQueryChange = debounce((evt: MediaQueryListEvent) => {
|
|
108
|
+
this.isMobile = evt.matches;
|
|
109
|
+
}, 64);
|
|
110
|
+
|
|
111
|
+
connectedCallback() {
|
|
112
|
+
this.mediaQueryList = window.matchMedia(
|
|
113
|
+
"screen and (max-width: 480px)"
|
|
114
|
+
);
|
|
115
|
+
this.isMobile = this.mediaQueryList.matches;
|
|
116
|
+
this.mediaQueryList.addEventListener(
|
|
117
|
+
"change",
|
|
118
|
+
this.handleMediaQueryChange
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
disconnectedCallback() {
|
|
123
|
+
this.mediaQueryList?.removeEventListener(
|
|
124
|
+
"change",
|
|
125
|
+
this.handleMediaQueryChange
|
|
126
|
+
);
|
|
127
|
+
}
|
|
35
128
|
}
|
|
@@ -2,6 +2,7 @@ import cx from "classnames";
|
|
|
2
2
|
import { LightningElement, api } from "lwc";
|
|
3
3
|
import { SelectOption } from "typings/custom";
|
|
4
4
|
import { toJson, normalizeBoolean } from "dxUtils/normalizers";
|
|
5
|
+
import { reflectBooleanAttribute } from "dxUtils/lwc";
|
|
5
6
|
|
|
6
7
|
export const DEFAULT_MISSING_MESSAGE = "This field is required";
|
|
7
8
|
|
|
@@ -10,7 +11,6 @@ export default class Select extends LightningElement {
|
|
|
10
11
|
@api autocomplete?: string;
|
|
11
12
|
@api label?: string;
|
|
12
13
|
@api messageWhenValueMissing: string = DEFAULT_MISSING_MESSAGE;
|
|
13
|
-
@api name?: string;
|
|
14
14
|
@api placeholder?: string;
|
|
15
15
|
@api size?: string;
|
|
16
16
|
|
|
@@ -39,6 +39,11 @@ export default class Select extends LightningElement {
|
|
|
39
39
|
|
|
40
40
|
set required(value) {
|
|
41
41
|
this._required = normalizeBoolean(value);
|
|
42
|
+
reflectBooleanAttribute(
|
|
43
|
+
this as unknown as LightningElement,
|
|
44
|
+
"required",
|
|
45
|
+
value
|
|
46
|
+
);
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
@api
|
|
@@ -51,11 +56,22 @@ export default class Select extends LightningElement {
|
|
|
51
56
|
this.updateSelectValue();
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
@api
|
|
60
|
+
get name() {
|
|
61
|
+
return this._name;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
set name(name) {
|
|
65
|
+
this._name = name;
|
|
66
|
+
this.setAttribute("name", name); // reflect to HTML
|
|
67
|
+
}
|
|
68
|
+
|
|
54
69
|
_disabled = false;
|
|
55
70
|
_size = "";
|
|
56
71
|
_required = false;
|
|
57
72
|
_options: Array<SelectOption> = [];
|
|
58
73
|
_value: string = "";
|
|
74
|
+
_name?: string;
|
|
59
75
|
_selectElement: HTMLSelectElement | null = null;
|
|
60
76
|
helpMessage?: string = "";
|
|
61
77
|
|
|
@@ -79,13 +95,16 @@ export default class Select extends LightningElement {
|
|
|
79
95
|
|
|
80
96
|
get selectElement() {
|
|
81
97
|
if (!this._selectElement) {
|
|
82
|
-
this._selectElement =
|
|
83
|
-
"select"
|
|
84
|
-
);
|
|
98
|
+
this._selectElement =
|
|
99
|
+
this.template.querySelector<HTMLSelectElement>("select");
|
|
85
100
|
}
|
|
86
101
|
return this._selectElement;
|
|
87
102
|
}
|
|
88
103
|
|
|
104
|
+
get isRequiredButEmpty() {
|
|
105
|
+
return this.required && !this.value;
|
|
106
|
+
}
|
|
107
|
+
|
|
89
108
|
@api
|
|
90
109
|
blur(): void {
|
|
91
110
|
if (this.selectElement) {
|
|
@@ -102,13 +121,17 @@ export default class Select extends LightningElement {
|
|
|
102
121
|
|
|
103
122
|
@api
|
|
104
123
|
reportValidity(): boolean {
|
|
105
|
-
const isInvalid = this.
|
|
124
|
+
const isInvalid = this.isRequiredButEmpty;
|
|
106
125
|
this.helpMessage = isInvalid
|
|
107
126
|
? this.messageWhenValueMissing || DEFAULT_MISSING_MESSAGE
|
|
108
127
|
: "";
|
|
109
128
|
return !isInvalid;
|
|
110
129
|
}
|
|
111
130
|
|
|
131
|
+
@api checkValidity(): boolean {
|
|
132
|
+
return !this.isRequiredButEmpty;
|
|
133
|
+
}
|
|
134
|
+
|
|
112
135
|
handleBlur(): void {
|
|
113
136
|
this.reportValidity();
|
|
114
137
|
this.dispatchEvent(new CustomEvent("blur"));
|