lightning-base-components 1.19.3-alpha → 1.19.5-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 +2066 -1632
- package/package.json +5 -1
- package/scopedImports/@salesforce-label-LightningProgressIndicator.stageNotStarted.js +1 -0
- package/src/lightning/alert/__examples__disabled/basic/basic.html +1 -1
- package/src/lightning/ariaObserver/__docs__/ariaObserver.md +12 -4
- package/src/lightning/ariaObserver/__examples__/connectChild/connectChild.js +3 -1
- package/src/lightning/baseCombobox/baseCombobox.html +1 -0
- package/src/lightning/buttonMenu/buttonMenu.js +16 -1
- package/src/lightning/colorPickerPanel/colorPickerPanel.html +1 -1
- package/src/lightning/confirm/__examples__disabled/basic/basic.html +1 -1
- package/src/lightning/datatable/datatable.js +19 -0
- package/src/lightning/datatable/state.js +1 -0
- package/src/lightning/datatable/templates/div/div.html +4 -2
- package/src/lightning/datatable/templates/table/table.html +4 -2
- package/src/lightning/fileDownload/resourceResolver.js +4 -3
- package/src/lightning/input/input.js +43 -29
- package/src/lightning/inputUtils/inputUtils.js +0 -12
- package/src/lightning/modal/__docs__/modal.md +2 -2
- package/src/lightning/modal/__examples__disabled/all/all.html +2 -2
- package/src/lightning/modal/__examples__disabled/allform/allform.html +1 -1
- package/src/lightning/modal/__examples__disabled/allformfull/allformfull.html +1 -1
- package/src/lightning/modal/__examples__disabled/basic/basic.html +2 -2
- package/src/lightning/modal/__examples__disabled/footless/footless.html +2 -2
- package/src/lightning/modal/__examples__disabled/headless/headless.html +2 -2
- package/src/lightning/modal/__modalUtils__/modalContainerTestConstants.js +15 -2
- package/src/lightning/modal/__modalUtils__/modalContainerTestMethods.js +6 -6
- package/src/lightning/modalBase/modalBase.js +3 -3
- package/src/lightning/numberUtils/numberUtils.js +269 -5
- package/src/lightning/primitiveCustomCell/primitiveCustomCell.js +5 -5
- package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +3 -3
- package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +39 -0
- package/src/lightning/primitiveHeaderFactory/sortableHeader.html +2 -2
- package/src/lightning/primitiveInputFile/primitiveInputFile.html +1 -0
- package/src/lightning/primitiveInputFile/primitiveInputFile.js +4 -0
- package/src/lightning/primitiveInputSimple/primitiveInputSimple.js +33 -12
- package/src/lightning/progressStep/progressStep.js +13 -2
- package/src/lightning/prompt/__examples__disabled/basic/basic.html +1 -1
- package/src/lightning/resizeObserver/resizeObserver.js +10 -15
- package/src/lightning/slider/slider.js +2 -2
- package/src/lightning/tabBar/tabBar.js +3 -1
- package/src/lightning/timepicker/timepicker.html +3 -3
- package/src/lightning/tooltipLibrary/tooltipLibrary.js +3 -1
- package/src/lightning/utils/queryFocusable.js +33 -15
- package/src/lightning/utilsPrivate/videoUtils.js +35 -0
- package/src/lightning/inputUtils/number.js +0 -267
|
@@ -1,3 +1,271 @@
|
|
|
1
|
+
import groupingSeparator from '@salesforce/i18n/number.groupingSeparator';
|
|
2
|
+
import decimalSeparator from '@salesforce/i18n/number.decimalSeparator';
|
|
3
|
+
import {
|
|
4
|
+
fromLocalizedDigits,
|
|
5
|
+
toLocalizedDigits,
|
|
6
|
+
numberFormat,
|
|
7
|
+
} from 'lightning/internationalizationLibrary';
|
|
8
|
+
import { isEmptyString } from 'lightning/inputUtils';
|
|
9
|
+
import { normalizeNumber } from 'lightning/utilsPrivate';
|
|
10
|
+
|
|
11
|
+
const VALID_NUMBER_CHARACTERS_EXPRESSION = new RegExp(
|
|
12
|
+
// eslint-disable-next-line no-useless-escape
|
|
13
|
+
'^[-+0-9kKmMbBtTeE.,\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9' +
|
|
14
|
+
'\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF' +
|
|
15
|
+
'\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF' +
|
|
16
|
+
'\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9' +
|
|
17
|
+
'\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9' +
|
|
18
|
+
'\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89' +
|
|
19
|
+
'\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49' +
|
|
20
|
+
'\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909' +
|
|
21
|
+
'\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9' +
|
|
22
|
+
']$'
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const SHORTCUT_FACTORS = {
|
|
26
|
+
k: 3,
|
|
27
|
+
m: 6,
|
|
28
|
+
b: 9,
|
|
29
|
+
t: 12,
|
|
30
|
+
};
|
|
31
|
+
const SHORTCUTS = ['k', 'm', 'b', 't'];
|
|
32
|
+
|
|
33
|
+
const NUMBER_SYMBOLS = ['+', '-'];
|
|
34
|
+
|
|
35
|
+
export function toIsoDecimal(numberAsString) {
|
|
36
|
+
const result = transformLocalizedNumberToIsoDecimal(numberAsString);
|
|
37
|
+
if (isNaN(result)) {
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isValidNumber(numberAsString) {
|
|
44
|
+
return !isNaN(transformLocalizedNumberToIsoDecimal(numberAsString));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function fromIsoDecimal(numberAsString) {
|
|
48
|
+
return toLocalizedDigits(numberAsString.replace('.', decimalSeparator));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// TODO: Too many options, simplify
|
|
52
|
+
export function increaseNumberByStep({
|
|
53
|
+
value,
|
|
54
|
+
increment,
|
|
55
|
+
step,
|
|
56
|
+
fractionDigits,
|
|
57
|
+
}) {
|
|
58
|
+
const startingValue = value === '' || value == null ? '0' : value;
|
|
59
|
+
|
|
60
|
+
const stepAsFloat = parseFloat(step);
|
|
61
|
+
|
|
62
|
+
let result;
|
|
63
|
+
if (isNaN(stepAsFloat)) {
|
|
64
|
+
result = parseFloat(startingValue) + increment;
|
|
65
|
+
} else {
|
|
66
|
+
// ideally we'd round the value to the closest correct step, so that if say the step is '2', and the
|
|
67
|
+
// current value is '1' it would increment to '2' instead of '3', since the former would be the valid
|
|
68
|
+
// number given the step constraint, however this would significantly complicate the code, keeping
|
|
69
|
+
// it simple for now.
|
|
70
|
+
const increaseBy = increment * stepAsFloat;
|
|
71
|
+
result = parseFloat(startingValue) + increaseBy;
|
|
72
|
+
}
|
|
73
|
+
return result.toFixed(fractionDigits);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function calculateFractionDigitsFromStep(step) {
|
|
77
|
+
let calculatedFractionDigits;
|
|
78
|
+
|
|
79
|
+
if (step) {
|
|
80
|
+
const stepAsString = String(step).toLowerCase();
|
|
81
|
+
if (stepAsString !== 'any') {
|
|
82
|
+
// lowering the case because we're checking for exponent format as well
|
|
83
|
+
let fractionDigits = 0;
|
|
84
|
+
if (
|
|
85
|
+
stepAsString.indexOf('.') >= 0 &&
|
|
86
|
+
stepAsString.indexOf('e') < 0
|
|
87
|
+
) {
|
|
88
|
+
const fractionalPart = stepAsString.split('.')[1];
|
|
89
|
+
// we're parsing to account for cases where the step is
|
|
90
|
+
// '1.0', or '1.000', etc.
|
|
91
|
+
if (parseInt(fractionalPart, 10) > 0) {
|
|
92
|
+
fractionDigits = fractionalPart.length;
|
|
93
|
+
}
|
|
94
|
+
} else if (stepAsString.indexOf('e-') > 0) {
|
|
95
|
+
// exponent form eg. 1.5e-5
|
|
96
|
+
const splitOnExponent = stepAsString.split('e-');
|
|
97
|
+
const fractionalPart = splitOnExponent[0].split('.')[1];
|
|
98
|
+
const exponentPart = splitOnExponent[1];
|
|
99
|
+
const fractionalPartLength = fractionalPart
|
|
100
|
+
? fractionalPart.length
|
|
101
|
+
: 0;
|
|
102
|
+
fractionDigits =
|
|
103
|
+
parseInt(exponentPart, 10) + fractionalPartLength;
|
|
104
|
+
}
|
|
105
|
+
calculatedFractionDigits = fractionDigits;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return calculatedFractionDigits;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function formatNumber(numberAsString, options) {
|
|
112
|
+
if (isEmptyString(numberAsString)) {
|
|
113
|
+
return '';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let formattedValue = numberAsString;
|
|
117
|
+
let inputValue = numberAsString;
|
|
118
|
+
|
|
119
|
+
// set formatter style & default options
|
|
120
|
+
const formatStyle = options.style;
|
|
121
|
+
const formatOptions = { style: formatStyle };
|
|
122
|
+
|
|
123
|
+
formatOptions.minimumFractionDigits = options.minimumFractionDigits;
|
|
124
|
+
formatOptions.maximumFractionDigits = options.maximumFractionDigits;
|
|
125
|
+
|
|
126
|
+
if (formatStyle === 'percent-fixed') {
|
|
127
|
+
// percent-fixed just uses percent format and divides the value by 100
|
|
128
|
+
// before passing to the library, this is to deal with the
|
|
129
|
+
// fact that percentages in salesforce are 0-100, not 0-1
|
|
130
|
+
formatOptions.style = 'percent';
|
|
131
|
+
const inputValueAsString = inputValue.toString();
|
|
132
|
+
const normalisedNumberInPercent = parseFloat(inputValue) / 100;
|
|
133
|
+
|
|
134
|
+
// If the number contains fraction digits and is not in an exponent format
|
|
135
|
+
if (
|
|
136
|
+
inputValueAsString.indexOf('.') > 0 &&
|
|
137
|
+
inputValueAsString.indexOf('e') < 0
|
|
138
|
+
) {
|
|
139
|
+
// Depending on the input number, division by 100 may lead to rounding errors
|
|
140
|
+
// (e.g 0.785 / 100 is 0.007850000000000001), so we need to round back
|
|
141
|
+
// to the correct precision, that is - existing number of fractional digits
|
|
142
|
+
// plus extra 2 for division by 100.
|
|
143
|
+
inputValue = normalisedNumberInPercent.toFixed(
|
|
144
|
+
inputValueAsString.split('.')[1].length + 2
|
|
145
|
+
);
|
|
146
|
+
} else {
|
|
147
|
+
inputValue = normalisedNumberInPercent;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
formattedValue = numberFormat(formatOptions).format(inputValue) || '';
|
|
153
|
+
} catch (ignore) {
|
|
154
|
+
// ignore any errors
|
|
155
|
+
}
|
|
156
|
+
return formattedValue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Exporting only to test, separators are only overridden in the tests
|
|
160
|
+
export function transformLocalizedNumberToIsoDecimal(
|
|
161
|
+
numberAsString,
|
|
162
|
+
separators
|
|
163
|
+
) {
|
|
164
|
+
if (numberAsString == null || numberAsString.length === 0) {
|
|
165
|
+
return '';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const decimalSymbol = separators
|
|
169
|
+
? separators.decimalSeparator
|
|
170
|
+
: decimalSeparator;
|
|
171
|
+
const groupingSymbol = separators
|
|
172
|
+
? separators.groupSeparator
|
|
173
|
+
: groupingSeparator;
|
|
174
|
+
|
|
175
|
+
// remove the grouping separator
|
|
176
|
+
let result = numberAsString.split(groupingSymbol).join('');
|
|
177
|
+
if (decimalSymbol !== '.') {
|
|
178
|
+
// replace the local decimal separator with a
|
|
179
|
+
result = result.replace(decimalSymbol, '.');
|
|
180
|
+
}
|
|
181
|
+
return expandShortcuts(addLeadingZeroIfNeeded(fromLocalizedDigits(result)));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function isValidNumberCharacter(character) {
|
|
185
|
+
return VALID_NUMBER_CHARACTERS_EXPRESSION.test(character);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* validate the string-typed number and return the number string
|
|
190
|
+
* @param {String} value, number string to be validated
|
|
191
|
+
* @returns a valid number in string-typed, otherwise, empty string
|
|
192
|
+
*/
|
|
193
|
+
export function stringifyNumber(value) {
|
|
194
|
+
const numericValue = typeof value === 'string' ? Number(value) : value;
|
|
195
|
+
const normalizedNumber = normalizeNumber(numericValue);
|
|
196
|
+
return normalizedNumber === undefined ? '' : String(value);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function hasValidNumberSymbol(value) {
|
|
200
|
+
const validSymbols = NUMBER_SYMBOLS.join('');
|
|
201
|
+
const matchSymbols = new RegExp(`[${validSymbols}]`);
|
|
202
|
+
return value.match(matchSymbols) ? true : false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function hasValidNumberShortcut(value) {
|
|
206
|
+
const result = value.toLowerCase().trim();
|
|
207
|
+
const kmb = SHORTCUTS.join('');
|
|
208
|
+
// Cannot have two shortcuts /([kmb])/g
|
|
209
|
+
const matchShortcuts = new RegExp(`([${kmb}])`, 'g');
|
|
210
|
+
const shortcutMatch = result.match(matchShortcuts);
|
|
211
|
+
if (shortcutMatch && shortcutMatch.length > 1) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
// Must end with 'm', 'k', 'b' and more than just a single letter
|
|
215
|
+
const matchEndsWith = new RegExp(`[${kmb}]$`);
|
|
216
|
+
const endsWithShortcut = result.match(matchEndsWith) !== null;
|
|
217
|
+
// has 'm' / 'k' / 'b' and more than just them (ie. result of 'm' / 'k' / 'b' are not valid.
|
|
218
|
+
return endsWithShortcut && result.length > 1;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Exported for testing only
|
|
222
|
+
export function expandShortcuts(isoValue) {
|
|
223
|
+
if (!hasValidNumberShortcut(isoValue)) {
|
|
224
|
+
return isoValue;
|
|
225
|
+
}
|
|
226
|
+
let result = isoValue.toLowerCase().trim();
|
|
227
|
+
const shortcut = result.charAt(result.length - 1);
|
|
228
|
+
// remove the suffix
|
|
229
|
+
result = result.substring(0, result.length - 1);
|
|
230
|
+
if (isNaN(result)) {
|
|
231
|
+
return isoValue;
|
|
232
|
+
}
|
|
233
|
+
const parts = result.split('.');
|
|
234
|
+
let fractionDigits = 0;
|
|
235
|
+
const hasDecimalPart = parts.length > 1;
|
|
236
|
+
if (hasDecimalPart) {
|
|
237
|
+
fractionDigits = parts[1].length;
|
|
238
|
+
}
|
|
239
|
+
const exponent = SHORTCUT_FACTORS[shortcut];
|
|
240
|
+
// since multiplication may result in loss of precision on javascript's part,
|
|
241
|
+
// we're calculating here the number of fraction digits needed and formatting
|
|
242
|
+
// the number at that
|
|
243
|
+
const newFractionDigits = Math.max(0, fractionDigits - exponent);
|
|
244
|
+
return parseFloat(result * Math.pow(10, exponent)).toFixed(
|
|
245
|
+
newFractionDigits
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function addLeadingZeroIfNeeded(result) {
|
|
250
|
+
// If the number starts with +. OR -. OR . ; insert a 0 before the decimal separator.
|
|
251
|
+
// eg. -.2 -> -0.2
|
|
252
|
+
const decimalSeparatorLocation = result.indexOf('.');
|
|
253
|
+
if (decimalSeparatorLocation === 0 || decimalSeparatorLocation === 1) {
|
|
254
|
+
const firstCharacter = result.charAt(0);
|
|
255
|
+
if (
|
|
256
|
+
firstCharacter === '+' ||
|
|
257
|
+
firstCharacter === '-' ||
|
|
258
|
+
firstCharacter === '.'
|
|
259
|
+
) {
|
|
260
|
+
result =
|
|
261
|
+
result.substring(0, decimalSeparatorLocation) +
|
|
262
|
+
'0' +
|
|
263
|
+
result.substring(decimalSeparatorLocation);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
|
|
1
269
|
/*
|
|
2
270
|
Returns a number of decimal places
|
|
3
271
|
ex:
|
|
@@ -9,7 +277,7 @@
|
|
|
9
277
|
decimalPlaces('.5e1') -> 0
|
|
10
278
|
decimalPlaces('.25e1') -> 1
|
|
11
279
|
*/
|
|
12
|
-
function
|
|
280
|
+
export function getDecimalPlaces(num) {
|
|
13
281
|
const match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
|
|
14
282
|
if (!match) {
|
|
15
283
|
return 0;
|
|
@@ -22,7 +290,3 @@ function decimalPlaces(num) {
|
|
|
22
290
|
(match[2] ? +match[2] : 0)
|
|
23
291
|
);
|
|
24
292
|
}
|
|
25
|
-
|
|
26
|
-
export default {
|
|
27
|
-
decimalPlaces,
|
|
28
|
-
};
|
|
@@ -42,13 +42,13 @@ export default class PrimitiveCustomCell extends LightningElement {
|
|
|
42
42
|
const typeAttributes = this.types.getType(
|
|
43
43
|
this.columnType
|
|
44
44
|
).typeAttributes;
|
|
45
|
+
const attrs = {};
|
|
45
46
|
if (Array.isArray(typeAttributes)) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}, {});
|
|
47
|
+
for (let i = 0, { length } = typeAttributes; i < length; i += 1) {
|
|
48
|
+
attrs[typeAttributes[i]] = this[`typeAttribute${i}`];
|
|
49
|
+
}
|
|
50
50
|
}
|
|
51
|
-
return
|
|
51
|
+
return attrs;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
@api
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
<div class={computedClass} style={columnStyles}>
|
|
3
3
|
|
|
4
4
|
<!-- Header Content -->
|
|
5
|
-
<span class="slds-th__action">
|
|
5
|
+
<span class="slds-th__action" style={thActionStyles}>
|
|
6
6
|
<template if:true={def.iconName}>
|
|
7
7
|
<div class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
|
|
8
8
|
<lightning-icon icon-name={def.iconName} size="x-small" class="slds-icon_container slds-m-right_xx-small" alternative-text={def.label} title={def.label}></lightning-icon>
|
|
9
9
|
<template if:false={def.hideLabel} class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
|
|
10
|
-
<span class=
|
|
10
|
+
<span class={getHeaderLabelStyle}>{def.label}</span>
|
|
11
11
|
</template>
|
|
12
12
|
</div>
|
|
13
13
|
</template>
|
|
14
14
|
<template if:false={def.iconName}>
|
|
15
|
-
<span class=
|
|
15
|
+
<span class={getHeaderLabelStyle} if:true={def.label} title={def.label}>{def.label}</span>
|
|
16
16
|
<span class="slds-truncate" if:false={def.label} title={def.ariaLabel}></span>
|
|
17
17
|
</template>
|
|
18
18
|
|
|
@@ -35,6 +35,7 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
35
35
|
_resizable;
|
|
36
36
|
_sortable = false;
|
|
37
37
|
_hideHeader = false;
|
|
38
|
+
_wrapTableHeader = false;
|
|
38
39
|
|
|
39
40
|
/************************** PUBLIC ATTRIBUTES ***************************/
|
|
40
41
|
|
|
@@ -88,6 +89,21 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
88
89
|
this.updateElementClasses();
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Defines whether the table header is wrapped
|
|
94
|
+
*
|
|
95
|
+
* @type {boolean}
|
|
96
|
+
*/
|
|
97
|
+
@api
|
|
98
|
+
get wrapTableHeader() {
|
|
99
|
+
return this._wrapTableHeader;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
set wrapTableHeader(value) {
|
|
103
|
+
this._wrapTableHeader = value;
|
|
104
|
+
this.updateElementClasses();
|
|
105
|
+
}
|
|
106
|
+
|
|
91
107
|
/**
|
|
92
108
|
* Defines whether the column is resizable
|
|
93
109
|
*
|
|
@@ -150,11 +166,25 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
150
166
|
const widthStyle = this.columnWidth
|
|
151
167
|
? `width: ${this.columnWidth}px;`
|
|
152
168
|
: '';
|
|
169
|
+
const heightStyle = this._wrapTableHeader ? 'min-height: 3rem' : '';
|
|
153
170
|
|
|
154
171
|
return `
|
|
155
172
|
${widthStyle}
|
|
156
173
|
${outlineStyle}
|
|
157
174
|
${offsetStyle}
|
|
175
|
+
${heightStyle}
|
|
176
|
+
`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get th Action styles
|
|
181
|
+
*
|
|
182
|
+
* @return {string} The computed classes
|
|
183
|
+
*/
|
|
184
|
+
get thActionStyles() {
|
|
185
|
+
const heightStyle = this._wrapTableHeader ? 'min-height: 3rem' : '';
|
|
186
|
+
return `
|
|
187
|
+
${heightStyle}
|
|
158
188
|
`;
|
|
159
189
|
}
|
|
160
190
|
|
|
@@ -182,6 +212,15 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
182
212
|
.toString();
|
|
183
213
|
}
|
|
184
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Computes styling for header label
|
|
217
|
+
*/
|
|
218
|
+
get getHeaderLabelStyle() {
|
|
219
|
+
return this._wrapTableHeader
|
|
220
|
+
? 'slds-line-clamp_small '
|
|
221
|
+
: 'slds-truncate';
|
|
222
|
+
}
|
|
223
|
+
|
|
185
224
|
/**
|
|
186
225
|
* Computes an option name
|
|
187
226
|
*
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<div class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
|
|
19
19
|
<lightning-icon icon-name={def.iconName} size="x-small" class="slds-icon_container slds-m-right_xx-small" alternative-text={def.label} title={def.label}></lightning-icon>
|
|
20
20
|
<template if:false={def.hideLabel} class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
|
|
21
|
-
<span class=
|
|
21
|
+
<span class={getHeaderLabelStyle}>{def.label}</span>
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
24
|
<!-- Arrow Icon - Rotates based on sorting direction -->
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
</div>
|
|
32
32
|
</template>
|
|
33
33
|
<template if:false={def.iconName}>
|
|
34
|
-
<span class=
|
|
34
|
+
<span class={getHeaderLabelStyle} title={def.label}>{def.label}</span>
|
|
35
35
|
<!-- Arrow Icon - Rotates based on sorting direction -->
|
|
36
36
|
<lightning-primitive-icon
|
|
37
37
|
class="slds-icon_container"
|
|
@@ -89,6 +89,10 @@ export default class LightningPrimitiveInputFile extends LightningElement {
|
|
|
89
89
|
this.dispatchEvent(new CustomEvent('focus'));
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
handleFileClick() {
|
|
93
|
+
this.inputElement.value = null;
|
|
94
|
+
}
|
|
95
|
+
|
|
92
96
|
handleChange() {
|
|
93
97
|
this._files = this.inputElement.files;
|
|
94
98
|
this.dispatchEvent(new CustomEvent('change'));
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
isValidNumberCharacter,
|
|
20
20
|
stringifyNumber,
|
|
21
21
|
toIsoDecimal,
|
|
22
|
-
} from 'lightning/
|
|
22
|
+
} from 'lightning/numberUtils';
|
|
23
23
|
|
|
24
24
|
import {
|
|
25
25
|
reflectAttribute,
|
|
@@ -50,6 +50,8 @@ const VALID_NUMBER_FORMATTERS = [
|
|
|
50
50
|
const DEFAULT_FORMATTER = VALID_NUMBER_FORMATTERS[0];
|
|
51
51
|
|
|
52
52
|
export default class LightningPrimitiveInputSimple extends LightningElement {
|
|
53
|
+
_type;
|
|
54
|
+
|
|
53
55
|
@api hasExternalLabel;
|
|
54
56
|
@api computedLabelClass;
|
|
55
57
|
@api required;
|
|
@@ -172,26 +174,40 @@ export default class LightningPrimitiveInputSimple extends LightningElement {
|
|
|
172
174
|
|
|
173
175
|
set value(value) {
|
|
174
176
|
const previousValue = this._value;
|
|
175
|
-
|
|
176
177
|
this._value = normalizeInput(value);
|
|
177
178
|
|
|
178
|
-
if (this._rendered
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
179
|
+
if (this._rendered) {
|
|
180
|
+
const badInput = this.validity.badInput;
|
|
181
|
+
|
|
182
|
+
if (this.isTypeNumber) {
|
|
183
|
+
this._value = stringifyNumber(value);
|
|
184
|
+
// the extra check for whether the value has changed is done for cases
|
|
185
|
+
// when the same value is set back in a change handler, this is to avoid
|
|
186
|
+
// the raw number from changing formatting under the user
|
|
187
|
+
// (eg. if the user typed 1,000 we want to preserve that formatting as the user
|
|
188
|
+
// types the value)
|
|
189
|
+
if (this._value !== previousValue) {
|
|
190
|
+
this.updateNumberValue(value);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// If updated value is invalid or not null, it should be updated
|
|
194
|
+
// Invalid numeric values should stay as-is to avoid programatically wiping a user-provided invalid
|
|
195
|
+
// value, such as '2e' from the input element. See @W-14121203
|
|
196
|
+
if (!badInput || !!value) {
|
|
197
|
+
this.setInputValueIfNeeded();
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
this.setInputValueIfNeeded();
|
|
187
201
|
}
|
|
188
202
|
}
|
|
203
|
+
}
|
|
189
204
|
|
|
205
|
+
setInputValueIfNeeded() {
|
|
190
206
|
// Again, due to the interop layer we need to check whether the value being set
|
|
191
207
|
// is different, otherwise we're duplicating the sets on the input, which result
|
|
192
208
|
// in different bugs like Japanese IME duplication of characters in Safari (likely a browser bug) or
|
|
193
209
|
// character position re-set in IE11.
|
|
194
|
-
if (this.
|
|
210
|
+
if (this.inputElement.value !== this.displayedValue) {
|
|
195
211
|
this.setInputValue(this.getDisplayedValue());
|
|
196
212
|
}
|
|
197
213
|
}
|
|
@@ -247,6 +263,11 @@ export default class LightningPrimitiveInputSimple extends LightningElement {
|
|
|
247
263
|
return this._value;
|
|
248
264
|
}
|
|
249
265
|
|
|
266
|
+
@api
|
|
267
|
+
getNumberRawValue() {
|
|
268
|
+
return this._numberRawValue;
|
|
269
|
+
}
|
|
270
|
+
|
|
250
271
|
/********* PRIVATE VARIABLES *********/
|
|
251
272
|
_formatter = DEFAULT_FORMATTER;
|
|
252
273
|
_showRawNumber = false;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import labelCurrentStage from '@salesforce/label/LightningProgressIndicator.currentStage';
|
|
2
2
|
import labelStageComplete from '@salesforce/label/LightningProgressIndicator.stageComplete';
|
|
3
|
+
import labelNotStartedStage from '@salesforce/label/LightningProgressIndicator.stageNotStarted';
|
|
3
4
|
import { LightningElement, api, track } from 'lwc';
|
|
4
5
|
import { classSet } from 'lightning/utils';
|
|
5
6
|
import { classListMutation } from 'lightning/utilsPrivate';
|
|
@@ -13,6 +14,7 @@ import base from './base.html';
|
|
|
13
14
|
const i18n = {
|
|
14
15
|
currentStage: labelCurrentStage,
|
|
15
16
|
stageComplete: labelStageComplete,
|
|
17
|
+
notStartedStage: labelNotStartedStage,
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
// Maps the status of the base progress-step to the icon it should render
|
|
@@ -35,6 +37,13 @@ export default class LightningProgressStep extends LightningElement {
|
|
|
35
37
|
|
|
36
38
|
@track state = {};
|
|
37
39
|
|
|
40
|
+
/**
|
|
41
|
+
* getter for the i18 constant containing the localized strings
|
|
42
|
+
*/
|
|
43
|
+
get i18n() {
|
|
44
|
+
return i18n;
|
|
45
|
+
}
|
|
46
|
+
|
|
38
47
|
updateInternal(newStatus, newType, newIndex, newActive, shouldFocus) {
|
|
39
48
|
classListMutation(
|
|
40
49
|
this.classList,
|
|
@@ -148,9 +157,11 @@ export default class LightningProgressStep extends LightningElement {
|
|
|
148
157
|
|
|
149
158
|
get assistiveText() {
|
|
150
159
|
if (this.state.status === 'completed') {
|
|
151
|
-
return `${this.label} - ${i18n.stageComplete}`;
|
|
160
|
+
return `${this.label} - ${this.i18n.stageComplete}`;
|
|
152
161
|
} else if (this.state.status === 'current') {
|
|
153
|
-
return `${this.label} - ${i18n.currentStage}`;
|
|
162
|
+
return `${this.label} - ${this.i18n.currentStage}`;
|
|
163
|
+
} else if (this.state.status === 'incomplete') {
|
|
164
|
+
return `${this.label} - ${this.i18n.notStartedStage}`;
|
|
154
165
|
}
|
|
155
166
|
return this.state.type === 'path' ? '' : this.label;
|
|
156
167
|
}
|
|
@@ -1,29 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
const DELAY_TIMEOUT = 16;
|
|
2
2
|
|
|
3
|
-
const DELAY_TIMEOUT = 200;
|
|
4
3
|
export class LightningResizeObserver {
|
|
5
4
|
constructor(resizeCallback) {
|
|
6
5
|
this._resizeObserverAvailable = typeof ResizeObserver === 'function';
|
|
7
|
-
|
|
8
|
-
const delayedCallback = (callback) => {
|
|
6
|
+
this._delayedResizeCallback = () => {
|
|
9
7
|
if (this._running) {
|
|
10
8
|
return;
|
|
11
9
|
}
|
|
12
10
|
this._running = true;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
// requestAnimationFrame is used to guard against the callback directly reading layout dimensions
|
|
12
|
+
// which may be mutating at the same time leading to layout thrashing
|
|
13
|
+
// eslint-disable-next-line @lwc/lwc/no-async-operation
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
// eslint-disable-next-line @lwc/lwc/no-async-operation
|
|
16
|
+
requestAnimationFrame(() => {
|
|
17
|
+
resizeCallback();
|
|
20
18
|
this._running = false;
|
|
21
19
|
});
|
|
20
|
+
}, DELAY_TIMEOUT);
|
|
22
21
|
};
|
|
23
|
-
this._delayedResizeCallback = delayedCallback.bind(
|
|
24
|
-
this,
|
|
25
|
-
resizeCallback
|
|
26
|
-
);
|
|
27
22
|
if (this._resizeObserverAvailable) {
|
|
28
23
|
this._resizeObserver = new ResizeObserver(
|
|
29
24
|
this._delayedResizeCallback
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
normalizeBoolean,
|
|
6
6
|
normalizeString as normalize,
|
|
7
7
|
} from 'lightning/utilsPrivate';
|
|
8
|
-
import
|
|
8
|
+
import { getDecimalPlaces } from 'lightning/numberUtils';
|
|
9
9
|
import { numberFormat } from 'lightning/internationalizationLibrary';
|
|
10
10
|
import {
|
|
11
11
|
InteractingState,
|
|
@@ -283,7 +283,7 @@ export default class LightningSlider extends LightningElement {
|
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// calculate decimal points from the step attribute
|
|
286
|
-
const decimalPlaces =
|
|
286
|
+
const decimalPlaces = getDecimalPlaces(this._step);
|
|
287
287
|
const formatConfig = { style: 'decimal' };
|
|
288
288
|
|
|
289
289
|
if (decimalPlaces > 0) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<template if:false={hasExternalLabel}>
|
|
3
|
+
<template if:true={required}>
|
|
4
|
+
<abbr class="slds-required" title={i18n.required}>*</abbr>
|
|
5
|
+
</template>
|
|
3
6
|
<label class={computedLabelClass}>
|
|
4
|
-
<template if:true={required}>
|
|
5
|
-
<abbr class="slds-required" title={i18n.required}>*</abbr>
|
|
6
|
-
</template>
|
|
7
7
|
{label}
|
|
8
8
|
</label>
|
|
9
9
|
<lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp} alternative-text={helptextAlternativeText}></lightning-helptext>
|
|
@@ -308,7 +308,9 @@ export class Tooltip {
|
|
|
308
308
|
tooltip.visible = this._visible;
|
|
309
309
|
tooltip.content = this._value;
|
|
310
310
|
|
|
311
|
-
this.
|
|
311
|
+
if (this._root && this._root.isConnected) {
|
|
312
|
+
this._ariaObserver.sync();
|
|
313
|
+
}
|
|
312
314
|
|
|
313
315
|
this.startPositioning();
|
|
314
316
|
document.addEventListener('keydown', this.handleEscape);
|