diff --git a/flow-client/.eslintrc.js b/flow-client/.eslintrc.js index 76310c2fe13..c012b7c976a 100644 --- a/flow-client/.eslintrc.js +++ b/flow-client/.eslintrc.js @@ -43,7 +43,8 @@ module.exports = { "no-ex-assign": 1, "no-return-assign": 1, "no-use-before-define": 1, - "no-useless-constructor": 1, + "no-useless-constructor": 0, + "@typescript-eslint/no-useless-constructor": 1, "prefer-template": 1, "@typescript-eslint/explicit-module-boundary-types": 0, diff --git a/flow-client/package.json b/flow-client/package.json index f220602f912..f23f57f7485 100644 --- a/flow-client/package.json +++ b/flow-client/package.json @@ -49,8 +49,7 @@ }, "dependencies": { "@types/validator": "13.1.0", - "lit-element": "^2.3.1", - "lit-html": "^1.2.1", + "lit": "2.0.0-rc.1", "validator": "13.1.17" } } diff --git a/flow-client/src/main/frontend/ConnectionIndicator.ts b/flow-client/src/main/frontend/ConnectionIndicator.ts index 1b777dee7f1..d8285a59497 100644 --- a/flow-client/src/main/frontend/ConnectionIndicator.ts +++ b/flow-client/src/main/frontend/ConnectionIndicator.ts @@ -14,8 +14,9 @@ * the License. */ -import { css, html, LitElement, property } from 'lit-element'; -import { classMap } from 'lit-html/directives/class-map'; +import { html, LitElement } from 'lit'; +import { property } from 'lit/decorators'; +import { classMap } from 'lit/directives/class-map'; import { ConnectionState, ConnectionStateStore } from './ConnectionState'; const DEFAULT_STYLE_ID = 'css-loading-indicator'; @@ -246,7 +247,7 @@ export class ConnectionIndicator extends LitElement { if (!document.getElementById(DEFAULT_STYLE_ID)) { const style = document.createElement('style'); style.id = DEFAULT_STYLE_ID; - style.textContent = this.getDefaultStyle().cssText; + style.textContent = this.getDefaultStyle(); document.head.appendChild(style); } } else { @@ -257,8 +258,8 @@ export class ConnectionIndicator extends LitElement { } } - private getDefaultStyle() { - return css` + private getDefaultStyle(): string { + return ` @keyframes v-progress-start { 0% { width: 0%; diff --git a/flow-client/src/main/frontend/VaadinDevmodeGizmo.ts b/flow-client/src/main/frontend/VaadinDevmodeGizmo.ts index 823315a6287..06993d1af1d 100644 --- a/flow-client/src/main/frontend/VaadinDevmodeGizmo.ts +++ b/flow-client/src/main/frontend/VaadinDevmodeGizmo.ts @@ -1,4 +1,5 @@ -import { css, html, LitElement, property } from 'lit-element'; +import { css, html, LitElement } from 'lit'; +import { property } from 'lit/decorators'; export class VaadinDevmodeGizmo extends LitElement { static BLUE_HSL = css`206, 100%, 70%`; diff --git a/flow-client/src/main/frontend/form/Field.ts b/flow-client/src/main/frontend/form/Field.ts index eca1903bf24..ed4dcfbddd2 100644 --- a/flow-client/src/main/frontend/form/Field.ts +++ b/flow-client/src/main/frontend/form/Field.ts @@ -1,4 +1,5 @@ -import { directive, Part, PropertyPart } from 'lit-html'; +import { ElementPart, noChange, nothing, PropertyPart } from 'lit'; +import { directive, Directive, DirectiveParameters, PartInfo, PartType } from 'lit/directive'; import { _fromString, AbstractModel, getBinderNode } from './Models'; interface Field { @@ -11,8 +12,6 @@ interface FieldState extends Field { name: string; strategy: FieldStrategy; } -const fieldStateMap = new WeakMap(); - export interface FieldStrategy extends Field { element: Element; } @@ -28,7 +27,7 @@ export abstract class AbstractFieldStrategy implements FieldStrategy { set value(value) { this.element.value = value; } - set errorMessage(_: string) {} + set errorMessage(_: string) {} // eslint-disable-line @typescript-eslint/no-empty-function setAttribute(key: string, val: any) { if (val) { this.element.setAttribute(key, ''); @@ -70,7 +69,7 @@ export class CheckedFieldStrategy extends GenericFieldStrategy { export class ComboBoxFieldStrategy extends VaadinFieldStrategy { get value() { - const selectedItem = (this.element as any).selectedItem; + const { selectedItem } = this.element as any; return selectedItem === null ? undefined : selectedItem; } set value(val: any) { @@ -98,98 +97,121 @@ export function getDefaultFieldStrategy(elm: any): FieldStrategy { return new SelectedFieldStrategy(elm); case 'vaadin-rich-text-editor': return new GenericFieldStrategy(elm); - case 'input': - if (/^(checkbox|radio)$/.test(elm.type)) { + default: + if (elm.localName === 'input' && /^(checkbox|radio)$/.test(elm.type)) { return new CheckedFieldStrategy(elm); } + return elm.constructor.version ? new VaadinFieldStrategy(elm) : new GenericFieldStrategy(elm); } - return elm.constructor.version ? new VaadinFieldStrategy(elm) : new GenericFieldStrategy(elm); } /** * Binds a form field component into a model. * - * Exmaple usage: + * Example usage: * * ``` * * * ``` */ -export const field = directive((model: AbstractModel, effect?: (element: Element) => void) => (part: Part) => { - const propertyPart = part as PropertyPart; - if (!(part instanceof PropertyPart) || propertyPart.committer.name !== '..') { - throw new Error('Only supports ...="" syntax'); - } - let fieldState: FieldState; - const element = propertyPart.committer.element as HTMLInputElement & Field; - - const binderNode = getBinderNode(model); - const fieldStrategy = binderNode.binder.getFieldStrategy(element); - - const convertFieldValue = (fieldValue: any) => { - const fromString = (model as any)[_fromString]; - return typeof fieldValue === 'string' && fromString ? fromString(fieldValue) : fieldValue; - }; - - if (fieldStateMap.has(propertyPart)) { - fieldState = fieldStateMap.get(propertyPart)!; - } else { - fieldState = { - name: '', - value: '', - required: false, - invalid: false, - errorMessage: '', - strategy: fieldStrategy - }; - fieldStateMap.set(propertyPart, fieldState); - - const updateValueFromElement = () => { - fieldState.value = fieldState.strategy.value; - binderNode.value = convertFieldValue(fieldState.value); - if (effect !== undefined) { - effect.call(element, element); +export const field = directive( + class extends Directive { + fieldState?: FieldState; + + constructor(partInfo: PartInfo) { + super(partInfo); + if (partInfo.type !== PartType.PROPERTY && partInfo.type !== PartType.ELEMENT) { + throw new Error('Use as " { - updateValueFromElement(); - }; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-vars + render(model: AbstractModel, effect?: (element: Element) => void) { + return nothing; + } - element.onchange = element.onblur = () => { - updateValueFromElement(); - binderNode.visited = true; - }; + update(part: PropertyPart | ElementPart, [model, effect]: DirectiveParameters) { + const element = part.element as HTMLInputElement & Field; + + const binderNode = getBinderNode(model); + const fieldStrategy = binderNode.binder.getFieldStrategy(element); + + const convertFieldValue = (fieldValue: any) => { + const fromString = (model as any)[_fromString]; + return typeof fieldValue === 'string' && fromString ? fromString(fieldValue) : fieldValue; + }; + + if (!this.fieldState) { + this.fieldState = { + name: '', + value: '', + required: false, + invalid: false, + errorMessage: '', + strategy: fieldStrategy + }; + + const { fieldState } = this; + + const updateValueFromElement = () => { + fieldState.value = fieldState.strategy.value; + binderNode.value = convertFieldValue(fieldState.value); + if (effect !== undefined) { + effect.call(element, element); + } + }; + + element.oninput = () => { + updateValueFromElement(); + }; + + const changeBlurHandler = () => { + updateValueFromElement(); + binderNode.visited = true; + }; + element.onblur = changeBlurHandler; + element.onchange = changeBlurHandler; + + element.checkValidity = () => !fieldState.invalid; + } - element.checkValidity = () => !fieldState.invalid; - } + const { fieldState } = this; + const { name } = binderNode; + if (name !== fieldState.name) { + fieldState.name = name; + element.setAttribute('name', name); + } - const name = binderNode.name; - if (name !== fieldState.name) { - fieldState.name = name; - element.setAttribute('name', name); - } + const { value } = binderNode; + const valueFromField = convertFieldValue(fieldState.value); + if (value !== valueFromField && !(Number.isNaN(value) && Number.isNaN(valueFromField))) { + fieldState.value = value; + fieldState.strategy.value = value; + } - const value = binderNode.value; - const valueFromField = convertFieldValue(fieldState.value); - if (value !== valueFromField && !(Number.isNaN(value) && Number.isNaN(valueFromField))) { - fieldState.strategy.value = fieldState.value = value; - } + const { required } = binderNode; + if (required !== fieldState.required) { + fieldState.required = required; + fieldState.strategy.required = required; + } - const required = binderNode.required; - if (required !== fieldState.required) { - fieldState.strategy.required = fieldState.required = required; - } + const firstError = binderNode.ownErrors ? binderNode.ownErrors[0] : undefined; + const errorMessage = (firstError && firstError.message) || ''; + if (errorMessage !== fieldState.errorMessage) { + fieldState.errorMessage = errorMessage; + fieldState.strategy.errorMessage = errorMessage; + } - const firstError = binderNode.ownErrors ? binderNode.ownErrors[0] : undefined; - const errorMessage = (firstError && firstError.message) || ''; - if (errorMessage !== fieldState.errorMessage) { - fieldState.strategy.errorMessage = fieldState.errorMessage = errorMessage; - } + const { invalid } = binderNode; + if (invalid !== fieldState.invalid) { + fieldState.invalid = invalid; + fieldState.strategy.invalid = invalid; + } - const invalid = binderNode.invalid; - if (invalid !== fieldState.invalid) { - fieldState.strategy.invalid = fieldState.invalid = invalid; + return noChange; + } } -}); +); diff --git a/flow-client/src/test/frontend/form/BinderTests.ts b/flow-client/src/test/frontend/form/BinderTests.ts index 560e91f40f8..f16a15039be 100644 --- a/flow-client/src/test/frontend/form/BinderTests.ts +++ b/flow-client/src/test/frontend/form/BinderTests.ts @@ -13,7 +13,8 @@ import { import {Employee, EmployeeModel, Order, OrderModel, TestEntity, TestModel} from "./TestModels"; -import {customElement, LitElement} from 'lit-element'; +import {LitElement} from 'lit'; +import {customElement} from 'lit/decorators'; @customElement('lit-order-view') class LitOrderView extends LitElement {} diff --git a/flow-client/src/test/frontend/form/FieldTests.ts b/flow-client/src/test/frontend/form/FieldTests.ts index 35cd467ebc2..978ad8a0c92 100644 --- a/flow-client/src/test/frontend/form/FieldTests.ts +++ b/flow-client/src/test/frontend/form/FieldTests.ts @@ -1,12 +1,10 @@ -/* tslint:disable:max-classes-per-file */ +/* eslint-disable no-unused-expressions, no-shadow */ -import {BinderNode} from "../../../main/frontend/form/BinderNode"; - -const {suite, test, beforeEach, afterEach} = intern.getInterface("tdd"); -const {assert} = intern.getPlugin("chai"); -/// -const {sinon} = intern.getPlugin('sinon'); -import { expect } from "chai"; +import { expect } from 'chai'; +import { LitElement, nothing, render } from 'lit'; +import { html, unsafeStatic } from 'lit/static-html'; +import { customElement, query } from 'lit/decorators'; +import { BinderNode } from '../../../main/frontend/form/BinderNode'; // API to test import { @@ -20,15 +18,16 @@ import { AbstractModel, FieldStrategy, AbstractFieldStrategy -} from "../../../main/frontend/form"; +} from '../../../main/frontend/form'; -import {OrderModel, TestModel, TestEntity, Order} from "./TestModels"; +import { OrderModel, TestModel, TestEntity, Order } from './TestModels'; -import { customElement, html, LitElement, query} from 'lit-element'; -import { PropertyPart, AttributeCommitter } from "lit-html"; - -suite("form/Field", () => { +const { suite, test, beforeEach, afterEach } = intern.getInterface('tdd'); +const { assert } = intern.getPlugin('chai'); +/// +const { sinon } = intern.getPlugin('sinon'); +suite('form/Field', () => { suite('field with text-field', () => { @customElement('mock-text-field') class MockTextFieldElement extends HTMLElement { @@ -81,25 +80,19 @@ suite("form/Field", () => { render() { return html` - + + id="customerFullNameField" + ...="${field(this.binder.model.customer.fullName)}" + > + id="customerNickNameField" + ...="${field(this.binder.model.customer.nickName)}" + > - + `; } } @@ -116,7 +109,11 @@ suite("form/Field", () => { test('should set name attribute', () => { sinon.assert.calledOnceWithExactly(orderViewWithTextField.notesField!.setAttributeSpy, 'name', 'notes'); - sinon.assert.calledOnceWithExactly(orderViewWithTextField.customerFullNameField!.setAttributeSpy, 'name', 'customer.fullName'); + sinon.assert.calledOnceWithExactly( + orderViewWithTextField.customerFullNameField!.setAttributeSpy, + 'name', + 'customer.fullName' + ); }); test('should only set name attribute once', async () => { @@ -148,10 +145,10 @@ suite("form/Field", () => { const emptyOrder = OrderModel.createEmptyValue(); orderViewWithTextField.binder.read({ ...emptyOrder, - notes: "foo", + notes: 'foo', customer: { ...emptyOrder.customer, - fullName: "bar" + fullName: 'bar' } }); await orderViewWithTextField.updateComplete; @@ -164,10 +161,10 @@ suite("form/Field", () => { const emptyOrder = OrderModel.createEmptyValue(); orderViewWithTextField.binder.read({ ...emptyOrder, - notes: "foo", + notes: 'foo', customer: { ...emptyOrder.customer, - fullName: "bar" + fullName: 'bar' } }); await orderViewWithTextField.updateComplete; @@ -204,10 +201,9 @@ suite("form/Field", () => { test('should update binder value on input event', async () => { orderViewWithTextField.requestUpdateSpy.resetHistory(); orderViewWithTextField.notesField!.value = 'foo'; - orderViewWithTextField.notesField!.dispatchEvent(new CustomEvent( - 'input', - {bubbles: true, composed: true, cancelable: false} - )); + orderViewWithTextField.notesField!.dispatchEvent( + new CustomEvent('input', { bubbles: true, composed: true, cancelable: false }) + ); await orderViewWithTextField.updateComplete; assert.equal(orderViewWithTextField.binder.value.notes, 'foo'); @@ -217,10 +213,9 @@ suite("form/Field", () => { test('should update binder value on change event', async () => { orderViewWithTextField.requestUpdateSpy.resetHistory(); orderViewWithTextField.notesField!.value = 'foo'; - orderViewWithTextField.notesField!.dispatchEvent(new CustomEvent( - 'change', - {bubbles: true, composed: true, cancelable: false} - )); + orderViewWithTextField.notesField!.dispatchEvent( + new CustomEvent('change', { bubbles: true, composed: true, cancelable: false }) + ); await orderViewWithTextField.updateComplete; assert.equal(orderViewWithTextField.binder.value.notes, 'foo'); @@ -230,10 +225,9 @@ suite("form/Field", () => { test('should update binder value on blur event', async () => { orderViewWithTextField.requestUpdateSpy.resetHistory(); orderViewWithTextField.notesField!.value = 'foo'; - orderViewWithTextField.notesField!.dispatchEvent(new CustomEvent( - 'blur', - {bubbles: true, composed: true, cancelable: false} - )); + orderViewWithTextField.notesField!.dispatchEvent( + new CustomEvent('blur', { bubbles: true, composed: true, cancelable: false }) + ); await orderViewWithTextField.updateComplete; assert.equal(orderViewWithTextField.binder.value.notes, 'foo'); @@ -241,25 +235,24 @@ suite("form/Field", () => { }); test('should set visited on blur event', async () => { - const binder = orderViewWithTextField.binder; + const { binder } = orderViewWithTextField; const binderNode = binder.for(binder.model.notes); expect(binderNode.visited).to.be.false; - orderViewWithTextField.notesField!.dispatchEvent(new CustomEvent( - 'blur', - {bubbles: true, composed: true, cancelable: false} - )); + orderViewWithTextField.notesField!.dispatchEvent( + new CustomEvent('blur', { bubbles: true, composed: true, cancelable: false }) + ); await orderViewWithTextField.updateComplete; expect(binderNode.visited).to.be.true; }); suite('number model', () => { - let view: OrderViewWithTextField, - priorityField: MockTextFieldElement, - binder: Binder; + let view: OrderViewWithTextField; + let priorityField: MockTextFieldElement; + let binder: Binder; - beforeEach(async() => { + beforeEach(async () => { view = orderViewWithTextField; binder = view.binder; priorityField = view.priorityField!; @@ -299,11 +292,10 @@ suite("form/Field", () => { priorityField.value = inputValue; priorityField.valueSpy.get.resetHistory(); priorityField.valueSpy.set.resetHistory(); - priorityField.dispatchEvent(new CustomEvent( - eventName, - {bubbles: true, composed: true, cancelable: false} - )); - await view.updateComplete; + priorityField.dispatchEvent( + new CustomEvent(eventName, { bubbles: true, composed: true, cancelable: false }) + ); + await view.updateComplete; // eslint-disable-line no-await-in-loop if (Number.isNaN(expectedNumber)) { // NaN never equals @@ -381,10 +373,16 @@ suite("form/Field", () => { test('should set name and required attributes once', async () => { sinon.assert.calledTwice(orderViewWithInput.customerFullNameField!.setAttributeSpy); - assert.deepEqual(orderViewWithInput.customerFullNameField!.setAttributeSpy.getCall(0).args, ['name', 'customer.fullName']); + assert.deepEqual(orderViewWithInput.customerFullNameField!.setAttributeSpy.getCall(0).args, [ + 'name', + 'customer.fullName' + ]); assert.deepEqual(orderViewWithInput.customerFullNameField!.setAttributeSpy.getCall(1).args, ['required', '']); sinon.assert.calledOnce(orderViewWithInput.customerNickNameField!.setAttributeSpy); - assert.deepEqual(orderViewWithInput.customerNickNameField!.setAttributeSpy.getCall(0).args, ['name', 'customer.nickName']); + assert.deepEqual(orderViewWithInput.customerNickNameField!.setAttributeSpy.getCall(0).args, [ + 'name', + 'customer.nickName' + ]); orderViewWithInput.binder.for(orderViewWithInput.binder.model.customer.fullName).value = 'foo'; await orderViewWithInput.updateComplete; @@ -396,9 +394,9 @@ suite("form/Field", () => { }); suite('number model', () => { - let view: OrderViewWithInput, - priorityField: MockInputElement, - binder: Binder; + let view: OrderViewWithInput; + let priorityField: MockInputElement; + let binder: Binder; beforeEach(async () => { view = orderViewWithInput; @@ -440,11 +438,10 @@ suite("form/Field", () => { priorityField.value = inputValue; priorityField.valueSpy.get.resetHistory(); priorityField.valueSpy.set.resetHistory(); - priorityField.dispatchEvent(new CustomEvent( - eventName, - {bubbles: true, composed: true, cancelable: false} - )); - await view.updateComplete; + priorityField.dispatchEvent( + new CustomEvent(eventName, { bubbles: true, composed: true, cancelable: false }) + ); + await view.updateComplete; // eslint-disable-line no-await-in-loop if (Number.isNaN(expectedNumber)) { // NaN never equals @@ -466,64 +463,94 @@ suite("form/Field", () => { }); suite('field/Strategy', () => { - const element = document.createElement('div'); + const div = document.createElement('div'); let currentStrategy: FieldStrategy; - let binder = new class StrategySpyBinder> extends Binder { + const binder = new (class StrategySpyBinder> extends Binder { getFieldStrategy(elm: any): FieldStrategy { currentStrategy = super.getFieldStrategy(elm); return currentStrategy; } - }(element, TestModel); + })(div, TestModel); async function resetBinderNodeValidation(binderNode: BinderNode>) { binderNode.validators = []; await binderNode.validate(); } - ['div', - 'input', - 'vaadin-rich-text-editor' - ].forEach(tag => { - test(`GenericFieldStrategy ${tag}`, async() => { - const element: Element & {value?: any} = document.createElement(tag); + @customElement('any-vaadin-element-tag') + // eslint-disable-next-line @typescript-eslint/no-unused-vars + class AnyVaadinElement extends LitElement { + static get version() { + return '1.0'; + } + + render() { + return html``; + } + } + + beforeEach(() => { + render(nothing, div); + }); + + ['div', 'input', 'vaadin-rich-text-editor'].forEach((tag) => { + test(`GenericFieldStrategy ${tag}`, async () => { + /* eslint-disable lit/binding-positions, lit/no-invalid-html */ + const tagName = unsafeStatic(tag); + const model = binder.model.fieldString; const binderNode = binder.for(model); binderNode.value = 'foo'; await resetBinderNodeValidation(binderNode); - binderNode.validators = [{message: 'any-err-msg', validate: () => false}]; + const renderElement = () => { + render(html`<${tagName} ${field(model)}>`, div); + return div.firstElementChild as Element & { value?: any }; + }; + + binderNode.validators = [{ message: 'any-err-msg', validate: () => false }]; - const part = new PropertyPart(new AttributeCommitter(element, '..', [])); - field(model)(part); + renderElement(); expect(currentStrategy instanceof GenericFieldStrategy).to.be.true; expect(currentStrategy.value).to.be.equal('foo'); await binderNode.validate(); - field(model)(part); + const element = renderElement(); + expect(element.hasAttribute('invalid')).to.be.true; expect(element.hasAttribute('errorMessage')).to.be.false; }); }); - [{tag: 'input', type: 'checkbox'}, - {tag: 'input', type: 'radio'}, - {tag: 'vaadin-checkbox', type: ''}, - {tag: 'vaadin-radio-button', type: ''} - ].forEach(({tag, type}) => { - test(`CheckedFieldStrategy ${tag} ${type}`, async() => { - const element: Element & {checked?: boolean} = document.createElement(tag); - type && element.setAttribute('type', type); + [ + { tag: 'input', type: 'checkbox' }, + { tag: 'input', type: 'radio' }, + { tag: 'vaadin-checkbox', type: '' }, + { tag: 'vaadin-radio-button', type: '' } + ].forEach(({ tag, type }) => { + test(`CheckedFieldStrategy ${tag} ${type}`, async () => { + const tagName = unsafeStatic(tag); + const model = binder.model.fieldBoolean; const binderNode = binder.for(model); + let element; + const renderElement = () => { + if (type) { + render(html`<${tagName} type="${type}" ${field(model)}>`, div); + } else { + render(html`<${tagName} ${field(model)}>`, div); + } + return div.firstElementChild as Element & { checked?: boolean }; + }; + binderNode.value = true; await resetBinderNodeValidation(binderNode); - binderNode.validators = [{message: 'any-err-msg', validate: () => false}]; + binderNode.validators = [{ message: 'any-err-msg', validate: () => false }]; - const part = new PropertyPart(new AttributeCommitter(element, '..', [])); - field(model)(part); + element = renderElement(); expect(currentStrategy instanceof CheckedFieldStrategy).to.be.true; expect(currentStrategy.value).to.be.true; @@ -531,48 +558,58 @@ suite("form/Field", () => { expect(element.checked).to.be.true; await binderNode.validate(); - field(model)(part); + element = renderElement(); expect(element.hasAttribute('invalid')).to.be.true; expect(element.hasAttribute('errorMessage')).to.be.false; }); }); test(`SelectedFieldStrategy`, async () => { - const element: Element & {selected?: boolean} = document.createElement('vaadin-list-box'); const model = binder.model.fieldBoolean; const binderNode = binder.for(model); + let element; + const renderElement = () => { + render(html``, div); + return div.firstElementChild as Element & { selected?: boolean }; + }; + binderNode.value = true; - binderNode.validators = [{message: 'any-err-msg', validate: () => false}]; + binderNode.validators = [{ message: 'any-err-msg', validate: () => false }]; - const part = new PropertyPart(new AttributeCommitter(element, '..', [])); - field(model)(part); + element = renderElement(); expect(currentStrategy instanceof SelectedFieldStrategy).to.be.true; expect(currentStrategy.value).to.be.true; expect(element.selected).to.be.true; await binderNode.validate(); - field(model)(part); + element = renderElement(); expect(element.hasAttribute('invalid')).to.be.true; expect(element.hasAttribute('errorMessage')).to.be.false; }); - - [{model: binder.model.fieldString as AbstractModel, value: 'a-string-value'}, - {model: binder.model.fieldBoolean as AbstractModel, value: true}, - {model: binder.model.fieldNumber as AbstractModel, value: 10}, - {model: binder.model.fieldObject as AbstractModel, value: {foo: true}}, - {model: binder.model.fieldArrayString as AbstractModel, value: ['a', 'b']}, - {model: binder.model.fieldArrayModel as AbstractModel, value: [{idString: 'id'}]} - ].forEach(async ({model, value}, idx) => { + [ + { model: binder.model.fieldString as AbstractModel, value: 'a-string-value' }, + { model: binder.model.fieldBoolean as AbstractModel, value: true }, + { model: binder.model.fieldNumber as AbstractModel, value: 10 }, + { model: binder.model.fieldObject as AbstractModel, value: { foo: true } }, + { model: binder.model.fieldArrayString as AbstractModel, value: ['a', 'b'] }, + { model: binder.model.fieldArrayModel as AbstractModel, value: [{ idString: 'id' }] } + ].forEach(async ({ model, value }, idx) => { test(`VaadinFieldStrategy ${model.constructor.name} ${idx}`, async () => { - const element: Element & { - value?: any, - invalid?: boolean, - required?: boolean, - errorMessage?: string} = document.createElement('any-vaadin-element-tag'); - (element.constructor as any).version = '1.0'; + let element; + const renderElement = () => { + render(html``, div); + const result = div.firstElementChild as Element & { + value?: any; + invalid?: boolean; + required?: boolean; + errorMessage?: string; + }; + return result; + }; + const binderNode = binder.for(model); binderNode.value = value; @@ -581,14 +618,9 @@ suite("form/Field", () => { binderNode.validators = []; await binderNode.validate(); - binderNode.validators = [ - {message: 'any-err-msg', validate: () => false}, - new Required() - ]; + binderNode.validators = [{ message: 'any-err-msg', validate: () => false }, new Required()]; - const part = new PropertyPart(new AttributeCommitter(element, '..', [])); - field(model)(part); - delete (element.constructor as any).version; + element = renderElement(); expect(currentStrategy instanceof VaadinFieldStrategy).to.be.true; expect(currentStrategy.value).to.be.equal(value); @@ -598,7 +630,7 @@ suite("form/Field", () => { expect(element.errorMessage).to.be.undefined; await binderNode.validate(); - field(model)(part); + element = renderElement(); expect(element.invalid).to.be.true; expect(element.errorMessage).to.be.equal('any-err-msg'); }); @@ -607,12 +639,12 @@ suite("form/Field", () => { test(`Strategy can be overridden in binder`, async () => { const element = document.createElement('div'); class MyStrategy extends AbstractFieldStrategy { - invalid = true; + invalid = true; required = true; } class MyBinder extends Binder { - getFieldStrategy(elm: any):FieldStrategy { + getFieldStrategy(elm: any): FieldStrategy { currentStrategy = new MyStrategy(elm); return currentStrategy; } @@ -622,11 +654,10 @@ suite("form/Field", () => { } const binder = new MyBinder(element); - const model = binder.model; + const { model } = binder; - const part = new PropertyPart(new AttributeCommitter(element, '..', [])); - field(model)(part); + render(html`
`, element); expect(currentStrategy instanceof MyStrategy).to.be.true; }); - }) + }); }); diff --git a/flow-client/src/test/frontend/form/ValidationTests.ts b/flow-client/src/test/frontend/form/ValidationTests.ts index 30e7e7ddafc..13ce54a5d58 100644 --- a/flow-client/src/test/frontend/form/ValidationTests.ts +++ b/flow-client/src/test/frontend/form/ValidationTests.ts @@ -1,26 +1,19 @@ -/* tslint:disable:max-classes-per-file */ +/* eslint-disable lit/no-template-arrow, no-unused-expressions, no-shadow */ -import {repeat} from "lit-html/directives/repeat"; - -const {suite, test, beforeEach, afterEach} = intern.getInterface("tdd"); -const {assert} = intern.getPlugin("chai"); -/// -const {sinon} = intern.getPlugin('sinon'); -import { expect } from "chai"; +import { expect } from 'chai'; +import { css, html, LitElement } from 'lit'; +import { customElement, query } from 'lit/decorators'; +import { repeat } from 'lit/directives/repeat'; // API to test -import { - Binder, - field, - Required, - ValidationError, - Validator, - ValueError -} from "../../../main/frontend/form"; +import { Binder, field, Required, ValidationError, Validator, ValueError } from '../../../main/frontend/form'; -import { IdEntity, IdEntityModel, Order, OrderModel, TestEntity, TestModel } from "./TestModels"; +import { IdEntity, IdEntityModel, Order, OrderModel, TestEntity, TestModel } from './TestModels'; -import { css, customElement, html, LitElement, query} from 'lit-element'; +const { suite, test, beforeEach, afterEach } = intern.getInterface('tdd'); +const { assert } = intern.getPlugin('chai'); +/// +const { sinon } = intern.getPlugin('sinon'); @customElement('order-view') class OrderView extends LitElement { @@ -35,34 +28,49 @@ class OrderView extends LitElement { @query('#priceError0') priceError!: HTMLOutputElement; static get styles() { - return css`input[invalid] {border: 2px solid red;}`; + return css` + input[invalid] { + border: 2px solid red; + } + `; } render() { - const {notes, products, customer: {fullName, nickName}} = this.binder.model; + const { + notes, + products, + customer: { fullName, nickName } + } = this.binder.model; + return html` - - - - - ${repeat(products, ({model: {description, price}}, index) => html`
- - - - ${this.binder.for(price).errors.map(error => error.message).join('\n')} - -
`)} -
${this.binder.submitting}
+ + + + + ${repeat( + products, + ({ model: { description, price } }, index) => html`
+ + + + ${this.binder + .for(price) + .errors.map((error) => error.message) + .join('\n')} + +
` + )} +
${this.binder.submitting}
`; } } -const sleep = async (t: number) => new Promise(resolve => setTimeout(() => resolve(), t)); +const sleep = async (t: number) => new Promise((resolve) => setTimeout(() => resolve(), t)); const fireEvent = async (elm: Element, name: string) => { elm.dispatchEvent(new CustomEvent(name)); return sleep(0); -} +}; -suite("form/Validation", () => { +suite('form/Validation', () => { let binder: Binder>; const view = document.createElement('div'); @@ -70,44 +78,40 @@ suite("form/Validation", () => { binder = new Binder(view, OrderModel); }); - test("should run all validators per model", async () => { - return binder.for(binder.model.customer).validate().then(errors => { - expect(errors.map(e => e.validator.constructor.name).sort()).to.eql([ - "Required", - "Size" - ]); - }); + test('should run all validators per model', async () => { + return binder + .for(binder.model.customer) + .validate() + .then((errors) => { + expect(errors.map((e) => e.validator.constructor.name).sort()).to.eql(['Required', 'Size']); + }); }); - test("should run all nested validations per model", async () => { - return binder.validate().then(errors => { - expect(errors.map(e => e.property)).to.eql([ - "customer.fullName", - "customer.fullName", - "notes" - ]); + test('should run all nested validations per model', async () => { + return binder.validate().then((errors) => { + expect(errors.map((e) => e.property)).to.eql(['customer.fullName', 'customer.fullName', 'notes']); }); }); - test("should run all validations per array items", async () => { + test('should run all validations per array items', async () => { binder.for(binder.model.products).appendItem(); binder.for(binder.model.products).appendItem(); - return binder.validate().then(errors => { - expect(errors.map(e => e.property)).to.eql([ - "customer.fullName", - "customer.fullName", - "notes", - "products.0.description", - "products.0.price", - "products.1.description", - "products.1.price" + return binder.validate().then((errors) => { + expect(errors.map((e) => e.property)).to.eql([ + 'customer.fullName', + 'customer.fullName', + 'notes', + 'products.0.description', + 'products.0.price', + 'products.1.description', + 'products.1.price' ]); }); }); suite('clearing', () => { - ['reset', 'clear'].forEach(methodName => { - test(`should reset validation on ${methodName}`, async() => { + ['reset', 'clear'].forEach((methodName) => { + test(`should reset validation on ${methodName}`, async () => { await binder.validate(); expect(binder.invalid).to.be.true; expect(binder.for(binder.model.customer.fullName).invalid).to.be.true; @@ -121,52 +125,64 @@ suite("form/Validation", () => { }); suite('submitTo', () => { - test("should be able to call submit() if onSubmit is pre configured", async () => { + test('should be able to call submit() if onSubmit is pre configured', async () => { const binder = new Binder(view, TestModel, { - onSubmit: async () => {} + onSubmit: async () => { + // do nothing + } }); const binderSubmitToSpy = sinon.spy(binder, 'submitTo'); await binder.submit(); sinon.assert.calledOnce(binderSubmitToSpy); }); - test("should return the result of the endpoint call when calling submit()", async () => { - const binder = new Binder(view, TestModel, {onSubmit: async (testEntity) => testEntity}); + test('should return the result of the endpoint call when calling submit()', async () => { + const binder = new Binder(view, TestModel, { onSubmit: async (testEntity) => testEntity }); const result = await binder.submit(); assert.deepEqual(result, binder.value); - }) + }); - test("should throw on validation failure", async () => { + test('should throw on validation failure', async () => { try { - await binder.submitTo(async() => {}); + await binder.submitTo(async () => { + // do nothing + }); expect.fail(); } catch (error) { expect(error.errors.length).to.gt(0); } }); - test("should re-throw on server failure", async () => { + test('should re-throw on server failure', async () => { binder.for(binder.model.customer.fullName).value = 'foobar'; binder.for(binder.model.notes).value = 'whatever'; try { - await binder.submitTo(async() => {throw new Error('whatever')}); + await binder.submitTo(async () => { + throw new Error('whatever'); + }); expect.fail(); } catch (error) { expect(error.message).to.be.equal('whatever'); } }); - test("should wrap server validation error", async () => { + test('should wrap server validation error', async () => { binder.for(binder.model.customer.fullName).value = 'foobar'; binder.for(binder.model.notes).value = 'whatever'; try { - await binder.submitTo(async() => {throw { - message: "Validation error in endpoint 'MyEndpoint' method 'saveMyBean'", - validationErrorData: [{ - message: "Object of type 'com.example.MyBean' has invalid property 'foo' with value 'baz', validation error: 'custom message'", - parameterName: "foo", - }] - }}); + await binder.submitTo(async () => { + // eslint-disable-next-line no-throw-literal + throw { + message: "Validation error in endpoint 'MyEndpoint' method 'saveMyBean'", + validationErrorData: [ + { + message: + "Object of type 'com.example.MyBean' has invalid property 'foo' with value 'baz', validation error: 'custom message'", + parameterName: 'foo' + } + ] + }; + }); expect.fail(); } catch (error) { expect(error.errors[0].message).to.be.equal('custom message'); @@ -175,17 +191,22 @@ suite("form/Validation", () => { } }); - test("should wrap server validation error with any message", async () => { + test('should wrap server validation error with any message', async () => { binder.for(binder.model.customer.fullName).value = 'foobar'; binder.for(binder.model.notes).value = 'whatever'; try { - await binder.submitTo(async() => {throw { - message: "Validation error in endpoint 'MyEndpoint' method 'saveMyBean'", - validationErrorData: [{ - message: "Custom server message", - parameterName: "bar", - }] - }}); + await binder.submitTo(async () => { + // eslint-disable-next-line no-throw-literal + throw { + message: "Validation error in endpoint 'MyEndpoint' method 'saveMyBean'", + validationErrorData: [ + { + message: 'Custom server message', + parameterName: 'bar' + } + ] + }; + }); expect.fail(); } catch (error) { expect(error.errors[0].message).to.be.equal('Custom server message'); @@ -194,11 +215,11 @@ suite("form/Validation", () => { } }); - test("record level cross field validation", async () => { - const byPropertyName = (value: string) => ((error: ValueError) => { + test('record level cross field validation', async () => { + const byPropertyName = (value: string) => (error: ValueError) => { const propertyName = typeof error.property === 'string' ? error.property : binder.for(error.property).name; return propertyName === value; - }); + }; const recordValidator = { validate(value: Order) { @@ -213,13 +234,13 @@ suite("form/Validation", () => { binder.addValidator(recordValidator); binder.for(binder.model.customer.fullName).value = 'foo'; - await binder.validate().then(errors => { - const crossFieldError = errors.find(error => error.validator === recordValidator); + await binder.validate().then((errors) => { + const crossFieldError = errors.find((error) => error.validator === recordValidator); expect(crossFieldError, 'recordValidator should not cause an error').to.be.undefined; }); binder.for(binder.model.customer.nickName).value = 'foo'; - return binder.validate().then(errors => { + return binder.validate().then((errors) => { const crossFieldError = errors.find(byPropertyName('customer.nickName')); expect(crossFieldError).not.to.be.undefined; crossFieldError && expect(crossFieldError.message).to.equal('cannot be the same'); @@ -234,80 +255,80 @@ suite("form/Validation", () => { binder = new Binder(view, IdEntityModel); }); - test("should not have validation errors for a model without validators", async () => { + test('should not have validation errors for a model without validators', async () => { assert.isEmpty(await binder.validate()); }); - test("should not have validation errors for a validator that returns true", async () => { - binder.addValidator({message: 'foo', validate: () => true}); + test('should not have validation errors for a validator that returns true', async () => { + binder.addValidator({ message: 'foo', validate: () => true }); assert.isEmpty(await binder.validate()); }); - test("should not have validation errors for a validator that returns an empty array", async () => { - binder.addValidator({message: 'foo', validate: () => []}); + test('should not have validation errors for a validator that returns an empty array', async () => { + binder.addValidator({ message: 'foo', validate: () => [] }); assert.isEmpty(await binder.validate()); }); - test("should fail validation after adding a synchronous validator to the model", async () => { - binder.addValidator({message: 'foo', validate: () => false}); - return binder.validate().then(errors => { - expect(errors[0].message).to.equal("foo"); + test('should fail validation after adding a synchronous validator to the model', async () => { + binder.addValidator({ message: 'foo', validate: () => false }); + return binder.validate().then((errors) => { + expect(errors[0].message).to.equal('foo'); expect(errors[0].property).to.equal(''); - expect(errors[0].value).to.eql({idString: ''}); + expect(errors[0].value).to.eql({ idString: '' }); }); }); - test("should fail validation after adding an asynchronous validator to the model", async () => { - class AsyncValidator implements Validator{ - message = "bar"; + test('should fail validation after adding an asynchronous validator to the model', async () => { + class AsyncValidator implements Validator { + message = 'bar'; validate = async () => { await sleep(10); return false; }; } binder.addValidator(new AsyncValidator()); - return binder.validate().then(errors => { - expect(errors[0].message).to.equal("bar"); + return binder.validate().then((errors) => { + expect(errors[0].message).to.equal('bar'); }); }); - test("should not have validations errors after adding validators to properties if property is not required", async () => { - binder.for(binder.model.idString).addValidator({message: 'foo', validate: () => false}); + test('should not have validations errors after adding validators to properties if property is not required', async () => { + binder.for(binder.model.idString).addValidator({ message: 'foo', validate: () => false }); const errors = await binder.validate(); assert.isEmpty(errors); }); - test("should fail after adding validators to properties if property is not required but it has a value", async () => { + test('should fail after adding validators to properties if property is not required but it has a value', async () => { binder.for(binder.model.idString).value = 'bar'; - binder.for(binder.model.idString).addValidator({message: 'foo', validate: () => false}); + binder.for(binder.model.idString).addValidator({ message: 'foo', validate: () => false }); const errors = await binder.validate(); - expect(errors[0].message).to.equal("foo"); + expect(errors[0].message).to.equal('foo'); expect(errors[0].property).to.equal('idString'); expect(errors[0].value).to.eql('bar'); }); - test("should fail after adding validators to properties if required and not value", async () => { - binder.for(binder.model.idString).addValidator({message: 'foo', validate: () => false}); + test('should fail after adding validators to properties if required and not value', async () => { + binder.for(binder.model.idString).addValidator({ message: 'foo', validate: () => false }); binder.for(binder.model.idString).addValidator(new Required()); const errors = await binder.validate(); expect(errors.length).to.equal(2); }); - test("should fail when validator returns a single ValidationResult", async () => { - binder.addValidator({message: 'foo', validate: () => ({ property: binder.model.idString })}); - return binder.validate().then(errors => { + test('should fail when validator returns a single ValidationResult', async () => { + binder.addValidator({ message: 'foo', validate: () => ({ property: binder.model.idString }) }); + return binder.validate().then((errors) => { expect(errors[0].message).to.equal('foo'); expect(errors[0].property).to.equal(binder.model.idString); - expect(errors[0].value).to.eql({idString: ''}); + expect(errors[0].value).to.eql({ idString: '' }); }); }); - test("should fail when validator returns an array of ValidationResult objects", async () => { - binder.addValidator({message: 'foo', validate: () => [{ property: binder.model.idString }]}); - return binder.validate().then(errors => { + test('should fail when validator returns an array of ValidationResult objects', async () => { + binder.addValidator({ message: 'foo', validate: () => [{ property: binder.model.idString }] }); + return binder.validate().then((errors) => { expect(errors[0].message).to.equal('foo'); expect(errors[0].property).to.equal(binder.model.idString); - expect(errors[0].value).to.eql({idString: ''}); + expect(errors[0].value).to.eql({ idString: '' }); }); }); @@ -340,13 +361,16 @@ suite("form/Validation", () => { binder = new Binder(view, TestModel); }); - test("should fail when validator returns an array of ValidationResult objects", async () => { - binder.addValidator({message: 'foo', validate: () => [ + test('should fail when validator returns an array of ValidationResult objects', async () => { + binder.addValidator({ + message: 'foo', + validate: () => [ { property: binder.model.fieldString }, { property: binder.model.fieldNumber }, { property: binder.model.fieldBoolean, message: 'bar' } - ]}); - return binder.validate().then(errors => { + ] + }); + return binder.validate().then((errors) => { expect(errors).has.lengthOf(3); expect(errors[0].message).to.equal('foo'); expect(errors[0].value).to.eql(TestModel.createEmptyValue()); @@ -370,10 +394,10 @@ suite("form/Validation", () => { }); afterEach(async () => { - document.body.removeChild(orderView) + document.body.removeChild(orderView); }); - ['change', 'blur'].forEach(event => { + ['change', 'blur'].forEach((event) => { test(`should validate field on ${event}`, async () => { expect(orderView.notes.hasAttribute('invalid')).to.be.false; await fireEvent(orderView.notes, event); @@ -413,6 +437,7 @@ suite("form/Validation", () => { await orderView.binder.submitTo(async (item) => item); expect.fail(); } catch (error) { + // do nothing } expect(orderView.notes.hasAttribute('invalid')).to.be.true; @@ -432,7 +457,7 @@ suite("form/Validation", () => { await orderView.binder.submitTo(async (item) => item); expect.fail(); } catch (error) { - expect((error as ValidationError).errors.map(e => e.property)).to.be.eql([ + expect((error as ValidationError).errors.map((e) => e.property)).to.be.eql([ 'customer.fullName', 'customer.fullName', 'notes', @@ -445,8 +470,7 @@ suite("form/Validation", () => { expect(orderView.description.hasAttribute('invalid')).to.be.true; expect(orderView.price.hasAttribute('invalid')).to.be.true; - expect(String(orderView.priceError.textContent).trim()) - .to.equal('must be greater than 0'); + expect(String(orderView.priceError.textContent).trim()).to.equal('must be greater than 0'); }); test(`should validate fields of arrays on submit`, async () => { @@ -461,6 +485,7 @@ suite("form/Validation", () => { await orderView.binder.submitTo(async (item) => item); expect.fail(); } catch (error) { + // do nothing } expect(orderView.description.hasAttribute('invalid')).to.be.true; @@ -482,6 +507,7 @@ suite("form/Validation", () => { await orderView.binder.submitTo(async (item) => item); expect.fail(); } catch (error) { + // do nothing } }); @@ -498,7 +524,7 @@ suite("form/Validation", () => { orderView.price.value = '10'; await fireEvent(orderView.price, 'change'); - const item = await orderView.binder.submitTo(async (item) => item) as Order; + const item = await orderView.binder.submitTo(async (item) => item); expect(item).not.to.be.undefined; expect(item.products[0].description).to.be.equal('bread'); expect(item.products[0].price).to.be.equal(10); @@ -507,38 +533,40 @@ suite("form/Validation", () => { }); test('should display server validation error', async () => { - binder.for(binder.model.customer.fullName).value='foobar'; - binder.for(binder.model.notes).value='whatever'; + binder.for(binder.model.customer.fullName).value = 'foobar'; + binder.for(binder.model.notes).value = 'whatever'; const requestUpdateSpy = sinon.spy(orderView, 'requestUpdate'); try { await binder.submitTo(async () => { requestUpdateSpy.resetHistory(); + // eslint-disable-next-line no-throw-literal throw { message: 'Validation error in endpoint "MyEndpoint" method "saveMyBean"', - validationErrorData: [{ - message: 'Invalid notes', - parameterName: 'notes', - }] - } + validationErrorData: [ + { + message: 'Invalid notes', + parameterName: 'notes' + } + ] + }; }); expect.fail(); } catch (error) { sinon.assert.calledOnce(requestUpdateSpy); await orderView.updateComplete; expect(binder.for(binder.model.notes).invalid).to.be.true; - expect(binder.for(binder.model.notes).ownErrors[0].message) - .to.equal('Invalid notes'); + expect(binder.for(binder.model.notes).ownErrors![0].message).to.equal('Invalid notes'); } }); - test("should display submitting state during submittion", async () => { + test('should display submitting state during submission', async () => { binder.for(binder.model.customer.fullName).value = 'Jane Doe'; binder.for(binder.model.notes).value = 'foo'; await orderView.updateComplete; expect(binder.submitting).to.be.false; const requestUpdateSpy = sinon.spy(orderView, 'requestUpdate'); - const endpoint = sinon.stub().callsFake(async() => { + const endpoint = sinon.stub().callsFake(async () => { sinon.assert.called(requestUpdateSpy); expect(binder.submitting).to.be.true; await orderView.updateComplete; @@ -555,11 +583,12 @@ suite("form/Validation", () => { }); // https://github.com/vaadin/flow/issues/8688 - test("should update binder properties after submit when a field changes value", async () => { + test('should update binder properties after submit when a field changes value', async () => { try { await orderView.binder.submitTo(async (item) => item); expect.fail(); } catch (error) { + // do nothing } const errorsOnSubmit = binder.errors.length; @@ -567,8 +596,8 @@ suite("form/Validation", () => { await fireEvent(orderView.notes, 'change'); const numberOfValidatorsOnNotesField = binder.for(binder.model.notes).validators.length; - if(errorsOnSubmit>=1){ - assert.equal(errorsOnSubmit-numberOfValidatorsOnNotesField, binder.errors.length); + if (errorsOnSubmit >= 1) { + assert.equal(errorsOnSubmit - numberOfValidatorsOnNotesField, binder.errors.length); } }); @@ -578,9 +607,7 @@ suite("form/Validation", () => { orderView.price.value = 'not a number'; await fireEvent(orderView.price, 'change'); - expect(String(orderView.priceError.textContent)) - .to.contain('must be a number') + expect(String(orderView.priceError.textContent)).to.contain('must be a number'); }); }); - }); diff --git a/flow-lit-template/src/test/java/com/vaadin/flow/component/littemplate/BundleLitParserTest.java b/flow-lit-template/src/test/java/com/vaadin/flow/component/littemplate/BundleLitParserTest.java index aafb2acea4e..706bbe6e1aa 100644 --- a/flow-lit-template/src/test/java/com/vaadin/flow/component/littemplate/BundleLitParserTest.java +++ b/flow-lit-template/src/test/java/com/vaadin/flow/component/littemplate/BundleLitParserTest.java @@ -23,7 +23,7 @@ import org.junit.Test; public class BundleLitParserTest { - private String content = "\n var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n };\n import { customElement, html, LitElement } from 'lit-element';\n let AboutView = class AboutView extends LitElement {\n render() {\n return html `\n
\n
\n \n Important\n \n
\n \n Save\n Cancel\n \n
\n
`;\n }\n };\n AboutView = __decorate([\n customElement('about-view')\n ], AboutView);\n export { AboutView };\n"; + private String content = "\n var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n };\n import { html, LitElement } from 'lit';\n import { customElement } from 'lit/decorators';\n let AboutView = class AboutView extends LitElement {\n render() {\n return html `\n
\n
\n \n Important\n \n
\n \n Save\n Cancel\n \n
\n
`;\n }\n };\n AboutView = __decorate([\n customElement('about-view')\n ], AboutView);\n export { AboutView };\n"; @Test public void parseTemplate() throws IOException { @@ -42,7 +42,7 @@ public void parseTemplateWithComments_commentsProperlyIgnored() throws IOException { final Element element = BundleLitParser.parseLitTemplateElement("in.ts", // @formatter:off - "import { html, LitElement } from 'lit-element';\n" + "import { html, LitElement } from 'lit';\n" + "\n" + "export class HelloLit extends LitElement {\n" + " /* comment **/\n" diff --git a/flow-lit-template/src/test/resources/META-INF/VAADIN/config/stats.json b/flow-lit-template/src/test/resources/META-INF/VAADIN/config/stats.json index f230f658b30..acfe8d645df 100644 --- a/flow-lit-template/src/test/resources/META-INF/VAADIN/config/stats.json +++ b/flow-lit-template/src/test/resources/META-INF/VAADIN/config/stats.json @@ -7,20 +7,20 @@ "modules": [ { "name": "../node_modules/@vaadin/flow-frontend/src/hello-world-lit.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\n export class HelloWorld extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('hello-world-lit', HelloWorld);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\n export class HelloWorld extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('hello-world-lit', HelloWorld);" }, { "name": "./frontend/MyElementFaultyMethods.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\nexport class MyLitElement extends LitElement {\n\n // Define public API properties\n // Define the element's template\n render() {\n return `\n \n
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\nexport class MyLitElement extends LitElement {\n\n // Define public API properties\n // Define the element's template\n render() {\n return `\n \n
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" }, { "name": "./frontend/MySuperLitElement.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element'; \nimport { SimpleLitTemplateShadowRoot } from './MyLitElement.js';\n export class MySuperLitElement extends MyLitElement { createRenderRoot() { return this; }} customElements.define('my-super-lit-element', MySuperLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit'; \nimport { SimpleLitTemplateShadowRoot } from './MyLitElement.js';\n export class MySuperLitElement extends MyLitElement { createRenderRoot() { return this; }} customElements.define('my-super-lit-element', MySuperLitElement);" }, { "id": "./frontend/my-form.ts", "name": "./frontend/my-form.ts", - "source": "import { html, LitElement } from 'lit-element';\r\n// @customElement(\"my-form\")\r\nexport class MyFormElement extends LitElement {\r\n render() {\r\n return html `\n

Hello

\n \n `;\r\n }\r\n}\r\ncustomElements.define(\"my-form\", MyFormElement);\r\n" + "source": "import { html, LitElement } from 'lit';\r\nimport { customElement } from 'lit/decorators';\r\n// @customElement(\"my-form\")\r\nexport class MyFormElement extends LitElement {\r\n render() {\r\n return html `\n

Hello

\n \n `;\r\n }\r\n}\r\ncustomElements.define(\"my-form\", MyFormElement);\r\n" } ] , @@ -30,12 +30,12 @@ "modules": [ { "name": "./frontend/MyLitElement.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\n export class MyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\n export class MyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" } , { "name": "./frontend/MyGreedyLitElement.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\n export class MyGreedyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
\\`Tag name doesn't match the JS module name
inner
greedy
\n `;}\n static get styles() { return css`:host { background-color: pink } incorrect content`; }\n}\n\n// Register the element with the browser\ncustomElements.define('my-greedy-element', MyGreedyLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\n export class MyGreedyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
\\`Tag name doesn't match the JS module name
inner
greedy
\n `;}\n static get styles() { return css`:host { background-color: pink } incorrect content`; }\n}\n\n// Register the element with the browser\ncustomElements.define('my-greedy-element', MyGreedyLitElement);" } ] } diff --git a/flow-lit-template/src/test/resources/frontend/my-lit-element-view.js b/flow-lit-template/src/test/resources/frontend/my-lit-element-view.js index 5381c0ca395..42bf9fdc115 100644 --- a/flow-lit-template/src/test/resources/frontend/my-lit-element-view.js +++ b/flow-lit-template/src/test/resources/frontend/my-lit-element-view.js @@ -1,5 +1,5 @@ -import { LitElement, html } from "lit-element"; +import { LitElement, html } from "lit"; export class SimpleLitTemplateShadowRoot extends LitElement { static get properties() { diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeUpdater.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeUpdater.java index 3047d3f7466..0de358f262b 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeUpdater.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeUpdater.java @@ -281,7 +281,7 @@ static JsonObject getJsonFileContent(File packageFile) throws IOException { UTF_8.name()); try { jsonContent = Json.parse(fileContent); - } catch (JsonException e) { + } catch (JsonException e) { // NOSONAR throw new JsonException(String .format("Cannot parse package file '%s'", packageFile)); } @@ -323,8 +323,7 @@ static Map getDefaultDependencies() { defaults.put("@polymer/polymer", POLYMER_VERSION); - defaults.put("lit-element", "2.5.0"); - defaults.put("lit-html", "1.4.0"); + defaults.put("lit", "2.0.0-rc.1"); return defaults; } diff --git a/flow-server/src/main/resources/com/vaadin/flow/server/frontend/types.d.ts b/flow-server/src/main/resources/com/vaadin/flow/server/frontend/types.d.ts index 7c7342734a8..9f7023e6f3e 100644 --- a/flow-server/src/main/resources/com/vaadin/flow/server/frontend/types.d.ts +++ b/flow-server/src/main/resources/com/vaadin/flow/server/frontend/types.d.ts @@ -4,7 +4,7 @@ // It is recommended to commit this file to the VCS. // You might want to change the configurations to fit your preferences declare module '*.css' { - import {CSSResult} from "lit-element"; - const content: CSSResult; + import { CSSResultGroup } from 'lit'; + const content: CSSResultGroup; export default content; } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java b/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java index e809d593b34..f24a8109610 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java @@ -461,7 +461,7 @@ public void generateVersionsJson_versionsGeneratedFromPackageJson_containsBothDe "{" + "\"vaadin\": {" + "\"dependencies\": {" - + "\"lit-element\": \"2.5.0\"," + + "\"lit\": \"2.0.0-rc.1\"," + "\"@vaadin/router\": \"1.7.2\"," + "\"@polymer/polymer\": \"3.2.0\"," + "}," @@ -471,7 +471,7 @@ public void generateVersionsJson_versionsGeneratedFromPackageJson_containsBothDe + "}" + "}," + "\"dependencies\": {" - + "\"lit-element\": \"2.5.0\"," + + "\"lit\": \"2.0.0-rc.1\"," + "\"@vaadin/router\": \"1.7.2\"," + "\"@polymer/polymer\": \"3.2.0\"," + "}," @@ -492,7 +492,7 @@ public void generateVersionsJson_versionsGeneratedFromPackageJson_containsBothDe final JsonObject versionsJson = Json.parse(FileUtils.readFileToString( generatedVersionsFile, StandardCharsets.UTF_8)); Assert.assertEquals( - "{" + "\"lit-element\":\"2.5.0\"," + "{" + "\"lit\":\"2.0.0-rc.1\"," + "\"@vaadin/router\":\"1.7.2\"," + "\"@polymer/polymer\":\"3.2.0\"," + "\"css-loader\":\"4.2.1\"," diff --git a/flow-server/src/test/resources/META-INF/VAADIN/config/stats.json b/flow-server/src/test/resources/META-INF/VAADIN/config/stats.json index 922bc9539b4..f3520426faf 100644 --- a/flow-server/src/test/resources/META-INF/VAADIN/config/stats.json +++ b/flow-server/src/test/resources/META-INF/VAADIN/config/stats.json @@ -7,15 +7,15 @@ "modules": [ { "name": "../node_modules/@vaadin/flow-frontend/src/hello-world-lit.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\n export class HelloWorld extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('hello-world-lit', HelloWorld);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\n export class HelloWorld extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('hello-world-lit', HelloWorld);" }, { "name": "./frontend/MyElementFaultyMethods.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\nexport class MyLitElement extends LitElement {\n\n // Define public API properties\n // Define the element's template\n render() {\n return `\n \n
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\nexport class MyLitElement extends LitElement {\n\n // Define public API properties\n // Define the element's template\n render() {\n return `\n \n
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" }, { "name": "./frontend/MySuperLitElement.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element'; \nimport { SimpleLitTemplateShadowRoot } from './MyLitElement.js';\n export class MySuperLitElement extends MyLitElement { createRenderRoot() { return this; }} customElements.define('my-super-lit-element', MySuperLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit'; \nimport { SimpleLitTemplateShadowRoot } from './MyLitElement.js';\n export class MySuperLitElement extends MyLitElement { createRenderRoot() { return this; }} customElements.define('my-super-lit-element', MySuperLitElement);" } ] , @@ -25,12 +25,12 @@ "modules": [ { "name": "./frontend/MyLitElement.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\n export class MyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\n export class MyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
Tag name doesn't match the JS module name
inner
Web components like you, too.
\n `;\n }\n}\n\n// Register the element with the browser\ncustomElements.define('my-element', MyLitElement);" } , { "name": "./frontend/MyGreedyLitElement.js", - "source": "// Import an element\nimport { LitElement, html } from 'lit-element';\n\n// Define an element class\n export class MyGreedyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
\\`Tag name doesn't match the JS module name
inner
greedy
\n `;}\n static get styles() { return css`:host { background-color: pink } incorrect content`; }\n}\n\n// Register the element with the browser\ncustomElements.define('my-greedy-element', MyGreedyLitElement);" + "source": "// Import an element\nimport { LitElement, html } from 'lit';\n\n// Define an element class\n export class MyGreedyLitElement extends LitElement {\n\n // Define the element's template\n render() {\n return html`\n \n
\\`Tag name doesn't match the JS module name
inner
greedy
\n `;}\n static get styles() { return css`:host { background-color: pink } incorrect content`; }\n}\n\n// Register the element with the browser\ncustomElements.define('my-greedy-element', MyGreedyLitElement);" } ] } diff --git a/flow-server/src/test/resources/frontend/my-lit-element-view.js b/flow-server/src/test/resources/frontend/my-lit-element-view.js index 5381c0ca395..42bf9fdc115 100644 --- a/flow-server/src/test/resources/frontend/my-lit-element-view.js +++ b/flow-server/src/test/resources/frontend/my-lit-element-view.js @@ -1,5 +1,5 @@ -import { LitElement, html } from "lit-element"; +import { LitElement, html } from "lit"; export class SimpleLitTemplateShadowRoot extends LitElement { static get properties() { diff --git a/flow-tests/test-application-theme/test-theme-reusable/frontend/ts-component.ts b/flow-tests/test-application-theme/test-theme-reusable/frontend/ts-component.ts index bf573c3804b..b03b69d3948 100644 --- a/flow-tests/test-application-theme/test-theme-reusable/frontend/ts-component.ts +++ b/flow-tests/test-application-theme/test-theme-reusable/frontend/ts-component.ts @@ -1,4 +1,5 @@ -import { css, customElement, html, LitElement } from "lit-element"; +import { css, html, LitElement } from "lit"; +import { customElement } from "lit/decorators"; import { applyTheme } from "./generated/theme"; @customElement("ts-component") diff --git a/flow-tests/test-ccdm-flow-navigation/frontend/views/about/about-view.ts b/flow-tests/test-ccdm-flow-navigation/frontend/views/about/about-view.ts index ec13e64f90c..d7b7f75f0a0 100644 --- a/flow-tests/test-ccdm-flow-navigation/frontend/views/about/about-view.ts +++ b/flow-tests/test-ccdm-flow-navigation/frontend/views/about/about-view.ts @@ -1,4 +1,5 @@ -import { LitElement, html, css, customElement } from 'lit-element'; +import { LitElement, html, css } from 'lit'; +import { customElement } from 'lit/decorators'; @customElement('about-view') export class AboutView extends LitElement { diff --git a/flow-tests/test-ccdm-flow-navigation/frontend/views/another/another-view.ts b/flow-tests/test-ccdm-flow-navigation/frontend/views/another/another-view.ts index ad2d5d6b374..28895f2bb09 100644 --- a/flow-tests/test-ccdm-flow-navigation/frontend/views/another/another-view.ts +++ b/flow-tests/test-ccdm-flow-navigation/frontend/views/another/another-view.ts @@ -1,4 +1,5 @@ -import { LitElement, html, css, customElement } from 'lit-element'; +import { LitElement, html, css } from 'lit'; +import { customElement } from 'lit/decorators'; @customElement('another-view') export class AboutView extends LitElement { diff --git a/flow-tests/test-ccdm-flow-navigation/frontend/views/main/main-view.ts b/flow-tests/test-ccdm-flow-navigation/frontend/views/main/main-view.ts index a6ed7ea01c9..580bd968f2d 100644 --- a/flow-tests/test-ccdm-flow-navigation/frontend/views/main/main-view.ts +++ b/flow-tests/test-ccdm-flow-navigation/frontend/views/main/main-view.ts @@ -14,7 +14,8 @@ * the License. */ -import { css, customElement, html, LitElement } from 'lit-element'; +import { css, html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators'; import { router } from 'Frontend/index'; diff --git a/flow-tests/test-ccdm/frontend/css-importing-test.ts b/flow-tests/test-ccdm/frontend/css-importing-test.ts index 3bc9b4ab23b..3ace103be09 100644 --- a/flow-tests/test-ccdm/frontend/css-importing-test.ts +++ b/flow-tests/test-ccdm/frontend/css-importing-test.ts @@ -1,10 +1,11 @@ -import { LitElement } from 'lit-element'; +import { LitElement } from 'lit'; import '@vaadin/vaadin-login/vaadin-login-overlay'; import styles from './test-styles.css'; // Regression test for flow#9167 (`styles` assignment will cause a type -// error if `styles` imported from `./test-styles.css` is not CSSResult +// error if `styles` imported from `./test-styles.css` is not a +// CSSResultGroup export class CSSImportingTest extends LitElement { static styles = styles; diff --git a/flow-tests/test-live-reload/frontend/custom-component.ts b/flow-tests/test-live-reload/frontend/custom-component.ts index 839ea135f7c..553c259886e 100644 --- a/flow-tests/test-live-reload/frontend/custom-component.ts +++ b/flow-tests/test-live-reload/frontend/custom-component.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement } from 'lit-element'; +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators'; @customElement('custom-component') export class CustomComponent extends LitElement { diff --git a/flow-tests/test-root-context/frontend/lit/AttributeLitTemplate.js b/flow-tests/test-root-context/frontend/lit-templates/AttributeLitTemplate.js similarity index 82% rename from flow-tests/test-root-context/frontend/lit/AttributeLitTemplate.js rename to flow-tests/test-root-context/frontend/lit-templates/AttributeLitTemplate.js index c88bf023a78..1a5e903bff8 100644 --- a/flow-tests/test-root-context/frontend/lit/AttributeLitTemplate.js +++ b/flow-tests/test-root-context/frontend/lit-templates/AttributeLitTemplate.js @@ -1,5 +1,5 @@ -import { LitElement, html } from "lit-element"; +import { LitElement, html } from "lit"; export class AttributeLitTemplate extends LitElement { render() { @@ -7,7 +7,7 @@ export class AttributeLitTemplate extends LitElement {
- + `; } } diff --git a/flow-tests/test-root-context/frontend/lit/SetInitialText.js b/flow-tests/test-root-context/frontend/lit-templates/SetInitialText.js similarity index 91% rename from flow-tests/test-root-context/frontend/lit/SetInitialText.js rename to flow-tests/test-root-context/frontend/lit-templates/SetInitialText.js index 788cd6deda2..4d84a489c9b 100644 --- a/flow-tests/test-root-context/frontend/lit/SetInitialText.js +++ b/flow-tests/test-root-context/frontend/lit-templates/SetInitialText.js @@ -1,5 +1,5 @@ -import { LitElement, html } from "lit-element"; +import { LitElement, html } from "lit"; export class SetInitialTextLit extends LitElement { render() { diff --git a/flow-tests/test-root-context/frontend/lit/lit-template-inner.js b/flow-tests/test-root-context/frontend/lit-templates/lit-template-inner.js similarity index 80% rename from flow-tests/test-root-context/frontend/lit/lit-template-inner.js rename to flow-tests/test-root-context/frontend/lit-templates/lit-template-inner.js index b9c4ebc88db..d4de186e17e 100644 --- a/flow-tests/test-root-context/frontend/lit/lit-template-inner.js +++ b/flow-tests/test-root-context/frontend/lit-templates/lit-template-inner.js @@ -1,4 +1,4 @@ -import {html, LitElement} from 'lit-element'; +import {html, LitElement} from 'lit'; class TemplateInner extends LitElement { diff --git a/flow-tests/test-root-context/frontend/lit/lit-template-outer.js b/flow-tests/test-root-context/frontend/lit-templates/lit-template-outer.js similarity index 87% rename from flow-tests/test-root-context/frontend/lit/lit-template-outer.js rename to flow-tests/test-root-context/frontend/lit-templates/lit-template-outer.js index 3cc8a56126e..2916fe4478a 100644 --- a/flow-tests/test-root-context/frontend/lit/lit-template-outer.js +++ b/flow-tests/test-root-context/frontend/lit-templates/lit-template-outer.js @@ -1,4 +1,4 @@ -import {html, LitElement} from 'lit-element'; +import {html, LitElement} from 'lit'; import './lit-template-inner.js'; class TemplateOuter extends LitElement { diff --git a/flow-tests/test-root-context/frontend/lit/simple-lit-template-no-shadow-root.js b/flow-tests/test-root-context/frontend/lit-templates/simple-lit-template-no-shadow-root.js similarity index 86% rename from flow-tests/test-root-context/frontend/lit/simple-lit-template-no-shadow-root.js rename to flow-tests/test-root-context/frontend/lit-templates/simple-lit-template-no-shadow-root.js index 4f5d01ac088..bf5e97d1edd 100644 --- a/flow-tests/test-root-context/frontend/lit/simple-lit-template-no-shadow-root.js +++ b/flow-tests/test-root-context/frontend/lit-templates/simple-lit-template-no-shadow-root.js @@ -1,5 +1,4 @@ -import { LitElement, html } from "lit-element"; import { SimpleLitTemplateShadowRoot } from "./simple-lit-template-shadow-root.js"; export class SimpleLitTemplateNoShadowRoot extends SimpleLitTemplateShadowRoot { diff --git a/flow-tests/test-root-context/frontend/lit/simple-lit-template-shadow-root.js b/flow-tests/test-root-context/frontend/lit-templates/simple-lit-template-shadow-root.js similarity index 90% rename from flow-tests/test-root-context/frontend/lit/simple-lit-template-shadow-root.js rename to flow-tests/test-root-context/frontend/lit-templates/simple-lit-template-shadow-root.js index 233ede4805b..1472897c643 100644 --- a/flow-tests/test-root-context/frontend/lit/simple-lit-template-shadow-root.js +++ b/flow-tests/test-root-context/frontend/lit-templates/simple-lit-template-shadow-root.js @@ -1,5 +1,5 @@ -import { LitElement, html } from "lit-element"; +import { LitElement, html } from "lit"; export class SimpleLitTemplateShadowRoot extends LitElement { static get properties() { diff --git a/flow-tests/test-root-context/frontend/lit/test-form.js b/flow-tests/test-root-context/frontend/lit-templates/test-form.js similarity index 78% rename from flow-tests/test-root-context/frontend/lit/test-form.js rename to flow-tests/test-root-context/frontend/lit-templates/test-form.js index 43ab9a4e736..d4f0fe34589 100644 --- a/flow-tests/test-root-context/frontend/lit/test-form.js +++ b/flow-tests/test-root-context/frontend/lit-templates/test-form.js @@ -1,4 +1,4 @@ -import {html, LitElement} from 'lit-element'; +import {html, LitElement} from 'lit'; class TestForm extends LitElement { diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/InnerTemplateVisibilityView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/InnerTemplateVisibilityView.java index babcf7eefdc..139c1434377 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/InnerTemplateVisibilityView.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/InnerTemplateVisibilityView.java @@ -18,14 +18,14 @@ public class InnerTemplateVisibilityView extends AbstractDivView { public static final String OUTER_ID = "outer"; @Tag("lit-template-inner") - @JsModule("./lit/lit-template-inner.js") + @JsModule("./lit-templates/lit-template-inner.js") public static class Inner extends LitTemplate { public Inner() { } } @Tag("lit-template-outer") - @JsModule("./lit/lit-template-outer.js") + @JsModule("./lit-templates/lit-template-outer.js") public static class Outer extends LitTemplate { @Id("inner") Inner inner; diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/LitTemplateAttributeView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/LitTemplateAttributeView.java index 72130b91991..58591f3661d 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/LitTemplateAttributeView.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/LitTemplateAttributeView.java @@ -12,7 +12,7 @@ @Route(value = "com.vaadin.flow.uitest.ui.littemplate.LitTemplateAttributeView", layout = ViewTestLayout.class) @Tag("attribute-lit-template") -@JsModule("lit/AttributeLitTemplate.js") +@JsModule("lit-templates/AttributeLitTemplate.js") public class LitTemplateAttributeView extends LitTemplate implements HasComponents { diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SetInitialTextLitView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SetInitialTextLitView.java index 0e5da2b415b..92335dbc938 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SetInitialTextLitView.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SetInitialTextLitView.java @@ -12,7 +12,7 @@ @Route(value = "com.vaadin.flow.uitest.ui.littemplate.SetInitialTextLitView", layout = ViewTestLayout.class) @Tag("set-initial-text-lit") -@JsModule("lit/SetInitialText.js") +@JsModule("lit-templates/SetInitialText.js") public class SetInitialTextLitView extends LitTemplate implements HasComponents { diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateNoShadowRootView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateNoShadowRootView.java index ecfc939f8fd..cb96fbd4042 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateNoShadowRootView.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateNoShadowRootView.java @@ -12,8 +12,8 @@ import com.vaadin.flow.uitest.servlet.ViewTestLayout; @Tag("simple-lit-template-no-shadow-root") -@JsModule("lit/simple-lit-template-no-shadow-root.js") -@NpmPackage(value = "lit-element", version = "2.1.0") +@JsModule("lit-templates/simple-lit-template-no-shadow-root.js") +@NpmPackage(value = "lit", version = "2.0.0-rc.1") @Route(value = "com.vaadin.flow.uitest.ui.littemplate.SimpleLitTemplateNoShadowRootView", layout = ViewTestLayout.class) public class SimpleLitTemplateNoShadowRootView extends LitTemplate { diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateShadowRootView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateShadowRootView.java index 9ebb66b10d0..e3538432fb4 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateShadowRootView.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/SimpleLitTemplateShadowRootView.java @@ -12,8 +12,8 @@ import com.vaadin.flow.uitest.servlet.ViewTestLayout; @Tag("simple-lit-template-shadow-root") -@JsModule("lit/simple-lit-template-shadow-root.js") -@NpmPackage(value = "lit-element", version = "2.1.0") +@JsModule("lit-templates/simple-lit-template-shadow-root.js") +@NpmPackage(value = "lit", version = "2.0.0-rc.1") @Route(value = "com.vaadin.flow.uitest.ui.littemplate.SimpleLitTemplateShadowRootView", layout = ViewTestLayout.class) public class SimpleLitTemplateShadowRootView extends LitTemplate { diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/TestForm.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/TestForm.java index 8895b2e68ee..ab052d7cf9c 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/TestForm.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/littemplate/TestForm.java @@ -21,7 +21,7 @@ import com.vaadin.flow.component.littemplate.LitTemplate; import com.vaadin.flow.component.template.Id; -@JsModule("lit/test-form.js") +@JsModule("lit-templates/test-form.js") @Tag("test-form") public class TestForm extends LitTemplate { diff --git a/flow-tests/test-themes/frontend/typescript/hello-world-view.ts b/flow-tests/test-themes/frontend/typescript/hello-world-view.ts index b7bb704ce47..4a71b731191 100644 --- a/flow-tests/test-themes/frontend/typescript/hello-world-view.ts +++ b/flow-tests/test-themes/frontend/typescript/hello-world-view.ts @@ -1,5 +1,6 @@ import '@vaadin/vaadin-text-field'; -import { customElement, html, LitElement } from 'lit-element'; +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators'; import styles from './hello-world-view.css';