lightning-base-components 1.15.1-alpha → 1.15.2-alpha
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/metadata/raptor.json +27 -2
- package/package.json +6 -2
- package/scopedImports/@salesforce-label-LightningMap.defaultTitle.js +1 -0
- package/src/lightning/alert/__docs__/alert.md +0 -2
- package/src/lightning/baseCombobox/baseCombobox.html +2 -1
- package/src/lightning/baseCombobox/baseCombobox.js +41 -6
- package/src/lightning/button/button.js +22 -1
- package/src/lightning/checkboxGroup/checkboxGroup.html +2 -2
- package/src/lightning/checkboxGroup/checkboxGroup.js +9 -5
- package/src/lightning/combobox/__docs__/combobox.md +3 -1
- package/src/lightning/combobox/combobox.js +0 -1
- package/src/lightning/confirm/__docs__/confirm.md +0 -2
- package/src/lightning/datatable/__docs__/datatable.md +45 -0
- package/src/lightning/datatable/__wdio__/utam/utam.html +15 -0
- package/src/lightning/datatable/__wdio__/utam/utam.spec.js +208 -183
- package/src/lightning/datatable/datatable.js +12 -7
- package/src/lightning/datatable/inlineEdit.js +0 -5
- package/src/lightning/datatable/inlineEditShared.js +4 -2
- package/src/lightning/datatable/keyboard.js +7 -3
- package/src/lightning/datatable/rowSelection.js +8 -2
- package/src/lightning/datatable/state.js +1 -0
- package/src/lightning/datatable/templates/table/table.html +2 -2
- package/src/lightning/datatable/wrapText.js +1 -0
- package/src/lightning/datepicker/datepicker.html +1 -0
- package/src/lightning/datepicker/datepicker.js +10 -0
- package/src/lightning/datetimepicker/datetimepicker.html +2 -0
- package/src/lightning/datetimepicker/datetimepicker.js +8 -0
- package/src/lightning/dualListbox/dualListbox.js +2 -1
- package/src/lightning/formattedAddress/__docs__/formattedAddress.md +3 -0
- package/src/lightning/formattedAddress/__examples__/customLocale/customLocale.html +22 -0
- package/src/lightning/formattedAddress/__examples__/customLocale/customLocale.js +3 -0
- package/src/lightning/formattedAddress/formattedAddress.js +7 -1
- package/src/lightning/groupedCombobox/groupedCombobox.html +2 -1
- package/src/lightning/groupedCombobox/groupedCombobox.js +16 -2
- package/src/lightning/input/input.html +6 -0
- package/src/lightning/input/input.js +2 -1
- package/src/lightning/inputAddress/__docs__/inputAddress.md +5 -0
- package/src/lightning/inputAddress/__examples__/customLocale/customLocale.html +12 -0
- package/src/lightning/inputAddress/__examples__/customLocale/customLocale.js +3 -0
- package/src/lightning/inputAddress/inputAddress.html +2 -0
- package/src/lightning/inputAddress/inputAddress.js +26 -3
- package/src/lightning/inputName/__docs__/inputName.md +2 -0
- package/src/lightning/inputName/inputName.html +4 -1
- package/src/lightning/inputUtils/inputUtils.js +11 -0
- package/src/lightning/picklist/picklist.js +6 -1
- package/src/lightning/prompt/__docs__/prompt.md +0 -2
- package/src/lightning/radioGroup/radioGroup.js +9 -0
- package/src/lightning/select/select.html +3 -1
- package/src/lightning/select/select.js +5 -1
- package/src/lightning/textarea/textarea.html +1 -0
- package/src/lightning/textarea/textarea.js +5 -0
- package/src/lightning/timepicker/timepicker.html +3 -1
- package/src/lightning/timepicker/timepicker.js +8 -0
- package/src/lightning/utilsPrivate/aria.js +26 -0
- package/src/lightning/utilsPrivate/linkify.js +1 -1
- package/src/lightning/utilsPrivate/utilsPrivate.js +7 -1
- package/src/lightning/icon/__component__/icon-spirite.spec.js +0 -59
|
@@ -6,6 +6,9 @@ examples:
|
|
|
6
6
|
- name: latitude
|
|
7
7
|
label: Formatted Address with Latitude/Longitude
|
|
8
8
|
description: Displays an address that includes latitude and longitude.
|
|
9
|
+
- name: customLocale
|
|
10
|
+
label: Formatted Address with Custom Locale
|
|
11
|
+
description: Displays an address in the format of a specific locale.
|
|
9
12
|
---
|
|
10
13
|
|
|
11
14
|
A `lightning-formatted-address` component displays addresses in a format and field order
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<h1 class="slds-text-heading_small">Address in Spanish format</h1>
|
|
3
|
+
|
|
4
|
+
<lightning-formatted-address
|
|
5
|
+
street="Avenida Concha Espina, Nº 1"
|
|
6
|
+
city="Madrid"
|
|
7
|
+
postal-code="28036"
|
|
8
|
+
country="España"
|
|
9
|
+
locale="es-ES"
|
|
10
|
+
></lightning-formatted-address>
|
|
11
|
+
|
|
12
|
+
<h1 class="slds-text-heading_small">Address in Japanese format</h1>
|
|
13
|
+
|
|
14
|
+
<lightning-formatted-address
|
|
15
|
+
street="下連雀1丁目1−83"
|
|
16
|
+
city="三鷹市"
|
|
17
|
+
country="日本"
|
|
18
|
+
province="東京都"
|
|
19
|
+
postal-code="181–0013"
|
|
20
|
+
locale="ja-JP"
|
|
21
|
+
></lightning-formatted-address>
|
|
22
|
+
</template>
|
|
@@ -25,6 +25,12 @@ export default class LightningFormattedAddress extends LightningElement {
|
|
|
25
25
|
|
|
26
26
|
@track href;
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* The locale of the address. The default value is 'en-US'.
|
|
30
|
+
* @type {string}
|
|
31
|
+
*/
|
|
32
|
+
@api locale = locale;
|
|
33
|
+
|
|
28
34
|
/**
|
|
29
35
|
* The street detail for the address.
|
|
30
36
|
* @type {string}
|
|
@@ -188,7 +194,7 @@ export default class LightningFormattedAddress extends LightningElement {
|
|
|
188
194
|
}
|
|
189
195
|
|
|
190
196
|
get address() {
|
|
191
|
-
const [langCode, countryCode] = locale.split('-');
|
|
197
|
+
const [langCode, countryCode] = this.locale.split('-');
|
|
192
198
|
return (
|
|
193
199
|
addressFormat.formatAddressAllFields(langCode, countryCode, {
|
|
194
200
|
address: this.street,
|
|
@@ -57,7 +57,8 @@
|
|
|
57
57
|
onendreached={handleEndReached}
|
|
58
58
|
ondropdownopen={handleDropdownOpen}
|
|
59
59
|
ondropdownopenrequest={handleDropdownOpenRequest}
|
|
60
|
-
onselect={handleSelect}
|
|
60
|
+
onselect={handleSelect}
|
|
61
|
+
disable-default-highlight={disableDefaultHighlight}>
|
|
61
62
|
</lightning-base-combobox>
|
|
62
63
|
</div>
|
|
63
64
|
<template if:true={_hasPills}>
|
|
@@ -45,6 +45,14 @@ export default class LightningGroupedCombobox extends LightningElement {
|
|
|
45
45
|
@api filterItems;
|
|
46
46
|
@api filterInputText;
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Whether disable the highlighting default item behavior
|
|
50
|
+
*
|
|
51
|
+
* @type {boolean}
|
|
52
|
+
* @memberof LightningGroupedCombobox
|
|
53
|
+
*/
|
|
54
|
+
@api disableDefaultHighlight;
|
|
55
|
+
|
|
48
56
|
@track _pills;
|
|
49
57
|
|
|
50
58
|
@track _variant;
|
|
@@ -378,9 +386,15 @@ export default class LightningGroupedCombobox extends LightningElement {
|
|
|
378
386
|
// eslint-disable-next-line @lwc/lwc/no-async-operation
|
|
379
387
|
requestAnimationFrame(() => {
|
|
380
388
|
if (this._connected) {
|
|
381
|
-
|
|
389
|
+
// If a new pill has been added but the markup-conditional hasn't had a chance to
|
|
390
|
+
// initialize the pill container, and causes a null gack. Adding a quick safety
|
|
391
|
+
// check here to avoid this case
|
|
392
|
+
const pillContainer = this.template.querySelector(
|
|
382
393
|
'lightning-pill-container'
|
|
383
|
-
)
|
|
394
|
+
);
|
|
395
|
+
if (pillContainer) {
|
|
396
|
+
pillContainer.scrollTop = 0;
|
|
397
|
+
}
|
|
384
398
|
}
|
|
385
399
|
});
|
|
386
400
|
}
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
<span class={computedLabelClass}>{label}</span>
|
|
66
66
|
<input type="checkbox" id="checkbox-toggle"
|
|
67
67
|
aria-label={computedAriaLabel}
|
|
68
|
+
aria-invalid={computedAriaInvalid}
|
|
68
69
|
accesskey={accesskey}
|
|
69
70
|
onblur={handleBlur}
|
|
70
71
|
onfocus={handleFocus}
|
|
@@ -101,6 +102,7 @@
|
|
|
101
102
|
</template>
|
|
102
103
|
<input type="checkbox" id="checkbox"
|
|
103
104
|
aria-label={computedAriaLabel}
|
|
105
|
+
aria-invalid={computedAriaInvalid}
|
|
104
106
|
accesskey={accesskey}
|
|
105
107
|
onblur={handleBlur}
|
|
106
108
|
onfocus={handleFocus}
|
|
@@ -127,6 +129,7 @@
|
|
|
127
129
|
<div class="slds-checkbox_add-button">
|
|
128
130
|
<input type="checkbox" id="checkbox-button"
|
|
129
131
|
aria-label={computedAriaLabel}
|
|
132
|
+
aria-invalid={computedAriaInvalid}
|
|
130
133
|
accesskey={accesskey}
|
|
131
134
|
class="slds-assistive-text"
|
|
132
135
|
onblur={handleBlur}
|
|
@@ -146,6 +149,7 @@
|
|
|
146
149
|
<div class="slds-form-element__control">
|
|
147
150
|
<span class="slds-radio">
|
|
148
151
|
<input type="radio" id="radio"
|
|
152
|
+
aria-invalid={computedAriaInvalid}
|
|
149
153
|
accesskey={accesskey}
|
|
150
154
|
onblur={handleBlur}
|
|
151
155
|
onfocus={handleFocus}
|
|
@@ -174,6 +178,7 @@
|
|
|
174
178
|
<lightning-primitive-file-droppable-zone multiple={multiple} disabled={disabled}>
|
|
175
179
|
<input type="file" id="input-file"
|
|
176
180
|
aria-label={computedAriaLabel}
|
|
181
|
+
aria-invalid={computedAriaInvalid}
|
|
177
182
|
accesskey={accesskey}
|
|
178
183
|
class="slds-file-selector__input slds-assistive-text"
|
|
179
184
|
onblur={handleBlur}
|
|
@@ -228,6 +233,7 @@
|
|
|
228
233
|
autocomplete={autocomplete}
|
|
229
234
|
accesskey={accesskey}
|
|
230
235
|
aria-label={computedAriaLabel}
|
|
236
|
+
aria-invalid={computedAriaInvalid}
|
|
231
237
|
disabled={disabled}
|
|
232
238
|
minlength="4"
|
|
233
239
|
maxlength="7"
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
synchronizeAttrs,
|
|
31
31
|
decorateInputForDragon,
|
|
32
32
|
setDecoratedDragonInputValueWithoutEvent,
|
|
33
|
+
computeAriaInvalid,
|
|
33
34
|
} from 'lightning/utilsPrivate';
|
|
34
35
|
import AriaObserver from 'lightning/ariaObserver';
|
|
35
36
|
import { normalizeInput } from './normalize';
|
|
@@ -1178,7 +1179,7 @@ export default class LightningInput extends LightningElement {
|
|
|
1178
1179
|
|
|
1179
1180
|
get computedAriaInvalid() {
|
|
1180
1181
|
// W-8796658: aria-invalid should always follow the visual indication of errors
|
|
1181
|
-
return
|
|
1182
|
+
return computeAriaInvalid(this._helpMessage, this.value);
|
|
1182
1183
|
}
|
|
1183
1184
|
|
|
1184
1185
|
get isLabelHidden() {
|
|
@@ -6,6 +6,9 @@ examples:
|
|
|
6
6
|
- name: stateAndCountryPicklists
|
|
7
7
|
label: Address With State and Country Picklists
|
|
8
8
|
description: Address fields support predefined lists of states and countries.
|
|
9
|
+
- name: customLocale
|
|
10
|
+
label: Address With Custom Locale
|
|
11
|
+
description: Address input fields ordered depending on custom locale value.
|
|
9
12
|
---
|
|
10
13
|
|
|
11
14
|
A `lightning-input-address` component creates a compound field that includes the following constituent fields.
|
|
@@ -290,6 +293,8 @@ The `label` attribute creates an HTML `<label>` element for your address.
|
|
|
290
293
|
To hide the compound field label from view and make it available to assistive technology, use the `label-hidden` variant.
|
|
291
294
|
This variant keeps the constituent field labels in view.
|
|
292
295
|
|
|
296
|
+
This component uses `button` elements for picklists to comply with the [Lightning Design System combobox blueprint](https://www.lightningdesignsystem.com/components/combobox/#%22Input%22-markup) for select-only comboboxes.
|
|
297
|
+
|
|
293
298
|
#### Custom Events
|
|
294
299
|
|
|
295
300
|
**`change`**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<lightning-input-address
|
|
3
|
+
address-label="Address"
|
|
4
|
+
street-label="Street"
|
|
5
|
+
city-label="City"
|
|
6
|
+
country-label="Country"
|
|
7
|
+
province-label="Prefecture"
|
|
8
|
+
postal-code-label="Postal Code"
|
|
9
|
+
locale="ja-JP"
|
|
10
|
+
field-level-help="Help Text for input address field" >
|
|
11
|
+
</lightning-input-address>
|
|
12
|
+
</template>
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
class="slds-form-element slds-show slds-size_6-of-6"
|
|
16
16
|
onchange={handleAddress}
|
|
17
17
|
placeholder={addressLookupPlaceholder}
|
|
18
|
+
label={addressLookupLabel}
|
|
18
19
|
disabled={disabled}>
|
|
19
20
|
</lightning-lookup-address>
|
|
20
21
|
</div>
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
<template if:true={field.isPicklist}>
|
|
66
67
|
<lightning-picklist
|
|
67
68
|
key={field.name}
|
|
69
|
+
suppress-none-option={field.suppressNoneOption}
|
|
68
70
|
data-field={field.name}
|
|
69
71
|
class={field.classnames}
|
|
70
72
|
name={field.name}
|
|
@@ -111,6 +111,13 @@ export default class LightningInputAddress extends LightningElement {
|
|
|
111
111
|
*/
|
|
112
112
|
@api addressLookupPlaceholder;
|
|
113
113
|
|
|
114
|
+
/**
|
|
115
|
+
* The label for the address lookup field option.
|
|
116
|
+
* Only visible when show-address-lookup is set to true and label string is passed
|
|
117
|
+
* @type {string}
|
|
118
|
+
*/
|
|
119
|
+
@api addressLookupLabel;
|
|
120
|
+
|
|
114
121
|
/**
|
|
115
122
|
* The array of label-value pairs for the province. Displays a dropdown menu of options.
|
|
116
123
|
* @type {list}
|
|
@@ -130,6 +137,12 @@ export default class LightningInputAddress extends LightningElement {
|
|
|
130
137
|
*/
|
|
131
138
|
@api countryDisabled;
|
|
132
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Determines the order of the inputs for the address field.
|
|
142
|
+
* @type {string}
|
|
143
|
+
*/
|
|
144
|
+
@api locale = locale;
|
|
145
|
+
|
|
133
146
|
@track _showAddressLookup;
|
|
134
147
|
@track _fieldLevelHelp;
|
|
135
148
|
@track _variant;
|
|
@@ -469,12 +482,12 @@ export default class LightningInputAddress extends LightningElement {
|
|
|
469
482
|
get inputOrder() {
|
|
470
483
|
const hasCountryPicklist =
|
|
471
484
|
this.fieldsTypeMeta.country.type === FIELD_TYPE.PICKLIST;
|
|
472
|
-
const [langCode, countryCode] = locale.split('-');
|
|
485
|
+
const [langCode, countryCode] = this.locale.split('-');
|
|
473
486
|
return getInputOrder(langCode, countryCode, hasCountryPicklist);
|
|
474
487
|
}
|
|
475
488
|
|
|
476
489
|
get requiredFields() {
|
|
477
|
-
const [langCode, countryCode] = locale.split('-');
|
|
490
|
+
const [langCode, countryCode] = this.locale.split('-');
|
|
478
491
|
return getRequiredFields(langCode, countryCode);
|
|
479
492
|
}
|
|
480
493
|
|
|
@@ -502,18 +515,28 @@ export default class LightningInputAddress extends LightningElement {
|
|
|
502
515
|
const rowList = row.map((field) => {
|
|
503
516
|
const { name, type, required, maxlength, autocomplete } = field;
|
|
504
517
|
const widthClass = getFieldWidthClass(field);
|
|
518
|
+
const value = this.getFieldValue(name);
|
|
519
|
+
const suppressNoneOption =
|
|
520
|
+
this.required &&
|
|
521
|
+
!!required &&
|
|
522
|
+
type === FIELD_TYPE.PICKLIST &&
|
|
523
|
+
value &&
|
|
524
|
+
value !== ''
|
|
525
|
+
? true
|
|
526
|
+
: false;
|
|
505
527
|
|
|
506
528
|
return {
|
|
507
529
|
isInput: type === FIELD_TYPE.INPUT,
|
|
508
530
|
isPicklist: type === FIELD_TYPE.PICKLIST,
|
|
509
531
|
isTextArea: type === FIELD_TYPE.TEXTAREA,
|
|
510
|
-
value:
|
|
532
|
+
value: value,
|
|
511
533
|
options: this.getFieldOptions(name),
|
|
512
534
|
required: this.required && !!required,
|
|
513
535
|
disabled: this.getFieldDisabled(name) || this.disabled,
|
|
514
536
|
classnames: `slds-form-element slds-show ${widthClass}`,
|
|
515
537
|
placeholder: this.getFieldPlaceholder(name),
|
|
516
538
|
label: this.getFieldLabel(name),
|
|
539
|
+
suppressNoneOption: suppressNoneOption,
|
|
517
540
|
autocomplete,
|
|
518
541
|
maxlength,
|
|
519
542
|
name,
|
|
@@ -154,6 +154,8 @@ See the __Custom Events__ section for a list of `event.target` properties. For m
|
|
|
154
154
|
You can use custom labels that display translated values. For more information, see the
|
|
155
155
|
[Access Static Resources, Labels, Internationalization Properties, and User IDs](docs/component-library/documentation/lwc/create_global_value_providers).
|
|
156
156
|
|
|
157
|
+
This component uses `button` elements for dropdown menus to comply with the [Lightning Design System combobox blueprint](https://www.lightningdesignsystem.com/components/combobox/#%22Input%22-markup) for select-only comboboxes.
|
|
158
|
+
|
|
157
159
|
#### Input Validation
|
|
158
160
|
|
|
159
161
|
When you set `required`, a red asterisk is displayed on the Last Name
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
<fieldset class="slds-form-element">
|
|
3
3
|
<legend class={computedLegendClass}>
|
|
4
4
|
<template if:true={required}>
|
|
5
|
-
<abbr class="slds-required" title={i18n.required}>*</abbr>
|
|
5
|
+
<abbr class="slds-required" title={i18n.required} aria-hidden="true">*</abbr>
|
|
6
6
|
</template>
|
|
7
7
|
{label}
|
|
8
|
+
<template if:true={required}>
|
|
9
|
+
<span class="slds-assistive-text">{i18n.required}</span>
|
|
10
|
+
</template>
|
|
8
11
|
</legend>
|
|
9
12
|
<template if:true={fieldLevelHelp}>
|
|
10
13
|
<lightning-helptext content={fieldLevelHelp}></lightning-helptext>
|
|
@@ -15,3 +15,14 @@ export function isEmptyString(s) {
|
|
|
15
15
|
(typeof s === 'string' && s.trim() === '')
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
export function isEmptyObject(obj) {
|
|
20
|
+
if (obj === undefined || obj === null || typeof obj !== 'object') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
// eslint-disable-next-line guard-for-in
|
|
24
|
+
for (const name in obj) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
@@ -31,6 +31,7 @@ export default class LightningPicklist extends LightningElement {
|
|
|
31
31
|
@api placeholder;
|
|
32
32
|
@api variant;
|
|
33
33
|
@api autocomplete = 'off';
|
|
34
|
+
@api suppressNoneOption;
|
|
34
35
|
|
|
35
36
|
set fieldLevelHelp(value) {
|
|
36
37
|
this._fieldLevelHelp = value;
|
|
@@ -86,6 +87,7 @@ export default class LightningPicklist extends LightningElement {
|
|
|
86
87
|
// reset the flag that hides the required indicator when we have no options
|
|
87
88
|
this._requiredButDisabled = false;
|
|
88
89
|
}
|
|
90
|
+
|
|
89
91
|
@api
|
|
90
92
|
get required() {
|
|
91
93
|
return this._required;
|
|
@@ -293,7 +295,10 @@ export default class LightningPicklist extends LightningElement {
|
|
|
293
295
|
// We could have set required=false if the picklist had no options, see updateDisabledState and updateRequiredState
|
|
294
296
|
const isRequiredPicklist = this.required || this._requiredButDisabled;
|
|
295
297
|
|
|
296
|
-
if (
|
|
298
|
+
if (
|
|
299
|
+
this.suppressNoneOption ||
|
|
300
|
+
(isRequiredPicklist && numberOfOptions === 1)
|
|
301
|
+
) {
|
|
297
302
|
return false;
|
|
298
303
|
}
|
|
299
304
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
The `lightning/prompt` module lets you create an prompt modal within your component. Use `LightningPrompt` on your components to ask the user to provide information before they continue.
|
|
2
2
|
|
|
3
|
-
`lightning/prompt` is not supported on mobile devices.
|
|
4
|
-
|
|
5
3
|
Use `LightningPrompt.open()` instead of the native `window.prompt()` for a more consistent user experience. They have similar functions, but `LightningPrompt.open()` works in cross-origin iframes, where the `.prompt()` method is no longer supported in Chrome and Safari. Unlike `window.prompt()`, `LightningPrompt.open()` doesn't halt execution on the page, it returns a Promise. Use `async`/`await` or `.then()` for any code you want to execute after the prompt has closed.
|
|
6
4
|
|
|
7
5
|
Import `LightningPrompt` from the `lightning/prompt` module in the component that will launch the prompt modal, and call `LightningPrompt.open()` with your desired attributes.
|
|
@@ -90,8 +90,17 @@ export default class LightningRadioGroup extends LightningElement {
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
get fieldsetElement() {
|
|
94
|
+
return this.template.querySelector('fieldset');
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
renderedCallback() {
|
|
94
98
|
this.synchronizeA11y();
|
|
99
|
+
synchronizeAttrs(this.fieldsetElement, {
|
|
100
|
+
'aria-describedby': getRealDOMId(
|
|
101
|
+
this.template.querySelector('[data-help-message]')
|
|
102
|
+
),
|
|
103
|
+
});
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
/**
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
onfocus={handleFocus}
|
|
22
22
|
required={required}
|
|
23
23
|
accesskey={accessKey}
|
|
24
|
-
size={size}
|
|
24
|
+
size={size}
|
|
25
|
+
aria-invalid={computedAriaInvalid}
|
|
26
|
+
>
|
|
25
27
|
<template for:each={options} for:item="option">
|
|
26
28
|
<template if:true={option.disabled}>
|
|
27
29
|
<option disabled key={option.value} value={option.value}>{option.label}</option>
|
|
@@ -80,11 +80,15 @@ export default class LightningSelect extends LightningElement {
|
|
|
80
80
|
}
|
|
81
81
|
synchronizeAttrs(this.selectElement, {
|
|
82
82
|
'aria-describedby': getRealDOMId(
|
|
83
|
-
this.template.querySelector('
|
|
83
|
+
this.template.querySelector('[data-help-message]')
|
|
84
84
|
),
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
get computedAriaInvalid() {
|
|
89
|
+
return !!this._helpMessage || undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
88
92
|
/**
|
|
89
93
|
* Help text detailing the purpose and function of the menu of options.
|
|
90
94
|
* The text is displayed in a tooltip above the menu.
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
<div class="slds-form-element__control slds-grow textarea-container">
|
|
10
10
|
<textarea id="input" class="slds-textarea"
|
|
11
11
|
aria-describedby={computedUniqueHelpElementId}
|
|
12
|
+
aria-invalid={computedAriaInvalid}
|
|
12
13
|
autocomplete={autocomplete}
|
|
13
14
|
oninput={handleInput}
|
|
14
15
|
onchange={handleChange}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
classListMutation,
|
|
11
11
|
decorateInputForDragon,
|
|
12
12
|
setDecoratedDragonInputValueWithoutEvent,
|
|
13
|
+
computeAriaInvalid,
|
|
13
14
|
} from 'lightning/utilsPrivate';
|
|
14
15
|
import {
|
|
15
16
|
InteractingState,
|
|
@@ -478,6 +479,10 @@ export default class LightningTextarea extends LightningElement {
|
|
|
478
479
|
}
|
|
479
480
|
return this._constraintApi;
|
|
480
481
|
}
|
|
482
|
+
|
|
483
|
+
get computedAriaInvalid() {
|
|
484
|
+
return computeAriaInvalid(this._helpMessage, this.value);
|
|
485
|
+
}
|
|
481
486
|
}
|
|
482
487
|
|
|
483
488
|
LightningTextarea.interopMap = {
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
normalizeBoolean,
|
|
24
24
|
synchronizeAttrs,
|
|
25
25
|
normalizeString,
|
|
26
|
+
computeAriaInvalid,
|
|
26
27
|
} from 'lightning/utilsPrivate';
|
|
27
28
|
import { normalizeVariant, VARIANT } from 'lightning/inputUtils';
|
|
28
29
|
|
|
@@ -543,4 +544,11 @@ export default class LightningTimePicker extends LightningElement {
|
|
|
543
544
|
this.ariaLabelledByElement.length
|
|
544
545
|
);
|
|
545
546
|
}
|
|
547
|
+
|
|
548
|
+
get computedAriaInvalid() {
|
|
549
|
+
const isAriaInvalid =
|
|
550
|
+
this.template.host.getAttribute('data-aria-invalid') ||
|
|
551
|
+
this._errorMessage;
|
|
552
|
+
return computeAriaInvalid(isAriaInvalid, this.value);
|
|
553
|
+
}
|
|
546
554
|
}
|
|
@@ -135,3 +135,29 @@ export function isAriaDescriptionSupported() {
|
|
|
135
135
|
}
|
|
136
136
|
return ariaDescriptionSupported;
|
|
137
137
|
}
|
|
138
|
+
|
|
139
|
+
export function updateAriaInvalidOnElement(element, isInvalid) {
|
|
140
|
+
if (isInvalid) {
|
|
141
|
+
element.setAttribute('aria-invalid', true);
|
|
142
|
+
} else {
|
|
143
|
+
element.removeAttribute('aria-invalid');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* If value is empty, then do no calculate aria-invalid. This is intentional for 240.
|
|
149
|
+
* In the future, we may be removing emptiness this check.
|
|
150
|
+
*
|
|
151
|
+
* Then if isInvalid is truthy, return true else return undefined to remove
|
|
152
|
+
* aria-invalid attribute.
|
|
153
|
+
*
|
|
154
|
+
* @param isInvalid
|
|
155
|
+
* @param value
|
|
156
|
+
* @returns {boolean|undefined}
|
|
157
|
+
*/
|
|
158
|
+
export function computeAriaInvalid(isInvalid, value) {
|
|
159
|
+
if (value === undefined || value === null || value === '') {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
return !!isInvalid || undefined;
|
|
163
|
+
}
|
|
@@ -107,6 +107,6 @@ export function parseToFormattedLinkifiedParts(text, ignoreNewLines = false) {
|
|
|
107
107
|
*/
|
|
108
108
|
export function parseToFormattedParts(text) {
|
|
109
109
|
return text.split(newLineRegex).map((part, index) => {
|
|
110
|
-
return index % 2 === 0 ? getTextPart(part) : getNewlinePart();
|
|
110
|
+
return index % 2 === 0 ? getTextPart(part) : getNewlinePart(index);
|
|
111
111
|
});
|
|
112
112
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export { assert } from './assert';
|
|
2
|
-
export {
|
|
2
|
+
export {
|
|
3
|
+
ARIA,
|
|
4
|
+
ARIA_TO_CAMEL,
|
|
5
|
+
isAriaDescriptionSupported,
|
|
6
|
+
updateAriaInvalidOnElement,
|
|
7
|
+
computeAriaInvalid,
|
|
8
|
+
} from './aria';
|
|
3
9
|
export { EventEmitter } from './eventEmitter';
|
|
4
10
|
export { toNorthAmericanPhoneNumber } from './phonify';
|
|
5
11
|
export * from './linkUtils';
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { createElement } from 'lwc';
|
|
2
|
-
import Element from 'lightning/icon';
|
|
3
|
-
|
|
4
|
-
function createIcon(props = {}) {
|
|
5
|
-
const element = createElement('lightning-icon', { is: Element });
|
|
6
|
-
|
|
7
|
-
Object.assign(element, props);
|
|
8
|
-
document.body.appendChild(element);
|
|
9
|
-
return element;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function verifySvgDataKey(element, value) {
|
|
13
|
-
const primitiveIcon = element.shadowRoot.querySelector(
|
|
14
|
-
'lightning-primitive-icon'
|
|
15
|
-
);
|
|
16
|
-
const svg = primitiveIcon.shadowRoot.querySelector('svg');
|
|
17
|
-
expect(svg.getAttribute('data-key')).toBe(value);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe('lightning-icon', () => {
|
|
21
|
-
it('should render with prebuilt icon for utility', () => {
|
|
22
|
-
const element = createIcon({
|
|
23
|
-
iconName: 'utility:check',
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
verifySvgDataKey(element, 'check');
|
|
27
|
-
});
|
|
28
|
-
it('should render with prebuilt icon for standard', () => {
|
|
29
|
-
const element = createIcon({
|
|
30
|
-
iconName: 'standard:account',
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
verifySvgDataKey(element, 'account');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should render with prebuilt icon for action', () => {
|
|
37
|
-
const element = createIcon({
|
|
38
|
-
iconName: 'action:back',
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
verifySvgDataKey(element, 'back');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should render with prebuilt icon for doctype', () => {
|
|
45
|
-
const element = createIcon({
|
|
46
|
-
iconName: 'doctype:image',
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
verifySvgDataKey(element, 'image');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should render with prebuilt icon for custom', () => {
|
|
53
|
-
const element = createIcon({
|
|
54
|
-
iconName: 'custom:custom1',
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
verifySvgDataKey(element, 'custom1');
|
|
58
|
-
});
|
|
59
|
-
});
|