@vaadin/crud 23.3.3 → 24.0.0-alpha10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/crud",
3
- "version": "23.3.3",
3
+ "version": "24.0.0-alpha10",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -37,16 +37,16 @@
37
37
  "dependencies": {
38
38
  "@open-wc/dedupe-mixin": "^1.3.0",
39
39
  "@polymer/polymer": "^3.0.0",
40
- "@vaadin/button": "~23.3.3",
41
- "@vaadin/component-base": "~23.3.3",
42
- "@vaadin/confirm-dialog": "~23.3.3",
43
- "@vaadin/dialog": "~23.3.3",
44
- "@vaadin/form-layout": "~23.3.3",
45
- "@vaadin/grid": "~23.3.3",
46
- "@vaadin/text-field": "~23.3.3",
47
- "@vaadin/vaadin-lumo-styles": "~23.3.3",
48
- "@vaadin/vaadin-material-styles": "~23.3.3",
49
- "@vaadin/vaadin-themable-mixin": "~23.3.3"
40
+ "@vaadin/button": "24.0.0-alpha10",
41
+ "@vaadin/component-base": "24.0.0-alpha10",
42
+ "@vaadin/confirm-dialog": "24.0.0-alpha10",
43
+ "@vaadin/dialog": "24.0.0-alpha10",
44
+ "@vaadin/form-layout": "24.0.0-alpha10",
45
+ "@vaadin/grid": "24.0.0-alpha10",
46
+ "@vaadin/text-field": "24.0.0-alpha10",
47
+ "@vaadin/vaadin-lumo-styles": "24.0.0-alpha10",
48
+ "@vaadin/vaadin-material-styles": "24.0.0-alpha10",
49
+ "@vaadin/vaadin-themable-mixin": "24.0.0-alpha10"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@esm-bundle/chai": "^4.3.4",
@@ -58,5 +58,5 @@
58
58
  "web-types.json",
59
59
  "web-types.lit.json"
60
60
  ],
61
- "gitHead": "1529ed623e053d28a3c1c66af55ebe402743ddd0"
61
+ "gitHead": "2e04534d8b47bcd216f89b5f849bafef1a73b174"
62
62
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -41,7 +41,7 @@ class CrudEditColumn extends GridColumn {
41
41
  */
42
42
  width: {
43
43
  type: String,
44
- value: '4em',
44
+ value: '4rem',
45
45
  },
46
46
 
47
47
  /**
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import '@vaadin/text-field/src/vaadin-text-field.js';
12
12
  import { FormLayout } from '@vaadin/form-layout/src/vaadin-form-layout.js';
13
+ import { capitalize } from './vaadin-crud-helpers.js';
13
14
  import { IncludedMixin } from './vaadin-crud-include-mixin.js';
14
15
 
15
16
  /**
@@ -62,7 +63,7 @@ class CrudForm extends IncludedMixin(FormLayout) {
62
63
  /** @private */
63
64
  __createField(parent, path) {
64
65
  const field = document.createElement('vaadin-text-field');
65
- field.label = this.__capitalize(path);
66
+ field.label = capitalize(path);
66
67
  field.path = path;
67
68
  field.required = true;
68
69
  parent.appendChild(field);
@@ -87,29 +88,6 @@ class CrudForm extends IncludedMixin(FormLayout) {
87
88
  this._fields = undefined;
88
89
  }
89
90
  }
90
-
91
- /** @private */
92
- __capitalize(path) {
93
- return path
94
- .toLowerCase()
95
- .replace(/([^\w]+)/g, ' ')
96
- .trim()
97
- .replace(/^./, (c) => c.toUpperCase());
98
- }
99
-
100
- /** @private */
101
- __set(path, val, obj) {
102
- if (obj && path) {
103
- path
104
- .split('.')
105
- .slice(0, -1)
106
- .reduce((o, p) => {
107
- o[p] = o[p] || {};
108
- return o[p];
109
- }, obj);
110
- this.set(path, val, obj);
111
- }
112
- }
113
91
  }
114
92
 
115
93
  customElements.define(CrudForm.is, CrudForm);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -14,6 +14,7 @@ import '@vaadin/grid/src/vaadin-grid-sorter.js';
14
14
  import '@vaadin/grid/src/vaadin-grid-filter.js';
15
15
  import './vaadin-crud-edit-column.js';
16
16
  import { Grid } from '@vaadin/grid/src/vaadin-grid.js';
17
+ import { capitalize, getProperty } from './vaadin-crud-helpers.js';
17
18
  import { IncludedMixin } from './vaadin-crud-include-mixin.js';
18
19
 
19
20
  /**
@@ -73,13 +74,15 @@ class CrudGrid extends IncludedMixin(Grid) {
73
74
 
74
75
  /** @private */
75
76
  __toggleEditColumn() {
76
- const el = this.querySelector('vaadin-crud-edit-column');
77
+ let editColumn = this.querySelector('vaadin-crud-edit-column');
77
78
  if (this.hideEditColumn) {
78
- if (el) {
79
- this.removeChild(el);
79
+ if (editColumn) {
80
+ this.removeChild(editColumn);
80
81
  }
81
- } else if (!el) {
82
- this.appendChild(document.createElement('vaadin-crud-edit-column'));
82
+ } else if (!editColumn) {
83
+ editColumn = document.createElement('vaadin-crud-edit-column');
84
+ editColumn.frozenToEnd = true;
85
+ this.appendChild(editColumn);
83
86
  }
84
87
  }
85
88
 
@@ -146,10 +149,10 @@ class CrudGrid extends IncludedMixin(Grid) {
146
149
  _generateHeader(path) {
147
150
  return path
148
151
  .substr(path.lastIndexOf('.') + 1)
149
- .replace(/([A-Z])/g, '-$1')
152
+ .replace(/([A-Z])/gu, '-$1')
150
153
  .toLowerCase()
151
- .replace(/-/g, ' ')
152
- .replace(/^./, (match) => match.toUpperCase());
154
+ .replace(/-/gu, ' ')
155
+ .replace(/^./u, (match) => match.toUpperCase());
153
156
  }
154
157
 
155
158
  /** @private */
@@ -167,7 +170,7 @@ class CrudGrid extends IncludedMixin(Grid) {
167
170
  col = document.createElement('vaadin-grid-column');
168
171
  parent.appendChild(col);
169
172
  col.renderer = (root, _column, model) => {
170
- root.textContent = path ? this.get(path, model.item) : model.item;
173
+ root.textContent = path ? getProperty(path, model.item) : model.item;
171
174
  };
172
175
  }
173
176
 
@@ -199,7 +202,6 @@ class CrudGrid extends IncludedMixin(Grid) {
199
202
 
200
203
  const textField = window.document.createElement('vaadin-text-field');
201
204
  textField.setAttribute('theme', 'small');
202
- textField.setAttribute('slot', 'filter');
203
205
  textField.setAttribute('focus-target', true);
204
206
  textField.style.width = '100%';
205
207
  if (this.noSort) {
@@ -266,34 +268,11 @@ class CrudGrid extends IncludedMixin(Grid) {
266
268
  __createGroup(parent, header) {
267
269
  const grp = document.createElement('vaadin-grid-column-group');
268
270
  if (header) {
269
- grp.header = this.__capitalize(header);
271
+ grp.header = capitalize(header);
270
272
  }
271
273
  parent.appendChild(grp);
272
274
  return grp;
273
275
  }
274
-
275
- /** @private */
276
- __capitalize(path) {
277
- return path
278
- .toLowerCase()
279
- .replace(/([^\w]+)/g, ' ')
280
- .trim()
281
- .replace(/^./, (c) => c.toUpperCase());
282
- }
283
-
284
- /** @private */
285
- __set(path, val, obj) {
286
- if (obj && path) {
287
- path
288
- .split('.')
289
- .slice(0, -1)
290
- .reduce((o, p) => {
291
- o[p] = o[p] || {};
292
- return o[p];
293
- }, obj);
294
- this.set(path, val, obj);
295
- }
296
- }
297
276
  }
298
277
 
299
278
  customElements.define(CrudGrid.is, CrudGrid);
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
+ *
5
+ * This program is available under Vaadin Commercial License and Service Terms.
6
+ *
7
+ *
8
+ * See https://vaadin.com/commercial-license-and-service-terms for the full
9
+ * license.
10
+ */
11
+
12
+ /**
13
+ * Convenience utility for capitalizing a string, with
14
+ * replacing non-alphanumeric characters with spaces.
15
+ */
16
+ export function capitalize(path: string): string;
17
+
18
+ /**
19
+ * Convenience method for reading a value from a path.
20
+ */
21
+ export function getProperty(path: string, obj: Record<string, unknown>): unknown;
22
+
23
+ /**
24
+ * Convenience utility for setting a value to a path.
25
+ *
26
+ * Note, if any part in the path is undefined, this
27
+ * function initializes it with an empty object.
28
+ */
29
+ export function setProperty(path: string, value: unknown, obj: Record<string, unknown>): void;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
+ *
5
+ * This program is available under Vaadin Commercial License and Service Terms.
6
+ *
7
+ *
8
+ * See https://vaadin.com/commercial-license-and-service-terms for the full
9
+ * license.
10
+ */
11
+ import { get, set } from '@polymer/polymer/lib/utils/path.js';
12
+
13
+ /**
14
+ * Convenience utility for capitalizing a string, with
15
+ * replacing non-alphanumeric characters with spaces.
16
+ *
17
+ * @param {string} path
18
+ * @return {string}
19
+ */
20
+ export function capitalize(path) {
21
+ return path
22
+ .toLowerCase()
23
+ .replace(/([^\w]+)/gu, ' ')
24
+ .trim()
25
+ .replace(/^./u, (c) => c.toUpperCase());
26
+ }
27
+
28
+ /**
29
+ * Convenience utility for reading a value from a path.
30
+ *
31
+ * @param {string} path
32
+ * @param {Object} obj
33
+ * @return {*}
34
+ */
35
+ export function getProperty(path, obj) {
36
+ return get(obj, path);
37
+ }
38
+
39
+ /**
40
+ * Convenience utility for setting a value to a path.
41
+ *
42
+ * Note, if any part in the path is undefined, this
43
+ * function initializes it with an empty object.
44
+ *
45
+ * @param {string} path
46
+ * @param {*} value
47
+ * @param {Object} obj
48
+ */
49
+ export function setProperty(path, value, obj) {
50
+ if (obj && path) {
51
+ path
52
+ .split('.')
53
+ .slice(0, -1)
54
+ .reduce((o, p) => {
55
+ // Create an object
56
+ if (!o[p]) {
57
+ o[p] = {};
58
+ }
59
+ return o[p];
60
+ }, obj);
61
+
62
+ set(obj, path, value);
63
+ }
64
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -8,6 +8,7 @@
8
8
  * See https://vaadin.com/commercial-license-and-service-terms for the full
9
9
  * license.
10
10
  */
11
+ import { setProperty } from './vaadin-crud-helpers.js';
11
12
 
12
13
  /**
13
14
  * @polymerMixin
@@ -46,17 +47,19 @@ export const IncludedMixin = (superClass) =>
46
47
  /** @private */
47
48
  __onExcludeChange(exclude) {
48
49
  if (typeof exclude === 'string') {
49
- this.exclude = exclude ? RegExp(exclude.replace(/, */g, '|'), 'i') : undefined;
50
+ this.exclude = exclude ? RegExp(exclude.replace(/, */gu, '|'), 'iu') : undefined;
50
51
  }
51
52
  }
52
53
 
53
54
  /** @private */
54
55
  __onIncludeChange(include) {
55
56
  if (typeof include === 'string') {
56
- this.include = include ? include.split(/, */) : undefined;
57
+ this.include = include ? include.split(/, */u) : undefined;
57
58
  } else if (!this._fields && Array.isArray(include)) {
58
59
  const item = {};
59
- this.include.forEach((path) => this.__set(path, null, item));
60
+ this.include.forEach((path) => {
61
+ setProperty(path, null, item);
62
+ });
60
63
  this._configure(item);
61
64
  }
62
65
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -176,7 +176,8 @@ export type CrudEventMap<T> = CrudCustomEventMap<T> & HTMLElementEventMap;
176
176
  * `save-button` | To replace the "Save" button.
177
177
  * `cancel-button`| To replace the "Cancel" button.
178
178
  * `delete-button`| To replace the "Delete" button.
179
- * `toolbar` | To replace the toolbar content. Add an element with the attribute `new-button` for the new item action.
179
+ * `toolbar` | To provide the toolbar content (by default, it's empty).
180
+ * `new-button` | To replace the "New item" button.
180
181
  *
181
182
  * #### Example:
182
183
  *
@@ -193,10 +194,8 @@ export type CrudEventMap<T> = CrudCustomEventMap<T> & HTMLElementEventMap;
193
194
  * <vaadin-text-field label="Surname" path="surname"></vaadin-text-field>
194
195
  * </vaadin-form-layout>
195
196
  *
196
- * <div slot="toolbar">
197
- * Total singers: [[size]]
198
- * <button new-button>New singer</button>
199
- * </div>
197
+ * <div slot="toolbar">Total singers: 2</div>
198
+ * <button slot="new-button">New singer</button>
200
199
  *
201
200
  * <button slot="save-button">Save changes</button>
202
201
  * <button slot="cancel-button">Discard changes</button>
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2000 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2000 - 2023 Vaadin Ltd.
4
4
  *
5
5
  * This program is available under Vaadin Commercial License and Service Terms.
6
6
  *
@@ -20,8 +20,23 @@ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
20
20
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
21
21
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
22
22
  import { MediaQueryController } from '@vaadin/component-base/src/media-query-controller.js';
23
- import { SlotMixin } from '@vaadin/component-base/src/slot-mixin.js';
23
+ import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
24
24
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
25
+ import { getProperty, setProperty } from './vaadin-crud-helpers.js';
26
+
27
+ /**
28
+ * @private
29
+ * A to initialize slotted button.
30
+ */
31
+ class ButtonSlotController extends SlotController {
32
+ constructor(host, type, theme) {
33
+ super(host, `${type}-button`, 'vaadin-button', {
34
+ initializer: (button) => {
35
+ button.setAttribute('theme', theme);
36
+ },
37
+ });
38
+ }
39
+ }
25
40
 
26
41
  /**
27
42
  * `<vaadin-crud>` is a Web Component for [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations.
@@ -79,7 +94,8 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
79
94
  * `save-button` | To replace the "Save" button.
80
95
  * `cancel-button`| To replace the "Cancel" button.
81
96
  * `delete-button`| To replace the "Delete" button.
82
- * `toolbar` | To replace the toolbar content. Add an element with the attribute `new-button` for the new item action.
97
+ * `toolbar` | To provide the toolbar content (by default, it's empty).
98
+ * `new-button` | To replace the "New item" button.
83
99
  *
84
100
  * #### Example:
85
101
  *
@@ -96,10 +112,8 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
96
112
  * <vaadin-text-field label="Surname" path="surname"></vaadin-text-field>
97
113
  * </vaadin-form-layout>
98
114
  *
99
- * <div slot="toolbar">
100
- * Total singers: [[size]]
101
- * <button new-button>New singer</button>
102
- * </div>
115
+ * <div slot="toolbar">Total singers: 2</div>
116
+ * <button slot="new-button">New singer</button>
103
117
  *
104
118
  * <button slot="save-button">Save changes</button>
105
119
  * <button slot="cancel-button">Discard changes</button>
@@ -169,10 +183,9 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
169
183
  * @extends HTMLElement
170
184
  * @mixes ControllerMixin
171
185
  * @mixes ElementMixin
172
- * @mixes SlotMixin
173
186
  * @mixes ThemableMixin
174
187
  */
175
- class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerElement)))) {
188
+ class Crud extends ControllerMixin(ElementMixin(ThemableMixin(PolymerElement))) {
176
189
  static get template() {
177
190
  return html`
178
191
  <style>
@@ -258,23 +271,11 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
258
271
 
259
272
  <div id="container">
260
273
  <div id="main">
261
- <slot name="grid">
262
- <vaadin-crud-grid
263
- theme$="[[_theme]]"
264
- id="grid"
265
- include="[[include]]"
266
- exclude="[[exclude]]"
267
- no-sort="[[noSort]]"
268
- no-filter="[[noFilter]]"
269
- no-head="[[noHead]]"
270
- hide-edit-column="[[editOnClick]]"
271
- ></vaadin-crud-grid>
272
- </slot>
273
-
274
- <div id="toolbar" part="toolbar" on-click="__new">
275
- <slot name="toolbar">
276
- <vaadin-button new-button="" id="new" theme="primary">[[i18n.newItem]]</vaadin-button>
277
- </slot>
274
+ <slot name="grid"></slot>
275
+
276
+ <div id="toolbar" part="toolbar">
277
+ <slot name="toolbar"></slot>
278
+ <slot name="new-button"></slot>
278
279
  </div>
279
280
  </div>
280
281
 
@@ -308,7 +309,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
308
309
  theme$="[[_theme]]"
309
310
  id="confirmCancel"
310
311
  on-confirm="__confirmCancel"
311
- cancel
312
+ cancel-button-visible
312
313
  confirm-text="[[i18n.confirm.cancel.button.confirm]]"
313
314
  cancel-text="[[i18n.confirm.cancel.button.dismiss]]"
314
315
  header="[[i18n.confirm.cancel.title]]"
@@ -320,7 +321,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
320
321
  theme$="[[_theme]]"
321
322
  id="confirmDelete"
322
323
  on-confirm="__confirmDelete"
323
- cancel
324
+ cancel-button-visible
324
325
  confirm-text="[[i18n.confirm.delete.button.confirm]]"
325
326
  cancel-text="[[i18n.confirm.delete.button.dismiss]]"
326
327
  header="[[i18n.confirm.delete.title]]"
@@ -345,7 +346,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
345
346
  * @private
346
347
  */
347
348
  _grid: {
348
- type: HTMLElement,
349
+ type: Object,
349
350
  observer: '__gridChanged',
350
351
  },
351
352
 
@@ -354,7 +355,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
354
355
  * @private
355
356
  */
356
357
  _form: {
357
- type: HTMLElement,
358
+ type: Object,
358
359
  observer: '__formChanged',
359
360
  },
360
361
 
@@ -363,34 +364,39 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
363
364
  * @private
364
365
  */
365
366
  _saveButton: {
366
- type: HTMLElement,
367
- observer: '__saveButtonChanged',
367
+ type: Object,
368
368
  },
369
369
 
370
370
  /**
371
- * A reference to the save button which will be teleported to the dialog
371
+ * A reference to the delete button which will be teleported to the dialog
372
372
  * @private
373
373
  */
374
374
  _deleteButton: {
375
- type: HTMLElement,
376
- observer: '__deleteButtonChanged',
375
+ type: Object,
377
376
  },
378
377
 
379
378
  /**
380
- * A reference to the save button which will be teleported to the dialog
379
+ * A reference to the cancel button which will be teleported to the dialog
381
380
  * @private
382
381
  */
383
382
  _cancelButton: {
384
- type: HTMLElement,
385
- observer: '__cancelButtonChanged',
383
+ type: Object,
386
384
  },
387
385
 
388
386
  /**
389
- * A reference to the editor header element will be teleported to the dialog.
387
+ * A reference to the default editor header element created by the CRUD
390
388
  * @private
391
389
  */
392
- _headerNode: {
393
- type: HTMLElement,
390
+ _defaultHeader: {
391
+ type: Object,
392
+ },
393
+
394
+ /**
395
+ * A reference to the "New item" button
396
+ * @private
397
+ */
398
+ _newButton: {
399
+ type: Object,
394
400
  },
395
401
 
396
402
  /**
@@ -629,13 +635,15 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
629
635
 
630
636
  static get observers() {
631
637
  return [
632
- '__headerPropsChanged(_headerNode, __isNew, i18n.newItem, i18n.editItem)',
638
+ '__headerPropsChanged(_defaultHeader, __isNew, i18n.newItem, i18n.editItem)',
633
639
  '__formPropsChanged(_form, _theme, include, exclude)',
640
+ '__gridPropsChanged(_grid, _theme, include, exclude, noFilter, noHead, noSort)',
634
641
  '__i18nChanged(i18n, _grid)',
635
642
  '__editOnClickChanged(editOnClick, _grid)',
636
643
  '__saveButtonPropsChanged(_saveButton, i18n.saveItem, __isDirty)',
637
644
  '__cancelButtonPropsChanged(_cancelButton, i18n.cancel)',
638
645
  '__deleteButtonPropsChanged(_deleteButton, i18n.deleteItem, __isNew)',
646
+ '__newButtonPropsChanged(_newButton, i18n.newItem)',
639
647
  ];
640
648
  }
641
649
 
@@ -644,59 +652,66 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
644
652
  return ['bottom', 'aside'].includes(editorPosition);
645
653
  }
646
654
 
647
- /** @protected */
648
- get slots() {
649
- // NOTE: order in which the toolbar buttons are listed matters.
650
- return {
651
- ...super.slots,
652
- header: () => {
653
- return document.createElement('h3');
654
- },
655
- form: () => {
656
- return document.createElement('vaadin-crud-form');
657
- },
658
- 'save-button': () => {
659
- const button = document.createElement('vaadin-button');
660
- button.id = 'save';
661
- button.setAttribute('theme', 'primary');
662
- return button;
663
- },
664
- 'cancel-button': () => {
665
- const button = document.createElement('vaadin-button');
666
- button.id = 'cancel';
667
- button.setAttribute('theme', 'tertiary');
668
- return button;
669
- },
670
- 'delete-button': () => {
671
- const button = document.createElement('vaadin-button');
672
- button.id = 'delete';
673
- button.setAttribute('theme', 'tertiary error');
674
- return button;
675
- },
676
- };
677
- }
678
-
679
655
  constructor() {
680
656
  super();
657
+
658
+ this.__cancel = this.__cancel.bind(this);
659
+ this.__delete = this.__delete.bind(this);
660
+ this.__save = this.__save.bind(this);
661
+ this.__new = this.__new.bind(this);
662
+ this.__onFormChange = this.__onFormChange.bind(this);
663
+ this.__onGridEdit = this.__onGridEdit.bind(this);
664
+ this.__onGridSizeChanged = this.__onGridSizeChanged.bind(this);
665
+ this.__onGridActiveItemChanged = this.__onGridActiveItemChanged.bind(this);
666
+
681
667
  this._observer = new FlattenedNodesObserver(this, (info) => {
682
668
  this.__onDomChange(info.addedNodes);
683
669
  });
684
670
  }
685
671
 
672
+ /** @protected */
673
+ get _headerNode() {
674
+ return this._headerController && this._headerController.node;
675
+ }
676
+
677
+ /**
678
+ * A reference to all fields inside the [`_form`](#/elements/vaadin-crud#property-_form) element
679
+ * @return {!Array<!HTMLElement>}
680
+ * @protected
681
+ */
682
+ get _fields() {
683
+ if (!this.__fields || !this.__fields.length) {
684
+ this.__fields = Array.from(this._form.querySelectorAll('*')).filter((e) => e.validate || e.checkValidity);
685
+ }
686
+ return this.__fields;
687
+ }
688
+
686
689
  /** @protected */
687
690
  ready() {
688
691
  super.ready();
689
- this.__save = this.__save.bind(this);
690
- this.__cancel = this.__cancel.bind(this);
691
- this.__delete = this.__delete.bind(this);
692
- this.__onFormChange = this.__onFormChange.bind(this);
693
- this.__onGridEdit = this.__onGridEdit.bind(this);
694
- this.__onGridSizeChanged = this.__onGridSizeChanged.bind(this);
695
- this.__onGridActiveItemChanged = this.__onGridActiveItemChanged.bind(this);
696
- this._grid = this.$.grid;
692
+
697
693
  this.$.dialog.$.overlay.addEventListener('vaadin-overlay-outside-click', this.__cancel);
698
694
  this.$.dialog.$.overlay.addEventListener('vaadin-overlay-escape-press', this.__cancel);
699
695
 
696
+ this._headerController = new SlotController(this, 'header', 'h3', {
697
+ initializer: (node) => {
698
+ this._defaultHeader = node;
699
+ },
700
+ });
701
+ this.addController(this._headerController);
702
+
703
+ this._gridController = new SlotController(this, 'grid', 'vaadin-crud-grid');
704
+ this.addController(this._gridController);
705
+
706
+ this.addController(new SlotController(this, 'form', 'vaadin-crud-form'));
707
+
708
+ this.addController(new ButtonSlotController(this, 'new', 'primary'));
709
+
710
+ // NOTE: order in which buttons are added should match the order of slots in template
711
+ this.addController(new ButtonSlotController(this, 'save', 'primary'));
712
+ this.addController(new ButtonSlotController(this, 'cancel', 'tertiary'));
713
+ this.addController(new ButtonSlotController(this, 'delete', 'tertiary error'));
714
+
700
715
  this.addController(
701
716
  new MediaQueryController(this._fullscreenMediaQuery, (matches) => {
702
717
  this._fullscreen = matches;
@@ -849,7 +864,8 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
849
864
  /** @private */
850
865
  __onDomChange(addedNodes) {
851
866
  // TODO: restore default button when a corresponding slotted button is removed.
852
- // Consider creating a controller to reuse custom helper logic from FieldMixin.
867
+ // This would require us to detect where to insert a button after teleporting it,
868
+ // which happens after opening a dialog and closing it (default editor position).
853
869
  addedNodes
854
870
  .filter((node) => node.nodeType === Node.ELEMENT_NODE)
855
871
  .forEach((node) => {
@@ -867,9 +883,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
867
883
  this._form = node;
868
884
  } else if (slotAttributeValue.indexOf('button') >= 0) {
869
885
  const [button] = slotAttributeValue.split('-');
870
- this[`_${button}Button`] = node;
871
- } else if (slotAttributeValue === 'header') {
872
- this._headerNode = node;
886
+ this.__setupSlottedButton(button, node);
873
887
  }
874
888
  });
875
889
 
@@ -963,12 +977,27 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
963
977
  }
964
978
 
965
979
  /**
966
- * @param {HTMLElement} saveButton
967
- * @param {HTMLElement | undefined} oldSaveButton
980
+ * @param {HTMLElement | undefined} form
981
+ * @param {string} theme
982
+ * @param {string | string[] | undefined} include
983
+ * @param {string | RegExp} exclude
968
984
  * @private
969
985
  */
970
- __saveButtonChanged(saveButton, oldSaveButton) {
971
- this.__setupSlottedButton(saveButton, oldSaveButton, this.__save);
986
+ // eslint-disable-next-line max-params
987
+ __gridPropsChanged(grid, theme, include, exclude, noFilter, noHead, noSort) {
988
+ if (grid && grid === this._gridController.defaultNode) {
989
+ grid.include = include;
990
+ grid.exclude = exclude;
991
+ grid.noFilter = noFilter;
992
+ grid.noHead = noHead;
993
+ grid.noSort = noSort;
994
+
995
+ if (theme) {
996
+ grid.setAttribute('theme', theme);
997
+ } else {
998
+ grid.removeAttribute('theme');
999
+ }
1000
+ }
972
1001
  }
973
1002
 
974
1003
  /**
@@ -984,15 +1013,6 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
984
1013
  }
985
1014
  }
986
1015
 
987
- /**
988
- * @param {HTMLElement} deleteButton
989
- * @param {HTMLElement | undefined} oldDeleteButton
990
- * @private
991
- */
992
- __deleteButtonChanged(deleteButton, oldDeleteButton) {
993
- this.__setupSlottedButton(deleteButton, oldDeleteButton, this.__delete);
994
- }
995
-
996
1016
  /**
997
1017
  * @param {HTMLElement | undefined} deleteButton
998
1018
  * @param {string} i18nLabel
@@ -1006,15 +1026,6 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1006
1026
  }
1007
1027
  }
1008
1028
 
1009
- /**
1010
- * @param {HTMLElement} cancelButton
1011
- * @param {HTMLElement | undefined} oldCancelButton
1012
- * @private
1013
- */
1014
- __cancelButtonChanged(cancelButton, oldCancelButton) {
1015
- this.__setupSlottedButton(cancelButton, oldCancelButton, this.__cancel);
1016
- }
1017
-
1018
1029
  /**
1019
1030
  * @param {HTMLElement | undefined} saveButton
1020
1031
  * @param {string} i18nLabel
@@ -1027,17 +1038,31 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1027
1038
  }
1028
1039
 
1029
1040
  /**
1041
+ * @param {HTMLElement | undefined} newButton
1042
+ * @param {string} i18nNewItem
1043
+ * @private
1044
+ */
1045
+ __newButtonPropsChanged(newButton, i18nNewItem) {
1046
+ if (newButton) {
1047
+ newButton.textContent = i18nNewItem;
1048
+ }
1049
+ }
1050
+
1051
+ /**
1052
+ * @param {string} type
1030
1053
  * @param {HTMLElement} newButton
1031
- * @param {HTMLElement | undefined | null} oldButton
1032
- * @param {Function} clickListener
1033
1054
  * @private
1034
1055
  */
1035
- __setupSlottedButton(newButton, oldButton, clickListener) {
1036
- if (oldButton && oldButton.parentElement) {
1037
- oldButton.parentElement.removeChild(oldButton);
1056
+ __setupSlottedButton(type, button) {
1057
+ const property = `_${type}Button`;
1058
+ const listener = `__${type}`;
1059
+
1060
+ if (this[property] && this[property] !== button) {
1061
+ this[property].remove();
1038
1062
  }
1039
1063
 
1040
- newButton.addEventListener('click', clickListener);
1064
+ button.addEventListener('click', this[listener]);
1065
+ this[property] = button;
1041
1066
  }
1042
1067
 
1043
1068
  /** @private */
@@ -1048,15 +1073,17 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1048
1073
  }
1049
1074
 
1050
1075
  /** @private */
1051
- __editOnClickChanged(editOnClick, _grid) {
1052
- if (!_grid) {
1076
+ __editOnClickChanged(editOnClick, grid) {
1077
+ if (!grid) {
1053
1078
  return;
1054
1079
  }
1055
1080
 
1081
+ grid.hideEditColumn = editOnClick;
1082
+
1056
1083
  if (editOnClick) {
1057
- _grid.addEventListener('active-item-changed', this.__onGridActiveItemChanged);
1084
+ grid.addEventListener('active-item-changed', this.__onGridActiveItemChanged);
1058
1085
  } else {
1059
- _grid.removeEventListener('active-item-changed', this.__onGridActiveItemChanged);
1086
+ grid.removeEventListener('active-item-changed', this.__onGridActiveItemChanged);
1060
1087
  }
1061
1088
  }
1062
1089
 
@@ -1157,7 +1184,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1157
1184
  this._fields.forEach((e) => {
1158
1185
  const path = e.path || e.getAttribute('path');
1159
1186
  if (path) {
1160
- e.value = this.get(path, item);
1187
+ e.value = getProperty(path, item);
1161
1188
  }
1162
1189
  });
1163
1190
 
@@ -1166,18 +1193,6 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1166
1193
  }
1167
1194
  }
1168
1195
 
1169
- /**
1170
- * A reference to all fields inside the [`_form`](#/elements/vaadin-crud#property-_form) element
1171
- * @return {!Array<!HTMLElement>}
1172
- * @protected
1173
- */
1174
- get _fields() {
1175
- if (!this.__fields || !this.__fields.length) {
1176
- this.__fields = Array.from(this._form.querySelectorAll('*')).filter((e) => e.validate || e.checkValidity);
1177
- }
1178
- return this.__fields;
1179
- }
1180
-
1181
1196
  /** @private */
1182
1197
  __validate() {
1183
1198
  return this._fields.every((e) => (e.validate || e.checkValidity).call(e));
@@ -1185,7 +1200,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1185
1200
 
1186
1201
  /** @private */
1187
1202
  __setHighlightedItem(item) {
1188
- if (this._grid === this.$.grid) {
1203
+ if (this._grid === this._gridController.defaultNode) {
1189
1204
  this._grid.selectedItems = item ? [item] : [];
1190
1205
  }
1191
1206
  }
@@ -1201,11 +1216,8 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1201
1216
  }
1202
1217
 
1203
1218
  /** @private */
1204
- __new(event) {
1205
- // This allows listening to parent element and fire only when clicking on default or custom new-button.
1206
- if (event.composedPath().some((e) => e.nodeType === 1 && e.hasAttribute('new-button'))) {
1207
- this.__confirmBeforeChangingEditedItem(null, true);
1208
- }
1219
+ __new() {
1220
+ this.__confirmBeforeChangingEditedItem(null, true);
1209
1221
  }
1210
1222
 
1211
1223
  /** @private */
@@ -1241,7 +1253,7 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1241
1253
  this._fields.forEach((e) => {
1242
1254
  const path = e.path || e.getAttribute('path');
1243
1255
  if (path) {
1244
- this.__set(path, e.value, item);
1256
+ setProperty(path, e.value, item);
1245
1257
  }
1246
1258
  });
1247
1259
  const evt = this.dispatchEvent(new CustomEvent('save', { detail: { item }, cancelable: true }));
@@ -1253,7 +1265,9 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1253
1265
  this.items.push(item);
1254
1266
  }
1255
1267
  } else {
1256
- this.editedItem = this.editedItem || {};
1268
+ if (!this.editedItem) {
1269
+ this.editedItem = {};
1270
+ }
1257
1271
  Object.assign(this.editedItem, item);
1258
1272
  }
1259
1273
  this._grid.clearCache();
@@ -1295,23 +1309,6 @@ class Crud extends SlotMixin(ControllerMixin(ElementMixin(ThemableMixin(PolymerE
1295
1309
  }
1296
1310
  }
1297
1311
 
1298
- /**
1299
- * Utility method for setting nested values in JSON objects but initializing empty keys unless `Polymer.Base.set`
1300
- * @private
1301
- */
1302
- __set(path, val, obj) {
1303
- if (obj && path) {
1304
- path
1305
- .split('.')
1306
- .slice(0, -1)
1307
- .reduce((o, p) => {
1308
- o[p] = o[p] || {};
1309
- return o[p];
1310
- }, obj);
1311
- this.set(path, val, obj);
1312
- }
1313
- }
1314
-
1315
1312
  /**
1316
1313
  * Fired when user wants to edit an existing item. If the default is prevented, then
1317
1314
  * a new item is not assigned to the form, giving that responsibility to the app, though
@@ -97,13 +97,6 @@ registerStyles(
97
97
  :host([dir='rtl']) [part='toolbar'] ::slotted(*:not(:first-child)) {
98
98
  margin-right: 0.5em;
99
99
  }
100
-
101
- vaadin-text-field[theme~='small'] {
102
- height: 24px;
103
- font-size: var(--material-small-font-size);
104
- margin: 0;
105
- padding: 0;
106
- }
107
100
  `,
108
101
  ],
109
102
  { moduleId: 'material-crud' },
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/crud",
4
- "version": "23.3.3",
4
+ "version": "24.0.0-alpha10",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -295,7 +295,7 @@
295
295
  },
296
296
  {
297
297
  "name": "vaadin-crud",
298
- "description": "`<vaadin-crud>` is a Web Component for [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations.\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-items) property.\n\nA grid and an editor will be automatically generated and configured based on the data structure provided.\n\n```html\n<vaadin-crud></vaadin-crud>\n```\n```js\nconst crud = document.querySelector('vaadin-crud');\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Data Provider Function\n\nOtherwise, you can provide a [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-dataProvider) function.\n\n```js\nconst crud = document.querySelector('vaadin-crud');\n\nconst users = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n\ncrud.dataProvider = (params, callback) => {\n const chunk = users.slice(params.page * params.pageSize, params.page * params.pageSize + params.pageSize);\n callback(chunk, people.length);\n};\n```\n\nNOTE: The auto-generated editor only supports string types. If you need to handle special cases\ncustomizing the editor is discussed below.\n\n### Customization\n\nAlternatively you can fully configure the component by using `slot` names.\n\nSlot name | Description\n---------------|----------------\n`grid` | To replace the auto-generated grid with a custom one.\n`form` | To replace the auto-generated form.\n`save-button` | To replace the \"Save\" button.\n`cancel-button`| To replace the \"Cancel\" button.\n`delete-button`| To replace the \"Delete\" button.\n`toolbar` | To replace the toolbar content. Add an element with the attribute `new-button` for the new item action.\n\n#### Example:\n\n```html\n<vaadin-crud id=\"crud\">\n <vaadin-grid slot=\"grid\">\n <vaadin-crud-edit-column></vaadin-crud-edit-column>\n <vaadin-grid-column id=\"column1\"></vaadin-grid-column>\n <vaadin-grid-column id=\"column2\"></vaadin-grid-column>\n </vaadin-grid>\n\n <vaadin-form-layout slot=\"form\">\n <vaadin-text-field label=\"First\" path=\"name\"></vaadin-text-field>\n <vaadin-text-field label=\"Surname\" path=\"surname\"></vaadin-text-field>\n </vaadin-form-layout>\n\n <div slot=\"toolbar\">\n Total singers: [[size]]\n <button new-button>New singer</button>\n </div>\n\n <button slot=\"save-button\">Save changes</button>\n <button slot=\"cancel-button\">Discard changes</button>\n <button slot=\"delete-button\">Delete singer</button>\n</vaadin-crud>\n```\n```js\nconst crud = document.querySelector('#crud');\n\nconst column1 = document.querySelector('#column1');\ncolumn1.headerRenderer = (root, column) => {\n root.textContent = 'Name';\n};\ncolumn1.renderer = (root, column, model) => {\n root.textContent = model.item.name;\n};\n\nconst column2 = document.querySelector('#column2');\ncolumn2.headerRenderer = (root, column) => {\n root.textContent = 'Surname';\n};\ncolumn2.renderer = (root, column, model) => {\n root.textContent = model.item.surname;\n};\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Helpers\n\nThe following elements are used to auto-configure the grid and the editor\n- [`<vaadin-crud-edit-column>`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud-edit-column)\n- `<vaadin-crud-grid>` - can be replaced with custom [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-grid)\n- `<vaadin-crud-form>` - can be replaced with custom [`<vaadin-form-layout>`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-form-layout)\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n----------------|----------------\n`toolbar` | Toolbar container at the bottom. By default it contains the the `new` button\n\nThe following custom properties are available:\n\nCustom Property | Description | Default\n----------------|----------------\n--vaadin-crud-editor-max-height | max height of editor when opened on the bottom | 40%\n--vaadin-crud-editor-max-width | max width of editor when opened on the side | 40%\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.",
298
+ "description": "`<vaadin-crud>` is a Web Component for [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations.\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-items) property.\n\nA grid and an editor will be automatically generated and configured based on the data structure provided.\n\n```html\n<vaadin-crud></vaadin-crud>\n```\n```js\nconst crud = document.querySelector('vaadin-crud');\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Data Provider Function\n\nOtherwise, you can provide a [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-dataProvider) function.\n\n```js\nconst crud = document.querySelector('vaadin-crud');\n\nconst users = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n\ncrud.dataProvider = (params, callback) => {\n const chunk = users.slice(params.page * params.pageSize, params.page * params.pageSize + params.pageSize);\n callback(chunk, people.length);\n};\n```\n\nNOTE: The auto-generated editor only supports string types. If you need to handle special cases\ncustomizing the editor is discussed below.\n\n### Customization\n\nAlternatively you can fully configure the component by using `slot` names.\n\nSlot name | Description\n---------------|----------------\n`grid` | To replace the auto-generated grid with a custom one.\n`form` | To replace the auto-generated form.\n`save-button` | To replace the \"Save\" button.\n`cancel-button`| To replace the \"Cancel\" button.\n`delete-button`| To replace the \"Delete\" button.\n`toolbar` | To provide the toolbar content (by default, it's empty).\n`new-button` | To replace the \"New item\" button.\n\n#### Example:\n\n```html\n<vaadin-crud id=\"crud\">\n <vaadin-grid slot=\"grid\">\n <vaadin-crud-edit-column></vaadin-crud-edit-column>\n <vaadin-grid-column id=\"column1\"></vaadin-grid-column>\n <vaadin-grid-column id=\"column2\"></vaadin-grid-column>\n </vaadin-grid>\n\n <vaadin-form-layout slot=\"form\">\n <vaadin-text-field label=\"First\" path=\"name\"></vaadin-text-field>\n <vaadin-text-field label=\"Surname\" path=\"surname\"></vaadin-text-field>\n </vaadin-form-layout>\n\n <div slot=\"toolbar\">Total singers: 2</div>\n <button slot=\"new-button\">New singer</button>\n\n <button slot=\"save-button\">Save changes</button>\n <button slot=\"cancel-button\">Discard changes</button>\n <button slot=\"delete-button\">Delete singer</button>\n</vaadin-crud>\n```\n```js\nconst crud = document.querySelector('#crud');\n\nconst column1 = document.querySelector('#column1');\ncolumn1.headerRenderer = (root, column) => {\n root.textContent = 'Name';\n};\ncolumn1.renderer = (root, column, model) => {\n root.textContent = model.item.name;\n};\n\nconst column2 = document.querySelector('#column2');\ncolumn2.headerRenderer = (root, column) => {\n root.textContent = 'Surname';\n};\ncolumn2.renderer = (root, column, model) => {\n root.textContent = model.item.surname;\n};\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Helpers\n\nThe following elements are used to auto-configure the grid and the editor\n- [`<vaadin-crud-edit-column>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud-edit-column)\n- `<vaadin-crud-grid>` - can be replaced with custom [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-grid)\n- `<vaadin-crud-form>` - can be replaced with custom [`<vaadin-form-layout>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-form-layout)\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n----------------|----------------\n`toolbar` | Toolbar container at the bottom. By default it contains the the `new` button\n\nThe following custom properties are available:\n\nCustom Property | Description | Default\n----------------|----------------\n--vaadin-crud-editor-max-height | max height of editor when opened on the bottom | 40%\n--vaadin-crud-editor-max-width | max width of editor when opened on the side | 40%\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.",
299
299
  "attributes": [
300
300
  {
301
301
  "name": "editor-position",
@@ -350,7 +350,7 @@
350
350
  },
351
351
  {
352
352
  "name": "include",
353
- "description": "A comma-separated list of fields to include in the generated grid and the generated editor.\n\nIt can be used to explicitly define the field order.\n\nWhen it is defined [`exclude`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-exclude) is ignored.\n\nDefault is undefined meaning that all properties in the object should be mapped to fields.",
353
+ "description": "A comma-separated list of fields to include in the generated grid and the generated editor.\n\nIt can be used to explicitly define the field order.\n\nWhen it is defined [`exclude`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-exclude) is ignored.\n\nDefault is undefined meaning that all properties in the object should be mapped to fields.",
354
354
  "value": {
355
355
  "type": [
356
356
  "string",
@@ -361,7 +361,7 @@
361
361
  },
362
362
  {
363
363
  "name": "exclude",
364
- "description": "A comma-separated list of fields to be excluded from the generated grid and the generated editor.\n\nWhen [`include`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-include) is defined, this parameter is ignored.\n\nDefault is to exclude all private fields (those properties starting with underscore)",
364
+ "description": "A comma-separated list of fields to be excluded from the generated grid and the generated editor.\n\nWhen [`include`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-include) is defined, this parameter is ignored.\n\nDefault is to exclude all private fields (those properties starting with underscore)",
365
365
  "value": {
366
366
  "type": [
367
367
  "string",
@@ -488,7 +488,7 @@
488
488
  },
489
489
  {
490
490
  "name": "include",
491
- "description": "A comma-separated list of fields to include in the generated grid and the generated editor.\n\nIt can be used to explicitly define the field order.\n\nWhen it is defined [`exclude`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-exclude) is ignored.\n\nDefault is undefined meaning that all properties in the object should be mapped to fields.",
491
+ "description": "A comma-separated list of fields to include in the generated grid and the generated editor.\n\nIt can be used to explicitly define the field order.\n\nWhen it is defined [`exclude`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-exclude) is ignored.\n\nDefault is undefined meaning that all properties in the object should be mapped to fields.",
492
492
  "value": {
493
493
  "type": [
494
494
  "string",
@@ -499,7 +499,7 @@
499
499
  },
500
500
  {
501
501
  "name": "exclude",
502
- "description": "A comma-separated list of fields to be excluded from the generated grid and the generated editor.\n\nWhen [`include`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-include) is defined, this parameter is ignored.\n\nDefault is to exclude all private fields (those properties starting with underscore)",
502
+ "description": "A comma-separated list of fields to be excluded from the generated grid and the generated editor.\n\nWhen [`include`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-include) is defined, this parameter is ignored.\n\nDefault is to exclude all private fields (those properties starting with underscore)",
503
503
  "value": {
504
504
  "type": [
505
505
  "string",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/crud",
4
- "version": "23.3.3",
4
+ "version": "24.0.0-alpha10",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -121,7 +121,7 @@
121
121
  },
122
122
  {
123
123
  "name": "vaadin-crud",
124
- "description": "`<vaadin-crud>` is a Web Component for [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations.\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-items) property.\n\nA grid and an editor will be automatically generated and configured based on the data structure provided.\n\n```html\n<vaadin-crud></vaadin-crud>\n```\n```js\nconst crud = document.querySelector('vaadin-crud');\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Data Provider Function\n\nOtherwise, you can provide a [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-dataProvider) function.\n\n```js\nconst crud = document.querySelector('vaadin-crud');\n\nconst users = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n\ncrud.dataProvider = (params, callback) => {\n const chunk = users.slice(params.page * params.pageSize, params.page * params.pageSize + params.pageSize);\n callback(chunk, people.length);\n};\n```\n\nNOTE: The auto-generated editor only supports string types. If you need to handle special cases\ncustomizing the editor is discussed below.\n\n### Customization\n\nAlternatively you can fully configure the component by using `slot` names.\n\nSlot name | Description\n---------------|----------------\n`grid` | To replace the auto-generated grid with a custom one.\n`form` | To replace the auto-generated form.\n`save-button` | To replace the \"Save\" button.\n`cancel-button`| To replace the \"Cancel\" button.\n`delete-button`| To replace the \"Delete\" button.\n`toolbar` | To replace the toolbar content. Add an element with the attribute `new-button` for the new item action.\n\n#### Example:\n\n```html\n<vaadin-crud id=\"crud\">\n <vaadin-grid slot=\"grid\">\n <vaadin-crud-edit-column></vaadin-crud-edit-column>\n <vaadin-grid-column id=\"column1\"></vaadin-grid-column>\n <vaadin-grid-column id=\"column2\"></vaadin-grid-column>\n </vaadin-grid>\n\n <vaadin-form-layout slot=\"form\">\n <vaadin-text-field label=\"First\" path=\"name\"></vaadin-text-field>\n <vaadin-text-field label=\"Surname\" path=\"surname\"></vaadin-text-field>\n </vaadin-form-layout>\n\n <div slot=\"toolbar\">\n Total singers: [[size]]\n <button new-button>New singer</button>\n </div>\n\n <button slot=\"save-button\">Save changes</button>\n <button slot=\"cancel-button\">Discard changes</button>\n <button slot=\"delete-button\">Delete singer</button>\n</vaadin-crud>\n```\n```js\nconst crud = document.querySelector('#crud');\n\nconst column1 = document.querySelector('#column1');\ncolumn1.headerRenderer = (root, column) => {\n root.textContent = 'Name';\n};\ncolumn1.renderer = (root, column, model) => {\n root.textContent = model.item.name;\n};\n\nconst column2 = document.querySelector('#column2');\ncolumn2.headerRenderer = (root, column) => {\n root.textContent = 'Surname';\n};\ncolumn2.renderer = (root, column, model) => {\n root.textContent = model.item.surname;\n};\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Helpers\n\nThe following elements are used to auto-configure the grid and the editor\n- [`<vaadin-crud-edit-column>`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud-edit-column)\n- `<vaadin-crud-grid>` - can be replaced with custom [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-grid)\n- `<vaadin-crud-form>` - can be replaced with custom [`<vaadin-form-layout>`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-form-layout)\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n----------------|----------------\n`toolbar` | Toolbar container at the bottom. By default it contains the the `new` button\n\nThe following custom properties are available:\n\nCustom Property | Description | Default\n----------------|----------------\n--vaadin-crud-editor-max-height | max height of editor when opened on the bottom | 40%\n--vaadin-crud-editor-max-width | max width of editor when opened on the side | 40%\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.",
124
+ "description": "`<vaadin-crud>` is a Web Component for [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations.\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-items) property.\n\nA grid and an editor will be automatically generated and configured based on the data structure provided.\n\n```html\n<vaadin-crud></vaadin-crud>\n```\n```js\nconst crud = document.querySelector('vaadin-crud');\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Data Provider Function\n\nOtherwise, you can provide a [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-dataProvider) function.\n\n```js\nconst crud = document.querySelector('vaadin-crud');\n\nconst users = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n\ncrud.dataProvider = (params, callback) => {\n const chunk = users.slice(params.page * params.pageSize, params.page * params.pageSize + params.pageSize);\n callback(chunk, people.length);\n};\n```\n\nNOTE: The auto-generated editor only supports string types. If you need to handle special cases\ncustomizing the editor is discussed below.\n\n### Customization\n\nAlternatively you can fully configure the component by using `slot` names.\n\nSlot name | Description\n---------------|----------------\n`grid` | To replace the auto-generated grid with a custom one.\n`form` | To replace the auto-generated form.\n`save-button` | To replace the \"Save\" button.\n`cancel-button`| To replace the \"Cancel\" button.\n`delete-button`| To replace the \"Delete\" button.\n`toolbar` | To provide the toolbar content (by default, it's empty).\n`new-button` | To replace the \"New item\" button.\n\n#### Example:\n\n```html\n<vaadin-crud id=\"crud\">\n <vaadin-grid slot=\"grid\">\n <vaadin-crud-edit-column></vaadin-crud-edit-column>\n <vaadin-grid-column id=\"column1\"></vaadin-grid-column>\n <vaadin-grid-column id=\"column2\"></vaadin-grid-column>\n </vaadin-grid>\n\n <vaadin-form-layout slot=\"form\">\n <vaadin-text-field label=\"First\" path=\"name\"></vaadin-text-field>\n <vaadin-text-field label=\"Surname\" path=\"surname\"></vaadin-text-field>\n </vaadin-form-layout>\n\n <div slot=\"toolbar\">Total singers: 2</div>\n <button slot=\"new-button\">New singer</button>\n\n <button slot=\"save-button\">Save changes</button>\n <button slot=\"cancel-button\">Discard changes</button>\n <button slot=\"delete-button\">Delete singer</button>\n</vaadin-crud>\n```\n```js\nconst crud = document.querySelector('#crud');\n\nconst column1 = document.querySelector('#column1');\ncolumn1.headerRenderer = (root, column) => {\n root.textContent = 'Name';\n};\ncolumn1.renderer = (root, column, model) => {\n root.textContent = model.item.name;\n};\n\nconst column2 = document.querySelector('#column2');\ncolumn2.headerRenderer = (root, column) => {\n root.textContent = 'Surname';\n};\ncolumn2.renderer = (root, column, model) => {\n root.textContent = model.item.surname;\n};\n\ncrud.items = [\n { name: 'John', surname: 'Lennon', role: 'singer' },\n { name: 'Ringo', surname: 'Starr', role: 'drums' },\n // ... more items\n];\n```\n\n### Helpers\n\nThe following elements are used to auto-configure the grid and the editor\n- [`<vaadin-crud-edit-column>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud-edit-column)\n- `<vaadin-crud-grid>` - can be replaced with custom [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-grid)\n- `<vaadin-crud-form>` - can be replaced with custom [`<vaadin-form-layout>`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-form-layout)\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n----------------|----------------\n`toolbar` | Toolbar container at the bottom. By default it contains the the `new` button\n\nThe following custom properties are available:\n\nCustom Property | Description | Default\n----------------|----------------\n--vaadin-crud-editor-max-height | max height of editor when opened on the bottom | 40%\n--vaadin-crud-editor-max-width | max width of editor when opened on the side | 40%\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.",
125
125
  "extension": true,
126
126
  "attributes": [
127
127
  {
@@ -196,14 +196,14 @@
196
196
  },
197
197
  {
198
198
  "name": ".include",
199
- "description": "A comma-separated list of fields to include in the generated grid and the generated editor.\n\nIt can be used to explicitly define the field order.\n\nWhen it is defined [`exclude`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-exclude) is ignored.\n\nDefault is undefined meaning that all properties in the object should be mapped to fields.",
199
+ "description": "A comma-separated list of fields to include in the generated grid and the generated editor.\n\nIt can be used to explicitly define the field order.\n\nWhen it is defined [`exclude`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-exclude) is ignored.\n\nDefault is undefined meaning that all properties in the object should be mapped to fields.",
200
200
  "value": {
201
201
  "kind": "expression"
202
202
  }
203
203
  },
204
204
  {
205
205
  "name": ".exclude",
206
- "description": "A comma-separated list of fields to be excluded from the generated grid and the generated editor.\n\nWhen [`include`](https://cdn.vaadin.com/vaadin-web-components/23.3.3/#/elements/vaadin-crud#property-include) is defined, this parameter is ignored.\n\nDefault is to exclude all private fields (those properties starting with underscore)",
206
+ "description": "A comma-separated list of fields to be excluded from the generated grid and the generated editor.\n\nWhen [`include`](https://cdn.vaadin.com/vaadin-web-components/24.0.0-alpha10/#/elements/vaadin-crud#property-include) is defined, this parameter is ignored.\n\nDefault is to exclude all private fields (those properties starting with underscore)",
207
207
  "value": {
208
208
  "kind": "expression"
209
209
  }