diff --git a/packages/button/LICENSE b/packages/button/LICENSE index d656cecbac..b577ea3808 100644 --- a/packages/button/LICENSE +++ b/packages/button/LICENSE @@ -175,7 +175,7 @@ END OF TERMS AND CONDITIONS - Copyright 2017 Vaadin Ltd. + Copyright 2021 Vaadin Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/button/README.md b/packages/button/README.md index 8d72c6ea25..075e907e3e 100644 --- a/packages/button/README.md +++ b/packages/button/README.md @@ -1,63 +1,5 @@ -# <vaadin-button> +# @vaadin/button -[Live Demo ↗](https://vaadin.com/components/vaadin-button/html-examples) -| -[API documentation ↗](https://vaadin.com/components/vaadin-button/html-api) +> ⚠️ Work in progress, please do not use this component yet. -[<vaadin-button>](https://vaadin.com/components/vaadin-button) is a Web Component providing an accessible and customizable button, part of the [Vaadin components](https://vaadin.com/components). - -[![npm version](https://badgen.net/npm/v/@vaadin/vaadin-button)](https://www.npmjs.com/package/@vaadin/vaadin-button) -[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/vaadinvaadin-button) -[![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC) - -```html -Primary -Secondary -Tertiary -``` - -[Screenshot of vaadin-button, using the default Lumo theme](https://vaadin.com/components/vaadin-button) - -## Installation - -Install `vaadin-button`: - -```sh -npm i @vaadin/vaadin-button --save -``` - -Once installed, import it in your application: - -```js -import '@vaadin/vaadin-button/vaadin-button.js'; -``` - -## Getting started - -Vaadin components use the Lumo theme by default. - -To use the Material theme, import the correspondent file from the `theme/material` folder. - -## Entry points - -- The component with the Lumo theme: - - `theme/lumo/vaadin-button.js` - -- The component with the Material theme: - - `theme/material/vaadin-button.js` - -- Alias for `theme/lumo/vaadin-button.js`: - - `vaadin-button.js` - -## Contributing - -Read the [contributing guide](https://vaadin.com/docs/latest/guide/contributing/overview) to learn about our development process, how to propose bugfixes and improvements, and how to test your changes to Vaadin components. - -## License - -Apache License 2.0 - -Vaadin collects development time usage statistics to improve this product. For details and to opt-out, see https://github.com/vaadin/vaadin-usage-statistics. +The new version of `vaadin-button` component. diff --git a/packages/button/package.json b/packages/button/package.json index e617a22709..31844cf22f 100644 --- a/packages/button/package.json +++ b/packages/button/package.json @@ -1,16 +1,15 @@ { - "name": "@vaadin/vaadin-button", + "name": "@vaadin/button", "version": "22.0.0-alpha3", "description": "vaadin-button", "main": "vaadin-button.js", "module": "vaadin-button.js", - "repository": "vaadin/vaadin-button", + "repository": "vaadin/web-components", "keywords": [ "Vaadin", "button", "web-components", - "web-component", - "polymer" + "web-component" ], "author": "Vaadin Ltd", "license": "Apache-2.0", @@ -26,6 +25,7 @@ ], "dependencies": { "@polymer/polymer": "^3.0.0", + "@vaadin/field-base": "^22.0.0-alpha3", "@vaadin/vaadin-control-state-mixin": "^22.0.0-alpha3", "@vaadin/vaadin-element-mixin": "^22.0.0-alpha3", "@vaadin/vaadin-lumo-styles": "^22.0.0-alpha3", @@ -35,7 +35,6 @@ "devDependencies": { "@esm-bundle/chai": "^4.3.4", "@vaadin/testing-helpers": "^0.2.1", - "@vaadin/vaadin-icon": "^22.0.0-alpha3", "sinon": "^9.2.4" }, "publishConfig": { diff --git a/packages/button/screenshot.png b/packages/button/screenshot.png deleted file mode 100644 index 3517f59ffe..0000000000 Binary files a/packages/button/screenshot.png and /dev/null differ diff --git a/packages/button/src/vaadin-button.d.ts b/packages/button/src/vaadin-button.d.ts index d9b09de9d6..4c89ab9fdd 100644 --- a/packages/button/src/vaadin-button.d.ts +++ b/packages/button/src/vaadin-button.d.ts @@ -1,53 +1,18 @@ -import { GestureEventListeners } from '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; - -import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; - -import { ControlStateMixin } from '@vaadin/vaadin-control-state-mixin/vaadin-control-state-mixin.js'; - -import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin.js'; - /** - * `` is a Web Component providing an accessible and customizable button. - * - * ```html - * - * - * ``` - * - * ```js - * document.querySelector('vaadin-button').addEventListener('click', () => alert('Hello World!')); - * ``` - * - * ### Styling - * - * The following shadow DOM parts are exposed for styling: - * - * Part name | Description - * ----------------|---------------- - * `label` | The label (text) inside the button - * `prefix` | A slot for e.g. an icon before the label - * `suffix` | A slot for e.g. an icon after the label - * - * - * The following attributes are exposed for styling: - * - * Attribute | Description - * --------- | ----------- - * `active` | Set when the button is pressed down, either with mouse, touch or the keyboard. - * `disabled` | Set when the button is disabled. - * `focus-ring` | Set when the button is focused using the keyboard. - * `focused` | Set when the button is focused. - * - * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation. + * @license + * Copyright (c) 2021 Vaadin Ltd. + * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ */ -declare class ButtonElement extends ElementMixin(ControlStateMixin(ThemableMixin(GestureEventListeners(HTMLElement)))) { - readonly focusElement: Element | null; -} +import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; +import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin.js'; +import { ActiveMixin } from '@vaadin/field-base/src/active-mixin.js'; +import { ControlStateMixin } from '@vaadin/vaadin-control-state-mixin/vaadin-control-state-mixin.js'; -declare global { - interface HTMLElementTagNameMap { - 'vaadin-button': ButtonElement; - } +declare class Button extends ControlStateMixin(ActiveMixin(ElementMixin(ThemableMixin(HTMLElement)))) { + /** + * A getter that returns the native button as a focusable element for ControlStateMixin. + */ + readonly focusElement: HTMLButtonElement | null; } -export { ButtonElement }; +export { Button }; diff --git a/packages/button/src/vaadin-button.js b/packages/button/src/vaadin-button.js index 706244bbaa..4decd10392 100644 --- a/packages/button/src/vaadin-button.js +++ b/packages/button/src/vaadin-button.js @@ -4,53 +4,17 @@ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ */ import { PolymerElement, html } from '@polymer/polymer/polymer-element.js'; -import { GestureEventListeners } from '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; -import { addListener } from '@polymer/polymer/lib/utils/gestures.js'; import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; -import { ControlStateMixin } from '@vaadin/vaadin-control-state-mixin/vaadin-control-state-mixin.js'; import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin.js'; +import { TabindexMixin } from '@vaadin/field-base/src/tabindex-mixin.js'; +import { ActiveMixin } from '@vaadin/field-base/src/active-mixin.js'; +import { FocusMixin } from '@vaadin/field-base/src/focus-mixin.js'; + +class Button extends ActiveMixin(TabindexMixin(FocusMixin(ElementMixin(ThemableMixin(PolymerElement))))) { + static get is() { + return 'vaadin-button'; + } -/** - * `` is a Web Component providing an accessible and customizable button. - * - * ```html - * - * - * ``` - * - * ```js - * document.querySelector('vaadin-button').addEventListener('click', () => alert('Hello World!')); - * ``` - * - * ### Styling - * - * The following shadow DOM parts are exposed for styling: - * - * Part name | Description - * ----------------|---------------- - * `label` | The label (text) inside the button - * `prefix` | A slot for e.g. an icon before the label - * `suffix` | A slot for e.g. an icon after the label - * - * - * The following attributes are exposed for styling: - * - * Attribute | Description - * --------- | ----------- - * `active` | Set when the button is pressed down, either with mouse, touch or the keyboard. - * `disabled` | Set when the button is disabled. - * `focus-ring` | Set when the button is focused using the keyboard. - * `focused` | Set when the button is focused. - * - * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation. - * - * @extends HTMLElement - * @mixes ElementMixin - * @mixes ControlStateMixin - * @mixes ThemableMixin - * @mixes GestureEventListeners - */ -class ButtonElement extends ElementMixin(ControlStateMixin(ThemableMixin(GestureEventListeners(PolymerElement)))) { static get template() { return html`
-
+ -
-
+ + -
-
+ + -
+
- `; } - static get is() { - return 'vaadin-button'; - } - + /** @protected */ ready() { super.ready(); - // Leaving default role in the native button, makes navigation announcement - // being different when using focus navigation (tab) versus using normal - // navigation (arrows). The first way announces the label on a button - // since the focus is moved programmatically, and the second on a group. - this.setAttribute('role', 'button'); - this.$.button.setAttribute('role', 'presentation'); - - this._addActiveListeners(); - } - - /** - * @protected - */ - disconnectedCallback() { - super.disconnectedCallback(); - - // `active` state is preserved when the element is disconnected between keydown and keyup events. - // reproducible in `` when closing on `Cancel` or `Today` click. - this.toggleAttribute('active', false); - } - - /** @private */ - _addActiveListeners() { - addListener(this, 'down', () => !this.disabled && this.setAttribute('active', '')); - addListener(this, 'up', () => this.removeAttribute('active')); - this.addEventListener( - 'keydown', - (e) => !this.disabled && [13, 32].indexOf(e.keyCode) >= 0 && this.setAttribute('active', '') - ); - this.addEventListener('keyup', () => this.removeAttribute('active')); - this.addEventListener('blur', () => this.removeAttribute('active')); - } - - /** - * @protected - * @return {Element} - */ - get focusElement() { - return this.$.button; + // By default, if the user hasn't provided a custom role, + // the role attribute is set to "button". + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'button'); + } } } -customElements.define(ButtonElement.is, ButtonElement); - -export { ButtonElement }; +export { Button }; diff --git a/packages/button/test/button.test.js b/packages/button/test/button.test.js index 3bdbc77fc0..b75bb40695 100644 --- a/packages/button/test/button.test.js +++ b/packages/button/test/button.test.js @@ -1,5 +1,5 @@ import { expect } from '@esm-bundle/chai'; -import sinon from 'sinon'; +import { sendKeys } from '@web/test-runner-commands'; import { arrowDownKeyDown, enterKeyDown, @@ -10,125 +10,248 @@ import { mouseup, spaceKeyDown, spaceKeyUp, - touchstart, - touchend + touchend, + touchstart } from '@vaadin/testing-helpers'; import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js'; -import '../vaadin-button.js'; +import { Button } from '../vaadin-button.js'; + +customElements.define(Button.is, Button); describe('vaadin-button', () => { - let vaadinButton, nativeButton, label; + let element; - beforeEach(() => { - vaadinButton = fixtureSync('Vaadin Button'); - nativeButton = vaadinButton.shadowRoot.querySelector('button'); - label = vaadinButton.shadowRoot.querySelector('[part=label]'); - }); + describe('custom element definition', () => { + let tagName; - it('should define button label using light DOM', () => { - const children = FlattenedNodesObserver.getFlattenedNodes(label); - expect(children[1].textContent).to.be.equal('Vaadin '); - expect(children[2].outerHTML).to.be.equal('Button'); - }); + beforeEach(() => { + element = fixtureSync(''); + tagName = element.tagName.toLowerCase(); + }); - it('can be disabled imperatively', () => { - vaadinButton.disabled = true; - expect(nativeButton.hasAttribute('disabled')).to.be.eql(true); - }); + it('should be defined in custom element registry', () => { + expect(customElements.get(tagName)).to.be.ok; + }); - it('should fire click event', () => { - const spy = sinon.spy(); - vaadinButton.addEventListener('click', spy); - vaadinButton.click(); - expect(spy.calledOnce).to.be.true; + it('should have a valid static "is" getter', () => { + expect(customElements.get(tagName).is).to.equal(tagName); + }); }); - it('should not fire click event when disabled', () => { - const spy = sinon.spy(); - vaadinButton.addEventListener('click', spy); - vaadinButton.disabled = true; - vaadinButton.click(); - expect(spy.called).to.be.false; - }); + describe('role', () => { + describe('default', () => { + beforeEach(() => { + element = fixtureSync('Press me'); + }); - it('host should have the `button` role', () => { - expect(vaadinButton.getAttribute('role')).to.be.eql('button'); - }); + it('should set role attribute to button by default', () => { + expect(element.getAttribute('role')).to.equal('button'); + }); + }); - it('native button should have type="button"', () => { - expect(nativeButton.getAttribute('type')).to.be.eql('button'); - }); + describe('custom', () => { + beforeEach(() => { + element = fixtureSync('Press me'); + }); - it('native button should have the `presentation` role', () => { - expect(nativeButton.getAttribute('role')).to.be.eql('presentation'); + it('should not override custom role attribute', () => { + expect(element.getAttribute('role')).to.equal('menuitem'); + }); + }); }); - (isIOS ? it.skip : it)('should have active attribute on mousedown', () => { - mousedown(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.true; - }); + describe('label', () => { + let label; - (isIOS ? it.skip : it)('should not have active attribute after mouseup', () => { - mousedown(vaadinButton); - mouseup(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.false; - }); + beforeEach(() => { + element = fixtureSync('Press me'); + label = element.shadowRoot.querySelector('[part=label]'); + }); - it('should have active attribute on touchstart', () => { - touchstart(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.true; + it('should define the button label using light DOM', () => { + const children = FlattenedNodesObserver.getFlattenedNodes(label); + expect(children[1].textContent).to.be.equal('Press me'); + }); }); - it('should not have active attribute after touchend', () => { - touchstart(vaadinButton); - touchend(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.false; - }); + describe('mixins', () => { + beforeEach(() => { + element = fixtureSync('Press me'); + }); - it('should have active attribute on enter', () => { - enterKeyDown(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.true; - }); + // TODO: Remove when it would be possible for an element: + // – to detect if it inherits DisabledMixin. + // – or to run a suit of the tests defined in DisabledMixin. + describe('DisabledMixin', () => { + it('should set disabled property to false by default', () => { + expect(element.disabled).to.be.false; + }); - it('should not have active attribute after enter', () => { - enterKeyDown(vaadinButton); - enterKeyUp(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.false; - }); + it('should reflect disabled property to attribute', () => { + element.disabled = true; + expect(element.hasAttribute('disabled')).to.be.true; + }); - it('should have active attribute on space', () => { - spaceKeyDown(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.true; - }); + it('should set the aria-disabled attribute when disabled', () => { + element.disabled = true; + expect(element.getAttribute('aria-disabled')).to.equal('true'); + }); + }); - it('should not have active attribute after space', () => { - spaceKeyDown(vaadinButton); - spaceKeyUp(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.false; - }); + // TODO: Remove when it would be possible for an element: + // – to detect if it inherits ActiveMixin. + // – or to run a suit of the tests defined in ActiveMixin. + describe('ActiveMixin', () => { + (isIOS ? it.skip : it)('should have active attribute on mousedown', () => { + mousedown(element); + expect(element.hasAttribute('active')).to.be.true; + }); - it('should not have active attribute on arrow key', () => { - arrowDownKeyDown(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.false; - }); + (isIOS ? it.skip : it)('should not have active attribute after mouseup', () => { + mousedown(element); + mouseup(element); + expect(element.hasAttribute('active')).to.be.false; + }); - it('should not have active attribute when disabled', () => { - vaadinButton.disabled = true; - mousedown(vaadinButton); - enterKeyDown(vaadinButton); - spaceKeyDown(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.false; - }); + it('should have active attribute on touchstart', () => { + touchstart(element); + expect(element.hasAttribute('active')).to.be.true; + }); - it('should not have active attribute when disconnected from the DOM', () => { - spaceKeyDown(vaadinButton); - vaadinButton.parentNode.removeChild(vaadinButton); - expect(vaadinButton.hasAttribute('active')).to.be.false; - }); + it('should not have active attribute after touchend', () => { + touchstart(element); + touchend(element); + expect(element.hasAttribute('active')).to.be.false; + }); + + it('should have active attribute on enter', () => { + enterKeyDown(element); + expect(element.hasAttribute('active')).to.be.true; + }); + + it('should not have active attribute after enter', () => { + enterKeyDown(element); + enterKeyUp(element); + expect(element.hasAttribute('active')).to.be.false; + }); + + it('should have active attribute on space', () => { + spaceKeyDown(element); + expect(element.hasAttribute('active')).to.be.true; + }); + + it('should not have active attribute after space', () => { + spaceKeyDown(element); + spaceKeyUp(element); + expect(element.hasAttribute('active')).to.be.false; + }); + + it('should not have active attribute on arrow key', () => { + arrowDownKeyDown(element); + expect(element.hasAttribute('active')).to.be.false; + }); + + it('should not have active attribute when disabled', () => { + element.disabled = true; + mousedown(element); + enterKeyDown(element); + spaceKeyDown(element); + expect(element.hasAttribute('active')).to.be.false; + }); + + it('should not have active attribute when disconnected from the DOM', () => { + spaceKeyDown(element); + element.parentNode.removeChild(element); + expect(element.hasAttribute('active')).to.be.false; + }); + + it('should not have active attribute after blur', () => { + spaceKeyDown(element); + element.dispatchEvent(new CustomEvent('blur')); + expect(element.hasAttribute('active')).to.be.false; + }); + }); + + // TODO: Remove when it would be possible for an element: + // – to detect if it inherits TabindexMixin. + // – or to run a suit of the tests defined in TabindexMixin. + describe('TabindexMixin', () => { + it('should set tabindex attribute to 0 by default', () => { + expect(element.getAttribute('tabindex')).to.be.equal('0'); + }); + + it('should reflect tabindex property to the attribute', () => { + element.tabindex = 1; + expect(element.getAttribute('tabindex')).to.be.equal('1'); + }); + + it('should reflect native tabIndex property to the attribute', () => { + element.tabIndex = 1; + expect(element.getAttribute('tabindex')).to.be.equal('1'); + }); + + it('should set tabindex attribute to -1 when disabled', () => { + element.tabIndex = 1; + element.disabled = true; + expect(element.getAttribute('tabindex')).to.be.equal('-1'); + }); + + it('should restore tabindex attribute when enabled', () => { + element.tabIndex = 1; + element.disabled = true; + element.disabled = false; + expect(element.getAttribute('tabindex')).to.be.equal('1'); + }); + + it('should restore tabindex attribute with the last known value when enabled', () => { + element.tabIndex = 1; + element.disabled = true; + element.tabIndex = 2; + expect(element.getAttribute('tabindex')).to.be.equal('-1'); + + element.disabled = false; + expect(element.getAttribute('tabindex')).to.be.equal('2'); + }); + }); + + // TODO: Remove when it would be possible for an element: + // – to detect if it inherits FocusMixin. + // – or to run a suit of the tests defined in FocusMixin. + describe('FocusMixin', () => { + describe('focusing with Tab', () => { + beforeEach(async () => { + // Focus on the button + await sendKeys({ press: 'Tab' }); + }); + + it('should set focused attribute', () => { + expect(element.hasAttribute('focused')).to.be.true; + }); + + it('should set focus-ring attribute', () => { + expect(element.hasAttribute('focus-ring')).to.be.true; + }); + }); + + describe('loosing focus with Shift+Tab', () => { + beforeEach(async () => { + // Focus on the button + await sendKeys({ press: 'Tab' }); + + // Focus out of the button + await sendKeys({ down: 'Shift' }); + await sendKeys({ press: 'Tab' }); + await sendKeys({ up: 'Shift' }); + }); + + it('should remove focused attribute', () => { + expect(element.hasAttribute('focused')).to.be.false; + }); - it('should not have active attribute after blur', () => { - spaceKeyDown(vaadinButton); - vaadinButton.dispatchEvent(new CustomEvent('blur')); - expect(vaadinButton.hasAttribute('active')).to.be.false; + it('should remove focus-ring attribute', () => { + expect(element.hasAttribute('focus-ring')).to.be.false; + }); + }); + }); }); }); diff --git a/packages/button/test/visual/lumo/button.test.js b/packages/button/test/visual/lumo/button.test.js index c8cddbcd05..c763fbd232 100644 --- a/packages/button/test/visual/lumo/button.test.js +++ b/packages/button/test/visual/lumo/button.test.js @@ -1,8 +1,15 @@ import { fixtureSync } from '@vaadin/testing-helpers/dist/fixture.js'; import { visualDiff } from '@web/test-runner-visual-regression'; +import { sendKeys } from '@web/test-runner-commands'; import '@vaadin/vaadin-icon/theme/lumo/vaadin-icon.js'; import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js'; -import '../../../theme/lumo/vaadin-button.js'; +// TODO: Remove in https://github.com/vaadin/web-components/issues/2224. +import './vaadin-button-styles.js'; +// TODO: Remove in https://github.com/vaadin/web-components/issues/2224. +import { Button } from '../../../src/vaadin-button.js'; + +// TODO: Remove in https://github.com/vaadin/web-components/issues/2224. +customElements.define(Button.is, Button); describe('button', () => { let div, element; @@ -20,7 +27,9 @@ describe('button', () => { }); it('focus-ring', async () => { - element.setAttribute('focus-ring', ''); + // Focus on the button + await sendKeys({ press: 'Tab' }); + await visualDiff(div, `${import.meta.url}_focus-ring`); }); diff --git a/packages/button/test/visual/lumo/vaadin-button-styles.js b/packages/button/test/visual/lumo/vaadin-button-styles.js new file mode 100644 index 0000000000..f10fbfaa16 --- /dev/null +++ b/packages/button/test/visual/lumo/vaadin-button-styles.js @@ -0,0 +1,13 @@ +/** + * @license + * Copyright (c) 2021 Vaadin Ltd. + * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ + */ +// TODO: Remove this file in https://github.com/vaadin/web-components/issues/2224. +import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; +import '../../../theme/lumo/vaadin-button-styles.js'; + +registerStyles('vaadin-button', css``, { + moduleId: 'lumo-button', + include: ['lumo-button-styles'] +}); diff --git a/packages/button/test/visual/material/button.test.js b/packages/button/test/visual/material/button.test.js index b48bad4f97..abd8029450 100644 --- a/packages/button/test/visual/material/button.test.js +++ b/packages/button/test/visual/material/button.test.js @@ -1,8 +1,15 @@ import { fixtureSync } from '@vaadin/testing-helpers/dist/fixture.js'; import { visualDiff } from '@web/test-runner-visual-regression'; +import { sendKeys } from '@web/test-runner-commands'; import '@vaadin/vaadin-icon/theme/material/vaadin-icon.js'; import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js'; -import '../../../theme/material/vaadin-button.js'; +// TODO: Remove in https://github.com/vaadin/web-components/issues/2224. +import './vaadin-button-styles.js'; +// TODO: Remove in https://github.com/vaadin/web-components/issues/2224. +import { Button } from '../../../src/vaadin-button.js'; + +// TODO: Remove in https://github.com/vaadin/web-components/issues/2224. +customElements.define(Button.is, Button); describe('button', () => { let div, element; @@ -20,7 +27,9 @@ describe('button', () => { }); it('focus-ring', async () => { - element.setAttribute('focus-ring', ''); + // Focus on the button + await sendKeys({ press: 'Tab' }); + await visualDiff(div, `${import.meta.url}_focus-ring`); }); diff --git a/packages/button/test/visual/material/vaadin-button-styles.js b/packages/button/test/visual/material/vaadin-button-styles.js new file mode 100644 index 0000000000..e0d413e91f --- /dev/null +++ b/packages/button/test/visual/material/vaadin-button-styles.js @@ -0,0 +1,13 @@ +/** + * @license + * Copyright (c) 2021 Vaadin Ltd. + * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ + */ +// TODO: Remove this file in https://github.com/vaadin/web-components/issues/2224. +import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; +import '../../../theme/material/vaadin-button-styles.js'; + +registerStyles('vaadin-button', css``, { + moduleId: 'material-button', + include: ['material-button-styles'] +}); diff --git a/packages/button/theme/lumo/vaadin-button-styles.js b/packages/button/theme/lumo/vaadin-button-styles.js index dac13cef2b..1bbe8c8140 100644 --- a/packages/button/theme/lumo/vaadin-button-styles.js +++ b/packages/button/theme/lumo/vaadin-button-styles.js @@ -6,7 +6,7 @@ import '@vaadin/vaadin-lumo-styles/style.js'; import '@vaadin/vaadin-lumo-styles/typography.js'; registerStyles( - 'vaadin-button', + '', css` :host { /* Sizing */ @@ -289,5 +289,5 @@ registerStyles( margin-right: 0; } `, - { moduleId: 'lumo-button' } + { moduleId: 'lumo-button-styles' } ); diff --git a/packages/button/theme/material/vaadin-button-styles.js b/packages/button/theme/material/vaadin-button-styles.js index b0644b840f..37b2b3261d 100644 --- a/packages/button/theme/material/vaadin-button-styles.js +++ b/packages/button/theme/material/vaadin-button-styles.js @@ -4,7 +4,7 @@ import '@vaadin/vaadin-material-styles/shadow.js'; import '@vaadin/vaadin-material-styles/typography.js'; registerStyles( - 'vaadin-button', + '', css` :host { padding: 8px; @@ -176,5 +176,5 @@ registerStyles( margin-right: 8px; } `, - { moduleId: 'material-button' } + { moduleId: 'material-button-styles' } ); diff --git a/packages/button/vaadin-button.js b/packages/button/vaadin-button.js index 1b2631acec..3716b9ba6a 100644 --- a/packages/button/vaadin-button.js +++ b/packages/button/vaadin-button.js @@ -1,2 +1,3 @@ import './theme/lumo/vaadin-button.js'; + export * from './src/vaadin-button.js'; diff --git a/packages/button/vaadin-directory-description.md b/packages/button/vaadin-directory-description.md deleted file mode 100644 index 13d0d24034..0000000000 --- a/packages/button/vaadin-directory-description.md +++ /dev/null @@ -1,16 +0,0 @@ - -# <vaadin-button> - -[![Available in Vaadin_Directory](https://img.shields.io/vaadin-directory/v/vaadinvaadin-button.svg)](https://vaadin.com/directory/component/vaadinvaadin-button) - -[<vaadin-button>](https://vaadin.com/components/vaadin-button) is a Web Component providing an accessible and customizable button, part of the [Vaadin components](https://vaadin.com/components). - - -[Screenshot of vaadin-button, using the default Lumo theme](https://vaadin.com/components/vaadin-button) - -## Example Usage -```html -Primary -Secondary -Tertiary -```