From d66189b76221c1aef3968c5e28fdcc0f252346f5 Mon Sep 17 00:00:00 2001 From: Tomi Virkki Date: Fri, 13 Dec 2024 17:09:09 +0200 Subject: [PATCH 1/7] experiment: add LitElement based version of vaadin-crud --- packages/crud/src/vaadin-crud-edit-column.js | 18 +-- packages/crud/src/vaadin-crud-form.js | 26 +--- packages/crud/src/vaadin-crud-grid-mixin.js | 1 + packages/crud/src/vaadin-crud-helpers.js | 44 ++++++ .../crud/src/vaadin-crud-include-mixin.js | 2 + packages/crud/src/vaadin-crud-mixin.js | 16 ++- packages/crud/src/vaadin-lit-crud-dialog.d.ts | 11 ++ packages/crud/src/vaadin-lit-crud-dialog.js | 126 ++++++++++++++++++ .../crud/src/vaadin-lit-crud-edit-column.d.ts | 11 ++ .../crud/src/vaadin-lit-crud-edit-column.js | 65 +++++++++ packages/crud/src/vaadin-lit-crud-edit.d.ts | 11 ++ packages/crud/src/vaadin-lit-crud-edit.js | 81 +++++++++++ packages/crud/src/vaadin-lit-crud-form.d.ts | 11 ++ packages/crud/src/vaadin-lit-crud-form.js | 77 +++++++++++ packages/crud/src/vaadin-lit-crud-grid.d.ts | 11 ++ packages/crud/src/vaadin-lit-crud-grid.js | 29 ++++ packages/crud/src/vaadin-lit-crud.js | 115 ++++++++++++++++ packages/crud/test/a11y-lit.test.js | 2 + packages/crud/test/a11y-polymer.test.js | 2 + .../test/{a11y.test.js => a11y.common.js} | 1 - packages/crud/test/crud-buttons-lit.test.js | 2 + .../crud/test/crud-buttons-polymer.test.js | 2 + ...buttons.test.js => crud-buttons.common.js} | 3 +- packages/crud/test/crud-editor-lit.test.js | 2 + .../crud/test/crud-editor-polymer.test.js | 2 + ...d-editor.test.js => crud-editor.common.js} | 3 +- packages/crud/test/crud-form-lit.test.js | 2 + packages/crud/test/crud-form-polymer.test.js | 2 + ...{crud-form.test.js => crud-form.common.js} | 1 - packages/crud/test/crud-grid-lit.test.js | 2 + packages/crud/test/crud-grid-polymer.test.js | 2 + .../test/crud-grid-properties-lit.test.js | 2 + .../test/crud-grid-properties-polymer.test.js | 2 + ...test.js => crud-grid-properties.common.js} | 1 - ...{crud-grid.test.js => crud-grid.common.js} | 1 - packages/crud/test/crud-lit.test.js | 2 + packages/crud/test/crud-polymer.test.js | 2 + .../test/{crud.test.js => crud.common.js} | 4 +- packages/crud/theme/lumo/vaadin-lit-crud.js | 8 ++ .../crud/theme/material/vaadin-lit-crud.js | 8 ++ packages/crud/vaadin-lit-crud-edit .js | 1 + packages/crud/vaadin-lit-crud-edit-column.js | 1 + packages/crud/vaadin-lit-crud.js | 2 + 43 files changed, 669 insertions(+), 48 deletions(-) create mode 100644 packages/crud/src/vaadin-lit-crud-dialog.d.ts create mode 100644 packages/crud/src/vaadin-lit-crud-dialog.js create mode 100644 packages/crud/src/vaadin-lit-crud-edit-column.d.ts create mode 100644 packages/crud/src/vaadin-lit-crud-edit-column.js create mode 100644 packages/crud/src/vaadin-lit-crud-edit.d.ts create mode 100644 packages/crud/src/vaadin-lit-crud-edit.js create mode 100644 packages/crud/src/vaadin-lit-crud-form.d.ts create mode 100644 packages/crud/src/vaadin-lit-crud-form.js create mode 100644 packages/crud/src/vaadin-lit-crud-grid.d.ts create mode 100644 packages/crud/src/vaadin-lit-crud-grid.js create mode 100644 packages/crud/src/vaadin-lit-crud.js create mode 100644 packages/crud/test/a11y-lit.test.js create mode 100644 packages/crud/test/a11y-polymer.test.js rename packages/crud/test/{a11y.test.js => a11y.common.js} (99%) create mode 100644 packages/crud/test/crud-buttons-lit.test.js create mode 100644 packages/crud/test/crud-buttons-polymer.test.js rename packages/crud/test/{crud-buttons.test.js => crud-buttons.common.js} (99%) create mode 100644 packages/crud/test/crud-editor-lit.test.js create mode 100644 packages/crud/test/crud-editor-polymer.test.js rename packages/crud/test/{crud-editor.test.js => crud-editor.common.js} (98%) create mode 100644 packages/crud/test/crud-form-lit.test.js create mode 100644 packages/crud/test/crud-form-polymer.test.js rename packages/crud/test/{crud-form.test.js => crud-form.common.js} (99%) create mode 100644 packages/crud/test/crud-grid-lit.test.js create mode 100644 packages/crud/test/crud-grid-polymer.test.js create mode 100644 packages/crud/test/crud-grid-properties-lit.test.js create mode 100644 packages/crud/test/crud-grid-properties-polymer.test.js rename packages/crud/test/{crud-grid-properties.test.js => crud-grid-properties.common.js} (99%) rename packages/crud/test/{crud-grid.test.js => crud-grid.common.js} (99%) create mode 100644 packages/crud/test/crud-lit.test.js create mode 100644 packages/crud/test/crud-polymer.test.js rename packages/crud/test/{crud.test.js => crud.common.js} (99%) create mode 100644 packages/crud/theme/lumo/vaadin-lit-crud.js create mode 100644 packages/crud/theme/material/vaadin-lit-crud.js create mode 100644 packages/crud/vaadin-lit-crud-edit .js create mode 100644 packages/crud/vaadin-lit-crud-edit-column.js create mode 100644 packages/crud/vaadin-lit-crud.js diff --git a/packages/crud/src/vaadin-crud-edit-column.js b/packages/crud/src/vaadin-crud-edit-column.js index 9110084fd73..498dbe8b83c 100644 --- a/packages/crud/src/vaadin-crud-edit-column.js +++ b/packages/crud/src/vaadin-crud-edit-column.js @@ -11,6 +11,7 @@ import './vaadin-crud-edit.js'; import { defineCustomElement } from '@vaadin/component-base/src/define.js'; import { GridColumn } from '@vaadin/grid/src/vaadin-grid-column.js'; +import { editColumnDefaultRenderer } from './vaadin-crud-helpers.js'; /** * `` is a helper element for the `` @@ -69,21 +70,8 @@ class CrudEditColumn extends GridColumn { * * @override */ - _defaultRenderer(root, _column) { - let edit = root.firstElementChild; - if (!edit) { - edit = document.createElement('vaadin-crud-edit'); - if (this.hasAttribute('theme')) { - edit.setAttribute('theme', this.getAttribute('theme')); - } - root.appendChild(edit); - } - - if (this.ariaLabel) { - edit.setAttribute('aria-label', this.ariaLabel); - } else { - edit.removeAttribute('aria-label'); - } + _defaultRenderer(root, column) { + editColumnDefaultRenderer(root, column); } } diff --git a/packages/crud/src/vaadin-crud-form.js b/packages/crud/src/vaadin-crud-form.js index 161f14d46df..0f352610272 100644 --- a/packages/crud/src/vaadin-crud-form.js +++ b/packages/crud/src/vaadin-crud-form.js @@ -11,7 +11,8 @@ import '@vaadin/text-field/src/vaadin-text-field.js'; import { defineCustomElement } from '@vaadin/component-base/src/define.js'; import { FormLayout } from '@vaadin/form-layout/src/vaadin-form-layout.js'; -import { capitalize } from './vaadin-crud-helpers.js'; +import { createField } from './vaadin-crud-helpers.js'; +import { createFields } from './vaadin-crud-helpers.js'; import { IncludedMixin } from './vaadin-crud-include-mixin.js'; /** @@ -64,31 +65,12 @@ class CrudForm extends IncludedMixin(FormLayout) { /** @private */ __createField(parent, path) { - const field = document.createElement('vaadin-text-field'); - field.label = capitalize(path); - field.path = path; - field.required = true; - parent.appendChild(field); - this._fields.push(field); - return field; + return createField(this, parent, path); } /** @private */ __createFields(parent, object, path) { - Object.keys(object).forEach((prop) => { - if (!this.include && this.exclude && this.exclude.test(prop)) { - return; - } - const newPath = (path ? `${path}.` : '') + prop; - if (object[prop] && typeof object[prop] === 'object') { - this.__createFields(parent, object[prop], newPath); - } else { - this.__createField(parent, newPath); - } - }); - if (!this._fields.length) { - this._fields = undefined; - } + return createFields(this, parent, object, path); } } diff --git a/packages/crud/src/vaadin-crud-grid-mixin.js b/packages/crud/src/vaadin-crud-grid-mixin.js index 0bd1c34d881..2bc42a04b08 100644 --- a/packages/crud/src/vaadin-crud-grid-mixin.js +++ b/packages/crud/src/vaadin-crud-grid-mixin.js @@ -45,6 +45,7 @@ export const CrudGridMixin = (superClass) => */ hideEditColumn: { type: Boolean, + sync: true, }, }; } diff --git a/packages/crud/src/vaadin-crud-helpers.js b/packages/crud/src/vaadin-crud-helpers.js index 068090e5587..a4a063c3957 100644 --- a/packages/crud/src/vaadin-crud-helpers.js +++ b/packages/crud/src/vaadin-crud-helpers.js @@ -66,3 +66,47 @@ export function setProperty(path, value, obj) { export function isValidEditorPosition(editorPosition) { return ['bottom', 'aside'].includes(editorPosition); } + +export function editColumnDefaultRenderer(root, column) { + let edit = root.firstElementChild; + if (!edit) { + edit = document.createElement('vaadin-crud-edit'); + if (column.hasAttribute('theme')) { + edit.setAttribute('theme', column.getAttribute('theme')); + } + root.appendChild(edit); + } + + if (column.ariaLabel) { + edit.setAttribute('aria-label', column.ariaLabel); + } else { + edit.removeAttribute('aria-label'); + } +} + +export function createField(crudForm, parent, path) { + const field = document.createElement('vaadin-text-field'); + field.label = capitalize(path); + field.path = path; + field.required = true; + parent.appendChild(field); + crudForm._fields.push(field); + return field; +} + +export function createFields(crudForm, parent, object, path) { + Object.keys(object).forEach((prop) => { + if (!crudForm.include && crudForm.exclude && crudForm.exclude.test(prop)) { + return; + } + const newPath = (path ? `${path}.` : '') + prop; + if (object[prop] && typeof object[prop] === 'object') { + crudForm.__createFields(parent, object[prop], newPath); + } else { + crudForm.__createField(parent, newPath); + } + }); + if (!crudForm._fields.length) { + crudForm._fields = undefined; + } +} diff --git a/packages/crud/src/vaadin-crud-include-mixin.js b/packages/crud/src/vaadin-crud-include-mixin.js index d5ef67e0156..923b60dafc0 100644 --- a/packages/crud/src/vaadin-crud-include-mixin.js +++ b/packages/crud/src/vaadin-crud-include-mixin.js @@ -29,6 +29,7 @@ export const IncludedMixin = (superClass) => exclude: { value: '^_', observer: '__onExcludeChange', + sync: true, }, /** @@ -40,6 +41,7 @@ export const IncludedMixin = (superClass) => */ include: { observer: '__onIncludeChange', + sync: true, }, }; } diff --git a/packages/crud/src/vaadin-crud-mixin.js b/packages/crud/src/vaadin-crud-mixin.js index 899d46f7d06..3ac598136a5 100644 --- a/packages/crud/src/vaadin-crud-mixin.js +++ b/packages/crud/src/vaadin-crud-mixin.js @@ -100,6 +100,7 @@ export const CrudMixin = (superClass) => type: Object, observer: '__editedItemChanged', notify: true, + sync: true, }, /** @@ -117,6 +118,7 @@ export const CrudMixin = (superClass) => value: '', reflectToAttribute: true, observer: '__editorPositionChanged', + sync: true, }, /** @@ -128,6 +130,7 @@ export const CrudMixin = (superClass) => editOnClick: { type: Boolean, value: false, + sync: true, }, /** @@ -194,6 +197,7 @@ export const CrudMixin = (superClass) => reflectToAttribute: true, notify: true, observer: '__editorOpenedChanged', + sync: true, }, /** @@ -218,6 +222,7 @@ export const CrudMixin = (superClass) => type: Boolean, value: false, reflectToAttribute: true, + sync: true, }, /** @@ -261,6 +266,7 @@ export const CrudMixin = (superClass) => */ i18n: { type: Object, + sync: true, value() { return { newItem: 'New item', @@ -295,7 +301,10 @@ export const CrudMixin = (superClass) => __dialogAriaLabel: String, /** @private */ - __isDirty: Boolean, + __isDirty: { + type: Boolean, + sync: true, + }, /** @private */ __isNew: Boolean, @@ -307,6 +316,7 @@ export const CrudMixin = (superClass) => _fullscreen: { type: Boolean, observer: '__fullscreenChanged', + sync: true, }, /** @@ -369,6 +379,10 @@ export const CrudMixin = (superClass) => ready() { super.ready(); + if (this.$.dialog.performUpdate) { + this.$.dialog.performUpdate(); + } + this.$.dialog.$.overlay.addEventListener('vaadin-overlay-outside-click', this.__cancel); this.$.dialog.$.overlay.addEventListener('vaadin-overlay-escape-press', this.__cancel); diff --git a/packages/crud/src/vaadin-lit-crud-dialog.d.ts b/packages/crud/src/vaadin-lit-crud-dialog.d.ts new file mode 100644 index 00000000000..58f73793621 --- /dev/null +++ b/packages/crud/src/vaadin-lit-crud-dialog.d.ts @@ -0,0 +1,11 @@ +/** + * @license + * Copyright (c) 2000 - 2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * + * See https://vaadin.com/commercial-license-and-service-terms for the full + * license. + */ +export * from './vaadin-crud-dialog.js'; diff --git a/packages/crud/src/vaadin-lit-crud-dialog.js b/packages/crud/src/vaadin-lit-crud-dialog.js new file mode 100644 index 00000000000..bd239adf76b --- /dev/null +++ b/packages/crud/src/vaadin-lit-crud-dialog.js @@ -0,0 +1,126 @@ +/** + * @license + * Copyright (c) 2000 - 2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * + * See https://vaadin.com/commercial-license-and-service-terms for the full + * license. + */ +import { css, html, LitElement } from 'lit'; +import { defineCustomElement } from '@vaadin/component-base/src/define.js'; +import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js'; +import { OverlayClassMixin } from '@vaadin/component-base/src/overlay-class-mixin.js'; +import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js'; +import { DialogBaseMixin } from '@vaadin/dialog/src/vaadin-dialog-base-mixin.js'; +import { dialogOverlay, resizableOverlay } from '@vaadin/dialog/src/vaadin-dialog-styles.js'; +import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js'; +import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js'; +import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; +import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js'; +import { crudDialogOverlayStyles } from './vaadin-crud-styles.js'; +/** + * An element used internally by ``. Not intended to be used separately. + * + * @customElement + * @extends HTMLElement + * @mixes DirMixin + * @mixes OverlayMixin + * @mixes ThemableMixin + * @private + */ +class CrudDialogOverlay extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LitElement)))) { + static get is() { + return 'vaadin-crud-dialog-overlay'; + } + + static get styles() { + return [overlayStyles, dialogOverlay, resizableOverlay, crudDialogOverlayStyles]; + } + + render() { + return html` +
+
+
+
+
+ +
+
+ + + +
+
+
+ `; + } + + /** + * @protected + * @override + */ + ready() { + super.ready(); + + // CRUD has header and footer but does not use renderers + this.setAttribute('has-header', ''); + this.setAttribute('has-footer', ''); + } +} + +defineCustomElement(CrudDialogOverlay); + +/** + * An element used internally by ``. Not intended to be used separately. + * @private + */ +class CrudDialog extends DialogBaseMixin(OverlayClassMixin(ThemePropertyMixin(PolylitMixin(LitElement)))) { + static get is() { + return 'vaadin-crud-dialog'; + } + + static get styles() { + return css` + :host { + display: none; + } + `; + } + + static get properties() { + return { + ariaLabel: { + type: String, + }, + + fullscreen: { + type: Boolean, + }, + }; + } + + render() { + return html` + + `; + } +} + +defineCustomElement(CrudDialog); diff --git a/packages/crud/src/vaadin-lit-crud-edit-column.d.ts b/packages/crud/src/vaadin-lit-crud-edit-column.d.ts new file mode 100644 index 00000000000..ed14b3934e1 --- /dev/null +++ b/packages/crud/src/vaadin-lit-crud-edit-column.d.ts @@ -0,0 +1,11 @@ +/** + * @license + * Copyright (c) 2000 - 2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * + * See https://vaadin.com/commercial-license-and-service-terms for the full + * license. + */ +export * from './vaadin-crud-edit-column.js'; diff --git a/packages/crud/src/vaadin-lit-crud-edit-column.js b/packages/crud/src/vaadin-lit-crud-edit-column.js new file mode 100644 index 00000000000..40aa95a45ef --- /dev/null +++ b/packages/crud/src/vaadin-lit-crud-edit-column.js @@ -0,0 +1,65 @@ +/** + * @license + * Copyright (c) 2000 - 2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * + * See https://vaadin.com/commercial-license-and-service-terms for the full + * license. + */ +import './vaadin-lit-crud-edit.js'; +import { defineCustomElement } from '@vaadin/component-base/src/define.js'; +import { GridColumn } from '@vaadin/grid/src/vaadin-lit-grid-column.js'; +import { editColumnDefaultRenderer } from './vaadin-crud-helpers.js'; + +/** + * + */ +class CrudEditColumn extends GridColumn { + static get is() { + return 'vaadin-crud-edit-column'; + } + + static get properties() { + return { + /** + * Width of the cells for this column. + * @private + */ + width: { + type: String, + value: '4rem', + }, + + /** + * Flex grow ratio for the cell widths. When set to 0, cell width is fixed. + * @private + */ + flexGrow: { + type: Number, + value: 0, + }, + + /** The arial-label for the edit button */ + ariaLabel: String, + }; + } + + static get observers() { + return ['_onRendererOrBindingChanged(_renderer, _cells, _bodyContentHidden, _cells.*, path, ariaLabel)']; + } + + /** + * Renders the crud edit element to the body cell. + * + * @override + */ + _defaultRenderer(root, column) { + editColumnDefaultRenderer(root, column); + } +} + +defineCustomElement(CrudEditColumn); + +export { CrudEditColumn }; diff --git a/packages/crud/src/vaadin-lit-crud-edit.d.ts b/packages/crud/src/vaadin-lit-crud-edit.d.ts new file mode 100644 index 00000000000..be0c5bf9118 --- /dev/null +++ b/packages/crud/src/vaadin-lit-crud-edit.d.ts @@ -0,0 +1,11 @@ +/** + * @license + * Copyright (c) 2000 - 2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * + * See https://vaadin.com/commercial-license-and-service-terms for the full + * license. + */ +export * from './vaadin-crud-edit.js'; diff --git a/packages/crud/src/vaadin-lit-crud-edit.js b/packages/crud/src/vaadin-lit-crud-edit.js new file mode 100644 index 00000000000..a0181df84bb --- /dev/null +++ b/packages/crud/src/vaadin-lit-crud-edit.js @@ -0,0 +1,81 @@ +/** + * @license + * Copyright (c) 2000 - 2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * + * See https://vaadin.com/commercial-license-and-service-terms for the full + * license. + */ + +import { html } from 'lit'; +import { Button } from '@vaadin/button/src/vaadin-lit-button.js'; +import { defineCustomElement } from '@vaadin/component-base/src/define.js'; +import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; + +/** + * Use registerStyles instead of the `