lightning-base-components 1.19.2-alpha → 1.19.4-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.
Files changed (45) hide show
  1. package/metadata/raptor.json +2066 -1632
  2. package/package.json +5 -1
  3. package/scopedImports/@salesforce-label-LightningProgressIndicator.stageNotStarted.js +1 -0
  4. package/src/lightning/alert/__examples__disabled/basic/basic.html +1 -1
  5. package/src/lightning/ariaObserver/__docs__/ariaObserver.md +12 -4
  6. package/src/lightning/ariaObserver/__examples__/connectChild/connectChild.js +3 -1
  7. package/src/lightning/baseCombobox/baseCombobox.html +1 -0
  8. package/src/lightning/buttonMenu/buttonMenu.js +16 -1
  9. package/src/lightning/colorPickerPanel/colorPickerPanel.html +1 -1
  10. package/src/lightning/confirm/__examples__disabled/basic/basic.html +1 -1
  11. package/src/lightning/datatable/datatable.js +19 -0
  12. package/src/lightning/datatable/state.js +1 -0
  13. package/src/lightning/datatable/templates/div/div.html +4 -2
  14. package/src/lightning/datatable/templates/table/table.html +4 -2
  15. package/src/lightning/fileDownload/resourceResolver.js +4 -3
  16. package/src/lightning/input/input.js +43 -29
  17. package/src/lightning/inputUtils/inputUtils.js +0 -12
  18. package/src/lightning/modal/__docs__/modal.md +2 -2
  19. package/src/lightning/modal/__examples__disabled/all/all.html +2 -2
  20. package/src/lightning/modal/__examples__disabled/allform/allform.html +1 -1
  21. package/src/lightning/modal/__examples__disabled/allformfull/allformfull.html +1 -1
  22. package/src/lightning/modal/__examples__disabled/basic/basic.html +2 -2
  23. package/src/lightning/modal/__examples__disabled/footless/footless.html +2 -2
  24. package/src/lightning/modal/__examples__disabled/headless/headless.html +2 -2
  25. package/src/lightning/modal/__modalUtils__/modalContainerTestConstants.js +15 -2
  26. package/src/lightning/modal/__modalUtils__/modalContainerTestMethods.js +6 -6
  27. package/src/lightning/modalBase/modalBase.js +3 -3
  28. package/src/lightning/numberUtils/numberUtils.js +269 -5
  29. package/src/lightning/primitiveCustomCell/primitiveCustomCell.js +5 -5
  30. package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +3 -3
  31. package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +39 -0
  32. package/src/lightning/primitiveHeaderFactory/sortableHeader.html +2 -2
  33. package/src/lightning/primitiveInputFile/primitiveInputFile.html +1 -0
  34. package/src/lightning/primitiveInputFile/primitiveInputFile.js +4 -0
  35. package/src/lightning/primitiveInputSimple/primitiveInputSimple.js +33 -12
  36. package/src/lightning/progressStep/progressStep.js +13 -2
  37. package/src/lightning/prompt/__examples__disabled/basic/basic.html +1 -1
  38. package/src/lightning/resizeObserver/resizeObserver.js +10 -15
  39. package/src/lightning/slider/slider.js +2 -2
  40. package/src/lightning/tabBar/tabBar.js +3 -1
  41. package/src/lightning/timepicker/timepicker.html +3 -3
  42. package/src/lightning/tooltipLibrary/tooltipLibrary.js +3 -1
  43. package/src/lightning/utils/queryFocusable.js +33 -15
  44. package/src/lightning/utilsPrivate/videoUtils.js +35 -0
  45. package/src/lightning/inputUtils/number.js +0 -267
@@ -1,29 +1,47 @@
1
+ // Matches lower cased tag names of standard inputable elements as well as
2
+ // custom elements whose tag names contain inputable names.
1
3
  const inputableNode = /input|select|textarea|button|object/;
2
4
 
3
5
  function visible(element) {
6
+ // Check computed style visibility first because it doesn't cause a layout
7
+ // reflow/recalculation.
8
+ if (window.getComputedStyle(element).visibility === 'hidden') {
9
+ return false;
10
+ }
11
+ // Perform the performance heavier `getBoundingClientRect()` last because
12
+ // it causes a page layout reflow/recalculation.
4
13
  const { width, height } = element.getBoundingClientRect();
5
- const noZeroSize = width > 0 || height > 0;
6
- return (
7
- noZeroSize && window.getComputedStyle(element).visibility !== 'hidden'
8
- );
14
+ return width > 0 || height > 0;
9
15
  }
10
16
 
11
17
  function focusable(element) {
12
- const nodeName = element.tagName.toLowerCase();
13
- const res =
14
- (inputableNode.test(nodeName) && !element.disabled) ||
15
- (nodeName === 'a' && element.href);
16
-
17
- return res && visible(element);
18
+ const tagName = element.tagName.toLowerCase();
19
+ if (
20
+ (tagName === 'a' && element.href) ||
21
+ (!element.disabled && inputableNode.test(tagName))
22
+ ) {
23
+ return visible(element);
24
+ }
25
+ return false;
18
26
  }
19
27
 
20
28
  function tabbable(element) {
21
- const isDataActionable =
22
- element.getAttribute('data-navigation') === 'enable';
23
- const tabIndex = element.tabIndex;
24
- return (tabIndex >= 0 && focusable(element)) || isDataActionable;
29
+ // Perform the "isDataActionable" first as `focusable()` is potentially
30
+ // performance heavy.
31
+ return (
32
+ element.dataset.navigation === 'enable' ||
33
+ (element.tabIndex >= 0 && focusable(element))
34
+ );
25
35
  }
26
36
 
27
37
  export function queryFocusable(element) {
28
- return [].slice.call(element.querySelectorAll('*'), 0).filter(tabbable);
38
+ const childElements = element.querySelectorAll('*');
39
+ const focusables = [];
40
+ for (let i = 0, { length } = childElements; i < length; i += 1) {
41
+ const child = childElements[i];
42
+ if (tabbable(child)) {
43
+ focusables.push(child);
44
+ }
45
+ }
46
+ return focusables;
29
47
  }
@@ -22,6 +22,11 @@ const ALLOWED_DOMAINS = new Set([
22
22
  'appiniummastertrial.secure.force.com',
23
23
  'embed.app.guidde.com',
24
24
  ]);
25
+ // In addition to:
26
+ // vimeo.com/showcase/*/embed
27
+ // *.my.site.com
28
+ // *.lightning.force.com
29
+ // *.my.salesforce-sites.com
25
30
 
26
31
  export function hasOnlyAllowedVideoIframes(htmlString) {
27
32
  if (htmlString && htmlString.indexOf('<iframe') > -1) {
@@ -55,5 +60,35 @@ function isUrlAllowed(url) {
55
60
  return path.match(regex) !== null;
56
61
  }
57
62
 
63
+ if (anchor.hostname === 'www.my.salesforce-sites.com') {
64
+ return false;
65
+ }
66
+ if (anchor.hostname.match(/^[\w-]+\.my\.salesforce-sites\.com$/)) {
67
+ return true;
68
+ }
69
+ if (anchor.hostname.match(/^[\w-]+\.sandbox\.my\.salesforce-sites\.com$/)) {
70
+ return true;
71
+ }
72
+
73
+ if (anchor.hostname === 'www.lightning.force.com') {
74
+ return false;
75
+ }
76
+ if (anchor.hostname.match(/^[\w-]+\.lightning\.force\.com$/)) {
77
+ return true;
78
+ }
79
+ if (anchor.hostname.match(/^[\w-]+\.sandbox\.lightning\.force\.com$/)) {
80
+ return true;
81
+ }
82
+
83
+ if (anchor.hostname === 'www.my.site.com') {
84
+ return false;
85
+ }
86
+ if (anchor.hostname.match(/^[\w-]+\.my\.site\.com$/)) {
87
+ return true;
88
+ }
89
+ if (anchor.hostname.match(/^[\w-]+\.sandbox\.my\.site\.com$/)) {
90
+ return true;
91
+ }
92
+
58
93
  return ALLOWED_DOMAINS.has(anchor.hostname);
59
94
  }
@@ -1,267 +0,0 @@
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 './utils';
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
- }