lightning-base-components 1.13.10-alpha → 1.14.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.
- package/metadata/raptor.json +24 -0
- package/package.json +20 -4
- package/scopedImports/@salesforce-internal-core.appVersion.js +1 -1
- package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsPlural.js +1 -0
- package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsSingular.js +1 -0
- package/scopedImports/@salesforce-label-LightningErrorMessage.validitySelectAtleastOne.js +1 -0
- package/scopedImports/@salesforce-label-LightningMap.titleWithAddress.js +1 -0
- package/scopedImports/@salesforce-label-LightningModalBase.cancelandclose.js +1 -0
- package/src/lightning/ariaObserver/__component__/ariaObserver.spec.js +112 -0
- package/src/lightning/ariaObserver/__docs__/ariaObserver.md +142 -0
- package/src/lightning/{utilsPrivate/contentMutation.js → ariaObserver/ariaObserver.js} +60 -98
- package/src/lightning/buttonMenu/keyboard.js +0 -10
- package/src/lightning/card/card.html +6 -0
- package/src/lightning/checkboxGroup/checkboxGroup.html +2 -2
- package/src/lightning/checkboxGroup/checkboxGroup.js +6 -1
- package/src/lightning/colorPickerCustom/colorPickerCustom.js +20 -1
- package/src/lightning/datatable/__docs__/datatable.md +55 -0
- package/src/lightning/datatable/__examples__/basic/basic.html +1 -1
- package/src/lightning/datatable/columns-shared.js +1 -1
- package/src/lightning/datatable/datatable.js +98 -30
- package/src/lightning/datatable/errors.js +20 -9
- package/src/lightning/datatable/headerActions.js +77 -49
- package/src/lightning/datatable/infiniteLoading.js +100 -28
- package/src/lightning/datatable/inlineEdit.js +505 -379
- package/src/lightning/datatable/inlineEditShared.js +24 -0
- package/src/lightning/datatable/keyboard.js +162 -127
- package/src/lightning/datatable/renderManager.js +201 -133
- package/src/lightning/datatable/rowLevelActions.js +17 -13
- package/src/lightning/datatable/rowNumber.js +54 -20
- package/src/lightning/datatable/rowSelection.js +760 -0
- package/src/lightning/datatable/rowSelectionShared.js +79 -0
- package/src/lightning/datatable/rows.js +17 -6
- package/src/lightning/datatable/state.js +16 -2
- package/src/lightning/datatable/templates/div/div.css +4 -0
- package/src/lightning/datatable/templates/div/div.html +6 -0
- package/src/lightning/datatable/templates/table/table.html +5 -0
- package/src/lightning/datatable/utils.js +14 -0
- package/src/lightning/datatable/wrapText.js +77 -47
- package/src/lightning/dualListbox/dualListbox.html +1 -1
- package/src/lightning/dualListbox/dualListbox.js +42 -0
- package/src/lightning/formattedDateTime/__docs__/formattedDateTime.md +36 -3
- package/src/lightning/formattedDateTime/__examples__/datetime/datetime.html +2 -2
- package/src/lightning/formattedDateTime/__examples__/datetime/datetime.js +3 -1
- package/src/lightning/formattedDateTime/__examples__/time/time.html +1 -1
- package/src/lightning/formattedDateTime/__examples__/time/time.js +3 -1
- package/src/lightning/formattedDateTime/formattedDateTime.js +1 -0
- package/src/lightning/input/input.html +1 -5
- package/src/lightning/input/input.js +69 -48
- package/src/lightning/inputUtils/validity.js +12 -1
- package/src/lightning/pillContainer/__docs__/pillContainer.md +45 -1
- package/src/lightning/primitiveCellActions/primitiveCellActions.js +69 -12
- package/src/lightning/primitiveCellFactory/cellWithStandardLayout.html +13 -11
- package/src/lightning/primitiveCellFactory/primitiveCellFactory.js +13 -8
- package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.html +17 -14
- package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.js +167 -98
- package/src/lightning/primitiveDatatableIeditTypeFactory/primitiveDatatableIeditTypeFactory.js +94 -69
- package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.html +4 -4
- package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.js +4 -4
- package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.js +99 -37
- package/src/lightning/progressIndicator/progressIndicator.js +1 -1
- package/src/lightning/progressStep/progressStep.js +30 -22
- package/src/lightning/staticMap/staticMap.html +1 -0
- package/src/lightning/staticMap/staticMap.js +39 -2
- package/src/lightning/utils/classSet.js +4 -1
- package/src/lightning/utilsPrivate/utilsPrivate.js +12 -1
- package/scopedImports/@salesforce-label-LightningModalBase.close.js +0 -1
- package/src/lightning/datatable/inlineEdit-shared.js +0 -14
- package/src/lightning/datatable/selector-shared.js +0 -38
- package/src/lightning/datatable/selector.js +0 -527
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file exists in order to get around circular dependencies.
|
|
3
|
+
* In this case, rowSelection.js has a dependency on rows.js;
|
|
4
|
+
* but rows.js also has a dependency on rowSelection.js for
|
|
5
|
+
* `isSelectedRow()` among others.
|
|
6
|
+
*
|
|
7
|
+
* We split out the functions that could cause circular dependencies with
|
|
8
|
+
* `rowSelection.js` into the `*Shared.js` files.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns whether or not the row is selected using the state and the rowKeyValue
|
|
13
|
+
* The state maintains the list of selected rows from which
|
|
14
|
+
* this value can be retrieved.
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} state - datatable state object
|
|
17
|
+
* @param {String} rowKeyValue
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export function isSelectedRow(state, rowKeyValue) {
|
|
21
|
+
return !!state.selectedRowsKeys[rowKeyValue];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns whether the row (whose row key value is specified)
|
|
26
|
+
* should be disabled or not.
|
|
27
|
+
* Should not disable if the row is selected.
|
|
28
|
+
* If the particular row is not selected, the row should be disabled
|
|
29
|
+
* when max-row-selection > 1 and the selection limit is reached
|
|
30
|
+
*
|
|
31
|
+
* Note: Do not disable selection when max-row-selection = 1 and
|
|
32
|
+
* a row has been selected.
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} state
|
|
35
|
+
* @param {String} rowKeyValue
|
|
36
|
+
* @returns {Boolean} whether the row should be disabled or not
|
|
37
|
+
*/
|
|
38
|
+
export function isDisabledRow(state, rowKeyValue) {
|
|
39
|
+
if (!isSelectedRow(state, rowKeyValue)) {
|
|
40
|
+
const maxRowSelection = getMaxRowSelection(state);
|
|
41
|
+
|
|
42
|
+
// when selection is 1, we should not disable selection
|
|
43
|
+
return (
|
|
44
|
+
maxRowSelection !== 1 &&
|
|
45
|
+
getCurrentSelectionLength(state) === maxRowSelection
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns which input type to use for row selection.
|
|
54
|
+
* If max-row-selection = 1, use radio buttons,
|
|
55
|
+
* otherwise, use checkboxes.
|
|
56
|
+
*
|
|
57
|
+
* @param {Object} state - datatable's state object
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
export function getRowSelectionInputType(state) {
|
|
61
|
+
if (getMaxRowSelection(state) === 1) {
|
|
62
|
+
return 'radio';
|
|
63
|
+
}
|
|
64
|
+
return 'checkbox';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getMaxRowSelection(state) {
|
|
68
|
+
return state.maxRowSelection;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function getCurrentSelectionLength(state) {
|
|
72
|
+
return getSelectedRowsKeys(state).length;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function getSelectedRowsKeys(state) {
|
|
76
|
+
return Object.keys(state.selectedRowsKeys).filter(
|
|
77
|
+
(key) => state.selectedRowsKeys[key]
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { assert } from 'lightning/utilsPrivate';
|
|
2
|
-
import { classSet, isObjectLike } from './utils';
|
|
2
|
+
import { classSet, isObjectLike, styleToString } from './utils';
|
|
3
3
|
import { isTreeType, getAttributesNames } from './types';
|
|
4
4
|
import {
|
|
5
5
|
isSelectedRow,
|
|
6
6
|
isDisabledRow,
|
|
7
7
|
getRowSelectionInputType,
|
|
8
|
-
} from './
|
|
8
|
+
} from './rowSelectionShared';
|
|
9
9
|
import { getTreeStateIndicatorFieldNames, getStateTreeColumn } from './tree';
|
|
10
10
|
import {
|
|
11
11
|
getColumns,
|
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
} from './columns';
|
|
18
18
|
import { isRowNumberColumn, getRowNumberErrorColumnDef } from './rowNumber';
|
|
19
19
|
import { getRowError } from './errors';
|
|
20
|
-
import {
|
|
20
|
+
import { getDirtyValueFromCell } from './inlineEditShared';
|
|
21
|
+
import { DEFAULT_ROW_HEIGHT } from './renderManager';
|
|
21
22
|
|
|
22
23
|
export function getData(state) {
|
|
23
24
|
return state.data;
|
|
@@ -115,7 +116,7 @@ export function uniqueRowKeyGenerator(keyField) {
|
|
|
115
116
|
*/
|
|
116
117
|
export function updateRowsAndCellIndexes() {
|
|
117
118
|
const { state, privateTypes: types } = this;
|
|
118
|
-
const { keyField, renderModeRoleBased } = state;
|
|
119
|
+
const { keyField, renderModeRoleBased, virtualize } = state;
|
|
119
120
|
const data = getData(state);
|
|
120
121
|
const columns = getColumns(state);
|
|
121
122
|
const computeUniqueRowKey = uniqueRowKeyGenerator(keyField);
|
|
@@ -141,11 +142,21 @@ export function updateRowsAndCellIndexes() {
|
|
|
141
142
|
row.classnames = resolveRowClassNames(row);
|
|
142
143
|
Object.assign(row, getRowStateForTree(rowData, state));
|
|
143
144
|
row.tabIndex = -1;
|
|
145
|
+
if (virtualize) {
|
|
146
|
+
row.style = styleToString({
|
|
147
|
+
position: 'absolute',
|
|
148
|
+
top: `${rowIndex * DEFAULT_ROW_HEIGHT}px`,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
144
151
|
|
|
145
152
|
columns.reduce((currentRow, colData, colIndex) => {
|
|
146
153
|
const { fieldName } = colData;
|
|
147
154
|
const colKeyValue = generateColKeyValue(colData, colIndex);
|
|
148
|
-
const dirtyValue =
|
|
155
|
+
const dirtyValue = getDirtyValueFromCell(
|
|
156
|
+
state,
|
|
157
|
+
row.key,
|
|
158
|
+
colKeyValue
|
|
159
|
+
);
|
|
149
160
|
const cellHasErrors = hasCellErrors(
|
|
150
161
|
rowErrors,
|
|
151
162
|
colData.fieldName,
|
|
@@ -391,7 +402,7 @@ function computeCellEditable(row, column) {
|
|
|
391
402
|
* @param {object} row - a row data object stored in datatable state. Must be truthy.
|
|
392
403
|
* @param {object} column - a column data object stored in datatable state. Must be truthy.
|
|
393
404
|
*/
|
|
394
|
-
function isCellEditable(row, column) {
|
|
405
|
+
export function isCellEditable(row, column) {
|
|
395
406
|
return !!resolveAttributeValue(column.editable, row);
|
|
396
407
|
}
|
|
397
408
|
|
|
@@ -17,8 +17,9 @@ export const getDefaultState = function () {
|
|
|
17
17
|
rows: [],
|
|
18
18
|
indexes: {},
|
|
19
19
|
|
|
20
|
-
//
|
|
20
|
+
// row selection
|
|
21
21
|
selectedRowsKeys: {},
|
|
22
|
+
lastSelectedRowKey: undefined,
|
|
22
23
|
maxRowSelection: undefined,
|
|
23
24
|
|
|
24
25
|
headerIndexes: {},
|
|
@@ -54,12 +55,25 @@ export const getDefaultState = function () {
|
|
|
54
55
|
// table render mode
|
|
55
56
|
renderModeRoleBased: false,
|
|
56
57
|
|
|
57
|
-
// viewport rendering
|
|
58
|
+
// viewport rendering and virtualization
|
|
58
59
|
enableViewportRendering: undefined,
|
|
60
|
+
virtualize: '',
|
|
61
|
+
bufferSize: 5, // number of extra rows rendered on each side outside of viewport
|
|
62
|
+
rowHeight: 30.5,
|
|
63
|
+
renderedRowCount: 0,
|
|
64
|
+
firstVisibleIndex: 0, // first row that should be visible in viewport
|
|
59
65
|
|
|
60
66
|
// inline edit
|
|
61
67
|
inlineEdit: {
|
|
68
|
+
rowKeyValue: undefined,
|
|
69
|
+
colKeyValue: undefined,
|
|
70
|
+
columnDef: {},
|
|
62
71
|
dirtyValues: {},
|
|
72
|
+
editedValue: undefined,
|
|
73
|
+
isPanelVisible: false,
|
|
74
|
+
massEditEnabled: false,
|
|
75
|
+
massEditSelectedRows: undefined,
|
|
76
|
+
resolvedAttributeTypes: {},
|
|
63
77
|
},
|
|
64
78
|
|
|
65
79
|
// errors
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
<div class="slds-line-height_reset table-header"
|
|
49
49
|
role="row"
|
|
50
50
|
aria-rowindex="1"
|
|
51
|
+
data-row-key-value="HEADER"
|
|
51
52
|
onprivateresizestart={handleResizeStart}
|
|
52
53
|
onprivateresizeend={handleResizeEnd}>
|
|
53
54
|
<template for:each={state.columns} for:item="def" for:index="colIndex">
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
tabindex={def.tabIndex}
|
|
59
60
|
aria-label={def.ariaLabel}
|
|
60
61
|
aria-sort={def.sortAriaLabel}
|
|
62
|
+
data-col-key-value={def.colKeyValue}
|
|
61
63
|
key={def.colKeyValue}>
|
|
62
64
|
|
|
63
65
|
<template if:true={def.fixedWidth}>
|
|
@@ -120,6 +122,7 @@
|
|
|
120
122
|
aria-setsize={row.setSize}
|
|
121
123
|
aria-posinset={row.posInSet}
|
|
122
124
|
aria-rowindex={row.ariaRowIndex}
|
|
125
|
+
style={row.style}
|
|
123
126
|
tabindex={row.tabIndex}>
|
|
124
127
|
<template for:each={row.cells} for:item="cell">
|
|
125
128
|
<template if:true={cell.isCheckbox}>
|
|
@@ -129,6 +132,7 @@
|
|
|
129
132
|
role="gridcell"
|
|
130
133
|
tabindex={cell.tabIndex}
|
|
131
134
|
data-label={cell.dataLabel}
|
|
135
|
+
data-col-key-value={cell.colKeyValue}
|
|
132
136
|
key={cell.colKeyValue}>
|
|
133
137
|
<lightning-primitive-cell-checkbox
|
|
134
138
|
dt-context-id={_datatableId}
|
|
@@ -154,6 +158,7 @@
|
|
|
154
158
|
aria-readonly={cell.ariaReadOnly}
|
|
155
159
|
tabindex={cell.tabIndex}
|
|
156
160
|
data-label={cell.dataLabel}
|
|
161
|
+
data-col-key-value={cell.colKeyValue}
|
|
157
162
|
key={cell.colKeyValue}>
|
|
158
163
|
<lightning-primitive-cell-factory
|
|
159
164
|
types={privateTypes}
|
|
@@ -202,6 +207,7 @@
|
|
|
202
207
|
aria-readonly={cell.ariaReadOnly}
|
|
203
208
|
tabindex={cell.tabIndex}
|
|
204
209
|
data-label={cell.dataLabel}
|
|
210
|
+
data-col-key-value={cell.colKeyValue}
|
|
205
211
|
key={cell.colKeyValue}>
|
|
206
212
|
<lightning-primitive-cell-factory
|
|
207
213
|
types={privateTypes}
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
<thead>
|
|
42
42
|
<!-- Column Header Row -->
|
|
43
43
|
<tr class="slds-line-height_reset"
|
|
44
|
+
data-row-key-value="HEADER"
|
|
44
45
|
onprivateresizestart={handleResizeStart}
|
|
45
46
|
onprivateresizeend={handleResizeEnd}>
|
|
46
47
|
<template for:each={state.columns} for:item="def" for:index="colIndex">
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
tabindex={def.tabIndex}
|
|
51
52
|
aria-label={def.ariaLabel}
|
|
52
53
|
aria-sort={def.sortAriaLabel}
|
|
54
|
+
data-col-key-value={def.colKeyValue}
|
|
53
55
|
key={def.colKeyValue}>
|
|
54
56
|
|
|
55
57
|
<template if:true={def.fixedWidth}>
|
|
@@ -117,6 +119,7 @@
|
|
|
117
119
|
role="gridcell"
|
|
118
120
|
tabindex={cell.tabIndex}
|
|
119
121
|
data-label={cell.dataLabel}
|
|
122
|
+
data-col-key-value={cell.colKeyValue}
|
|
120
123
|
key={cell.colKeyValue}>
|
|
121
124
|
<lightning-primitive-cell-checkbox
|
|
122
125
|
dt-context-id={_datatableId}
|
|
@@ -142,6 +145,7 @@
|
|
|
142
145
|
scope="row"
|
|
143
146
|
tabindex={cell.tabIndex}
|
|
144
147
|
data-label={cell.dataLabel}
|
|
148
|
+
data-col-key-value={cell.colKeyValue}
|
|
145
149
|
key={cell.colKeyValue}>
|
|
146
150
|
<lightning-primitive-cell-factory
|
|
147
151
|
types={privateTypes}
|
|
@@ -190,6 +194,7 @@
|
|
|
190
194
|
aria-readonly={cell.ariaReadOnly}
|
|
191
195
|
tabindex={cell.tabIndex}
|
|
192
196
|
data-label={cell.dataLabel}
|
|
197
|
+
data-col-key-value={cell.colKeyValue}
|
|
193
198
|
key={cell.colKeyValue}>
|
|
194
199
|
<lightning-primitive-cell-factory
|
|
195
200
|
types={privateTypes}
|
|
@@ -109,3 +109,17 @@ export function getScrollOffsetFromTableEnd(el) {
|
|
|
109
109
|
el.scrollHeight - el.parentNode.scrollTop - el.parentNode.clientHeight
|
|
110
110
|
);
|
|
111
111
|
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Utility for converting arrays and plain objects to style strings
|
|
115
|
+
* @param {Array|Object} style
|
|
116
|
+
* @returns {string} representing array/object as a string
|
|
117
|
+
*/
|
|
118
|
+
export function styleToString(style) {
|
|
119
|
+
if (!Array.isArray(style)) {
|
|
120
|
+
return Object.entries(style)
|
|
121
|
+
.map(([key, value]) => `${key}:${value}`)
|
|
122
|
+
.join(';');
|
|
123
|
+
}
|
|
124
|
+
return style.join(';');
|
|
125
|
+
}
|
|
@@ -3,8 +3,10 @@ import labelWrapText from '@salesforce/label/LightningDatatable.wrapText';
|
|
|
3
3
|
import { getStateColumnIndex, getColumns } from './columns';
|
|
4
4
|
import { normalizeBoolean } from 'lightning/utilsPrivate';
|
|
5
5
|
import { normalizeNumberAttribute } from './utils';
|
|
6
|
+
import { getDefaultState } from './state';
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
+
const WRAP_TEXT_DEFAULT = false;
|
|
9
|
+
const NON_WRAPPABLE_TYPES = [
|
|
8
10
|
'action',
|
|
9
11
|
'boolean',
|
|
10
12
|
'button',
|
|
@@ -13,17 +15,33 @@ const nonWrapableTypes = [
|
|
|
13
15
|
'rowNumber',
|
|
14
16
|
];
|
|
15
17
|
|
|
16
|
-
const WRAP_TEXT_DEFAULT = false;
|
|
17
|
-
|
|
18
18
|
const i18n = {
|
|
19
19
|
clipText: labelClipText,
|
|
20
20
|
wrapText: labelWrapText,
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
/************************** WRAP TEXT STATE **************************/
|
|
24
|
+
|
|
25
|
+
// Returns a boolean representing whether or not the column should be text wrapped
|
|
26
|
+
export function getWrapTextState(state = getDefaultState(), colKeyValue) {
|
|
27
|
+
return state.wrapText[colKeyValue] || WRAP_TEXT_DEFAULT;
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
// Sets a boolean value in state's wrapText object against the column key value
|
|
31
|
+
// representing whether or not the column is text wrapped
|
|
32
|
+
export function setWrapTextState(state = getDefaultState(), columnDefinition) {
|
|
33
|
+
const { colKeyValue, type, wrapText } = columnDefinition;
|
|
34
|
+
|
|
35
|
+
if (isWrappableType(type)) {
|
|
36
|
+
state.wrapText[colKeyValue] =
|
|
37
|
+
normalizeBoolean(wrapText) || WRAP_TEXT_DEFAULT;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/************************** WRAP TEXT MAX LINES **************************/
|
|
42
|
+
|
|
43
|
+
// Normalizes and sets wrapTextMaxLines in datatable's state object
|
|
44
|
+
// The normalized value should be a positive integer or it'll fall back to undefined
|
|
27
45
|
export function setWrapTextMaxLines(state, value) {
|
|
28
46
|
state.wrapTextMaxLines = normalizeNumberAttribute(
|
|
29
47
|
'wrapTextMaxLines',
|
|
@@ -33,6 +51,8 @@ export function setWrapTextMaxLines(state, value) {
|
|
|
33
51
|
);
|
|
34
52
|
}
|
|
35
53
|
|
|
54
|
+
// Sets the `wrapText` and `wrapTextMaxLines` values in the cell object for all cells in a column
|
|
55
|
+
// These values are used by primitiveCellFactory to set the required classes on the cell for wrapping
|
|
36
56
|
function updateWrapTextAndMaxLinesValuesInCells(state, colIndex, colKeyValue) {
|
|
37
57
|
state.rows.forEach((row) => {
|
|
38
58
|
const cell = row.cells[colIndex];
|
|
@@ -43,39 +63,17 @@ function updateWrapTextAndMaxLinesValuesInCells(state, colIndex, colKeyValue) {
|
|
|
43
63
|
});
|
|
44
64
|
}
|
|
45
65
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
updateWrapTextAndMaxLinesValuesInCells(state, colIndex, colKeyValue);
|
|
61
|
-
|
|
62
|
-
// lets force a refresh on this column, because the wrapText checked value changed.
|
|
63
|
-
colData.actions = Object.assign({}, colData.actions);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function getWrapTextState(state = getDefaultState(), colKeyValue) {
|
|
67
|
-
return state.wrapText[colKeyValue] || WRAP_TEXT_DEFAULT;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function setWrapTextState(state = getDefaultState(), columnDefinition) {
|
|
71
|
-
const { colKeyValue, type, wrapText } = columnDefinition;
|
|
72
|
-
|
|
73
|
-
if (isWrapableType(type)) {
|
|
74
|
-
state.wrapText[colKeyValue] =
|
|
75
|
-
normalizeBoolean(wrapText) || WRAP_TEXT_DEFAULT;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
66
|
+
/************************** HEADER ACTIONS **************************/
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns an object representing the two internal header actions that datatable
|
|
70
|
+
* provides - Wrap Text and Clip Text.
|
|
71
|
+
* Each header action contains a label, title, action name and its selected value (checked)
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} state - datatable's state object
|
|
74
|
+
* @param {Object} columnDefinition - datatable's column definitions
|
|
75
|
+
* @returns
|
|
76
|
+
*/
|
|
79
77
|
export function getActions(state, columnDefinition) {
|
|
80
78
|
const wrapTextActions = [];
|
|
81
79
|
const { hideDefaultActions, type, colKeyValue } = columnDefinition;
|
|
@@ -84,7 +82,7 @@ export function getActions(state, columnDefinition) {
|
|
|
84
82
|
setWrapTextState(state, columnDefinition);
|
|
85
83
|
|
|
86
84
|
// if not hidden and isWrapable, sets the internal actions
|
|
87
|
-
if (
|
|
85
|
+
if (isWrappableType(type) && !hideDefaultActions) {
|
|
88
86
|
const isTextWrapped = getWrapTextState(state, colKeyValue);
|
|
89
87
|
|
|
90
88
|
wrapTextActions.push({
|
|
@@ -105,19 +103,51 @@ export function getActions(state, columnDefinition) {
|
|
|
105
103
|
return wrapTextActions;
|
|
106
104
|
}
|
|
107
105
|
|
|
106
|
+
/**
|
|
107
|
+
* If the action is an internal action and if the wrapText value for a column
|
|
108
|
+
* needs to be changed in the state, change it to the new value and update
|
|
109
|
+
* the check mark to represent the currently selected action
|
|
110
|
+
*
|
|
111
|
+
* @param {Object} state - datatable's state object
|
|
112
|
+
* @param {String} action - action that was selected/triggered
|
|
113
|
+
* @param {String} colKeyValue - column key value
|
|
114
|
+
*/
|
|
108
115
|
export function handleTriggeredAction(state, action, colKeyValue) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
const actionName = action.name;
|
|
117
|
+
if (actionName === 'wrapText' || actionName === 'clipText') {
|
|
118
|
+
// If state should be changed
|
|
119
|
+
if (state.wrapText[colKeyValue] !== (actionName === 'wrapText')) {
|
|
120
|
+
state.wrapText[colKeyValue] = actionName === 'wrapText';
|
|
113
121
|
|
|
114
122
|
updateSelectedOptionInHeaderActions(state, colKeyValue);
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
126
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
// Update the 'checked' value of the each action to show which action is selected
|
|
128
|
+
// and which action is not selected
|
|
129
|
+
function updateSelectedOptionInHeaderActions(state, colKeyValue) {
|
|
130
|
+
const columns = getColumns(state);
|
|
131
|
+
const colIndex = getStateColumnIndex(state, colKeyValue);
|
|
132
|
+
const colData = columns[colIndex];
|
|
133
|
+
|
|
134
|
+
colData.actions.internalActions.forEach((action) => {
|
|
135
|
+
if (action.name === 'wrapText') {
|
|
136
|
+
action.checked = state.wrapText[colKeyValue];
|
|
137
|
+
}
|
|
138
|
+
if (action.name === 'clipText') {
|
|
139
|
+
action.checked = !state.wrapText[colKeyValue];
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
updateWrapTextAndMaxLinesValuesInCells(state, colIndex, colKeyValue);
|
|
144
|
+
|
|
145
|
+
// Force a refresh on this column, because the wrapText checked value changed.
|
|
146
|
+
colData.actions = Object.assign({}, colData.actions);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/************************** HELPER FUNCTIONS **************************/
|
|
150
|
+
|
|
151
|
+
function isWrappableType(type) {
|
|
152
|
+
return NON_WRAPPABLE_TYPES.indexOf(type) < 0;
|
|
123
153
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp}></lightning-helptext>
|
|
10
10
|
<div class="slds-form-element__control">
|
|
11
11
|
<div class="slds-dueling-list" onfocusin={handleFocus} onfocusout={handleBlur}>
|
|
12
|
-
<div class="slds-assistive-text" id="assertive-thing" aria-live="assertive"
|
|
12
|
+
<div class="slds-assistive-text" id="assertive-thing" aria-live="assertive">{_messageToDisplay}</div>
|
|
13
13
|
<div class="slds-assistive-text" id="keyboard-interacton">{i18n.componentAssistiveText}</div>
|
|
14
14
|
<div class={computedLeftColumnClass}>
|
|
15
15
|
<span class="slds-form-element__label" id="source-list-label">{sourceLabel}</span>
|
|
@@ -14,6 +14,8 @@ import labelRequiredOptionError from '@salesforce/label/LightningDualListbox.req
|
|
|
14
14
|
import labelUpButtonAssistiveText from '@salesforce/label/LightningDualListbox.upButtonAssistiveText';
|
|
15
15
|
import labelMoveSelectionToAssistiveText from '@salesforce/label/LightningDualListbox.moveSelectionToAssistiveText';
|
|
16
16
|
import labelLoadingText from '@salesforce/label/LightningCombobox.loadingText';
|
|
17
|
+
import labelMovedOptionsSingular from '@salesforce/label/LightningDualListbox.movedOptionsSingular';
|
|
18
|
+
import labelMovedOptionsPlural from '@salesforce/label/LightningDualListbox.movedOptionsPlural';
|
|
17
19
|
import { LightningElement, api, track } from 'lwc';
|
|
18
20
|
import { handleKeyDownOnOption } from './keyboard';
|
|
19
21
|
import { classSet, formatLabel } from 'lightning/utils';
|
|
@@ -47,6 +49,8 @@ const i18n = {
|
|
|
47
49
|
upButtonAssistiveText: labelUpButtonAssistiveText,
|
|
48
50
|
moveSelectionToAssistiveText: labelMoveSelectionToAssistiveText,
|
|
49
51
|
loadingText: labelLoadingText,
|
|
52
|
+
movedOptionsSingular: labelMovedOptionsSingular,
|
|
53
|
+
movedOptionsPlural: labelMovedOptionsPlural,
|
|
50
54
|
};
|
|
51
55
|
|
|
52
56
|
/**
|
|
@@ -117,6 +121,9 @@ export default class LightningDualListbox extends LightningElement {
|
|
|
117
121
|
@track highlightedOptions = [];
|
|
118
122
|
@track focusableInSource;
|
|
119
123
|
@track focusableInSelected;
|
|
124
|
+
@track highlightedOptionsLabel = [];
|
|
125
|
+
|
|
126
|
+
_messageToDisplay = '';
|
|
120
127
|
|
|
121
128
|
isFocusOnList = false;
|
|
122
129
|
|
|
@@ -705,6 +712,8 @@ export default class LightningDualListbox extends LightningElement {
|
|
|
705
712
|
);
|
|
706
713
|
}
|
|
707
714
|
|
|
715
|
+
this.movedOptions(addToSelect);
|
|
716
|
+
|
|
708
717
|
const oldSelectedValues = this._selectedValues;
|
|
709
718
|
this._selectedValues = newValues;
|
|
710
719
|
const invalidMove =
|
|
@@ -730,6 +739,7 @@ export default class LightningDualListbox extends LightningElement {
|
|
|
730
739
|
this.interactingState.leave();
|
|
731
740
|
this.isFocusOnList = false;
|
|
732
741
|
this.highlightedOptions = [];
|
|
742
|
+
this.highlightedOptionsLabel = [];
|
|
733
743
|
this.optionToFocus = null;
|
|
734
744
|
}
|
|
735
745
|
|
|
@@ -785,6 +795,7 @@ export default class LightningDualListbox extends LightningElement {
|
|
|
785
795
|
const start = all ? options.length : this.lastSelected;
|
|
786
796
|
let val, select;
|
|
787
797
|
this.highlightedOptions = [];
|
|
798
|
+
this.highlightedOptionsLabel = [];
|
|
788
799
|
for (let i = 0; i < options.length; i++) {
|
|
789
800
|
select = (i - start) * (i - end) <= 0;
|
|
790
801
|
if (select) {
|
|
@@ -889,6 +900,7 @@ export default class LightningDualListbox extends LightningElement {
|
|
|
889
900
|
if (this.selectedList !== currentList || !isMultiple) {
|
|
890
901
|
if (this.selectedList) {
|
|
891
902
|
this.highlightedOptions = [];
|
|
903
|
+
this.highlightedOptionsLabel = [];
|
|
892
904
|
this.lastSelected = -1;
|
|
893
905
|
}
|
|
894
906
|
this.selectedList = currentList;
|
|
@@ -1013,6 +1025,36 @@ export default class LightningDualListbox extends LightningElement {
|
|
|
1013
1025
|
}
|
|
1014
1026
|
if (!isSame) {
|
|
1015
1027
|
this.highlightedOptions = [];
|
|
1028
|
+
this.highlightedOptionsLabel = [];
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
movedOptions(addToSelect) {
|
|
1033
|
+
const listName = addToSelect ? this.selectedLabel : this.sourceLabel;
|
|
1034
|
+
|
|
1035
|
+
for (let i = 0; i < this.highlightedOptions.length; i++) {
|
|
1036
|
+
let selectedOption = addToSelect
|
|
1037
|
+
? this.computedSourceList.filter(
|
|
1038
|
+
(item) => item.value === this.highlightedOptions[i]
|
|
1039
|
+
)
|
|
1040
|
+
: this.computedSelectedList.filter(
|
|
1041
|
+
(item) => item.value === this.highlightedOptions[i]
|
|
1042
|
+
);
|
|
1043
|
+
this.highlightedOptionsLabel.push(selectedOption[0].label);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
if (this.highlightedOptions.length) {
|
|
1047
|
+
const strToFormat =
|
|
1048
|
+
this.highlightedOptions.length > 1
|
|
1049
|
+
? i18n.movedOptionsPlural
|
|
1050
|
+
: i18n.movedOptionsSingular;
|
|
1051
|
+
this._messageToDisplay = formatLabel(
|
|
1052
|
+
strToFormat,
|
|
1053
|
+
this.highlightedOptionsLabel.join(', '),
|
|
1054
|
+
listName
|
|
1055
|
+
);
|
|
1056
|
+
} else {
|
|
1057
|
+
this._messageToDisplay = '';
|
|
1016
1058
|
}
|
|
1017
1059
|
}
|
|
1018
1060
|
}
|
|
@@ -45,11 +45,11 @@ are specified, the component uses the default date format based on the user's lo
|
|
|
45
45
|
|
|
46
46
|
The locale determines the order and format of the month, day, and year. For example, the English (United States) locale's date format is Oct 14, 2020 and the French (France) locale's date format is 14 Oct 2020. The locale doesn't determine the time zone. Time zone is a separate setting.
|
|
47
47
|
|
|
48
|
-
The locale also determines whether to display time as 24-hour time or 12-hour time with AM and PM.
|
|
48
|
+
The locale also determines whether to display time as 24-hour time or 12-hour time with AM and PM. You can override the locale default with the `hour12` attribute. See _Date and Time Display Examples_ for more information.
|
|
49
49
|
|
|
50
|
-
Specify optional attributes to modify the date and time display, overriding the locale's default formatting.
|
|
50
|
+
Specify optional attributes listed in the Specification tab to modify the date and time display, overriding the locale's default formatting.
|
|
51
51
|
|
|
52
|
-
In the
|
|
52
|
+
In the Mini-Playground in the Examples tab, the component is limited to the en-US locale.
|
|
53
53
|
|
|
54
54
|
#### Time Zone Considerations
|
|
55
55
|
|
|
@@ -132,6 +132,35 @@ Displays: 1/11/2019, 6:53 PM EST
|
|
|
132
132
|
</template>
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
+
Displays: 1/11/2019, 18:53 EST
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<template>
|
|
139
|
+
<lightning-formatted-date-time
|
|
140
|
+
value="1547250828000"
|
|
141
|
+
year="numeric"
|
|
142
|
+
month="numeric"
|
|
143
|
+
day="numeric"
|
|
144
|
+
hour="2-digit"
|
|
145
|
+
hour12={ampm}
|
|
146
|
+
minute="2-digit"
|
|
147
|
+
time-zone-name="short"
|
|
148
|
+
time-zone="America/New_York"
|
|
149
|
+
>
|
|
150
|
+
</lightning-formatted-date-time>
|
|
151
|
+
</template>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Set the `hour12` attribute using a variable. If set to `false` or any other string directly, the component interprets its value as true.
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
import { LightningElement } from 'lwc';
|
|
158
|
+
|
|
159
|
+
export default class FormattedDateTimeHour12 extends LightningElement {
|
|
160
|
+
ampm = false;
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
135
164
|
#### Date and Time Stored in Salesforce
|
|
136
165
|
|
|
137
166
|
Salesforce uses the ISO8601 format `YYYY-MM-DD` to store date fields, which store a date without time, and includes no time zone information.
|
|
@@ -186,6 +215,10 @@ Displays: December 03, 2017, 12:00 PM
|
|
|
186
215
|
</template>
|
|
187
216
|
```
|
|
188
217
|
|
|
218
|
+
#### Usage Considerations
|
|
219
|
+
|
|
220
|
+
This component has usage differences from its Aura counterpart. See [Base Components: Aura Vs Lightning Web Components](docs/component-library/documentation/lwc/lwc.migrate_map_aura_lwc_components) in the Lightning Web Components Developer Guide.
|
|
221
|
+
|
|
189
222
|
#### Source Code
|
|
190
223
|
|
|
191
224
|
`lightning-formatted-date-time` is available in the [Base Components Recipes GitHub repository](https://github.com/salesforce/base-components-recipes#documentation). It's transpiled into the `c` namespace so that you can use it in your own projects.
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<p><lightning-formatted-date-time value="1547250828000" year="2-digit" month="short" day="2-digit" hour="numeric"
|
|
5
5
|
weekday="long" era="short"></lightning-formatted-date-time></p>
|
|
6
6
|
<p><lightning-formatted-date-time value="1547250828000" year="numeric" month="numeric" day="numeric" hour="2-digit"
|
|
7
|
-
minute="2-digit" time-zone-name="short"
|
|
7
|
+
minute="2-digit" time-zone-name="short"></lightning-formatted-date-time></p>
|
|
8
8
|
<p><lightning-formatted-date-time value="1547250828000" year="numeric" month="numeric" day="numeric" hour="2-digit"
|
|
9
|
-
minute="2-digit" time-zone="UTC" time-zone-name="short" hour12=
|
|
9
|
+
minute="2-digit" time-zone="UTC" time-zone-name="short" hour12={ampm}></lightning-formatted-date-time></p>
|
|
10
10
|
</div>
|
|
11
11
|
</template>
|