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
-```
-
-[](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).
-
-
-[](https://vaadin.com/components/vaadin-button)
-
-## Example Usage
-```html
-Primary
-Secondary
-Tertiary
-```