@vaadin/grid-pro 22.0.0-alpha7

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 (35) hide show
  1. package/LICENSE +262 -0
  2. package/README.md +72 -0
  3. package/package.json +58 -0
  4. package/src/interfaces.d.ts +1 -0
  5. package/src/vaadin-grid-pro-edit-checkbox.js +21 -0
  6. package/src/vaadin-grid-pro-edit-column.d.ts +85 -0
  7. package/src/vaadin-grid-pro-edit-column.js +282 -0
  8. package/src/vaadin-grid-pro-edit-select.js +128 -0
  9. package/src/vaadin-grid-pro-edit-text-field.js +26 -0
  10. package/src/vaadin-grid-pro-inline-editing-mixin.d.ts +40 -0
  11. package/src/vaadin-grid-pro-inline-editing-mixin.js +483 -0
  12. package/src/vaadin-grid-pro.d.ts +95 -0
  13. package/src/vaadin-grid-pro.js +68 -0
  14. package/theme/lumo/vaadin-grid-pro-edit-checkbox.js +2 -0
  15. package/theme/lumo/vaadin-grid-pro-edit-column.js +4 -0
  16. package/theme/lumo/vaadin-grid-pro-edit-select-styles.js +24 -0
  17. package/theme/lumo/vaadin-grid-pro-edit-select.js +5 -0
  18. package/theme/lumo/vaadin-grid-pro-edit-text-field-styles.js +6 -0
  19. package/theme/lumo/vaadin-grid-pro-edit-text-field.js +3 -0
  20. package/theme/lumo/vaadin-grid-pro-editor-styles.js +41 -0
  21. package/theme/lumo/vaadin-grid-pro-styles.js +19 -0
  22. package/theme/lumo/vaadin-grid-pro.js +3 -0
  23. package/theme/material/vaadin-grid-pro-edit-checkbox.js +2 -0
  24. package/theme/material/vaadin-grid-pro-edit-column.js +4 -0
  25. package/theme/material/vaadin-grid-pro-edit-select-styles.js +17 -0
  26. package/theme/material/vaadin-grid-pro-edit-select.js +5 -0
  27. package/theme/material/vaadin-grid-pro-edit-text-field-styles.js +6 -0
  28. package/theme/material/vaadin-grid-pro-edit-text-field.js +3 -0
  29. package/theme/material/vaadin-grid-pro-editor-styles.js +21 -0
  30. package/theme/material/vaadin-grid-pro-styles.js +13 -0
  31. package/theme/material/vaadin-grid-pro.js +3 -0
  32. package/vaadin-grid-pro-edit-column.d.ts +1 -0
  33. package/vaadin-grid-pro-edit-column.js +3 -0
  34. package/vaadin-grid-pro.d.ts +2 -0
  35. package/vaadin-grid-pro.js +3 -0
@@ -0,0 +1,282 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2021 Vaadin Ltd.
4
+ * This program is available under Commercial Vaadin Developer License 4.0 (CVDLv4).
5
+ * See <a href="https://vaadin.com/license/cvdl-4.0">the website</a> for the complete license.
6
+ */
7
+ import { get, set } from '@polymer/polymer/lib/utils/path.js';
8
+ import { GridColumn } from '@vaadin/grid/src/vaadin-grid-column.js';
9
+ import './vaadin-grid-pro-edit-checkbox.js';
10
+ import './vaadin-grid-pro-edit-select.js';
11
+ import './vaadin-grid-pro-edit-text-field.js';
12
+
13
+ /**
14
+ * `<vaadin-grid-pro-edit-column>` is a helper element for the `<vaadin-grid-pro>`
15
+ * that provides default inline editing for the items.
16
+ *
17
+ * __Note that the `path` property must be explicitly specified for edit column.__
18
+ *
19
+ * #### Example:
20
+ * ```html
21
+ * <vaadin-grid-pro items="[[items]]">
22
+ * <vaadin-grid-pro-edit-column path="name.first"></vaadin-grid-pro-edit-column>
23
+ *
24
+ * <vaadin-grid-column>
25
+ * ...
26
+ * ```
27
+ *
28
+ * @extends GridColumn
29
+ */
30
+ class GridProEditColumn extends GridColumn {
31
+ static get is() {
32
+ return 'vaadin-grid-pro-edit-column';
33
+ }
34
+
35
+ static get properties() {
36
+ return {
37
+ /**
38
+ * Custom function for rendering the cell content in edit mode.
39
+ * Receives three arguments:
40
+ *
41
+ * - `root` The cell content DOM element. Append your editor component to it.
42
+ * - `column` The `<vaadin-grid-pro-edit-column>` element.
43
+ * - `model` The object with the properties related with
44
+ * the rendered item, contains:
45
+ * - `model.index` The index of the item.
46
+ * - `model.item` The item.
47
+ * - `model.expanded` Sublevel toggle state.
48
+ * - `model.level` Level of the tree represented with a horizontal offset of the toggle button.
49
+ * - `model.selected` Selected state.
50
+ * - `model.detailsOpened` Details opened state.
51
+ * @type {!GridBodyRenderer | null | undefined}
52
+ */
53
+ editModeRenderer: Function,
54
+
55
+ /**
56
+ * The list of options which should be passed to cell editor component.
57
+ * Used with the `select` editor type, to provide a list of items.
58
+ * @type {!Array<string>}
59
+ */
60
+ editorOptions: {
61
+ type: Array,
62
+ value: () => []
63
+ },
64
+
65
+ /**
66
+ * Type of the cell editor component to be rendered. Allowed values:
67
+ * - `text` (default) - renders a text field
68
+ * - `checkbox` - renders a checkbox
69
+ * - `select` - renders a select with a list of items passed as `editorOptions`
70
+ *
71
+ * Editor type is set to `custom` when `editModeRenderer` is set.
72
+ * @attr {text|checkbox|select|custom} editor-type
73
+ * @type {!GridProEditorType}
74
+ */
75
+ editorType: {
76
+ type: String,
77
+ notify: true, // FIXME(web-padawan): needed by Flow counterpart
78
+ value: 'text'
79
+ },
80
+
81
+ /**
82
+ * Path of the property used for the value of the editor component.
83
+ * @attr {string} editor-value-path
84
+ * @type {string}
85
+ */
86
+ editorValuePath: {
87
+ type: String,
88
+ value: 'value'
89
+ },
90
+
91
+ /**
92
+ * JS Path of the property in the item used for the editable content.
93
+ */
94
+ path: {
95
+ type: String,
96
+ observer: '_pathChanged'
97
+ },
98
+
99
+ /** @private */
100
+ _oldRenderer: Function
101
+ };
102
+ }
103
+
104
+ static get observers() {
105
+ return ['_editModeRendererChanged(editModeRenderer, __initialized)', '_cellsChanged(_cells.*)'];
106
+ }
107
+
108
+ constructor() {
109
+ super();
110
+
111
+ this.__editModeRenderer = function (root, column) {
112
+ const cell = root.assignedSlot.parentNode;
113
+
114
+ const tagName = column._getEditorTagName(cell);
115
+ if (!root.firstElementChild || root.firstElementChild.localName.toLowerCase() !== tagName) {
116
+ root.innerHTML = `
117
+ <${tagName}></${tagName}>
118
+ `;
119
+ }
120
+ };
121
+ }
122
+
123
+ /** @private */
124
+ _pathChanged(path) {
125
+ if (!path || path.length == 0) {
126
+ throw new Error('You should specify the path for the edit column');
127
+ }
128
+ }
129
+
130
+ /** @private */
131
+ _cellsChanged() {
132
+ this._cells.forEach((cell) => {
133
+ const part = cell.getAttribute('part');
134
+ if (part.indexOf('editable-cell') < 0) {
135
+ cell.setAttribute('part', part + ' editable-cell');
136
+ }
137
+ });
138
+ }
139
+
140
+ /** @private */
141
+ _editModeRendererChanged(renderer) {
142
+ if (renderer) {
143
+ this.editorType = 'custom';
144
+ } else if (this._oldRenderer) {
145
+ this.editorType = 'text';
146
+ }
147
+
148
+ this._oldRenderer = renderer;
149
+ }
150
+
151
+ /**
152
+ * @param {!HTMLElement} cell
153
+ * @return {string}
154
+ * @protected
155
+ */
156
+ _getEditorTagName(cell) {
157
+ return this.editorType === 'custom' ? this._getEditorComponent(cell).localName : this._getTagNameByType();
158
+ }
159
+
160
+ /**
161
+ * @param {!HTMLElement} cell
162
+ * @return {HTMLElement | null}
163
+ * @protected
164
+ */
165
+ _getEditorComponent(cell) {
166
+ return this.editorType === 'custom'
167
+ ? cell._content.firstElementChild
168
+ : cell._content.querySelector(this._getEditorTagName(cell));
169
+ }
170
+
171
+ /** @private */
172
+ _getTagNameByType() {
173
+ let type;
174
+ switch (this.editorType) {
175
+ case 'checkbox':
176
+ type = 'checkbox';
177
+ break;
178
+ case 'select':
179
+ type = 'select';
180
+ break;
181
+ case 'text':
182
+ default:
183
+ type = 'text-field';
184
+ break;
185
+ }
186
+ return this.constructor.is.replace('column', type);
187
+ }
188
+
189
+ /** @private */
190
+ _focusEditor(editor) {
191
+ editor.focus();
192
+ if (this.editorType === 'checkbox') {
193
+ editor.setAttribute('focus-ring', '');
194
+ } else if (editor instanceof HTMLInputElement) {
195
+ editor.select();
196
+ } else if (editor.focusElement && editor.focusElement instanceof HTMLInputElement) {
197
+ editor.focusElement.select();
198
+ }
199
+ }
200
+
201
+ /**
202
+ * @param {!HTMLElement} editor
203
+ * @return {unknown}
204
+ * @protected
205
+ */
206
+ _getEditorValue(editor) {
207
+ const path = this.editorType === 'checkbox' ? 'checked' : this.editorValuePath;
208
+ return get(editor, path);
209
+ }
210
+
211
+ /** @private */
212
+ _renderEditor(cell, model) {
213
+ cell.__savedRenderer = this._renderer || cell._renderer;
214
+ cell._renderer = this.editModeRenderer || this.__editModeRenderer;
215
+
216
+ this._clearCellContent(cell);
217
+ this._runRenderer(cell._renderer, cell, model);
218
+ }
219
+
220
+ /** @private */
221
+ _removeEditor(cell, _model) {
222
+ if (!cell.__savedRenderer) return;
223
+
224
+ cell._renderer = cell.__savedRenderer;
225
+ cell.__savedRenderer = undefined;
226
+
227
+ this._clearCellContent(cell);
228
+
229
+ const row = cell.parentElement;
230
+ this._grid._updateItem(row, row._item);
231
+ }
232
+
233
+ /** @private */
234
+ _setEditorOptions(editor) {
235
+ if (this.editorOptions && this.editorOptions.length) {
236
+ editor.options = this.editorOptions;
237
+ }
238
+ }
239
+
240
+ /** @private */
241
+ _setEditorValue(editor, value) {
242
+ const path = this.editorType === 'checkbox' ? 'checked' : this.editorValuePath;
243
+ // FIXME(yuriy): Required for the flow counterpart as it is passing the string value to webcomponent
244
+ value = this.editorType === 'checkbox' && typeof value === 'string' ? value == 'true' : value;
245
+ set(editor, path, value);
246
+ editor.notifyPath && editor.notifyPath(path, value);
247
+ }
248
+
249
+ /**
250
+ * @param {!HTMLElement} cell
251
+ * @param {!GridItemModel} model
252
+ * @protected
253
+ */
254
+ _startCellEdit(cell, model) {
255
+ this._renderEditor(cell, model);
256
+
257
+ const editor = this._getEditorComponent(cell);
258
+ editor.addEventListener('focusout', this._grid.__boundEditorFocusOut);
259
+ editor.addEventListener('focusin', this._grid.__boundEditorFocusIn);
260
+ editor.addEventListener('internal-tab', this._grid.__boundCancelCellSwitch);
261
+ document.body.addEventListener('focusin', this._grid.__boundGlobalFocusIn);
262
+ this._setEditorOptions(editor);
263
+ this._setEditorValue(editor, get(model.item, this.path));
264
+ editor._grid = this._grid;
265
+ this._focusEditor(editor);
266
+ }
267
+
268
+ /**
269
+ * @param {!HTMLElement} cell
270
+ * @param {!GridItemModel} model
271
+ * @protected
272
+ */
273
+ _stopCellEdit(cell, model) {
274
+ document.body.removeEventListener('focusin', this._grid.__boundGlobalFocusIn);
275
+
276
+ this._removeEditor(cell, model);
277
+ }
278
+ }
279
+
280
+ customElements.define(GridProEditColumn.is, GridProEditColumn);
281
+
282
+ export { GridProEditColumn };
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2021 Vaadin Ltd.
4
+ * This program is available under Commercial Vaadin Developer License 4.0 (CVDLv4).
5
+ * See <a href="https://vaadin.com/license/cvdl-4.0">the website</a> for the complete license.
6
+ */
7
+ import { Select } from '@vaadin/select/src/vaadin-select.js';
8
+ import '@vaadin/item/src/vaadin-item.js';
9
+ import '@vaadin/list-box/src/vaadin-list-box.js';
10
+
11
+ /**
12
+ * An element used internally by `<vaadin-grid-pro>`. Not intended to be used separately.
13
+ *
14
+ * @extends Select
15
+ * @private
16
+ */
17
+ class GridProEditSelect extends Select {
18
+ static get is() {
19
+ return 'vaadin-grid-pro-edit-select';
20
+ }
21
+
22
+ static get properties() {
23
+ return {
24
+ options: {
25
+ type: Array,
26
+ value: () => []
27
+ },
28
+
29
+ _grid: {
30
+ type: Object
31
+ },
32
+
33
+ _initialized: {
34
+ type: Boolean
35
+ }
36
+ };
37
+ }
38
+
39
+ static get observers() {
40
+ return ['_optionsChanged(options)'];
41
+ }
42
+
43
+ ready() {
44
+ super.ready();
45
+
46
+ this.setAttribute('theme', 'grid-pro-editor');
47
+
48
+ this.__boundOnKeyDown = this.__onOverlayKeyDown.bind(this);
49
+ this._overlayElement.addEventListener('keydown', this.__boundOnKeyDown);
50
+ }
51
+
52
+ _onKeyDown(e) {
53
+ super._onKeyDown(e);
54
+
55
+ if (this.options.length === 0 && /^(ArrowDown|Down|ArrowUp|Up|Enter|SpaceBar| )$/.test(e.key)) {
56
+ console.warn('Missing "editorOptions" for <vaadin-grid-pro-edit-column> select editor!');
57
+ }
58
+ // Event handled in select, stop here
59
+ if (e.defaultPrevented) {
60
+ e.stopPropagation();
61
+ }
62
+ }
63
+
64
+ __onOverlayKeyDown(e) {
65
+ if (e.keyCode === 9) {
66
+ !this._grid.singleCellEdit && this._grid._switchEditCell(e);
67
+ }
68
+ }
69
+
70
+ _valueChanged(value, oldValue) {
71
+ super._valueChanged(value, oldValue);
72
+
73
+ // select is first created without a value
74
+ if (value === '' && oldValue === undefined) {
75
+ return;
76
+ }
77
+ if (this._initialized) {
78
+ const enter = this._enterKeydown;
79
+ if (enter && this._grid.enterNextRow) {
80
+ this._grid._switchEditCell(enter);
81
+ } else if (this._grid.singleCellEdit) {
82
+ this._grid._stopEdit(false, true);
83
+ } else {
84
+ this.focus();
85
+ }
86
+ }
87
+ }
88
+
89
+ _optionsChanged(options) {
90
+ if (options && options.length) {
91
+ this.renderer = (root) => {
92
+ if (root.firstChild) {
93
+ return;
94
+ }
95
+ const listBox = document.createElement('vaadin-list-box');
96
+ listBox.selected = options.indexOf(this.value);
97
+ options.forEach((option) => {
98
+ const item = document.createElement('vaadin-item');
99
+ item.textContent = option;
100
+ listBox.appendChild(item);
101
+ });
102
+
103
+ // save the "keydown" event for Enter
104
+ listBox.addEventListener('keydown', (e) => {
105
+ if (e.keyCode === 13) {
106
+ this._enterKeydown = e;
107
+ }
108
+ });
109
+
110
+ root.appendChild(listBox);
111
+ };
112
+
113
+ this._overlayElement.addEventListener('vaadin-overlay-outside-click', () => {
114
+ this._grid._stopEdit();
115
+ });
116
+
117
+ // FIXME(web-padawan): _updateValueSlot() in `vaadin-select` resets opened to false
118
+ // see https://github.com/vaadin/vaadin-list-mixin/issues/49
119
+ setTimeout(() => {
120
+ this.opened = true;
121
+ // any value change after first open will stop edit
122
+ this._initialized = true;
123
+ });
124
+ }
125
+ }
126
+ }
127
+
128
+ customElements.define(GridProEditSelect.is, GridProEditSelect);
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2021 Vaadin Ltd.
4
+ * This program is available under Commercial Vaadin Developer License 4.0 (CVDLv4).
5
+ * See <a href="https://vaadin.com/license/cvdl-4.0">the website</a> for the complete license.
6
+ */
7
+ import { TextField } from '@vaadin/text-field/src/vaadin-text-field.js';
8
+
9
+ /**
10
+ * An element used internally by `<vaadin-grid-pro>`. Not intended to be used separately.
11
+ *
12
+ * @extends TextField
13
+ * @private
14
+ */
15
+ class GridProEditText extends TextField {
16
+ static get is() {
17
+ return 'vaadin-grid-pro-edit-text-field';
18
+ }
19
+
20
+ ready() {
21
+ super.ready();
22
+ this.setAttribute('theme', 'grid-pro-editor');
23
+ }
24
+ }
25
+
26
+ customElements.define(GridProEditText.is, GridProEditText);
@@ -0,0 +1,40 @@
1
+ declare function InlineEditingMixin<T extends new (...args: any[]) => {}>(base: T): T & InlineEditingMixinConstructor;
2
+
3
+ interface InlineEditingMixinConstructor {
4
+ new (...args: any[]): InlineEditingMixin;
5
+ }
6
+
7
+ interface InlineEditingMixin {
8
+ /**
9
+ * When true, pressing Enter while in cell edit mode
10
+ * will move focus to the editable cell in the next row
11
+ * (Shift + Enter - same, but for previous row).
12
+ * @attr {boolean} enter-next-row
13
+ */
14
+ enterNextRow: boolean | null | undefined;
15
+
16
+ /**
17
+ * When true, after moving to next or previous editable cell using
18
+ * Tab / Shift+Tab, it will be focused without edit mode.
19
+ *
20
+ * When `enterNextRow` is true, pressing Enter will also
21
+ * preserve edit mode, otherwise, it will have no effect.
22
+ * @attr {boolean} single-cell-edit
23
+ */
24
+ singleCellEdit: boolean | null | undefined;
25
+
26
+ /**
27
+ * When true, the grid enters cell edit mode on a single click
28
+ * instead of the default double click.
29
+ * @attr {boolean} edit-on-click
30
+ */
31
+ editOnClick: boolean | null | undefined;
32
+
33
+ _checkImports(): void;
34
+
35
+ _stopEdit(shouldCancel?: boolean, shouldRestoreFocus?: boolean): void;
36
+
37
+ _switchEditCell(e: KeyboardEvent): void;
38
+ }
39
+
40
+ export { InlineEditingMixin, InlineEditingMixinConstructor };