@vaadin/crud 22.0.0-rc1 → 23.0.0-alpha2
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 +12 -13
- package/src/vaadin-crud-dialog.js +121 -0
- package/src/vaadin-crud-edit.d.ts +2 -2
- package/src/vaadin-crud-edit.js +5 -5
- package/src/vaadin-crud-grid.js +81 -30
- package/src/vaadin-crud.js +227 -71
- package/theme/lumo/vaadin-crud-styles.js +94 -105
- package/theme/material/vaadin-crud-styles.js +84 -81
- package/src/vaadin-dialog-layout.js +0 -241
- package/theme/vaadin-dialog-layout-overlay-styles.js +0 -45
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/crud",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "23.0.0-alpha2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -35,23 +35,22 @@
|
|
|
35
35
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
36
36
|
"@polymer/iron-media-query": "^3.0.0",
|
|
37
37
|
"@polymer/polymer": "^3.0.0",
|
|
38
|
-
"@vaadin/button": "
|
|
39
|
-
"@vaadin/component-base": "
|
|
40
|
-
"@vaadin/confirm-dialog": "
|
|
41
|
-
"@vaadin/dialog": "
|
|
42
|
-
"@vaadin/form-layout": "
|
|
43
|
-
"@vaadin/grid": "
|
|
44
|
-
"@vaadin/text-field": "
|
|
38
|
+
"@vaadin/button": "23.0.0-alpha2",
|
|
39
|
+
"@vaadin/component-base": "23.0.0-alpha2",
|
|
40
|
+
"@vaadin/confirm-dialog": "23.0.0-alpha2",
|
|
41
|
+
"@vaadin/dialog": "23.0.0-alpha2",
|
|
42
|
+
"@vaadin/form-layout": "23.0.0-alpha2",
|
|
43
|
+
"@vaadin/grid": "23.0.0-alpha2",
|
|
44
|
+
"@vaadin/text-field": "23.0.0-alpha2",
|
|
45
45
|
"@vaadin/vaadin-license-checker": "^2.1.0",
|
|
46
|
-
"@vaadin/vaadin-lumo-styles": "
|
|
47
|
-
"@vaadin/vaadin-material-styles": "
|
|
48
|
-
"@vaadin/vaadin-themable-mixin": "
|
|
46
|
+
"@vaadin/vaadin-lumo-styles": "23.0.0-alpha2",
|
|
47
|
+
"@vaadin/vaadin-material-styles": "23.0.0-alpha2",
|
|
48
|
+
"@vaadin/vaadin-themable-mixin": "23.0.0-alpha2"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@esm-bundle/chai": "^4.3.4",
|
|
52
|
-
"@vaadin/polymer-legacy-adapter": "22.0.0-rc1",
|
|
53
52
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
54
53
|
"sinon": "^9.2.1"
|
|
55
54
|
},
|
|
56
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "070f586dead02ca41b66717820c647f48bf1665f"
|
|
57
56
|
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2017 - 2021 Vaadin Ltd.
|
|
4
|
+
* This program is available under Commercial Vaadin Developer License 4.0, available at https://vaadin.com/license/cvdl-4.0.
|
|
5
|
+
*/
|
|
6
|
+
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
|
7
|
+
import { Dialog, DialogOverlay } from '@vaadin/dialog/src/vaadin-dialog.js';
|
|
8
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
9
|
+
|
|
10
|
+
registerStyles(
|
|
11
|
+
'vaadin-crud-dialog-overlay',
|
|
12
|
+
css`
|
|
13
|
+
[part='overlay'] {
|
|
14
|
+
max-width: 54em;
|
|
15
|
+
min-width: 20em;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
[part='content'] {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
padding: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
[part='scroller'] {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
overflow: auto;
|
|
28
|
+
flex: auto;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
[part='footer'] {
|
|
32
|
+
display: flex;
|
|
33
|
+
flex: none;
|
|
34
|
+
flex-direction: row-reverse;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
:host([fullscreen]) {
|
|
38
|
+
top: 0;
|
|
39
|
+
left: 0;
|
|
40
|
+
right: 0;
|
|
41
|
+
bottom: 0;
|
|
42
|
+
padding: 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
:host([fullscreen]) [part='overlay'] {
|
|
46
|
+
height: 100vh;
|
|
47
|
+
width: 100vw;
|
|
48
|
+
border-radius: 0 !important;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:host([fullscreen]) [part='content'] {
|
|
52
|
+
flex: 1;
|
|
53
|
+
}
|
|
54
|
+
`,
|
|
55
|
+
{ moduleId: 'vaadin-crud-dialog-overlay-styles' }
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
let memoizedTemplate;
|
|
59
|
+
|
|
60
|
+
const editorTemplate = html`
|
|
61
|
+
<div part="scroller" role="group" aria-labelledby="header">
|
|
62
|
+
<div part="header" id="header">
|
|
63
|
+
<slot name="header"></slot>
|
|
64
|
+
</div>
|
|
65
|
+
<slot name="form"></slot>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div part="footer" role="toolbar">
|
|
69
|
+
<slot name="save-button"></slot>
|
|
70
|
+
<slot name="cancel-button"></slot>
|
|
71
|
+
<slot name="delete-button"></slot>
|
|
72
|
+
</div>
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
class CrudDialogOverlay extends DialogOverlay {
|
|
76
|
+
static get is() {
|
|
77
|
+
return 'vaadin-crud-dialog-overlay';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static get template() {
|
|
81
|
+
if (!memoizedTemplate) {
|
|
82
|
+
memoizedTemplate = super.template.cloneNode(true);
|
|
83
|
+
const contentPart = memoizedTemplate.content.querySelector('[part="content"]');
|
|
84
|
+
const defaultSlot = contentPart.querySelector('slot:not([name])');
|
|
85
|
+
contentPart.removeChild(defaultSlot);
|
|
86
|
+
contentPart.appendChild(editorTemplate.content.cloneNode(true));
|
|
87
|
+
}
|
|
88
|
+
return memoizedTemplate;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
customElements.define('vaadin-crud-dialog-overlay', CrudDialogOverlay);
|
|
93
|
+
|
|
94
|
+
class CrudDialog extends Dialog {
|
|
95
|
+
/**
|
|
96
|
+
* Override template to provide custom overlay tag name.
|
|
97
|
+
*/
|
|
98
|
+
static get template() {
|
|
99
|
+
return html`
|
|
100
|
+
<style>
|
|
101
|
+
:host {
|
|
102
|
+
display: none;
|
|
103
|
+
}
|
|
104
|
+
</style>
|
|
105
|
+
|
|
106
|
+
<vaadin-crud-dialog-overlay
|
|
107
|
+
id="overlay"
|
|
108
|
+
on-opened-changed="_onOverlayOpened"
|
|
109
|
+
on-mousedown="_bringOverlayToFront"
|
|
110
|
+
on-touchstart="_bringOverlayToFront"
|
|
111
|
+
theme$="[[theme]]"
|
|
112
|
+
modeless="[[modeless]]"
|
|
113
|
+
with-backdrop="[[!modeless]]"
|
|
114
|
+
resizable$="[[resizable]]"
|
|
115
|
+
focus-trap
|
|
116
|
+
></vaadin-crud-dialog-overlay>
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
customElements.define('vaadin-crud-dialog', CrudDialog);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { Button } from '@vaadin/button/src/vaadin-button.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* `<vaadin-crud-edit>` is a helper element for `<vaadin-grid-column>` that provides
|
|
@@ -13,7 +13,7 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
13
13
|
* Typical usage is in a `<vaadin-grid-column>` of a custom `<vaadin-grid>` inside
|
|
14
14
|
* a `<vaadin-crud>` to enable editing.
|
|
15
15
|
*/
|
|
16
|
-
declare class CrudEdit extends
|
|
16
|
+
declare class CrudEdit extends Button {}
|
|
17
17
|
|
|
18
18
|
declare global {
|
|
19
19
|
interface HTMLElementTagNameMap {
|
package/src/vaadin-crud-edit.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Copyright (c) 2017 - 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Commercial Vaadin Developer License 4.0, available at https://vaadin.com/license/cvdl-4.0.
|
|
5
5
|
*/
|
|
6
|
-
import { html
|
|
7
|
-
import {
|
|
6
|
+
import { html } from '@polymer/polymer/polymer-element.js';
|
|
7
|
+
import { Button } from '@vaadin/button/src/vaadin-button.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* `<vaadin-crud-edit>` is a helper element for `<vaadin-grid-column>` that provides
|
|
@@ -17,7 +17,7 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
17
17
|
* @extends HTMLElement
|
|
18
18
|
* @mixes ThemableMixin
|
|
19
19
|
*/
|
|
20
|
-
class CrudEdit extends
|
|
20
|
+
class CrudEdit extends Button {
|
|
21
21
|
static get template() {
|
|
22
22
|
return html`
|
|
23
23
|
<style>
|
|
@@ -25,6 +25,7 @@ class CrudEdit extends ThemableMixin(PolymerElement) {
|
|
|
25
25
|
display: block;
|
|
26
26
|
}
|
|
27
27
|
</style>
|
|
28
|
+
<div part="icon"></div>
|
|
28
29
|
`;
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -37,7 +38,6 @@ class CrudEdit extends ThemableMixin(PolymerElement) {
|
|
|
37
38
|
super.ready();
|
|
38
39
|
this.addEventListener('click', this.__onClick);
|
|
39
40
|
this.setAttribute('aria-label', 'Edit');
|
|
40
|
-
this.setAttribute('role', 'button');
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/** @private */
|
|
@@ -57,4 +57,4 @@ class CrudEdit extends ThemableMixin(PolymerElement) {
|
|
|
57
57
|
*/
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
customElements.define(CrudEdit.is, CrudEdit);
|
package/src/vaadin-crud-grid.js
CHANGED
|
@@ -109,10 +109,27 @@ class CrudGrid extends IncludedMixin(Grid) {
|
|
|
109
109
|
*/
|
|
110
110
|
_configure(item) {
|
|
111
111
|
this.innerHTML = '';
|
|
112
|
-
this.__createColumns(this, item);
|
|
112
|
+
this.__createColumns(this, item, undefined, this.__getPropertyDepth(item));
|
|
113
113
|
this.__toggleEditColumn();
|
|
114
114
|
}
|
|
115
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
|
+
|
|
116
133
|
/**
|
|
117
134
|
* Parse the camelCase column names into sentence case headers.
|
|
118
135
|
* @param {string} path
|
|
@@ -130,25 +147,38 @@ class CrudGrid extends IncludedMixin(Grid) {
|
|
|
130
147
|
|
|
131
148
|
/** @private */
|
|
132
149
|
__createColumn(parent, path) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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 ? this.get(path, model.item) : model.item;
|
|
164
|
+
};
|
|
165
|
+
}
|
|
138
166
|
|
|
139
167
|
if (!this.noHead && path) {
|
|
168
|
+
// Create a header renderer for the column (or column group)
|
|
140
169
|
col.headerRenderer = (root) => {
|
|
141
170
|
const label = this._generateHeader(path);
|
|
142
171
|
|
|
143
|
-
if (!this.noSort) {
|
|
144
|
-
|
|
172
|
+
if (col.__sortColumnGroup || (this.noFilter && !this.noSort)) {
|
|
173
|
+
// The column is either the sorter group column or the root level
|
|
174
|
+
// sort column (in case a filter isn't used at all) => add the sort indicator
|
|
175
|
+
const sorter = document.createElement('vaadin-grid-sorter');
|
|
145
176
|
sorter.setAttribute('path', path);
|
|
146
177
|
sorter.textContent = label;
|
|
147
178
|
root.appendChild(sorter);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const filter = window.document.createElement('vaadin-grid-filter');
|
|
179
|
+
} else if (!this.noFilter) {
|
|
180
|
+
// Filtering is enabled in this crud-grid, create the filter element
|
|
181
|
+
const filter = document.createElement('vaadin-grid-filter');
|
|
152
182
|
filter.setAttribute('path', path);
|
|
153
183
|
filter.style.display = 'flex';
|
|
154
184
|
|
|
@@ -164,42 +194,63 @@ class CrudGrid extends IncludedMixin(Grid) {
|
|
|
164
194
|
|
|
165
195
|
filter.appendChild(textField);
|
|
166
196
|
root.appendChild(filter);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (this.noSort && this.noFilter) {
|
|
197
|
+
} else if (this.noSort && this.noFilter) {
|
|
198
|
+
// Neither sorter nor filter are enabled, just add the label
|
|
170
199
|
root.textContent = label;
|
|
171
200
|
}
|
|
172
201
|
};
|
|
173
202
|
}
|
|
174
|
-
|
|
175
|
-
parent.appendChild(col);
|
|
176
|
-
return col;
|
|
177
203
|
}
|
|
178
204
|
|
|
179
|
-
/**
|
|
180
|
-
|
|
181
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Creates the column structure for the (sub)object.
|
|
207
|
+
*
|
|
208
|
+
* @param {HTMLElement} parent May be the crud-grid or a column group.
|
|
209
|
+
* @param {Object} object The object to create the sub-columns for.
|
|
210
|
+
* @param {string} path The property path from the root item to the object.
|
|
211
|
+
* @param {number} depth The depth of the object in the object hierarchy.
|
|
212
|
+
* @private
|
|
213
|
+
**/
|
|
214
|
+
__createColumns(parent, object, path, depth) {
|
|
215
|
+
if (object && typeof object === 'object') {
|
|
216
|
+
// Iterate over the object properties
|
|
182
217
|
Object.keys(object).forEach((prop) => {
|
|
183
218
|
if (!this.include && this.exclude && this.exclude.test(prop)) {
|
|
184
219
|
return;
|
|
185
220
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
221
|
+
// Sub-object of the current object
|
|
222
|
+
const subObject = object[prop];
|
|
223
|
+
// Full path to the sub-object
|
|
224
|
+
const subObjectPath = path ? `${path}.${prop}` : prop;
|
|
225
|
+
|
|
226
|
+
// The column element for the sub-object
|
|
227
|
+
let subObjectColumn = parent;
|
|
228
|
+
if (!this.noHead && depth > 1) {
|
|
229
|
+
const isSubObject = subObject && typeof subObject === 'object';
|
|
230
|
+
// If the sub-object is an actual object, create a column group with the property
|
|
231
|
+
// name as the header text, otherwise create a group without a header
|
|
232
|
+
subObjectColumn = this.__createGroup(parent, isSubObject ? prop : undefined);
|
|
192
233
|
}
|
|
234
|
+
|
|
235
|
+
// Run recursively for the sub-object level
|
|
236
|
+
this.__createColumns(subObjectColumn, subObject, subObjectPath, depth - 1);
|
|
193
237
|
});
|
|
238
|
+
} else if (depth > 1) {
|
|
239
|
+
// The object has been fully traversed, but empty wrapping column
|
|
240
|
+
// groups are still needed to complete the full object depth
|
|
241
|
+
this.__createColumns(this.__createGroup(parent), undefined, path, depth - 1);
|
|
194
242
|
} else {
|
|
195
|
-
|
|
243
|
+
// The column group depth is complete, create the actual leaf column
|
|
244
|
+
this.__createColumn(parent, path);
|
|
196
245
|
}
|
|
197
246
|
}
|
|
198
247
|
|
|
199
248
|
/** @private */
|
|
200
|
-
__createGroup(parent,
|
|
249
|
+
__createGroup(parent, header) {
|
|
201
250
|
const grp = document.createElement('vaadin-grid-column-group');
|
|
202
|
-
|
|
251
|
+
if (header) {
|
|
252
|
+
grp.header = this.__capitalize(header);
|
|
253
|
+
}
|
|
203
254
|
parent.appendChild(grp);
|
|
204
255
|
return grp;
|
|
205
256
|
}
|