@vaadin/crud 24.6.0-beta1 → 24.6.0-rc1

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": "24.6.0-beta1",
3
+ "version": "24.6.0-rc1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -37,21 +37,21 @@
37
37
  "dependencies": {
38
38
  "@open-wc/dedupe-mixin": "^1.3.0",
39
39
  "@polymer/polymer": "^3.0.0",
40
- "@vaadin/a11y-base": "24.6.0-beta1",
41
- "@vaadin/button": "24.6.0-beta1",
42
- "@vaadin/component-base": "24.6.0-beta1",
43
- "@vaadin/confirm-dialog": "24.6.0-beta1",
44
- "@vaadin/dialog": "24.6.0-beta1",
45
- "@vaadin/form-layout": "24.6.0-beta1",
46
- "@vaadin/grid": "24.6.0-beta1",
47
- "@vaadin/overlay": "24.6.0-beta1",
48
- "@vaadin/text-field": "24.6.0-beta1",
49
- "@vaadin/vaadin-lumo-styles": "24.6.0-beta1",
50
- "@vaadin/vaadin-material-styles": "24.6.0-beta1",
51
- "@vaadin/vaadin-themable-mixin": "24.6.0-beta1"
40
+ "@vaadin/a11y-base": "24.6.0-rc1",
41
+ "@vaadin/button": "24.6.0-rc1",
42
+ "@vaadin/component-base": "24.6.0-rc1",
43
+ "@vaadin/confirm-dialog": "24.6.0-rc1",
44
+ "@vaadin/dialog": "24.6.0-rc1",
45
+ "@vaadin/form-layout": "24.6.0-rc1",
46
+ "@vaadin/grid": "24.6.0-rc1",
47
+ "@vaadin/overlay": "24.6.0-rc1",
48
+ "@vaadin/text-field": "24.6.0-rc1",
49
+ "@vaadin/vaadin-lumo-styles": "24.6.0-rc1",
50
+ "@vaadin/vaadin-material-styles": "24.6.0-rc1",
51
+ "@vaadin/vaadin-themable-mixin": "24.6.0-rc1"
52
52
  },
53
53
  "devDependencies": {
54
- "@vaadin/chai-plugins": "24.6.0-beta1",
54
+ "@vaadin/chai-plugins": "24.6.0-rc1",
55
55
  "@vaadin/testing-helpers": "^1.0.0",
56
56
  "sinon": "^18.0.0"
57
57
  },
@@ -60,5 +60,5 @@
60
60
  "web-types.json",
61
61
  "web-types.lit.json"
62
62
  ],
63
- "gitHead": "ab28efb0dcf2cd1ef72100e2e8f32232fa49aacc"
63
+ "gitHead": "d62ba309e3286777ad3ea7e015d50a2c4976bb42"
64
64
  }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
12
+ import type { IncludedMixinClass } from './vaadin-crud-include-mixin.js';
13
+
14
+ /**
15
+ * A mixin providing common crud grid functionality.
16
+ */
17
+ export declare function CrudGridMixin<T extends Constructor<HTMLElement>>(
18
+ base: T,
19
+ ): Constructor<CrudGridMixinClass> & Constructor<IncludedMixinClass> & T;
20
+
21
+ export declare class CrudGridMixinClass {
22
+ /**
23
+ * Disable filtering in the generated columns.
24
+ * @attr {boolean} no-filter
25
+ */
26
+ noFilter: boolean | null | undefined;
27
+
28
+ /**
29
+ * Disable sorting in the generated columns.
30
+ * @attr {boolean} no-sort
31
+ */
32
+ noSort: boolean | null | undefined;
33
+
34
+ /**
35
+ * Do not add headers to columns.
36
+ * @attr {boolean} no-head
37
+ */
38
+ noHead: boolean | null | undefined;
39
+ }
@@ -0,0 +1,266 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2024 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 { capitalize, getProperty } from './vaadin-crud-helpers.js';
12
+ import { IncludedMixin } from './vaadin-crud-include-mixin.js';
13
+
14
+ /**
15
+ * A mixin providing common crud-grid functionality.
16
+ *
17
+ * @polymerMixin
18
+ * @mixes IncludedMixin
19
+ */
20
+ export const CrudGridMixin = (superClass) =>
21
+ class extends IncludedMixin(superClass) {
22
+ static get properties() {
23
+ return {
24
+ /**
25
+ * Disable filtering in the generated columns.
26
+ * @attr {boolean} no-filter
27
+ */
28
+ noFilter: Boolean,
29
+
30
+ /**
31
+ * Disable sorting in the generated columns.
32
+ * @attr {boolean} no-sort
33
+ */
34
+ noSort: Boolean,
35
+
36
+ /**
37
+ * Do not add headers to columns.
38
+ * @attr {boolean} no-head
39
+ */
40
+ noHead: Boolean,
41
+
42
+ /** @private */
43
+ __hideEditColumn: Boolean,
44
+ };
45
+ }
46
+
47
+ static get observers() {
48
+ return ['__onItemsChange(items)', '__onHideEditColumnChange(hideEditColumn)'];
49
+ }
50
+
51
+ /** @private */
52
+ __onItemsChange(items) {
53
+ if ((!this.dataProvider || this.dataProvider === this._arrayDataProvider) && !this.include && items && items[0]) {
54
+ this._configure(items[0]);
55
+ }
56
+ }
57
+
58
+ /** @private */
59
+ __onHideEditColumnChange() {
60
+ if (this.firstChild) {
61
+ this.__toggleEditColumn();
62
+ }
63
+ }
64
+
65
+ /** @private */
66
+ __toggleEditColumn() {
67
+ let editColumn = this.querySelector('vaadin-crud-edit-column');
68
+ if (this.hideEditColumn) {
69
+ if (editColumn) {
70
+ this.removeChild(editColumn);
71
+ }
72
+ } else if (!editColumn) {
73
+ editColumn = document.createElement('vaadin-crud-edit-column');
74
+ editColumn.frozenToEnd = true;
75
+ this.appendChild(editColumn);
76
+ }
77
+ }
78
+
79
+ /** @private */
80
+ __dataProviderWrapper(params, callback) {
81
+ this.__dataProvider(params, (items, size) => {
82
+ if (this.innerHTML === '' && !this.include && items[0]) {
83
+ this._configure(items[0]);
84
+ }
85
+ callback(items, size);
86
+ });
87
+ }
88
+
89
+ /**
90
+ * @override
91
+ * @private
92
+ */
93
+ _dataProviderChanged(dataProvider, oldDataProvider) {
94
+ if (this._arrayDataProvider === dataProvider) {
95
+ super._dataProviderChanged(dataProvider, oldDataProvider);
96
+ } else if (this.__dataProviderWrapper !== dataProvider) {
97
+ this.innerHTML = '';
98
+ this.__dataProvider = dataProvider;
99
+ this.dataProvider = this.__dataProviderWrapper;
100
+ super._dataProviderChanged(this.__dataProviderWrapper, oldDataProvider);
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Auto-generate grid columns based on the JSON structure of the object provided.
106
+ *
107
+ * Method will be executed when items or dataProvider is assigned.
108
+ * @private
109
+ */
110
+ _configure(item) {
111
+ this.innerHTML = '';
112
+ this.__createColumns(this, item, undefined, this.__getPropertyDepth(item));
113
+ this.__toggleEditColumn();
114
+ }
115
+
116
+ /**
117
+ * Return the deepest property depth of the object
118
+ * @private
119
+ */
120
+ __getPropertyDepth(object) {
121
+ if (!object || typeof object !== 'object') {
122
+ return 0;
123
+ }
124
+
125
+ return Object.keys(object).reduce((deepest, prop) => {
126
+ if (this.exclude && this.exclude.test(prop)) {
127
+ return deepest;
128
+ }
129
+ return Math.max(deepest, 1 + this.__getPropertyDepth(object[prop]));
130
+ }, 0);
131
+ }
132
+
133
+ /**
134
+ * Parse the camelCase column names into sentence case headers.
135
+ * @param {string} path
136
+ * @return {string}
137
+ * @protected
138
+ */
139
+ _generateHeader(path) {
140
+ return path
141
+ .substr(path.lastIndexOf('.') + 1)
142
+ .replace(/([A-Z])/gu, '-$1')
143
+ .toLowerCase()
144
+ .replace(/-/gu, ' ')
145
+ .replace(/^./u, (match) => match.toUpperCase());
146
+ }
147
+
148
+ /** @private */
149
+ __createColumn(parent, path) {
150
+ let col;
151
+ if (!this.noFilter && !this.noSort && !parent.__sortColumnGroup) {
152
+ // This crud-grid has both a sorter and a filter, but neither has yet been
153
+ // created => col should become the sorter group column
154
+ col = this.__createGroup(parent);
155
+ col.__sortColumnGroup = true;
156
+ // Create the filter column under this sorter group column
157
+ this.__createColumn(col, path);
158
+ } else {
159
+ // In all other cases, col should be a regular column with a renderer
160
+ col = document.createElement('vaadin-grid-column');
161
+ parent.appendChild(col);
162
+ col.renderer = (root, _column, model) => {
163
+ root.textContent = path ? getProperty(path, model.item) : model.item;
164
+ };
165
+ }
166
+
167
+ if (!this.noHead && path) {
168
+ // Create a header renderer for the column (or column group)
169
+ col.headerRenderer = (root) => {
170
+ if (root.firstElementChild) {
171
+ return;
172
+ }
173
+
174
+ const label = this._generateHeader(path);
175
+
176
+ if (col.__sortColumnGroup || (this.noFilter && !this.noSort)) {
177
+ // The column is either the sorter group column or the root level
178
+ // sort column (in case a filter isn't used at all) => add the sort indicator
179
+ const sorter = document.createElement('vaadin-grid-sorter');
180
+ sorter.setAttribute('path', path);
181
+ // TODO: Localize aria labels
182
+ sorter.setAttribute('aria-label', `Sort by ${label}`);
183
+ sorter.textContent = label;
184
+ root.appendChild(sorter);
185
+ } else if (!this.noFilter) {
186
+ // Filtering is enabled in this crud-grid, create the filter element
187
+ const filter = document.createElement('vaadin-grid-filter');
188
+ filter.setAttribute('path', path);
189
+ // TODO: Localize aria labels
190
+ filter.setAttribute('aria-label', `Filter by ${label}`);
191
+ filter.style.display = 'flex';
192
+
193
+ const textField = window.document.createElement('vaadin-text-field');
194
+ textField.setAttribute('theme', 'small');
195
+ textField.setAttribute('focus-target', true);
196
+ textField.style.width = '100%';
197
+ if (this.noSort) {
198
+ textField.placeholder = label;
199
+ }
200
+ textField.addEventListener('value-changed', (event) => {
201
+ filter.value = event.detail.value;
202
+ });
203
+
204
+ filter.appendChild(textField);
205
+ root.appendChild(filter);
206
+ } else if (this.noSort && this.noFilter) {
207
+ // Neither sorter nor filter are enabled, just add the label
208
+ root.textContent = label;
209
+ }
210
+ };
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Creates the column structure for the (sub)object.
216
+ *
217
+ * @param {HTMLElement} parent May be the crud-grid or a column group.
218
+ * @param {Object} object The object to create the sub-columns for.
219
+ * @param {string} path The property path from the root item to the object.
220
+ * @param {number} depth The depth of the object in the object hierarchy.
221
+ * @private
222
+ */
223
+ __createColumns(parent, object, path, depth) {
224
+ if (object && typeof object === 'object') {
225
+ // Iterate over the object properties
226
+ Object.keys(object).forEach((prop) => {
227
+ if (!this.include && this.exclude && this.exclude.test(prop)) {
228
+ return;
229
+ }
230
+ // Sub-object of the current object
231
+ const subObject = object[prop];
232
+ // Full path to the sub-object
233
+ const subObjectPath = path ? `${path}.${prop}` : prop;
234
+
235
+ // The column element for the sub-object
236
+ let subObjectColumn = parent;
237
+ if (!this.noHead && depth > 1) {
238
+ const isSubObject = subObject && typeof subObject === 'object';
239
+ // If the sub-object is an actual object, create a column group with the property
240
+ // name as the header text, otherwise create a group without a header
241
+ subObjectColumn = this.__createGroup(parent, isSubObject ? prop : undefined);
242
+ }
243
+
244
+ // Run recursively for the sub-object level
245
+ this.__createColumns(subObjectColumn, subObject, subObjectPath, depth - 1);
246
+ });
247
+ } else if (depth > 1) {
248
+ // The object has been fully traversed, but empty wrapping column
249
+ // groups are still needed to complete the full object depth
250
+ this.__createColumns(this.__createGroup(parent), undefined, path, depth - 1);
251
+ } else {
252
+ // The column group depth is complete, create the actual leaf column
253
+ this.__createColumn(parent, path);
254
+ }
255
+ }
256
+
257
+ /** @private */
258
+ __createGroup(parent, header) {
259
+ const grp = document.createElement('vaadin-grid-column-group');
260
+ if (header) {
261
+ grp.header = capitalize(header);
262
+ }
263
+ parent.appendChild(grp);
264
+ return grp;
265
+ }
266
+ };
@@ -9,30 +9,12 @@
9
9
  * license.
10
10
  */
11
11
  import { Grid } from '@vaadin/grid/src/vaadin-grid.js';
12
- import { IncludedMixin } from './vaadin-crud-include-mixin.js';
12
+ import { CrudGridMixin } from './vaadin-crud-grid-mixin.js';
13
13
 
14
14
  /**
15
15
  * An element used internally by `<vaadin-crud>`. Not intended to be used separately.
16
16
  */
17
- declare class CrudGrid extends IncludedMixin(Grid) {
18
- /**
19
- * Disable filtering in the generated columns.
20
- * @attr {boolean} no-filter
21
- */
22
- noFilter: boolean | null | undefined;
23
-
24
- /**
25
- * Disable sorting in the generated columns.
26
- * @attr {boolean} no-sort
27
- */
28
- noSort: boolean | null | undefined;
29
-
30
- /**
31
- * Do not add headers to columns.
32
- * @attr {boolean} no-head
33
- */
34
- noHead: boolean | null | undefined;
35
- }
17
+ declare class CrudGrid extends CrudGridMixin(Grid) {}
36
18
 
37
19
  declare global {
38
20
  interface HTMLElementTagNameMap {
@@ -15,265 +15,19 @@ import '@vaadin/grid/src/vaadin-grid-sorter.js';
15
15
  import './vaadin-crud-edit-column.js';
16
16
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
17
17
  import { Grid } from '@vaadin/grid/src/vaadin-grid.js';
18
- import { capitalize, getProperty } from './vaadin-crud-helpers.js';
19
- import { IncludedMixin } from './vaadin-crud-include-mixin.js';
18
+ import { CrudGridMixin } from './vaadin-crud-grid-mixin.js';
20
19
 
21
20
  /**
22
21
  * An element used internally by `<vaadin-crud>`. Not intended to be used separately.
23
22
  *
24
23
  * @extends Grid
25
- * @mixes IncludedMixin
24
+ * @mixes CrudGridMixin
26
25
  * @private
27
26
  */
28
- class CrudGrid extends IncludedMixin(Grid) {
27
+ class CrudGrid extends CrudGridMixin(Grid) {
29
28
  static get is() {
30
29
  return 'vaadin-crud-grid';
31
30
  }
32
-
33
- static get properties() {
34
- return {
35
- /**
36
- * Disable filtering in the generated columns.
37
- * @attr {boolean} no-filter
38
- */
39
- noFilter: Boolean,
40
-
41
- /**
42
- * Disable sorting in the generated columns.
43
- * @attr {boolean} no-sort
44
- */
45
- noSort: Boolean,
46
-
47
- /**
48
- * Do not add headers to columns.
49
- * @attr {boolean} no-head
50
- */
51
- noHead: Boolean,
52
-
53
- /** @private */
54
- __hideEditColumn: Boolean,
55
- };
56
- }
57
-
58
- static get observers() {
59
- return ['__onItemsChange(items)', '__onHideEditColumnChange(hideEditColumn)'];
60
- }
61
-
62
- /** @private */
63
- __onItemsChange(items) {
64
- if ((!this.dataProvider || this.dataProvider === this._arrayDataProvider) && !this.include && items && items[0]) {
65
- this._configure(items[0]);
66
- }
67
- }
68
-
69
- /** @private */
70
- __onHideEditColumnChange() {
71
- if (this.firstChild) {
72
- this.__toggleEditColumn();
73
- }
74
- }
75
-
76
- /** @private */
77
- __toggleEditColumn() {
78
- let editColumn = this.querySelector('vaadin-crud-edit-column');
79
- if (this.hideEditColumn) {
80
- if (editColumn) {
81
- this.removeChild(editColumn);
82
- }
83
- } else if (!editColumn) {
84
- editColumn = document.createElement('vaadin-crud-edit-column');
85
- editColumn.frozenToEnd = true;
86
- this.appendChild(editColumn);
87
- }
88
- }
89
-
90
- /** @private */
91
- __dataProviderWrapper(params, callback) {
92
- this.__dataProvider(params, (items, size) => {
93
- if (this.innerHTML === '' && !this.include && items[0]) {
94
- this._configure(items[0]);
95
- }
96
- callback(items, size);
97
- });
98
- }
99
-
100
- /**
101
- * @override
102
- * @private
103
- */
104
- _dataProviderChanged(dataProvider, oldDataProvider) {
105
- if (this._arrayDataProvider === dataProvider) {
106
- super._dataProviderChanged(dataProvider, oldDataProvider);
107
- } else if (this.__dataProviderWrapper !== dataProvider) {
108
- this.innerHTML = '';
109
- this.__dataProvider = dataProvider;
110
- this.dataProvider = this.__dataProviderWrapper;
111
- super._dataProviderChanged(this.__dataProviderWrapper, oldDataProvider);
112
- }
113
- }
114
-
115
- /**
116
- * Auto-generate grid columns based on the JSON structure of the object provided.
117
- *
118
- * Method will be executed when items or dataProvider is assigned.
119
- * @private
120
- */
121
- _configure(item) {
122
- this.innerHTML = '';
123
- this.__createColumns(this, item, undefined, this.__getPropertyDepth(item));
124
- this.__toggleEditColumn();
125
- }
126
-
127
- /**
128
- * Return the deepest property depth of the object
129
- * @private
130
- */
131
- __getPropertyDepth(object) {
132
- if (!object || typeof object !== 'object') {
133
- return 0;
134
- }
135
-
136
- return Object.keys(object).reduce((deepest, prop) => {
137
- if (this.exclude && this.exclude.test(prop)) {
138
- return deepest;
139
- }
140
- return Math.max(deepest, 1 + this.__getPropertyDepth(object[prop]));
141
- }, 0);
142
- }
143
-
144
- /**
145
- * Parse the camelCase column names into sentence case headers.
146
- * @param {string} path
147
- * @return {string}
148
- * @protected
149
- */
150
- _generateHeader(path) {
151
- return path
152
- .substr(path.lastIndexOf('.') + 1)
153
- .replace(/([A-Z])/gu, '-$1')
154
- .toLowerCase()
155
- .replace(/-/gu, ' ')
156
- .replace(/^./u, (match) => match.toUpperCase());
157
- }
158
-
159
- /** @private */
160
- __createColumn(parent, path) {
161
- let col;
162
- if (!this.noFilter && !this.noSort && !parent.__sortColumnGroup) {
163
- // This crud-grid has both a sorter and a filter, but neither has yet been
164
- // created => col should become the sorter group column
165
- col = this.__createGroup(parent);
166
- col.__sortColumnGroup = true;
167
- // Create the filter column under this sorter group column
168
- this.__createColumn(col, path);
169
- } else {
170
- // In all other cases, col should be a regular column with a renderer
171
- col = document.createElement('vaadin-grid-column');
172
- parent.appendChild(col);
173
- col.renderer = (root, _column, model) => {
174
- root.textContent = path ? getProperty(path, model.item) : model.item;
175
- };
176
- }
177
-
178
- if (!this.noHead && path) {
179
- // Create a header renderer for the column (or column group)
180
- col.headerRenderer = (root) => {
181
- if (root.firstElementChild) {
182
- return;
183
- }
184
-
185
- const label = this._generateHeader(path);
186
-
187
- if (col.__sortColumnGroup || (this.noFilter && !this.noSort)) {
188
- // The column is either the sorter group column or the root level
189
- // sort column (in case a filter isn't used at all) => add the sort indicator
190
- const sorter = document.createElement('vaadin-grid-sorter');
191
- sorter.setAttribute('path', path);
192
- // TODO: Localize aria labels
193
- sorter.setAttribute('aria-label', `Sort by ${label}`);
194
- sorter.textContent = label;
195
- root.appendChild(sorter);
196
- } else if (!this.noFilter) {
197
- // Filtering is enabled in this crud-grid, create the filter element
198
- const filter = document.createElement('vaadin-grid-filter');
199
- filter.setAttribute('path', path);
200
- // TODO: Localize aria labels
201
- filter.setAttribute('aria-label', `Filter by ${label}`);
202
- filter.style.display = 'flex';
203
-
204
- const textField = window.document.createElement('vaadin-text-field');
205
- textField.setAttribute('theme', 'small');
206
- textField.setAttribute('focus-target', true);
207
- textField.style.width = '100%';
208
- if (this.noSort) {
209
- textField.placeholder = label;
210
- }
211
- textField.addEventListener('value-changed', (event) => {
212
- filter.value = event.detail.value;
213
- });
214
-
215
- filter.appendChild(textField);
216
- root.appendChild(filter);
217
- } else if (this.noSort && this.noFilter) {
218
- // Neither sorter nor filter are enabled, just add the label
219
- root.textContent = label;
220
- }
221
- };
222
- }
223
- }
224
-
225
- /**
226
- * Creates the column structure for the (sub)object.
227
- *
228
- * @param {HTMLElement} parent May be the crud-grid or a column group.
229
- * @param {Object} object The object to create the sub-columns for.
230
- * @param {string} path The property path from the root item to the object.
231
- * @param {number} depth The depth of the object in the object hierarchy.
232
- * @private
233
- */
234
- __createColumns(parent, object, path, depth) {
235
- if (object && typeof object === 'object') {
236
- // Iterate over the object properties
237
- Object.keys(object).forEach((prop) => {
238
- if (!this.include && this.exclude && this.exclude.test(prop)) {
239
- return;
240
- }
241
- // Sub-object of the current object
242
- const subObject = object[prop];
243
- // Full path to the sub-object
244
- const subObjectPath = path ? `${path}.${prop}` : prop;
245
-
246
- // The column element for the sub-object
247
- let subObjectColumn = parent;
248
- if (!this.noHead && depth > 1) {
249
- const isSubObject = subObject && typeof subObject === 'object';
250
- // If the sub-object is an actual object, create a column group with the property
251
- // name as the header text, otherwise create a group without a header
252
- subObjectColumn = this.__createGroup(parent, isSubObject ? prop : undefined);
253
- }
254
-
255
- // Run recursively for the sub-object level
256
- this.__createColumns(subObjectColumn, subObject, subObjectPath, depth - 1);
257
- });
258
- } else if (depth > 1) {
259
- // The object has been fully traversed, but empty wrapping column
260
- // groups are still needed to complete the full object depth
261
- this.__createColumns(this.__createGroup(parent), undefined, path, depth - 1);
262
- } else {
263
- // The column group depth is complete, create the actual leaf column
264
- this.__createColumn(parent, path);
265
- }
266
- }
267
-
268
- /** @private */
269
- __createGroup(parent, header) {
270
- const grp = document.createElement('vaadin-grid-column-group');
271
- if (header) {
272
- grp.header = capitalize(header);
273
- }
274
- parent.appendChild(grp);
275
- return grp;
276
- }
277
31
  }
278
32
 
279
33
  defineCustomElement(CrudGrid);
@@ -62,3 +62,7 @@ export function setProperty(path, value, obj) {
62
62
  set(obj, path, value);
63
63
  }
64
64
  }
65
+
66
+ export function isValidEditorPosition(editorPosition) {
67
+ return ['bottom', 'aside'].includes(editorPosition);
68
+ }