diff --git a/.eslintrc.json b/.eslintrc.json index f9b5e8b..fea230e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,15 +1,15 @@ { - "extends": "vaadin", + "extends": [ + "eslint:recommended", + "plugin:prettier/recommended" + ], + "plugins": ["prettier"], "env": { "browser": true, - "node": true, "es6": true }, - "plugins": [ - "html" - ], - "globals": { - "Polymer": false, - "Vaadin": false + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2018 } } diff --git a/.gemini.yml b/.gemini.yml deleted file mode 100644 index 8b911a0..0000000 --- a/.gemini.yml +++ /dev/null @@ -1,22 +0,0 @@ -rootUrl: http://localhost:8080/components/vaadin-checkbox/test/visual/ -gridUrl: http://localhost:4444/wd/hub -screenshotsDir: ./test/visual/screens - -system: - plugins: - polyserve: - port: 8080 - sauce: true - -browsers: - chrome: - desiredCapabilities: - browserName: "chrome" - version: "67.0" - platform: "Windows 10" - - firefox: - desiredCapabilities: - browserName: "firefox" - version: "47.0" - platform: "Windows 10" diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..9a8c97f --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,33 @@ +### Description + + +### Live Demo + +https://glitch.com/edit/#!/vaadin-checkbox-issue + + +### Steps to Reproduce + + +### Expected Results + + +### Actual Results + + +### Browsers Affected + +- [ ] Chrome +- [ ] Firefox +- [ ] Safari +- [ ] iOS Safari +- [ ] Android Chrome + +### Version + +- vaadin-checkbox: vX.X.X diff --git a/.github/workflows/sauce.yml b/.github/workflows/sauce.yml new file mode 100644 index 0000000..3d25b22 --- /dev/null +++ b/.github/workflows/sauce.yml @@ -0,0 +1,47 @@ +name: sauce + +on: + push: + branches: + - '**' + tags-ignore: + - '*.*' + +jobs: + unit-tests: + runs-on: ubuntu-latest + if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')" + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + + - name: Install dependencies + run: npm install + + - name: SauceLabs tests + env: + SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} + SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} + run: npm run test:sauce + + visual-tests: + runs-on: ubuntu-latest + if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')" + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + + - name: Install dependencies + run: npm install + + - name: Visual tests + env: + SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} + SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} + run: npm run test:visual diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..65e2568 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,43 @@ +name: tests + +on: [pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + + - name: Install dependencies + run: npm install + + - name: Check version + run: npm run check-version + + - name: Lint JavaScript + run: npm run lint:js + + - name: Lint CSS + run: npm run lint:css + + - name: Lint typings + run: npm run lint:types + + unit-tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + + - name: Install dependencies + run: npm install + + - name: Unit tests + run: npm test diff --git a/.hermione.conf.js b/.hermione.conf.js new file mode 100644 index 0000000..a151f26 --- /dev/null +++ b/.hermione.conf.js @@ -0,0 +1,24 @@ +module.exports = { + browsers: { + chrome: { + baseUrl: 'http://localhost:8080/test/visual/', + screenshotsDir: (test) => { + const folder = test.title.replace(/-(lumo|material)(-)?(rtl|ltr)?/, ''); + return `test/visual/screens/${folder}`; + }, + desiredCapabilities: { + browserName: 'chrome', + version: '85.0', + platform: 'Windows 10' + } + } + }, + plugins: { + 'hermione-esm': { + port: 8080 + }, + 'hermione-sauce': { + verbose: false + } + } +}; diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3506f0e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "printWidth": 120, + "trailingComma": "none", + "htmlWhitespaceSensitivity": "strict" +} diff --git a/.stylelintrc b/.stylelintrc index b2189e2..5a1a6a7 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,3 +1,6 @@ { - "extends": "stylelint-config-vaadin" + "extends": [ + "stylelint-config-vaadin", + "stylelint-config-prettier" + ] } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8d07a9c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,64 +0,0 @@ -sudo: false -dist: xenial -language: node_js -node_js: 8.11 - -cache: - directories: - - node_modules - -addons: - firefox: latest - chrome: stable - -jobs: - include: - - if: type = push - env: TEST_SUITE=unit_tests POLYMER=2 - - if: type = push - env: TEST_SUITE=visual_tests POLYMER=2 - - if: type = push - env: TEST_SUITE=unit_tests POLYMER=3 - - if: type = pull_request - env: POLYMER=2 - addons: - firefox: latest - chrome: stable - - if: type = pull_request - env: POLYMER=3 - addons: - firefox: latest - chrome: stable - - if: type = cron - env: TEST_SUITE=unit_tests POLYMER=2 - -script: - - if [[ "$POLYMER" = "2" ]]; then - npm -q i && npm i -q --no-save bower polymer-cli && bower -q i && - if [[ "$TRAVIS_EVENT_TYPE" = "pull_request" ]]; then - npm run check && - npm run lint && - xvfb-run -s '-screen 0 1024x768x24' wct; - elif [[ "$TRAVIS_EVENT_TYPE" = "cron" ]]; then - wct --env saucelabs-cron; - elif [[ "$TEST_SUITE" = "visual_tests" ]]; then - npm i -q --no-save gemini@^4.0.0 gemini-sauce gemini-polyserve && - gemini test test/visual; - else - wct --env saucelabs; - fi; - fi - - if [[ "$POLYMER" = "3" ]]; then - npm --no-save -q install -g yarn bower magi-cli web-component-tester polymer-modulizer && - rm -rf node_modules && - magi p3-convert --out . --import-style=name && - yarn install --flat && - if [[ "$TRAVIS_EVENT_TYPE" = "pull_request" ]]; then - xvfb-run -s '-screen 0 1024x768x24' wct --npm; - else - wct --npm --env saucelabs; - fi; - fi - -after_success: - - "cat ${TRAVIS_BUILD_DIR}/coverage/lcov.info | coveralls" diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 312e28c..0000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,28 +0,0 @@ -### Description - - -### Expected outcome - - -### Actual outcome - - -### Live Demo - - -### Steps to reproduce - - -### Browsers Affected - -- [ ] Chrome -- [ ] Firefox -- [ ] Safari -- [ ] Edge -- [ ] IE 11 -- [ ] iOS Safari -- [ ] Android Chrome diff --git a/README.md b/README.md index a9bb148..efc13cb 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,3 @@ -[![npm version](https://badgen.net/npm/v/@vaadin/vaadin-checkbox)](https://www.npmjs.com/package/@vaadin/vaadin-checkbox) -[![Bower version](https://badgen.net/github/release/vaadin/vaadin-checkbox)](https://github.com/vaadin/vaadin-checkbox/releases) -[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/vaadin/vaadin-checkbox) -[![Build Status](https://travis-ci.org/vaadin/vaadin-checkbox.svg?branch=master)](https://travis-ci.org/vaadin/vaadin-checkbox) -[![Coverage Status](https://coveralls.io/repos/github/vaadin/vaadin-checkbox/badge.svg?branch=master)](https://coveralls.io/github/vaadin/vaadin-checkbox?branch=master) -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/vaadin/web-components?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/vaadinvaadin-checkbox) -[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/vaadinvaadin-checkbox.svg)](https://vaadin.com/directory/component/vaadinvaadin-checkbox) - # <vaadin-checkbox> [Live Demo ↗](https://vaadin.com/components/vaadin-checkbox/html-examples) @@ -16,17 +6,13 @@ [<vaadin-checkbox>](https://vaadin.com/components/vaadin-checkbox) is a Web Component providing an accessible and customizable checkbox, part of the [Vaadin components](https://vaadin.com/components). - +[![npm version](https://badgen.net/npm/v/@vaadin/vaadin-checkbox)](https://www.npmjs.com/package/@vaadin/vaadin-checkbox) +[![Build Status](https://travis-ci.org/vaadin/vaadin-checkbox.svg?branch=master)](https://travis-ci.org/vaadin/vaadin-checkbox) +[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/vaadin/vaadin-checkbox) +[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/vaadinvaadin-checkbox) +[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/vaadinvaadin-checkbox.svg)](https://vaadin.com/directory/component/vaadinvaadin-checkbox) +[![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC) + ```html Checked Unchecked @@ -37,28 +23,6 @@ ## Installation -The Vaadin components are distributed as Bower and npm packages. -Please note that the version range is the same, as the API has not changed. -You should not mix Bower and npm versions in the same application, though. - -Unlike the official Polymer Elements, the converted Polymer 3 compatible Vaadin components -are only published on npm, not pushed to GitHub repositories. - -### Polymer 2 and HTML Imports Compatible Version - -Install `vaadin-checkbox`: - -```sh -bower i vaadin/vaadin-checkbox --save -``` - -Once installed, import it in your application: - -```html - -``` -### Polymer 3 and ES Modules Compatible Version - Install `vaadin-checkbox`: ```sh @@ -81,41 +45,44 @@ To use the Material theme, import the correspondent file from the `theme/materia - The component with the Lumo theme: - `theme/lumo/vaadin-checkbox.html` + `theme/lumo/vaadin-checkbox.js` - The component with the Material theme: - `theme/material/vaadin-checkbox.html` + `theme/material/vaadin-checkbox.js` -- Alias for `theme/lumo/vaadin-checkbox.html`: +- Alias for `theme/lumo/vaadin-checkbox.js`: - `vaadin-checkbox.html` + `vaadin-checkbox.js` -## Running demos and tests in a browser +## Running API docs and tests in a browser 1. Fork the `vaadin-checkbox` repository and clone it locally. -1. Make sure you have [npm](https://www.npmjs.com/) and [Bower](https://bower.io) installed. +1. Make sure you have [node.js](https://nodejs.org/) 12.x installed. -1. When in the `vaadin-checkbox` directory, run `npm install` and then `bower install` to install dependencies. +1. Make sure you have [npm](https://www.npmjs.com/) installed. + +1. When in the `vaadin-checkbox` directory, run `npm install` to install dependencies. 1. Run `npm start`, browser will automatically open the component API documentation. -1. You can also open demo or in-browser tests by adding **demo** or **test** to the URL, for example: +1. You can also open visual tests, for example: - - http://127.0.0.1:3000/components/vaadin-checkbox/demo - - http://127.0.0.1:3000/components/vaadin-checkbox/test + - http://127.0.0.1:3000/test/visual/checkbox.html ## Running tests from the command line -1. When in the `vaadin-checkbox` directory, run `polymer test` +1. When in the `vaadin-checkbox` directory, run `npm test` +## Debugging tests in the browser -## Following the coding style +1. Run `npm run debug`, then choose manual mode (M) and open the link in browser. -We are using [ESLint](http://eslint.org/) for linting JavaScript code. You can check if your code is following our standards by running `npm run lint`, which will automatically lint all `.js` files as well as JavaScript snippets inside `.html` files. +## Following the coding style +We are using [ESLint](http://eslint.org/) for linting JavaScript code. You can check if your code is following our standards by running `npm run lint`, which will automatically lint all `.js` files. ## Big Thanks diff --git a/bower.json b/bower.json deleted file mode 100644 index af03d4d..0000000 --- a/bower.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "vaadin-checkbox", - "homepage": "https://vaadin.com/components", - "authors": [ - "Vaadin Ltd" - ], - "description": "vaadin-checkbox", - "main": [ - "vaadin-checkbox.html", - "theme/material/vaadin-checkbox-group.html", - "theme/material/vaadin-checkbox.html" - ], - "keywords": [ - "Vaadin", - "checkbox", - "web-components", - "web-component", - "polymer" - ], - "license": "Apache-2.0", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "package-lock.json", - "wct.conf.js" - ], - "dependencies": { - "polymer": "^2.0.0", - "vaadin-control-state-mixin": "vaadin/vaadin-control-state-mixin#^2.2.1", - "vaadin-themable-mixin": "vaadin/vaadin-themable-mixin#^1.6.1", - "vaadin-lumo-styles": "vaadin/vaadin-lumo-styles#^1.4.1", - "vaadin-material-styles": "vaadin/vaadin-material-styles#^1.2.0", - "vaadin-element-mixin": "vaadin/vaadin-element-mixin#^2.4.1" - }, - "devDependencies": { - "iron-component-page": "^3.0.0", - "iron-test-helpers": "^2.0.0", - "webcomponentsjs": "^1.0.1", - "web-component-tester": "^6.1.5", - "vaadin-demo-helpers": "vaadin/vaadin-demo-helpers#^3.0.0", - "iron-form": "^2.0.1", - "vaadin-button": "vaadin/vaadin-button#^2.4.0" - } -} diff --git a/demo/.eslintrc.json b/demo/.eslintrc.json deleted file mode 100644 index 881bce1..0000000 --- a/demo/.eslintrc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "rules": { - }, - "globals": { - "CheckboxDemo": false, - "DemoReadyEventEmitter": false - } -} diff --git a/demo/checkbox-basic-demos.html b/demo/checkbox-basic-demos.html deleted file mode 100644 index 71d849e..0000000 --- a/demo/checkbox-basic-demos.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - diff --git a/demo/checkbox-demo.js b/demo/checkbox-demo.js deleted file mode 100644 index 460b518..0000000 --- a/demo/checkbox-demo.js +++ /dev/null @@ -1,11 +0,0 @@ -window.CheckboxDemo = superClass => { - return class extends superClass { - static get properties() { - return { - }; - } - }; -}; -window.addEventListener('WebComponentsReady', () => { - document.body.removeAttribute('unresolved'); -}); diff --git a/demo/checkbox-presentation-demos.html b/demo/checkbox-presentation-demos.html deleted file mode 100644 index 09fded0..0000000 --- a/demo/checkbox-presentation-demos.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - diff --git a/demo/checkbox-styling-demos.html b/demo/checkbox-styling-demos.html deleted file mode 100644 index dcdc196..0000000 --- a/demo/checkbox-styling-demos.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - diff --git a/demo/checkbox-theme-variants-demos.html b/demo/checkbox-theme-variants-demos.html deleted file mode 100644 index b3011ed..0000000 --- a/demo/checkbox-theme-variants-demos.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - diff --git a/demo/checkbox-validation-demos.html b/demo/checkbox-validation-demos.html deleted file mode 100644 index 97a025c..0000000 --- a/demo/checkbox-validation-demos.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - diff --git a/demo/demos.json b/demo/demos.json deleted file mode 100644 index 52e2e80..0000000 --- a/demo/demos.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "Vaadin Checkbox", - "pages": [ - { - "name": "Basics", - "url": "checkbox-basic-demos", - "src": "checkbox-basic-demos.html", - "meta": { - "title": "Vaadin Checkbox Basics", - "description": "", - "image": "" - } - } - , - { - "name": "Validation", - "url": "checkbox-validation-demos", - "src": "checkbox-validation-demos.html", - "meta": { - "title": "Vaadin Checkbox Validations", - "description": "", - "image": "" - } - } - , - { - "name": "Presentation", - "url": "checkbox-presentation-demos", - "src": "checkbox-presentation-demos.html", - "meta": { - "title": "Vaadin Checkbox Presentations", - "description": "", - "image": "" - } - } - , - { - "name": "Theme Variants", - "url": "checkbox-theme-variants-demos", - "src": "checkbox-theme-variants-demos.html", - "meta": { - "title": "vaadin-checkbox Theme Variants", - "description": "", - "image": "" - } - } - , - { - "name": "Styling", - "url": "checkbox-styling-demos", - "src": "checkbox-styling-demos.html", - "meta": { - "title": "vaadin-checkbox-group Styling Examples", - "description": "", - "image": "" - } - } - ] -} diff --git a/demo/index.html b/demo/index.html deleted file mode 100644 index 7dee16c..0000000 --- a/demo/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - Vaadin Checkbox Examples - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gen-tsd.json b/gen-tsd.json deleted file mode 100644 index f4a47d8..0000000 --- a/gen-tsd.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "excludeFiles": [ - "wct.conf.js", - "index.html", - "demo/**/*", - "test/**/*", - "theme/**/*" - ] -} diff --git a/index.html b/index.html index 9aff708..c72b121 100644 --- a/index.html +++ b/index.html @@ -5,10 +5,12 @@ vaadin-checkbox - - - + + + diff --git a/magi-p3-post.js b/magi-p3-post.js deleted file mode 100644 index 9e2fc2d..0000000 --- a/magi-p3-post.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - files: [ - 'vaadin-checkbox.js', - 'vaadin-checkbox-group.js' - ], - from: [ - /import '\.\/theme\/lumo\/vaadin-(.+)\.js';/ - ], - to: [ - `import './theme/lumo/vaadin-$1.js';\nexport * from './src/vaadin-$1.js';` - ] -}; diff --git a/package.json b/package.json index 6c41d75..8c0b64e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "name": "@vaadin/vaadin-checkbox", "version": "2.5.0", "description": "vaadin-checkbox", - "main": "vaadin-checkbox.html", + "main": "vaadin-checkbox.js", + "module": "vaadin-checkbox.js", "repository": "vaadin/vaadin-checkbox", "keywords": [ "Vaadin", @@ -23,26 +24,62 @@ "src", "theme" ], + "scripts": { + "debug": "web-test-runner test/*.test.js --watch", + "check-version": "magi check-version", + "lint": "npm run lint:js && npm run lint:css && npm run lint:types", + "lint:css": "stylelint src/*.js theme/**/*-styles.js", + "lint:js": "eslint src theme test", + "lint:types": "tsc", + "prestart": "polymer analyze vaadin-* > analysis.json", + "preversion": "magi update-version", + "screenshots": "hermione test/visual/test.js --update-refs", + "start": "web-dev-server --node-resolve --open", + "test": "web-test-runner test/*.test.js --coverage", + "test:sauce": "TEST_ENV=sauce npm test", + "test:visual": "hermione test/visual/test.js" + }, "husky": { "hooks": { - "pre-commit": "npm run lint" + "pre-commit": "lint-staged" } }, - "scripts": { - "test": "wct", - "check": "npm-run-all --parallel check:*", - "check:bower": "magi check-bower", - "check:version": "magi check-version", - "lint": "npm-run-all --parallel lint:*", - "lint:css": "stylelint *.html src/*.html demo/*.html theme/**/*.html test/*html", - "lint:html": "eslint *.html src demo test --ext .html", - "lint:js": "eslint *.js test", - "lint:polymer": "polymer lint --rules polymer-2 --input ./src/*.html ./theme/**/*.html", - "prestart": "polymer analyze vaadin-* > analysis.json", - "start": "polymer serve --port 3000 --open", - "preversion": "magi update-version" + "lint-staged": { + "*.js": [ + "eslint --fix", + "prettier --write" + ] + }, + "dependencies": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.2.1", + "@vaadin/vaadin-themable-mixin": "^1.6.2", + "@vaadin/vaadin-lumo-styles": "^1.6.1", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-element-mixin": "^2.4.1" }, "devDependencies": { - "@vaadin/vaadin-component-dev-dependencies": "^3.0.0" + "@esm-bundle/chai": "^4.1.5", + "@open-wc/testing-helpers": "^1.8.0", + "@polymer/iron-component-page": "^4.0.0", + "@polymer/iron-test-helpers": "^3.0.0", + "@web/dev-server": "~0.0.25", + "@web/test-runner": "~0.10.0", + "@web/test-runner-saucelabs": "~0.1.3", + "eslint": "^7.14.0", + "eslint-config-prettier": "^6.15.0", + "eslint-plugin-prettier": "^3.1.4", + "hermione": "^3.9.0", + "hermione-esm": "^0.4.0", + "hermione-sauce": "^0.1.0", + "husky": "^4.3.0", + "lint-staged": "^10.5.1", + "magi-cli": "^0.28.0", + "prettier": "^2.2.0", + "sinon": "^9.2.0", + "stylelint": "^13.8.0", + "stylelint-config-prettier": "^8.0.2", + "stylelint-config-vaadin": "^0.2.7", + "typescript": "^4.1.2" } } diff --git a/src/vaadin-checkbox-group.d.ts b/src/vaadin-checkbox-group.d.ts new file mode 100644 index 0000000..266d16d --- /dev/null +++ b/src/vaadin-checkbox-group.d.ts @@ -0,0 +1,142 @@ +import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; + +import { DirMixin } from '@vaadin/vaadin-element-mixin/vaadin-dir-mixin.js'; + +import { CheckboxElement } from './vaadin-checkbox.js'; + +/** + * Fired when the `invalid` property changes. + */ +export type CheckboxGroupInvalidChanged = CustomEvent<{ value: boolean }>; + +/** + * Fired when the `value` property changes. + */ +export type CheckboxGroupValueChanged = CustomEvent<{ value: Array }>; + +export interface CheckboxGroupElementEventMap { + 'invalid-changed': CheckboxGroupInvalidChanged; + + 'value-changed': CheckboxGroupValueChanged; +} + +export interface CheckboxGroupEventMap extends HTMLElementEventMap, CheckboxGroupElementEventMap {} + +/** + * `` is a Polymer element for grouping vaadin-checkboxes. + * + * ```html + * + * English + * Français + * Deutsch + * + * ``` + * + * ### Styling + * + * The following shadow DOM parts are available for styling: + * + * Part name | Description + * ----------------|---------------- + * `label` | The label element + * `group-field` | The element that wraps checkboxes + * `error-message` | The error message element + * + * The following state attributes are available for styling: + * + * Attribute | Description | Part name + * -----------|-------------|------------ + * `disabled` | Set when the checkbox group and its children are disabled. | :host + * `focused` | Set when the checkbox group contains focus | :host + * `has-label` | Set when the element has a label | :host + * `has-value` | Set when the element has a value | :host + * `has-helper` | Set when the element has helper text or slot | :host + * `has-error-message` | Set when the element has an error message, regardless if the field is valid or not | :host + * `required` | Set when the element is required | :host + * `invalid` | Set when the element is invalid | :host + * + * See [ThemableMixin – how to apply styles for shadow parts](https://github.com/vaadin/vaadin-themable-mixin/wiki) + * + * @fires {CustomEvent} invalid-changed + * @fires {CustomEvent>} value-changed + */ +declare class CheckboxGroupElement extends ThemableMixin(DirMixin(HTMLElement)) { + /** + * The current disabled state of the checkbox group. True if group and all internal checkboxes are disabled. + */ + disabled: boolean | null | undefined; + + /** + * String used for the label element. + */ + label: string | null | undefined; + + /** + * Value of the checkbox group. + * Note: toggling the checkboxes modifies the value by creating new + * array each time, to override Polymer dirty-checking for arrays. + * You can still use Polymer array mutation methods to update the value. + */ + value: string[]; + + /** + * Error to show when the input value is invalid. + * @attr {string} error-message + */ + errorMessage: string | null | undefined; + + /** + * String used for the helper text. + * @attr {string} helper-text + */ + helperText: string | null; + + /** + * Specifies that the user must fill in a value. + */ + required: boolean | null | undefined; + + /** + * This property is set to true when the control value is invalid. + */ + invalid: boolean; + + /** + * Returns true if `value` is valid. + * `` uses this to check the validity or all its elements. + * + * @returns True if the value is valid. + */ + validate(): boolean; + + _addCheckboxToValue(value: string): void; + + _removeCheckboxFromValue(value: string): void; + + _changeSelectedCheckbox(checkbox: CheckboxElement | null): void; + + _containsFocus(): boolean; + + _setFocused(focused: boolean): void; + + addEventListener( + type: K, + listener: (this: CheckboxGroupElement, ev: CheckboxGroupEventMap[K]) => void, + options?: boolean | AddEventListenerOptions + ): void; + + removeEventListener( + type: K, + listener: (this: CheckboxGroupElement, ev: CheckboxGroupEventMap[K]) => void, + options?: boolean | EventListenerOptions + ): void; +} + +declare global { + interface HTMLElementTagNameMap { + 'vaadin-checkbox-group': CheckboxGroupElement; + } +} + +export { CheckboxGroupElement }; diff --git a/src/vaadin-checkbox-group.html b/src/vaadin-checkbox-group.html deleted file mode 100644 index d9e27e4..0000000 --- a/src/vaadin-checkbox-group.html +++ /dev/null @@ -1,424 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/vaadin-checkbox-group.js b/src/vaadin-checkbox-group.js new file mode 100644 index 0000000..dda59aa --- /dev/null +++ b/src/vaadin-checkbox-group.js @@ -0,0 +1,413 @@ +/** + * @license + * Copyright (c) 2020 Vaadin Ltd. + * 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 { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js'; +import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; +import { DirMixin } from '@vaadin/vaadin-element-mixin/vaadin-dir-mixin.js'; +import { CheckboxElement } from './vaadin-checkbox.js'; + +/** + * `` is a Polymer element for grouping vaadin-checkboxes. + * + * ```html + * + * English + * Français + * Deutsch + * + * ``` + * + * ### Styling + * + * The following shadow DOM parts are available for styling: + * + * Part name | Description + * ----------------|---------------- + * `label` | The label element + * `group-field` | The element that wraps checkboxes + * `error-message` | The error message element + * + * The following state attributes are available for styling: + * + * Attribute | Description | Part name + * -----------|-------------|------------ + * `disabled` | Set when the checkbox group and its children are disabled. | :host + * `focused` | Set when the checkbox group contains focus | :host + * `has-label` | Set when the element has a label | :host + * `has-value` | Set when the element has a value | :host + * `has-helper` | Set when the element has helper text or slot | :host + * `has-error-message` | Set when the element has an error message, regardless if the field is valid or not | :host + * `required` | Set when the element is required | :host + * `invalid` | Set when the element is invalid | :host + * + * See [ThemableMixin – how to apply styles for shadow parts](https://github.com/vaadin/vaadin-themable-mixin/wiki) + * + * @fires {CustomEvent} invalid-changed + * @fires {CustomEvent>} value-changed + * + * @extends HTMLElement + * @mixes ThemableMixin + * @mixes DirMixin + * @element vaadin-checkbox-group + */ +class CheckboxGroupElement extends ThemableMixin(DirMixin(PolymerElement)) { + static get template() { + return html` + + +
+ + +
+ +
+ +
+ [[helperText]] +
+ +
[[errorMessage]]
+
+ `; + } + + static get is() { + return 'vaadin-checkbox-group'; + } + + static get properties() { + return { + /** + * The current disabled state of the checkbox group. True if group and all internal checkboxes are disabled. + */ + disabled: { + type: Boolean, + reflectToAttribute: true, + observer: '_disabledChanged' + }, + + /** + * String used for the label element. + */ + label: { + type: String, + value: '', + observer: '_labelChanged' + }, + + /** + * Value of the checkbox group. + * Note: toggling the checkboxes modifies the value by creating new + * array each time, to override Polymer dirty-checking for arrays. + * You can still use Polymer array mutation methods to update the value. + * @type {!Array} + */ + value: { + type: Array, + value: () => [], + notify: true + }, + + /** + * Error to show when the input value is invalid. + * @attr {string} error-message + */ + errorMessage: { + type: String, + value: '', + observer: '_errorMessageChanged' + }, + + /** + * String used for the helper text. + * @attr {string} helper-text + * @type {string | null} + */ + helperText: { + type: String, + value: '', + observer: '_helperTextChanged' + }, + + /** + * Specifies that the user must fill in a value. + */ + required: { + type: Boolean, + reflectToAttribute: true + }, + + /** + * This property is set to true when the control value is invalid. + * @type {boolean} + */ + invalid: { + type: Boolean, + reflectToAttribute: true, + notify: true, + value: false + }, + + /** @private */ + _hasSlottedHelper: Boolean + }; + } + + static get observers() { + return ['_updateValue(value, value.splices)']; + } + + ready() { + super.ready(); + + this.addEventListener('focusin', () => this._setFocused(this._containsFocus())); + + this.addEventListener('focusout', (e) => { + // validate when stepping out of the checkbox group + if ( + !this._checkboxes.some( + (checkbox) => e.relatedTarget === checkbox || checkbox.shadowRoot.contains(e.relatedTarget) + ) + ) { + this.validate(); + this._setFocused(false); + } + }); + + const checkedChangedListener = (e) => { + this._changeSelectedCheckbox(e.target); + }; + + this._observer = new FlattenedNodesObserver(this, (info) => { + const addedCheckboxes = this._filterCheckboxes(info.addedNodes); + + addedCheckboxes.forEach((checkbox) => { + checkbox.addEventListener('checked-changed', checkedChangedListener); + if (this.disabled) { + checkbox.disabled = true; + } + if (checkbox.checked) { + this._addCheckboxToValue(checkbox.value); + } else if (this.value.indexOf(checkbox.value) > -1) { + checkbox.checked = true; + } + }); + + this._filterCheckboxes(info.removedNodes).forEach((checkbox) => { + checkbox.removeEventListener('checked-changed', checkedChangedListener); + if (checkbox.checked) { + this._removeCheckboxFromValue(checkbox.value); + } + }); + + this._setOrToggleHasHelperAttribute(); + + const hasValue = (checkbox) => { + const { value } = checkbox; + return checkbox.hasAttribute('value') || (value && value !== 'on'); + }; + if (!addedCheckboxes.every(hasValue)) { + console.warn('Please add value attribute to all checkboxes in checkbox group'); + } + }); + } + + /** + * Returns true if `value` is valid. + * `` uses this to check the validity or all its elements. + * + * @return {boolean} True if the value is valid. + */ + validate() { + this.invalid = this.required && this.value.length === 0; + return !this.invalid; + } + + /** @private */ + get _checkboxes() { + return this._filterCheckboxes(this.querySelectorAll('*')); + } + + /** @private */ + _filterCheckboxes(nodes) { + return Array.from(nodes).filter((child) => child instanceof CheckboxElement); + } + + /** @private */ + _disabledChanged(disabled) { + this.setAttribute('aria-disabled', disabled); + + this._checkboxes.forEach((checkbox) => (checkbox.disabled = disabled)); + } + + /** + * @param {string} value + * @protected + */ + _addCheckboxToValue(value) { + if (this.value.indexOf(value) === -1) { + this.value = this.value.concat(value); + } + } + + /** + * @param {string} value + * @protected + */ + _removeCheckboxFromValue(value) { + this.value = this.value.filter((v) => v !== value); + } + + /** + * @param {CheckboxElement} checkbox + * @protected + */ + _changeSelectedCheckbox(checkbox) { + if (this._updatingValue) { + return; + } + + if (checkbox.checked) { + this._addCheckboxToValue(checkbox.value); + } else { + this._removeCheckboxFromValue(checkbox.value); + } + } + + /** @private */ + _updateValue(value) { + // setting initial value to empty array, skip validation + if (value.length === 0 && this._oldValue === undefined) { + return; + } + + if (value.length) { + this.setAttribute('has-value', ''); + } else { + this.removeAttribute('has-value'); + } + + this._oldValue = value; + // set a flag to avoid updating loop + this._updatingValue = true; + // reflect the value array to checkboxes + this._checkboxes.forEach((checkbox) => { + checkbox.checked = value.indexOf(checkbox.value) > -1; + }); + this._updatingValue = false; + + this.validate(); + } + + /** @private */ + _labelChanged(label) { + this._setOrToggleAttribute('has-label', !!label); + } + + /** @private */ + _errorMessageChanged(errorMessage) { + this._setOrToggleAttribute('has-error-message', !!errorMessage); + } + + /** @private */ + _helperTextChanged(helperText) { + this._setOrToggleAttribute('has-helper', !!helperText); + } + + /** @private */ + _setOrToggleAttribute(name, value) { + if (!name) { + return; + } + + if (value) { + this.setAttribute(name, typeof value === 'boolean' ? '' : value); + } else { + this.removeAttribute(name); + } + } + + /** @private */ + _getErrorMessageAriaHidden(invalid, errorMessage) { + return (!errorMessage || !invalid).toString(); + } + + /** + * @return {boolean} + * @protected + */ + _containsFocus() { + const root = this.getRootNode(); + // Safari 9 needs polyfilled `_activeElement` to return correct node + const activeElement = root._activeElement !== undefined ? root._activeElement : root.activeElement; + return this.contains(activeElement); + } + + /** + * @param {boolean} focused + * @protected + */ + _setFocused(focused) { + if (focused) { + this.setAttribute('focused', ''); + } else { + this.removeAttribute('focused'); + } + } + + /** @private */ + _setOrToggleHasHelperAttribute() { + const slottedNodes = this.shadowRoot.querySelector(`[name="helper"]`).assignedNodes(); + // Only has slotted helper if not a text node + // Text nodes are added by the helperText prop and not the helper slot + // The filter is added due to shady DOM triggering this slotchange event on helperText prop change + this._hasSlottedHelper = slottedNodes.filter((node) => node.nodeType !== 3).length > 0; + + this._setOrToggleAttribute('has-helper', this._hasSlottedHelper ? 'slotted' : !!this.helperText); + } + + /** @private */ + _getHelperTextAriaHidden(helperText, hasSlottedHelper) { + return (!(helperText || hasSlottedHelper)).toString(); + } +} + +customElements.define(CheckboxGroupElement.is, CheckboxGroupElement); + +export { CheckboxGroupElement }; diff --git a/src/vaadin-checkbox.d.ts b/src/vaadin-checkbox.d.ts new file mode 100644 index 0000000..7fb1aa3 --- /dev/null +++ b/src/vaadin-checkbox.d.ts @@ -0,0 +1,109 @@ +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'; + +/** + * Fired when the `checked` property changes. + */ +export type CheckboxCheckedChanged = CustomEvent<{ value: boolean }>; + +/** + * Fired when the `indeterminate` property changes. + */ +export type CheckboxIndeterminateChanged = CustomEvent<{ value: boolean }>; + +export interface CheckboxElementEventMap { + 'checked-changed': CheckboxCheckedChanged; + + 'indeterminate-changed': CheckboxIndeterminateChanged; +} + +export interface CheckboxEventMap extends HTMLElementEventMap, CheckboxElementEventMap {} + +/** + * `` is a Web Component for customized checkboxes. + * + * ```html + * + * Make my profile visible + * + * ``` + * + * ### Styling + * + * The following shadow DOM parts are available for styling: + * + * Part name | Description + * ------------------|---------------- + * `checkbox` | The wrapper element for the native + * `label` | The wrapper element in which the component's children, namely the label, is slotted + * + * The following state attributes are available for styling: + * + * Attribute | Description | Part name + * -------------|-------------|-------------- + * `active` | Set when the checkbox is pressed down, either with mouse, touch or the keyboard. | `:host` + * `disabled` | Set when the checkbox is disabled. | `:host` + * `focus-ring` | Set when the checkbox is focused using the keyboard. | `:host` + * `focused` | Set when the checkbox is focused. | `:host` + * `indeterminate` | Set when the checkbox is in indeterminate mode. | `:host` + * `checked` | Set when the checkbox is checked. | `:host` + * `empty` | Set when there is no label provided. | `label` + * + * See [ThemableMixin – how to apply styles for shadow parts](https://github.com/vaadin/vaadin-themable-mixin/wiki) + * + * @fires {CustomEvent} checked-changed + * @fires {CustomEvent} indeterminate-changed + */ +declare class CheckboxElement extends ElementMixin( + ControlStateMixin(ThemableMixin(GestureEventListeners(HTMLElement))) +) { + readonly focusElement: HTMLInputElement; + + /** + * Name of the element. + */ + name: string; + + /** + * True if the checkbox is checked. + */ + checked: boolean; + + /** + * Indeterminate state of the checkbox when it's neither checked nor unchecked, but undetermined. + * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Indeterminate_state_checkboxes + */ + indeterminate: boolean; + + /** + * The value given to the data submitted with the checkbox's name to the server when the control is inside a form. + */ + value: string | null | undefined; + + _toggleChecked(): void; + + addEventListener( + type: K, + listener: (this: CheckboxElement, ev: CheckboxEventMap[K]) => void, + options?: boolean | AddEventListenerOptions + ): void; + + removeEventListener( + type: K, + listener: (this: CheckboxElement, ev: CheckboxEventMap[K]) => void, + options?: boolean | EventListenerOptions + ): void; +} + +declare global { + interface HTMLElementTagNameMap { + 'vaadin-checkbox': CheckboxElement; + } +} + +export { CheckboxElement }; diff --git a/src/vaadin-checkbox.html b/src/vaadin-checkbox.html deleted file mode 100644 index 6c4748e..0000000 --- a/src/vaadin-checkbox.html +++ /dev/null @@ -1,344 +0,0 @@ - - - - - - - - - - - - diff --git a/src/vaadin-checkbox.js b/src/vaadin-checkbox.js new file mode 100644 index 0000000..84cdc5a --- /dev/null +++ b/src/vaadin-checkbox.js @@ -0,0 +1,336 @@ +/** + * @license + * Copyright (c) 2020 Vaadin Ltd. + * 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 { 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 for customized checkboxes. + * + * ```html + * + * Make my profile visible + * + * ``` + * + * ### Styling + * + * The following shadow DOM parts are available for styling: + * + * Part name | Description + * ------------------|---------------- + * `checkbox` | The wrapper element for the native + * `label` | The wrapper element in which the component's children, namely the label, is slotted + * + * The following state attributes are available for styling: + * + * Attribute | Description | Part name + * -------------|-------------|-------------- + * `active` | Set when the checkbox is pressed down, either with mouse, touch or the keyboard. | `:host` + * `disabled` | Set when the checkbox is disabled. | `:host` + * `focus-ring` | Set when the checkbox is focused using the keyboard. | `:host` + * `focused` | Set when the checkbox is focused. | `:host` + * `indeterminate` | Set when the checkbox is in indeterminate mode. | `:host` + * `checked` | Set when the checkbox is checked. | `:host` + * `empty` | Set when there is no label provided. | `label` + * + * See [ThemableMixin – how to apply styles for shadow parts](https://github.com/vaadin/vaadin-themable-mixin/wiki) + * + * @fires {CustomEvent} checked-changed + * @fires {CustomEvent} indeterminate-changed + * + * @extends HTMLElement + * @mixes ElementMixin + * @mixes ControlStateMixin + * @mixes ThemableMixin + * @mixes GestureEventListeners + */ +class CheckboxElement extends ElementMixin(ControlStateMixin(ThemableMixin(GestureEventListeners(PolymerElement)))) { + static get template() { + return html` + + + + `; + } + + static get is() { + return 'vaadin-checkbox'; + } + + static get version() { + return '2.5.0'; + } + + static get properties() { + return { + /** + * True if the checkbox is checked. + * @type {boolean} + */ + checked: { + type: Boolean, + value: false, + notify: true, + observer: '_checkedChanged', + reflectToAttribute: true + }, + + /** + * Indeterminate state of the checkbox when it's neither checked nor unchecked, but undetermined. + * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Indeterminate_state_checkboxes + * @type {boolean} + */ + indeterminate: { + type: Boolean, + notify: true, + observer: '_indeterminateChanged', + reflectToAttribute: true, + value: false + }, + + /** + * The value given to the data submitted with the checkbox's name to the server when the control is inside a form. + */ + value: { + type: String, + value: 'on' + }, + + /** @private */ + _nativeCheckbox: { + type: Object + } + }; + } + + constructor() { + super(); + /** + * @type {string} + * Name of the element. + */ + this.name; + } + + get name() { + return this.checked ? this._storedName : ''; + } + + set name(name) { + this._storedName = name; + } + + ready() { + super.ready(); + + this.setAttribute('role', 'checkbox'); + + this._nativeCheckbox = this.shadowRoot.querySelector('input[type="checkbox"]'); + + this.addEventListener('click', this._handleClick.bind(this)); + + this._addActiveListeners(); + + const attrName = this.getAttribute('name'); + if (attrName) { + this.name = attrName; + } + + this.shadowRoot + .querySelector('[part~="label"]') + .querySelector('slot') + .addEventListener('slotchange', this._updateLabelAttribute.bind(this)); + + this._updateLabelAttribute(); + } + + /** @private */ + _updateLabelAttribute() { + const label = this.shadowRoot.querySelector('[part~="label"]'); + const assignedNodes = label.firstElementChild.assignedNodes(); + if (this._isAssignedNodesEmpty(assignedNodes)) { + label.setAttribute('empty', ''); + } else { + label.removeAttribute('empty'); + } + } + + /** @private */ + _isAssignedNodesEmpty(nodes) { + // The assigned nodes considered to be empty if there is no slotted content or only one empty text node + return ( + nodes.length === 0 || + (nodes.length == 1 && nodes[0].nodeType == Node.TEXT_NODE && nodes[0].textContent.trim() === '') + ); + } + + /** @private */ + _checkedChanged(checked) { + if (this.indeterminate) { + this.setAttribute('aria-checked', 'mixed'); + } else { + this.setAttribute('aria-checked', Boolean(checked)); + } + } + + /** @private */ + _indeterminateChanged(indeterminate) { + if (indeterminate) { + this.setAttribute('aria-checked', 'mixed'); + } else { + this.setAttribute('aria-checked', this.checked); + } + } + + /** @private */ + _addActiveListeners() { + // DOWN + this._addEventListenerToNode(this, 'down', (e) => { + if (this.__interactionsAllowed(e)) { + this.setAttribute('active', ''); + } + }); + + // UP + this._addEventListenerToNode(this, 'up', () => this.removeAttribute('active')); + + // KEYDOWN + this.addEventListener('keydown', (e) => { + if (this.__interactionsAllowed(e) && e.keyCode === 32) { + e.preventDefault(); + this.setAttribute('active', ''); + } + }); + + // KEYUP + this.addEventListener('keyup', (e) => { + if (this.__interactionsAllowed(e) && e.keyCode === 32) { + e.preventDefault(); + this._toggleChecked(); + this.removeAttribute('active'); + + if (this.indeterminate) { + this.indeterminate = false; + } + } + }); + } + + /** + * @return {!HTMLInputElement} + * @protected + */ + get focusElement() { + return this.shadowRoot.querySelector('input'); + } + + /** + * True if users' interactions (mouse or keyboard) + * should toggle the checkbox + */ + __interactionsAllowed(e) { + if (this.disabled) { + return false; + } + + // https://github.com/vaadin/vaadin-checkbox/issues/63 + if (e.target.localName === 'a') { + return false; + } + + return true; + } + + /** @private */ + _handleClick(e) { + if (this.__interactionsAllowed(e)) { + if (!this.indeterminate) { + if (e.composedPath()[0] !== this._nativeCheckbox) { + e.preventDefault(); + this._toggleChecked(); + } + } else { + /* + * Required for IE 11 and Edge. + * See issue here: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7344418/ + */ + this.indeterminate = false; + e.preventDefault(); + this._toggleChecked(); + } + } + } + + /** @protected */ + _toggleChecked() { + this.checked = !this.checked; + this.dispatchEvent(new CustomEvent('change', { composed: false, bubbles: true })); + } + + /** + * Fired when the user commits a value change. + * + * @event change + */ +} + +customElements.define(CheckboxElement.is, CheckboxElement); + +export { CheckboxElement }; diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index a19562b..0000000 --- a/test/.eslintrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "globals": { - "WCT": false, - "describe": false, - "beforeEach": false, - "fixture": false, - "it": false, - "sinon": false, - "expect": false, - "gemini": false, - "MockInteractions": false, - "animationFrameFlush": false - } -} diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 0000000..7eeefc3 --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "env": { + "mocha": true + } +} diff --git a/test/a11y.test.js b/test/a11y.test.js new file mode 100644 index 0000000..37ab452 --- /dev/null +++ b/test/a11y.test.js @@ -0,0 +1,60 @@ +import { expect } from '@esm-bundle/chai'; +import { fixtureSync } from '@open-wc/testing-helpers'; +import '../vaadin-checkbox.js'; + +describe('a11y', () => { + let checkbox; + + beforeEach(() => { + checkbox = fixtureSync('Vaadin Checkbox'); + }); + + it('should set aria-checked to "false" when indeterminate is first set to false, then checked is set to false', () => { + checkbox.checked = false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('false'); + }); + + it('should set aria-checked to "false" when checked is first set to false, then indeterminate is set to false', () => { + checkbox.checked = false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('false'); + }); + + it('should set aria-checked to "true" when indeterminate is first set to false, then checked is set to true', () => { + checkbox.checked = true; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('true'); + }); + + it('should set aria-checked to "true" when checked is first set to true, then indeterminate is set to false', () => { + checkbox.checked = true; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('true'); + }); + + it('should set aria-checked to "mixed" when indeterminate is first set to true, then checked is set to false', () => { + checkbox.indeterminate = true; + checkbox.checked = false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('mixed'); + }); + + it('should set aria-checked to "mixed" when checked is first set to false, then indeterminate is set to true', () => { + checkbox.checked = false; + checkbox.indeterminate = true; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('mixed'); + }); + + it('should set aria-checked to "mixed" when indeterminate is first set to true, then checked is set to true', () => { + checkbox.indeterminate = true; + checkbox.checked = true; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('mixed'); + }); + + it('should set aria-checked to "mixed" when checked is first set to true, then indeterminate is set to true', () => { + checkbox.checked = true; + checkbox.indeterminate = true; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('mixed'); + }); + + it('should set aria-checked to "false" when checked is set to null', () => { + checkbox.checked = null; + expect(checkbox.getAttribute('aria-checked')).to.eql('false'); + }); +}); diff --git a/test/accessibility.html b/test/accessibility.html deleted file mode 100644 index 1535976..0000000 --- a/test/accessibility.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - vaadin-checkbox tests - - - - - - - - - - - - - diff --git a/test/checkbox-group.test.js b/test/checkbox-group.test.js new file mode 100644 index 0000000..8720d4c --- /dev/null +++ b/test/checkbox-group.test.js @@ -0,0 +1,500 @@ +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { fixtureSync } from '@open-wc/testing-helpers'; +import '@polymer/polymer/lib/elements/dom-bind.js'; +import '../vaadin-checkbox-group.js'; + +describe('vaadin-checkbox-group', () => { + let group, checkboxes; + + beforeEach(() => { + group = fixtureSync(` + + Checkbox 1 + Checkbox 2 + Checkbox 3 + + `); + checkboxes = group.querySelectorAll('vaadin-checkbox'); + group._observer.flush(); + }); + + it('does not set a role', () => { + expect(group.getAttribute('role')).to.eq(null); + }); + + it('changes aria-disabled on disabled change', () => { + group.disabled = true; + expect(group.getAttribute('aria-disabled')).to.eq('true'); + }); + + it('can be disabled imperatively', () => { + group.disabled = true; + expect(group.hasAttribute('disabled')).to.be.true; + expect(checkboxes[0].hasAttribute('disabled')).to.be.true; + }); + + it('should set disabled property to dynamically added checkboxes', () => { + group.disabled = true; + const checkbox = document.createElement('vaadin-checkbox'); + checkbox.value = '4'; + group.appendChild(checkbox); + group._observer.flush(); + expect(checkbox.disabled).to.be.true; + }); + + it('should add dynamically added checked checkbox value to checkbox group value', () => { + const checkbox = document.createElement('vaadin-checkbox'); + checkbox.value = 'new'; + checkbox.checked = true; + group.appendChild(checkbox); + group._observer.flush(); + expect(group.value).to.include('new'); + }); + + it('should not add duplicate values when added checked checkbox already included in value', () => { + const checkbox = document.createElement('vaadin-checkbox'); + checkbox.value = 'new'; + checkbox.checked = true; + group.value = ['new']; + group.appendChild(checkbox); + group._observer.flush(); + expect(group.value).to.eql(['new']); + }); + + it('should check dynamically added checkbox if included in value', () => { + const checkbox = document.createElement('vaadin-checkbox'); + checkbox.value = 'new'; + group.value = ['new']; + group.appendChild(checkbox); + group._observer.flush(); + expect(group.value).to.eql(['new']); + expect(checkbox.checked).to.be.true; + }); + + it('should remove checked checkbox value from checkbox group value, when checkbox is dynamically removed', () => { + const checkbox = checkboxes[0]; + checkbox.checked = true; + group.removeChild(checkbox); + group._observer.flush(); + expect(group.value).to.not.include('1'); + }); + + it('should create new array instance for checkbox group value when checkbox dynamically added', () => { + const value = group.value; + const checkbox = document.createElement('vaadin-checkbox'); + checkbox.value = 'new'; + checkbox.checked = true; + group.appendChild(checkbox); + group._observer.flush(); + expect(group.value).to.not.equal(value); + }); + + it('should create new array instance for checkbox group value when checkbox dynamically removed', () => { + const value = group.value; + const checkbox = checkboxes[0]; + checkbox.checked = true; + group.removeChild(checkbox); + group._observer.flush(); + expect(group.value).to.not.equal(value); + }); + + it('should not change checkbox group value if a removed checkbox is checked', () => { + const checkbox = checkboxes[0]; + group.removeChild(checkbox); + group._observer.flush(); + checkbox.checked = true; + expect(group.value).to.not.include('1'); + }); + + it('should set proper value to checkbox-group when a checkbox is checked', () => { + checkboxes[0].checked = true; + expect(group.value).to.deep.equal(['1']); + checkboxes[1].checked = true; + expect(group.value).to.deep.equal(['1', '2']); + }); + + it('should set proper value to checkbox-group when a checkbox is unchecked', () => { + checkboxes[0].checked = true; + checkboxes[1].checked = true; + expect(group.value).to.deep.equal(['1', '2']); + checkboxes[1].checked = false; + expect(group.value).to.deep.equal(['1']); + }); + + it('should check proper checkbox when value is set', () => { + group.value = ['2']; + expect(checkboxes[1].checked).to.be.true; + group.value = ['1', '3']; + expect(checkboxes[0].checked).to.be.true; + expect(checkboxes[2].checked).to.be.true; + }); + + it('should uncheck proper checkbox when value is removed', () => { + group.value = ['1', '3']; + expect(checkboxes[0].checked).to.be.true; + expect(checkboxes[2].checked).to.be.true; + group.value = ['1']; + expect(checkboxes[0].checked).to.be.true; + expect(checkboxes[2].checked).to.be.false; + }); + + it('should set focused attribute on focusin event dispatched', () => { + checkboxes[0].dispatchEvent(new CustomEvent('focusin', { composed: true, bubbles: true })); + expect(group.hasAttribute('focused')).to.be.true; + }); + + it('should not set focused attribute on focusin event dispatched when disabled', () => { + group.disabled = true; + checkboxes[0].dispatchEvent(new CustomEvent('focusin', { composed: true, bubbles: true })); + expect(group.hasAttribute('focused')).to.be.false; + }); + + it('should remove focused attribute on checkbox focusout', () => { + checkboxes[0].dispatchEvent(new CustomEvent('focusin', { composed: true, bubbles: true })); + checkboxes[0].dispatchEvent(new CustomEvent('focusout', { composed: true, bubbles: true })); + expect(group.hasAttribute('focused')).to.be.false; + }); + + it('should remove focused attribute on checkbox-group focusout', () => { + checkboxes[0].dispatchEvent(new CustomEvent('focusin', { composed: true, bubbles: true })); + group.dispatchEvent(new CustomEvent('focusout', { composed: true, bubbles: true })); + expect(group.hasAttribute('focused')).to.be.false; + }); + + it('should NOT steal focus from currently focused element', () => { + const focusInput = document.createElement('input'); + document.body.appendChild(focusInput); + focusInput.focus(); + group.value = '2'; + expect(document.activeElement).to.be.equal(focusInput); + document.body.removeChild(focusInput); + }); + + it('should update has-label attribute when setting label', () => { + expect(group.hasAttribute('has-label')).to.be.false; + group.label = 'foo'; + expect(group.hasAttribute('has-label')).to.be.true; + }); + + it('should not have has-value attribute by default', () => { + expect(group.hasAttribute('has-value')).to.be.false; + }); + + it('should toggle has-value attribute on value change', () => { + group.value = ['2']; + expect(group.hasAttribute('has-value')).to.be.true; + group.value = []; + expect(group.hasAttribute('has-value')).to.be.false; + }); + + it('should add label to checkbox group when a label is dynamically set', () => { + group.label = 'foo'; + expect(group.shadowRoot.querySelector('label').innerText).to.be.equal('foo'); + }); + + it('should be possible to uncheck the checkbox on reattaching of the group', () => { + const container = group.parentElement; + container.removeChild(group); + container.appendChild(group); + group._observer.flush(); + checkboxes[0].checked = true; + checkboxes[0].checked = false; + expect(checkboxes[0].checked).to.be.false; + }); + + it('should not fire change event on programmatic value change', () => { + const spy = sinon.spy(); + group.addEventListener('change', spy); + group.value = ['2']; + expect(spy.called).to.be.false; + }); + + describe('warnings', () => { + beforeEach(() => { + sinon.stub(console, 'warn'); + }); + + afterEach(() => { + console.warn.restore(); + }); + + it('should warn when adding checkbox without value', () => { + const checkbox = document.createElement('vaadin-checkbox'); + group.appendChild(checkbox); + group._observer.flush(); + expect(console.warn.callCount).to.equal(1); + }); + + it('should not warn when adding checkbox with value attribute', () => { + const checkbox = document.createElement('vaadin-checkbox'); + checkbox.setAttribute('value', 'something'); + group.appendChild(checkbox); + group._observer.flush(); + expect(console.warn.callCount).to.equal(0); + }); + + it('should not warn when adding checkbox with value property', () => { + const checkbox = document.createElement('vaadin-checkbox'); + checkbox.value = 'something'; + group.appendChild(checkbox); + group._observer.flush(); + expect(console.warn.callCount).to.equal(0); + }); + }); + + describe('error message', () => { + it('setting errorMessage updates has-error-message attribute', function () { + group.errorMessage = 'foo'; + expect(group.hasAttribute('has-error-message')).to.be.true; + }); + + it('setting errorMessage to empty string does not update has-error-message attribute', function () { + group.errorMessage = ''; + expect(group.hasAttribute('has-error-message')).to.be.false; + }); + + it('setting errorMessage to null does not update has-error-message attribute', function () { + group.errorMessage = null; + expect(group.hasAttribute('has-error-message')).to.be.false; + }); + }); + + describe('helper text', () => { + it('setting helper updates has-helper attribute', function () { + group.helperText = 'foo'; + expect(group.hasAttribute('has-helper')).to.be.true; + }); + + it('setting helper to empty string does not update has-helper attribute', function () { + group.helperText = ''; + expect(group.hasAttribute('has-helper')).to.be.false; + }); + + it('setting helper to null does not update has-helper attribute', function () { + group.helperText = null; + expect(group.hasAttribute('has-helper')).to.be.false; + }); + + it('setting helper with slot updates has-helper attribute', function () { + const helper = document.createElement('div'); + helper.setAttribute('slot', 'helper'); + helper.textContent = 'foo'; + group.appendChild(helper); + group._observer.flush(); + + expect(group.hasAttribute('has-helper')).to.be.true; + }); + }); +}); + +describe('validation', () => { + function blur(target, relatedTarget) { + const event = new CustomEvent('focusout', { bubbles: true, composed: true }); + event.relatedTarget = relatedTarget; + target.dispatchEvent(event); + } + + let group, checkboxes; + + beforeEach(() => { + group = fixtureSync(` + + English + Français + Deutsch + + `); + checkboxes = group.querySelectorAll('vaadin-checkbox'); + group._observer.flush(); + }); + + it('should not have invalid attribute initially', () => { + expect(group.hasAttribute('invalid')).to.be.false; + }); + + it('should not add invalid attribute if required attribute is not present', () => { + checkboxes[0].checked = true; + checkboxes[0].checked = false; + expect(group.hasAttribute('invalid')).to.be.false; + }); + + it('should add invalid attribute if required attribute is present and checkbox group value is empty', () => { + group.required = true; + checkboxes[0].checked = true; + checkboxes[0].checked = false; + expect(group.hasAttribute('invalid')).to.be.true; + }); + + it('should remove invalid attribute if checkbox group value is not empty', () => { + group.required = true; + checkboxes[0].checked = true; + checkboxes[0].checked = false; + expect(group.hasAttribute('invalid')).to.be.true; + + checkboxes[0].checked = true; + expect(group.hasAttribute('invalid')).to.be.false; + }); + + it('should pass validation and set invalid when field is required and user blurs out of the group', () => { + group.required = true; + blur(group, document.body); + expect(group.invalid).to.be.true; + }); + + it('should not run validation while user is tabbing between checkboxes inside of the group', () => { + group.required = true; + const spy = sinon.spy(group, 'validate'); + blur(group, checkboxes[1]); + expect(spy.called).to.be.false; + }); + + it('should not run validation while user is tabbing between checkboxes and focus moves to native checkbox', () => { + group.required = true; + const spy = sinon.spy(group, 'validate'); + blur(group, checkboxes[1].focusElement); + expect(spy.called).to.be.false; + }); + + it('should not show the error message initially', () => { + group.errorMessage = 'Error message'; + expect(group.shadowRoot.querySelector('[part="error-message"]').getAttribute('aria-hidden')).to.be.equal('true'); + }); + + it('should show the error message if validation status is invalid', () => { + group.errorMessage = 'Error message'; + group.invalid = true; + expect(group.shadowRoot.querySelector('[part="error-message"]').getAttribute('aria-hidden')).to.be.equal('false'); + }); +}); + +describe('array mutation methods', () => { + let bind, group, checkboxes; + + beforeEach(() => { + group = fixtureSync(` + + + + + `); + bind = document.querySelector('dom-bind'); + checkboxes = group.querySelectorAll('vaadin-checkbox'); + group._observer.flush(); + }); + + it('should notify the value changes from inside', () => { + expect(bind.value).to.be.instanceOf(Array); + expect(bind.value.length).to.equal(0); + checkboxes[0].checked = true; + expect(bind.value.length).to.equal(1); + expect(bind.value[0]).to.equal('a'); + }); + + it('should update checkboxes when a checkbox value is updated using push', () => { + bind.push('value', 'a'); + expect(checkboxes[0].checked).to.be.true; + }); + + it('should update checkboxes when a checkbox value is updated using pop', () => { + bind.value = ['a', 'b']; + bind.pop('value'); + expect(checkboxes[0].checked).to.be.true; + expect(checkboxes[1].checked).to.be.false; + }); + + it('should update checkboxes when a checkbox value is updated using push', () => { + bind.value = ['b']; + bind.unshift('value', 'a'); + expect(checkboxes[1].checked).to.be.true; + expect(checkboxes[0].checked).to.be.true; + }); + + it('should update checkboxes when a checkbox value is updated using unshift', () => { + bind.value = ['a', 'b']; + bind.shift('value'); + expect(checkboxes[0].checked).to.be.false; + expect(checkboxes[1].checked).to.be.true; + }); + + it('should update checkboxes when a checkbox value is updated using splice', () => { + bind.value = ['a', 'b']; + bind.splice('value', 1, 1, 'c'); + expect(checkboxes[0].checked).to.be.true; + expect(checkboxes[1].checked).to.be.false; + expect(checkboxes[2].checked).to.be.true; + }); +}); + +describe('wrapping', () => { + let group; + + beforeEach(() => { + group = fixtureSync(` + + Checkbox 1 + Checkbox 2 + Checkbox 3 + Checkbox 4 + Checkbox 5 + Checkbox 6 + Checkbox 7 + Checkbox 8 + Checkbox 9 + Checkbox 10 + Checkbox 11 + Checkbox 12 + + `); + group._observer.flush(); + }); + + it('should not overflow horizontally', () => { + const parentWidth = group.parentElement.offsetWidth; + + expect(group.offsetWidth).to.be.lte(parentWidth); + expect(group.shadowRoot.querySelector('[part~="group-field"]').offsetWidth).to.be.lte(parentWidth); + }); + + it('should wrap checkboxes', () => { + const checkboxes = Array.from(group.children); + const { top: firstTop, left: firstLeft } = checkboxes[0].getBoundingClientRect(); + + const wrapped = Array.from(checkboxes) + .slice(1) + .filter((checkbox) => checkbox.getBoundingClientRect().top > firstTop); + + expect(wrapped).to.not.be.empty; + expect(wrapped[0].getBoundingClientRect().left).to.equal(firstLeft); + }); +}); + +describe('helper slot', () => { + let group; + + beforeEach(() => { + group = fixtureSync(` + +
foo
+
+ `); + group._observer.flush(); + }); + + it('should set has-helper attribute when slotted helper is provided', function () { + expect(group.hasAttribute('has-helper')).to.be.true; + }); + + it('should remove has-helper attribute when slotted helper is removed', function () { + const helper = group.querySelector('[slot="helper"]'); + group.removeChild(helper); + group._observer.flush(); + expect(group.hasAttribute('has-helper')).to.be.false; + }); +}); diff --git a/test/checkbox.test.js b/test/checkbox.test.js new file mode 100644 index 0000000..d22352f --- /dev/null +++ b/test/checkbox.test.js @@ -0,0 +1,288 @@ +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { fixtureSync, nextFrame } from '@open-wc/testing-helpers'; +import { downAndUp, keyDownOn, keyUpOn } from '@polymer/iron-test-helpers/mock-interactions.js'; +import '../vaadin-checkbox.js'; + +describe('checkbox', () => { + let checkbox, nativeCheckbox, label; + + const down = (node) => { + node.dispatchEvent(new CustomEvent('down')); + }; + + const up = (node) => { + node.dispatchEvent(new CustomEvent('up')); + }; + + beforeEach(() => { + checkbox = fixtureSync( + 'Vaadin Checkbox with Terms & Conditions' + ); + nativeCheckbox = checkbox._nativeCheckbox; + label = checkbox.shadowRoot.querySelector('[part="label"]'); + }); + + it('should define checkbox label using light DOM', () => { + const slot = label.querySelector('slot'); + const nodes = slot.assignedNodes({ flatten: true }); + expect(nodes[0].textContent).to.be.equal('Vaadin '); + expect(nodes[1].outerHTML).to.be.equal('Checkbox'); + }); + + it('should have input as focusElement', () => { + expect(checkbox.focusElement).to.be.eql(nativeCheckbox); + }); + + it('can be disabled imperatively', () => { + checkbox.disabled = true; + expect(nativeCheckbox.hasAttribute('disabled')).to.be.eql(true); + }); + + it('has default value "on"', () => { + expect(checkbox.value).to.be.eql('on'); + }); + + it('fires click event', (done) => { + checkbox.addEventListener('click', () => { + done(); + }); + downAndUp(checkbox); + }); + + it('should have proper name', () => { + expect(checkbox.name).to.eq(''); + checkbox.checked = true; + expect(checkbox.name).to.eq('test-checkbox'); + }); + + it('should have display: none when hidden', () => { + checkbox.setAttribute('hidden', ''); + expect(getComputedStyle(checkbox).display).to.equal('none'); + }); + + it('should toggle on host click', () => { + checkbox.click(); + + expect(checkbox.checked).to.be.true; + + checkbox.click(); + + expect(checkbox.checked).to.be.false; + }); + + it('should not toggle on link inside host click', () => { + const slot = label.querySelector('slot'); + const link = slot.assignedNodes({ flatten: true })[3]; + expect(link.outerHTML).to.be.equal('Terms & Conditions'); + link.click(); + expect(checkbox.checked).to.be.false; + }); + + it('should not toggle on click when disabled', () => { + checkbox.disabled = true; + label.click(); + expect(checkbox.checked).to.be.false; + }); + + it('should bind checked to the native checkbox and vice versa', () => { + checkbox.checked = true; + expect(nativeCheckbox.checked).to.be.eql(true); + + nativeCheckbox.checked = false; + nativeCheckbox.dispatchEvent(new CustomEvent('change')); + expect(checkbox.checked).to.be.eql(false); + }); + + it('should bind indeterminate to the native checkbox and vice versa', () => { + checkbox.indeterminate = true; + expect(nativeCheckbox.indeterminate).to.be.eql(true); + + nativeCheckbox.indeterminate = false; + nativeCheckbox.dispatchEvent(new CustomEvent('change')); + expect(checkbox.indeterminate).to.be.eql(false); + }); + + it('should set aria-checked to "true" when checked', () => { + checkbox.checked = true; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('true'); + }); + + it('should set aria-checked to "false" when unchecked', () => { + checkbox.checked = false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('false'); + }); + + it('should set aria-checked to "mixed" when indeterminate', () => { + checkbox.indeterminate = true; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('mixed'); + }); + + it('should set indeterminate to false when clicked the first time', () => { + checkbox.indeterminate = true; + + checkbox.click(); + + expect(checkbox.indeterminate).to.be.false; + }); + + it('native checkbox should have the `presentation` role', () => { + expect(checkbox.getAttribute('role')).to.be.eql('checkbox'); + }); + + it('host should have the `checkbox` role', () => { + expect(checkbox.getAttribute('role')).to.be.eql('checkbox'); + }); + + it('should have active attribute on down', () => { + down(checkbox); + + expect(checkbox.hasAttribute('active')).to.be.true; + }); + + it('should not have active attribute after up', () => { + down(checkbox); + + up(checkbox); + + expect(checkbox.hasAttribute('active')).to.be.false; + }); + + it('should have active attribute on space', () => { + keyDownOn(checkbox, 32); + + expect(checkbox.hasAttribute('active')).to.be.true; + }); + + it('should not have active attribute after space', () => { + keyDownOn(checkbox, 32); + + keyUpOn(checkbox, 32); + + expect(checkbox.hasAttribute('active')).to.be.false; + }); + + it('should be checked after space when initially checked is false and indeterminate is true', () => { + checkbox.checked = false; + checkbox.indeterminate = true; + + keyDownOn(checkbox, 32); + keyUpOn(checkbox, 32); + + expect(checkbox.checked).to.be.true; + expect(checkbox.indeterminate).to.be.false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('true'); + }); + + it('should not be checked after space when initially checked is true and indeterminate is true', () => { + checkbox.checked = true; + checkbox.indeterminate = true; + + keyDownOn(checkbox, 32); + keyUpOn(checkbox, 32); + + expect(checkbox.checked).to.be.false; + expect(checkbox.indeterminate).to.be.false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('false'); + }); + + it('should be checked after click when initially checked is false and indeterminate is true', () => { + checkbox.checked = false; + checkbox.indeterminate = true; + + checkbox.click(); + + expect(checkbox.checked).to.be.true; + expect(checkbox.indeterminate).to.be.false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('true'); + }); + + it('should not be checked after click when initially checked is true and indeterminate is true', () => { + checkbox.checked = true; + checkbox.indeterminate = true; + + checkbox.click(); + + expect(checkbox.checked).to.be.false; + expect(checkbox.indeterminate).to.be.false; + expect(checkbox.getAttribute('aria-checked')).to.be.eql('false'); + }); + + it('should set empty attribute on part label when the label was removed', async () => { + while (checkbox.firstChild) { + checkbox.removeChild(checkbox.firstChild); + } + + await nextFrame(); + + expect(label.hasAttribute('empty')).to.be.true; + }); + + describe('change event', () => { + it('should not fire change-event when changing checked value programmatically', () => { + checkbox.addEventListener('change', () => { + throw new Error('Should not come here!'); + }); + checkbox.checked = true; + }); + + it('should fire change-event when user checks the element', (done) => { + checkbox.addEventListener('change', () => done()); + checkbox.click(); + }); + + it('should fire change-event when user unchecks the element', (done) => { + checkbox.checked = true; + checkbox.addEventListener('change', () => done()); + checkbox.click(); + }); + + it('should bubble', () => { + const spy = sinon.spy(); + checkbox.addEventListener('change', spy); + + checkbox.click(); + + const event = spy.getCall(0).args[0]; + expect(event).to.have.property('bubbles', true); + }); + + it('should not be composed', () => { + const spy = sinon.spy(); + checkbox.addEventListener('change', spy); + + checkbox.click(); + + const event = spy.getCall(0).args[0]; + expect(event).to.have.property('composed', false); + }); + }); +}); + +describe('empty label', () => { + let checkbox, label; + + beforeEach(() => { + checkbox = fixtureSync(''); + label = checkbox.shadowRoot.querySelector('[part="label"]'); + }); + + it('should set empty attribute on part label when there is no label', () => { + expect(label.hasAttribute('empty')).to.be.true; + }); + + it('should set empty attribute on part label when there is only one empty text node added', async () => { + const textNode = document.createTextNode(' '); + checkbox.appendChild(textNode); + await nextFrame(); + expect(label.hasAttribute('empty')).to.be.true; + }); + + it('should remove empty attribute from part label when the label is added', async () => { + const paragraph = document.createElement('p'); + paragraph.textContent = 'Added label'; + checkbox.appendChild(paragraph); + await nextFrame(); + expect(label.hasAttribute('empty')).to.be.false; + }); +}); diff --git a/test/index.html b/test/index.html deleted file mode 100644 index dcc9fa2..0000000 --- a/test/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - vaadin-checkbox tests - - - - - - - diff --git a/test/test-suites.js b/test/test-suites.js deleted file mode 100644 index 35a3fdd..0000000 --- a/test/test-suites.js +++ /dev/null @@ -1,5 +0,0 @@ -window.VaadinCheckboxSuites = [ - 'vaadin-checkbox_test.html', - 'vaadin-checkbox-group_test.html', - 'accessibility.html' -]; diff --git a/test/typings/time-picker.types.ts b/test/typings/time-picker.types.ts new file mode 100644 index 0000000..318f4d3 --- /dev/null +++ b/test/typings/time-picker.types.ts @@ -0,0 +1,24 @@ +import '../../src/vaadin-checkbox'; +import '../../src/vaadin-checkbox-group'; + +const checkbox = document.createElement('vaadin-checkbox'); + +const assert = (value: T) => value; + +checkbox.addEventListener('checked-changed', (event) => { + assert(event.detail.value); +}); + +checkbox.addEventListener('indeterminate-changed', (event) => { + assert(event.detail.value); +}); + +const group = document.createElement('vaadin-checkbox-group'); + +group.addEventListener('invalid-changed', (event) => { + assert(event.detail.value); +}); + +group.addEventListener('value-changed', (event) => { + assert(event.detail.value); +}); diff --git a/test/vaadin-checkbox-group_test.html b/test/vaadin-checkbox-group_test.html deleted file mode 100644 index 3b96835..0000000 --- a/test/vaadin-checkbox-group_test.html +++ /dev/null @@ -1,579 +0,0 @@ - - - - - vaadin-checkbox-group tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/vaadin-checkbox_test.html b/test/vaadin-checkbox_test.html deleted file mode 100644 index 456549d..0000000 --- a/test/vaadin-checkbox_test.html +++ /dev/null @@ -1,404 +0,0 @@ - - - - - vaadin-checkbox tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/visual/checkbox.html b/test/visual/checkbox.html new file mode 100644 index 0000000..e796799 --- /dev/null +++ b/test/visual/checkbox.html @@ -0,0 +1,45 @@ + + + + + Checkbox tests + + + + +
+ Default +
+ Checked +
+ Disabled +
+ Disabled checked +
+ Indeterminate checked +
+ Disabled indeterminate +
+ Focused +
+ Empty + + +
+ + + diff --git a/test/visual/default-rtl.html b/test/visual/default-rtl.html deleted file mode 100644 index 4a0645c..0000000 --- a/test/visual/default-rtl.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - -
- Are you drunk? - - - Yes - - - - No - - - - Maybe - - - - - Empty labels -
- -
- - 1 - 2 - -
- -
- - Checkbox 1 - Checkbox 2 - Checkbox 3 - Checkbox 4 - Checkbox 5 - Checkbox 6 - Checkbox 7 - Checkbox 8 - Checkbox 9 - Checkbox 10 - -
- - - - diff --git a/test/visual/default.html b/test/visual/default.html deleted file mode 100644 index 235a3a1..0000000 --- a/test/visual/default.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - -
- Are you drunk? - - - Yes - - - - No - - - - Maybe - - - Empty labels - - -
- -
- - 1 - 2 - -
- -
- - 1 - 2 - -
- -
- - 1 - 2 - -
- -
- - 1 - 2 - -
- -
- - 1 - 2 - -
- -
- - 1 - 2 - -
- -
- - 1 - 2 - -
- -
- - 1 - 2 - -
- -
- - Checkbox 1 - Checkbox 2 - Checkbox 3 - Checkbox 4 - Checkbox 5 - Checkbox 6 - Checkbox 7 - Checkbox 8 - Checkbox 9 - Checkbox 10 - -
- - - - diff --git a/test/visual/group.html b/test/visual/group.html new file mode 100644 index 0000000..0507a8f --- /dev/null +++ b/test/visual/group.html @@ -0,0 +1,30 @@ + + + + + Checkbox group tests + + + + +
+ + 1 + 2 + +
+ + + diff --git a/test/visual/screens/checkbox-group-theme/lumo-checkbox-group-helper-above.png b/test/visual/screens/checkbox-group-theme/lumo-checkbox-group-helper-above.png new file mode 100644 index 0000000..eadef91 Binary files /dev/null and b/test/visual/screens/checkbox-group-theme/lumo-checkbox-group-helper-above.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-default.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-default.png new file mode 100644 index 0000000..7d216e3 Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-default.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-disabled.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-disabled.png new file mode 100644 index 0000000..b9d4893 Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-disabled.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-focused.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-focused.png new file mode 100644 index 0000000..a870c87 Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-focused.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-helper.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-helper.png new file mode 100644 index 0000000..cb064d1 Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-helper.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid-helper.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid-helper.png new file mode 100644 index 0000000..031383d Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid-helper.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid-rtl.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid-rtl.png new file mode 100644 index 0000000..f4f9205 Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid-rtl.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid.png new file mode 100644 index 0000000..ab66803 Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-invalid.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-vertical.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-vertical.png new file mode 100644 index 0000000..e18a2fc Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-vertical.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-wrapping-ltr.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-wrapping-ltr.png new file mode 100644 index 0000000..4199886 Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-wrapping-ltr.png differ diff --git a/test/visual/screens/checkbox-group/lumo-checkbox-group-wrapping-rtl.png b/test/visual/screens/checkbox-group/lumo-checkbox-group-wrapping-rtl.png new file mode 100644 index 0000000..8d711bc Binary files /dev/null and b/test/visual/screens/checkbox-group/lumo-checkbox-group-wrapping-rtl.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-default.png b/test/visual/screens/checkbox-group/material-checkbox-group-default.png new file mode 100644 index 0000000..5879d8b Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-default.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-disabled.png b/test/visual/screens/checkbox-group/material-checkbox-group-disabled.png new file mode 100644 index 0000000..4cfdc81 Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-disabled.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-focused.png b/test/visual/screens/checkbox-group/material-checkbox-group-focused.png new file mode 100644 index 0000000..d11cbe5 Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-focused.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-helper.png b/test/visual/screens/checkbox-group/material-checkbox-group-helper.png new file mode 100644 index 0000000..4ea3eeb Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-helper.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-invalid-helper.png b/test/visual/screens/checkbox-group/material-checkbox-group-invalid-helper.png new file mode 100644 index 0000000..dc23a4c Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-invalid-helper.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-invalid-rtl.png b/test/visual/screens/checkbox-group/material-checkbox-group-invalid-rtl.png new file mode 100644 index 0000000..a3fa67a Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-invalid-rtl.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-invalid.png b/test/visual/screens/checkbox-group/material-checkbox-group-invalid.png new file mode 100644 index 0000000..dc23a4c Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-invalid.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-vertical.png b/test/visual/screens/checkbox-group/material-checkbox-group-vertical.png new file mode 100644 index 0000000..96e9517 Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-vertical.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-wrapping-ltr.png b/test/visual/screens/checkbox-group/material-checkbox-group-wrapping-ltr.png new file mode 100644 index 0000000..0de19bb Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-wrapping-ltr.png differ diff --git a/test/visual/screens/checkbox-group/material-checkbox-group-wrapping-rtl.png b/test/visual/screens/checkbox-group/material-checkbox-group-wrapping-rtl.png new file mode 100644 index 0000000..195e6f7 Binary files /dev/null and b/test/visual/screens/checkbox-group/material-checkbox-group-wrapping-rtl.png differ diff --git a/test/visual/screens/checkbox/lumo-checkbox-ltr.png b/test/visual/screens/checkbox/lumo-checkbox-ltr.png new file mode 100644 index 0000000..dd18858 Binary files /dev/null and b/test/visual/screens/checkbox/lumo-checkbox-ltr.png differ diff --git a/test/visual/screens/checkbox/lumo-checkbox-rtl.png b/test/visual/screens/checkbox/lumo-checkbox-rtl.png new file mode 100644 index 0000000..ee7aa85 Binary files /dev/null and b/test/visual/screens/checkbox/lumo-checkbox-rtl.png differ diff --git a/test/visual/screens/checkbox/material-checkbox-ltr.png b/test/visual/screens/checkbox/material-checkbox-ltr.png new file mode 100644 index 0000000..85759cc Binary files /dev/null and b/test/visual/screens/checkbox/material-checkbox-ltr.png differ diff --git a/test/visual/screens/checkbox/material-checkbox-rtl.png b/test/visual/screens/checkbox/material-checkbox-rtl.png new file mode 100644 index 0000000..130f471 Binary files /dev/null and b/test/visual/screens/checkbox/material-checkbox-rtl.png differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/checked/chrome.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/checked/chrome.png deleted file mode 100644 index 784235c..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/checked/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/checked/firefox.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/checked/firefox.png deleted file mode 100644 index cb5867e..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/checked/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/default/chrome.png deleted file mode 100644 index 7af949a..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/default/firefox.png deleted file mode 100644 index 2ef1dfe..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/checked/chrome.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/checked/chrome.png deleted file mode 100644 index 83dd5be..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/checked/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/checked/firefox.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/checked/firefox.png deleted file mode 100644 index ef2c0ad..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/checked/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/default/chrome.png deleted file mode 100644 index 8c23fba..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/default/firefox.png deleted file mode 100644 index 85bfe81..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-rtl-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-lumo/checked/chrome.png b/test/visual/screens/vaadin-checkbox/default-tests-lumo/checked/chrome.png deleted file mode 100644 index fe09426..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-lumo/checked/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-lumo/checked/firefox.png b/test/visual/screens/vaadin-checkbox/default-tests-lumo/checked/firefox.png deleted file mode 100644 index e438bf4..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-lumo/checked/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/default-tests-lumo/default/chrome.png deleted file mode 100644 index 1ffc39a..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/default-tests-lumo/default/firefox.png deleted file mode 100644 index 225f265..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-lumo/focus-ring/chrome.png b/test/visual/screens/vaadin-checkbox/default-tests-lumo/focus-ring/chrome.png deleted file mode 100644 index 440b5b3..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-lumo/focus-ring/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-lumo/focus-ring/firefox.png b/test/visual/screens/vaadin-checkbox/default-tests-lumo/focus-ring/firefox.png deleted file mode 100644 index b8d4b05..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-lumo/focus-ring/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-material/checked/chrome.png b/test/visual/screens/vaadin-checkbox/default-tests-material/checked/chrome.png deleted file mode 100644 index 52bed2f..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-material/checked/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-material/checked/firefox.png b/test/visual/screens/vaadin-checkbox/default-tests-material/checked/firefox.png deleted file mode 100644 index b545214..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-material/checked/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/default-tests-material/default/chrome.png deleted file mode 100644 index b86e42a..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/default-tests-material/default/firefox.png deleted file mode 100644 index 2cf7169..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-material/focus-ring/chrome.png b/test/visual/screens/vaadin-checkbox/default-tests-material/focus-ring/chrome.png deleted file mode 100644 index c4cd1e8..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-material/focus-ring/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/default-tests-material/focus-ring/firefox.png b/test/visual/screens/vaadin-checkbox/default-tests-material/focus-ring/firefox.png deleted file mode 100644 index 1ccd8a3..0000000 Binary files a/test/visual/screens/vaadin-checkbox/default-tests-material/focus-ring/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/disabled-group-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/disabled-group-tests-lumo/default/chrome.png deleted file mode 100644 index 8ddd014..0000000 Binary files a/test/visual/screens/vaadin-checkbox/disabled-group-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/disabled-group-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/disabled-group-tests-lumo/default/firefox.png deleted file mode 100644 index c59c2f9..0000000 Binary files a/test/visual/screens/vaadin-checkbox/disabled-group-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/disabled-group-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/disabled-group-tests-material/default/chrome.png deleted file mode 100644 index 3549b31..0000000 Binary files a/test/visual/screens/vaadin-checkbox/disabled-group-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/disabled-group-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/disabled-group-tests-material/default/firefox.png deleted file mode 100644 index f248447..0000000 Binary files a/test/visual/screens/vaadin-checkbox/disabled-group-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/focus-tests-lumo/focus/chrome.png b/test/visual/screens/vaadin-checkbox/focus-tests-lumo/focus/chrome.png deleted file mode 100644 index a5ab492..0000000 Binary files a/test/visual/screens/vaadin-checkbox/focus-tests-lumo/focus/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/focus-tests-lumo/focus/firefox.png b/test/visual/screens/vaadin-checkbox/focus-tests-lumo/focus/firefox.png deleted file mode 100644 index 2a6036c..0000000 Binary files a/test/visual/screens/vaadin-checkbox/focus-tests-lumo/focus/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/focus-tests-material/focus/chrome.png b/test/visual/screens/vaadin-checkbox/focus-tests-material/focus/chrome.png deleted file mode 100644 index dc1e629..0000000 Binary files a/test/visual/screens/vaadin-checkbox/focus-tests-material/focus/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/focus-tests-material/focus/firefox.png b/test/visual/screens/vaadin-checkbox/focus-tests-material/focus/firefox.png deleted file mode 100644 index 81ee5e9..0000000 Binary files a/test/visual/screens/vaadin-checkbox/focus-tests-material/focus/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/group-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/group-tests-lumo/default/chrome.png deleted file mode 100644 index 6862bce..0000000 Binary files a/test/visual/screens/vaadin-checkbox/group-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/group-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/group-tests-lumo/default/firefox.png deleted file mode 100644 index 11b7573..0000000 Binary files a/test/visual/screens/vaadin-checkbox/group-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/group-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/group-tests-material/default/chrome.png deleted file mode 100644 index 9a2b24c..0000000 Binary files a/test/visual/screens/vaadin-checkbox/group-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/group-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/group-tests-material/default/firefox.png deleted file mode 100644 index a1801ed..0000000 Binary files a/test/visual/screens/vaadin-checkbox/group-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/helper-text-above-field-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/helper-text-above-field-tests-lumo/default/chrome.png deleted file mode 100644 index 1dc536a..0000000 Binary files a/test/visual/screens/vaadin-checkbox/helper-text-above-field-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/helper-text-above-field-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/helper-text-above-field-tests-lumo/default/firefox.png deleted file mode 100644 index 08113f8..0000000 Binary files a/test/visual/screens/vaadin-checkbox/helper-text-above-field-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/helper-text-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/helper-text-tests-lumo/default/chrome.png deleted file mode 100644 index bbde5b3..0000000 Binary files a/test/visual/screens/vaadin-checkbox/helper-text-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/helper-text-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/helper-text-tests-lumo/default/firefox.png deleted file mode 100644 index aacd800..0000000 Binary files a/test/visual/screens/vaadin-checkbox/helper-text-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/helper-text-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/helper-text-tests-material/default/chrome.png deleted file mode 100644 index af6bbb5..0000000 Binary files a/test/visual/screens/vaadin-checkbox/helper-text-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/helper-text-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/helper-text-tests-material/default/firefox.png deleted file mode 100644 index eb9956a..0000000 Binary files a/test/visual/screens/vaadin-checkbox/helper-text-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-lumo/default/chrome.png deleted file mode 100644 index ca20f2e..0000000 Binary files a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-lumo/default/firefox.png deleted file mode 100644 index 9ce7585..0000000 Binary files a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-material/default/chrome.png deleted file mode 100644 index a6e5bcc..0000000 Binary files a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-material/default/firefox.png deleted file mode 100644 index a99ae47..0000000 Binary files a/test/visual/screens/vaadin-checkbox/theme-vertical-group-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-lumo/error/chrome.png b/test/visual/screens/vaadin-checkbox/validation-rtl-tests-lumo/error/chrome.png deleted file mode 100644 index 674d337..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-lumo/error/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-lumo/error/firefox.png b/test/visual/screens/vaadin-checkbox/validation-rtl-tests-lumo/error/firefox.png deleted file mode 100644 index d828603..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-lumo/error/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-material/error/chrome.png b/test/visual/screens/vaadin-checkbox/validation-rtl-tests-material/error/chrome.png deleted file mode 100644 index 6d80777..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-material/error/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-material/error/firefox.png b/test/visual/screens/vaadin-checkbox/validation-rtl-tests-material/error/firefox.png deleted file mode 100644 index 8068188..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-rtl-tests-material/error/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-tests-lumo/error/chrome.png b/test/visual/screens/vaadin-checkbox/validation-tests-lumo/error/chrome.png deleted file mode 100644 index 38c32b5..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-tests-lumo/error/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-tests-lumo/error/firefox.png b/test/visual/screens/vaadin-checkbox/validation-tests-lumo/error/firefox.png deleted file mode 100644 index 03fef44..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-tests-lumo/error/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-tests-material/error/chrome.png b/test/visual/screens/vaadin-checkbox/validation-tests-material/error/chrome.png deleted file mode 100644 index 813f788..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-tests-material/error/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-tests-material/error/firefox.png b/test/visual/screens/vaadin-checkbox/validation-tests-material/error/firefox.png deleted file mode 100644 index 35090b2..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-tests-material/error/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-with-helper-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/validation-with-helper-tests-material/default/chrome.png deleted file mode 100644 index 813f788..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-with-helper-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/validation-with-helper-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/validation-with-helper-tests-material/default/firefox.png deleted file mode 100644 index 35090b2..0000000 Binary files a/test/visual/screens/vaadin-checkbox/validation-with-helper-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/wrapping-group-tests-lumo/default/chrome.png deleted file mode 100644 index c8e7590..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/wrapping-group-tests-lumo/default/firefox.png deleted file mode 100644 index dfc85ad..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/wrapping-group-tests-material/default/chrome.png deleted file mode 100644 index dfdc254..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/wrapping-group-tests-material/default/firefox.png deleted file mode 100644 index e2a54f1..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-group-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-lumo/default/chrome.png b/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-lumo/default/chrome.png deleted file mode 100644 index 248f325..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-lumo/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-lumo/default/firefox.png b/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-lumo/default/firefox.png deleted file mode 100644 index 602a403..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-lumo/default/firefox.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-material/default/chrome.png b/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-material/default/chrome.png deleted file mode 100644 index 0c60351..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-material/default/chrome.png and /dev/null differ diff --git a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-material/default/firefox.png b/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-material/default/firefox.png deleted file mode 100644 index 6b084b3..0000000 Binary files a/test/visual/screens/vaadin-checkbox/wrapping-rtl-tests-material/default/firefox.png and /dev/null differ diff --git a/test/visual/test.js b/test/visual/test.js index 9b1b52d..d494e12 100644 --- a/test/visual/test.js +++ b/test/visual/test.js @@ -1,129 +1,85 @@ -gemini.suite('vaadin-checkbox', function(rootSuite) { - function wait(actions, find) { - actions.wait(5000); - } +describe('vaadin-checkbox', () => { + const locator = '#tests[data-ready]'; + + ['lumo', 'material'].forEach((theme) => { + ['ltr', 'rtl'].forEach((dir) => { + it(`checkbox-${theme}-${dir}`, function () { + return this.browser + .url(`checkbox.html?theme=${theme}&dir=${dir}`) + .waitForVisible(locator, 10000) + .assertView(`${theme}-checkbox-${dir}`, locator); + }); - function goToAboutBlank(actions, find) { - // Firefox stops responding on socket after a test, workaround: - return actions.executeJS(function(window) { - window.location.href = 'about:blank'; // just go away, please! + it(`checkbox-group-${theme}-${dir}`, function () { + return this.browser + .url(`wrapping.html?theme=${theme}&dir=${dir}`) + .waitForVisible(locator, 10000) + .assertView(`${theme}-checkbox-group-wrapping-${dir}`, locator); + }); }); - } - - rootSuite - .before(wait) - .after(goToAboutBlank); - ['lumo', 'material'].forEach(theme => { - gemini.suite(`default-tests-${theme}`, function(suite) { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#default-tests') - .capture('default') - .capture('focus-ring', function(actions) { - actions.executeJS(function(window) { - window.document.querySelector('vaadin-checkbox').setAttribute('focus-ring', ''); - }); + it(`checkbox-group-${theme}`, function () { + return this.browser + .url(`group.html?theme=${theme}`) + .waitForVisible(locator, 10000) + .assertView(`${theme}-checkbox-group-default`, locator) + .execute(() => { + const group = window.document.querySelector('vaadin-checkbox-group'); + group.setAttribute('theme', 'vertical'); }) - .capture('checked', function(actions) { - actions.executeJS(function(window) { - window.document.querySelector('vaadin-checkbox').checked = true; - }); - }); - }); - - gemini.suite(`group-tests-${theme}`, (suite) => { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#group-tests') - .capture('default'); - }); - - gemini.suite(`theme-vertical-group-tests-${theme}`, (suite) => { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#theme-vertical-group-tests') - .capture('default'); - }); - - gemini.suite(`disabled-group-tests-${theme}`, (suite) => { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#disabled-group-tests') - .capture('default'); - }); - - gemini.suite(`validation-tests-${theme}`, function(suite) { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#validation-tests') - .capture('error'); - }); - - gemini.suite(`focus-tests-${theme}`, function(suite) { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#focus-tests') - .capture('focus'); - }); - - gemini.suite(`wrapping-group-tests-${theme}`, function(suite) { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#wrapping-group-tests') - .capture('default'); - }); - - gemini.suite(`helper-text-tests-${theme}`, function(suite) { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#helper-text-tests') - .capture('default'); + .assertView(`${theme}-checkbox-group-vertical`, locator) + .execute(() => { + const group = window.document.querySelector('vaadin-checkbox-group'); + group.removeAttribute('theme'); + group.disabled = true; + }) + .assertView(`${theme}-checkbox-group-disabled`, locator) + .execute(() => { + const group = window.document.querySelector('vaadin-checkbox-group'); + group.disabled = false; + group.setAttribute('focused', ''); + group.firstElementChild.setAttribute('focus-ring', ''); + }) + .assertView(`${theme}-checkbox-group-focused`, locator) + .execute(() => { + const group = window.document.querySelector('vaadin-checkbox-group'); + group.removeAttribute('focused'); + group.firstElementChild.removeAttribute('focus-ring'); + group.helperText = 'Helper text'; + }) + .assertView(`${theme}-checkbox-group-helper`, locator) + .execute(() => { + const group = window.document.querySelector('vaadin-checkbox-group'); + group.helperText = null; + group.required = true; + group.errorMessage = 'Please choose a number'; + group.validate(); + }) + .assertView(`${theme}-checkbox-group-invalid`, locator) + .execute(() => { + window.document.documentElement.setAttribute('dir', 'rtl'); + }) + .assertView(`${theme}-checkbox-group-invalid-rtl`, locator) + .execute(() => { + window.document.documentElement.removeAttribute('dir'); + const group = window.document.querySelector('vaadin-checkbox-group'); + group.helperText = 'Helper text'; + }) + .assertView(`${theme}-checkbox-group-invalid-helper`, locator); }); if (theme === 'lumo') { - gemini.suite(`helper-text-above-field-tests-${theme}`, function(suite) { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#helper-text-above-field-tests') - .capture('default'); - }); - } - - if (theme === 'material') { - gemini.suite(`validation-with-helper-tests-${theme}`, function(suite) { - suite - .setUrl(`default.html?theme=${theme}`) - .setCaptureElements('#validation-with-helper-tests') - .capture('default'); + it(`checkbox-group-theme-${theme}`, function () { + return this.browser + .url(`group.html?theme=${theme}`) + .waitForVisible(locator, 10000) + .execute(() => { + const group = window.document.querySelector('vaadin-checkbox-group'); + group.helperText = 'Helper text'; + group.setAttribute('theme', 'helper-above-field'); + }) + .assertView(`${theme}-checkbox-group-helper-above`, locator); }); } - - gemini.suite(`default-rtl-tests-${theme}`, function(suite) { - suite - .setUrl(`default-rtl.html?theme=${theme}`) - .setCaptureElements('#default-tests') - .capture('default') - .capture('checked', function(actions) { - actions.executeJS(function(window) { - window.document.querySelector('vaadin-checkbox').checked = true; - }); - }); - }); - - gemini.suite(`validation-rtl-tests-${theme}`, function(suite) { - suite - .setUrl(`default-rtl.html?theme=${theme}`) - .setCaptureElements('#validation-tests') - .capture('error'); - }); - - gemini.suite(`wrapping-rtl-tests-${theme}`, function(suite) { - suite - .setUrl(`default-rtl.html?theme=${theme}`) - .setCaptureElements('#wrapping-group-tests') - .capture('default'); - }); }); - }); diff --git a/test/visual/wrapping.html b/test/visual/wrapping.html new file mode 100644 index 0000000..84236d6 --- /dev/null +++ b/test/visual/wrapping.html @@ -0,0 +1,40 @@ + + + + + Checkbox group tests + + + + +
+ + Checkbox 1 + Checkbox 2 + Checkbox 3 + Checkbox 4 + Checkbox 5 + Checkbox 6 + Checkbox 7 + Checkbox 8 + Checkbox 9 + Checkbox 10 + +
+ + + diff --git a/theme/lumo/vaadin-checkbox-group-styles.html b/theme/lumo/vaadin-checkbox-group-styles.html deleted file mode 100644 index 7222654..0000000 --- a/theme/lumo/vaadin-checkbox-group-styles.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - diff --git a/theme/lumo/vaadin-checkbox-group-styles.js b/theme/lumo/vaadin-checkbox-group-styles.js new file mode 100644 index 0000000..5c78007 --- /dev/null +++ b/theme/lumo/vaadin-checkbox-group-styles.js @@ -0,0 +1,101 @@ +import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; +import '@vaadin/vaadin-lumo-styles/color.js'; +import '@vaadin/vaadin-lumo-styles/mixins/required-field.js'; + +registerStyles( + 'vaadin-checkbox-group', + css` + :host { + color: var(--lumo-body-text-color); + font-size: var(--lumo-font-size-m); + font-family: var(--lumo-font-family); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-tap-highlight-color: transparent; + padding: var(--lumo-space-xs) 0; + } + + :host::before { + height: var(--lumo-size-m); + box-sizing: border-box; + display: inline-flex; + align-items: center; + } + + :host([theme~='vertical']) [part='group-field'] { + display: flex; + flex-direction: column; + } + + [part='label'] { + padding-bottom: 0.7em; + } + + :host([disabled]) [part='label'] { + color: var(--lumo-disabled-text-color); + -webkit-text-fill-color: var(--lumo-disabled-text-color); + } + + :host([focused]:not([disabled])) [part='label'] { + color: var(--lumo-primary-text-color); + } + + :host(:hover:not([disabled]):not([focused])) [part='label'], + :host(:hover:not([disabled]):not([focused])) [part='helper-text'], + :host(:hover:not([disabled]):not([focused])) [part='helper-text'] ::slotted(*) { + color: var(--lumo-body-text-color); + } + + :host([has-helper]) [part='helper-text']::before { + content: ''; + display: block; + height: 0.4em; + } + + [part='helper-text'], + [part='helper-text'] ::slotted(*) { + display: block; + color: var(--lumo-secondary-text-color); + font-size: var(--lumo-font-size-xs); + line-height: var(--lumo-line-height-xs); + margin-left: calc(var(--lumo-border-radius-m) / 4); + transition: color 0.2s; + } + + /* helper-text position */ + :host([has-helper][theme~='helper-above-field']) [part='helper-text']::before { + display: none; + } + + :host([has-helper][theme~='helper-above-field']) [part='helper-text']::after { + content: ''; + display: block; + height: 0.4em; + } + + :host([has-helper][theme~='helper-above-field']) [part='label'] { + order: 0; + padding-bottom: 0.4em; + } + + :host([has-helper][theme~='helper-above-field']) [part='helper-text'] { + order: 1; + } + + :host([has-helper][theme~='helper-above-field']) [part='group-field'] { + order: 2; + } + + :host([has-helper][theme~='helper-above-field']) [part='error-message'] { + order: 3; + } + + /* Touch device adjustment */ + @media (pointer: coarse) { + :host(:hover:not([disabled]):not([focused])) [part='label'] { + color: var(--lumo-secondary-text-color); + } + } + `, + { moduleId: 'lumo-checkbox-group', include: ['lumo-required-field'] } +); diff --git a/theme/lumo/vaadin-checkbox-group.html b/theme/lumo/vaadin-checkbox-group.html deleted file mode 100644 index 17c9632..0000000 --- a/theme/lumo/vaadin-checkbox-group.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/theme/lumo/vaadin-checkbox-group.js b/theme/lumo/vaadin-checkbox-group.js new file mode 100644 index 0000000..de6fb3a --- /dev/null +++ b/theme/lumo/vaadin-checkbox-group.js @@ -0,0 +1,3 @@ +import './vaadin-checkbox-styles.js'; +import './vaadin-checkbox-group-styles.js'; +import '../../src/vaadin-checkbox-group.js'; diff --git a/theme/lumo/vaadin-checkbox-styles.html b/theme/lumo/vaadin-checkbox-styles.html deleted file mode 100644 index a504c74..0000000 --- a/theme/lumo/vaadin-checkbox-styles.html +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/theme/lumo/vaadin-checkbox-styles.js b/theme/lumo/vaadin-checkbox-styles.js new file mode 100644 index 0000000..aeb612b --- /dev/null +++ b/theme/lumo/vaadin-checkbox-styles.js @@ -0,0 +1,159 @@ +import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; +import '@vaadin/vaadin-lumo-styles/color.js'; +import '@vaadin/vaadin-lumo-styles/style.js'; + +registerStyles( + 'vaadin-checkbox', + css` + :host { + -webkit-tap-highlight-color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + cursor: default; + outline: none; + } + + [part='label']:not([empty]) { + margin: 0.1875em 0.875em 0.1875em 0.375em; + } + + [part='checkbox'] { + width: calc(1em + 2px); + height: calc(1em + 2px); + margin: 0.1875em; + position: relative; + border-radius: var(--lumo-border-radius-s); + background-color: var(--lumo-contrast-20pct); + transition: transform 0.2s cubic-bezier(0.12, 0.32, 0.54, 2), background-color 0.15s; + pointer-events: none; + line-height: 1.2; + } + + :host([indeterminate]) [part='checkbox'], + :host([checked]) [part='checkbox'] { + background-color: var(--lumo-primary-color); + } + + /* Needed to align the checkbox nicely on the baseline */ + [part='checkbox']::before { + content: '\\2003'; + } + + /* Checkmark */ + [part='checkbox']::after { + content: ''; + display: inline-block; + width: 0; + height: 0; + border: 0 solid var(--lumo-primary-contrast-color); + border-width: 0.1875em 0 0 0.1875em; + box-sizing: border-box; + transform-origin: 0 0; + position: absolute; + top: 0.8125em; + left: 0.5em; + transform: scale(0.55) rotate(-135deg); + opacity: 0; + } + + :host([checked]) [part='checkbox']::after { + opacity: 1; + width: 0.625em; + height: 1.0625em; + } + + /* Indeterminate checkmark */ + :host([indeterminate]) [part='checkbox']::after { + transform: none; + opacity: 1; + top: 45%; + height: 10%; + left: 22%; + right: 22%; + width: auto; + border: 0; + background-color: var(--lumo-primary-contrast-color); + transition: opacity 0.25s; + } + + /* Focus ring */ + :host([focus-ring]) [part='checkbox'] { + box-shadow: 0 0 0 3px var(--lumo-primary-color-50pct); + } + + /* Disabled */ + :host([disabled]) { + pointer-events: none; + color: var(--lumo-disabled-text-color); + } + + :host([disabled]) [part='label'] ::slotted(*) { + color: inherit; + } + + :host([disabled]) [part='checkbox'] { + background-color: var(--lumo-contrast-10pct); + } + + :host([disabled]) [part='checkbox']::after { + border-color: var(--lumo-contrast-30pct); + } + + :host([indeterminate][disabled]) [part='checkbox']::after { + background-color: var(--lumo-contrast-30pct); + } + + /* RTL specific styles */ + :host([dir='rtl']) [part='label']:not([empty]) { + margin: 0.1875em 0.375em 0.1875em 0.875em; + } + + /* Transition the checkmark if activated with the mouse (disabled for grid select-all this way) */ + :host(:hover) [part='checkbox']::after { + transition: width 0.1s, height 0.25s; + } + + /* Used for activation "halo" */ + [part='checkbox']::before { + color: transparent; + display: inline-block; + width: 100%; + height: 100%; + border-radius: inherit; + background-color: inherit; + transform: scale(1.4); + opacity: 0; + transition: transform 0.1s, opacity 0.8s; + } + + /* Hover */ + :host(:not([checked]):not([indeterminate]):not([disabled]):hover) [part='checkbox'] { + background-color: var(--lumo-contrast-30pct); + } + + /* Disable hover for touch devices */ + @media (pointer: coarse) { + :host(:not([checked]):not([indeterminate]):not([disabled]):hover) [part='checkbox'] { + background-color: var(--lumo-contrast-20pct); + } + } + + /* Active */ + :host([active]) [part='checkbox'] { + transform: scale(0.9); + transition-duration: 0.05s; + } + + :host([active][checked]) [part='checkbox'] { + transform: scale(1.1); + } + + :host([active]:not([checked])) [part='checkbox']::before { + transition-duration: 0.01s, 0.01s; + transform: scale(0); + opacity: 0.4; + } + `, + { moduleId: 'lumo-checkbox' } +); diff --git a/theme/lumo/vaadin-checkbox.html b/theme/lumo/vaadin-checkbox.html deleted file mode 100644 index e6f67b9..0000000 --- a/theme/lumo/vaadin-checkbox.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/theme/lumo/vaadin-checkbox.js b/theme/lumo/vaadin-checkbox.js new file mode 100644 index 0000000..feb6434 --- /dev/null +++ b/theme/lumo/vaadin-checkbox.js @@ -0,0 +1,2 @@ +import './vaadin-checkbox-styles.js'; +import '../../src/vaadin-checkbox.js'; diff --git a/theme/material/vaadin-checkbox-group-styles.html b/theme/material/vaadin-checkbox-group-styles.html deleted file mode 100644 index 56627b8..0000000 --- a/theme/material/vaadin-checkbox-group-styles.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - diff --git a/theme/material/vaadin-checkbox-group-styles.js b/theme/material/vaadin-checkbox-group-styles.js new file mode 100644 index 0000000..dd24fe0 --- /dev/null +++ b/theme/material/vaadin-checkbox-group-styles.js @@ -0,0 +1,72 @@ +import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; +import '@vaadin/vaadin-material-styles/color.js'; +import '@vaadin/vaadin-material-styles/mixins/required-field.js'; + +registerStyles( + 'vaadin-checkbox-group', + css` + :host { + display: inline-flex; + position: relative; + padding-top: 8px; + margin-bottom: 8px; + outline: none; + color: var(--material-body-text-color); + font-size: var(--material-body-font-size); + line-height: 24px; + font-family: var(--material-font-family); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + :host::before { + line-height: 32px; + } + + :host([has-label]) { + padding-top: 24px; + } + + [part='label']:empty { + display: none; + } + + [part='label']:empty::before { + content: '\\00a0'; + position: absolute; + } + + :host([theme~='vertical']) [part='group-field'] { + display: flex; + flex-direction: column; + } + + :host([disabled]) [part='label'] { + color: var(--material-disabled-text-color); + -webkit-text-fill-color: var(--material-disabled-text-color); + } + + :host([focused]:not([invalid])) [part='label'] { + color: var(--material-primary-text-color); + } + + /* According to material theme guidelines, helper text should be hidden when error message is set and input is invalid */ + :host([has-helper][invalid][has-error-message]) [part='helper-text'] { + display: none; + } + + :host([has-helper]) [part='helper-text']::before { + content: ''; + display: block; + height: 6px; + } + + [part='helper-text'], + [part='helper-text'] ::slotted(*) { + font-size: 0.75rem; + line-height: 1; + color: var(--material-secondary-text-color); + } + `, + { moduleId: 'material-checkbox-group', include: ['material-required-field'] } +); diff --git a/theme/material/vaadin-checkbox-group.html b/theme/material/vaadin-checkbox-group.html deleted file mode 100644 index 01f114a..0000000 --- a/theme/material/vaadin-checkbox-group.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/theme/material/vaadin-checkbox-group.js b/theme/material/vaadin-checkbox-group.js new file mode 100644 index 0000000..de6fb3a --- /dev/null +++ b/theme/material/vaadin-checkbox-group.js @@ -0,0 +1,3 @@ +import './vaadin-checkbox-styles.js'; +import './vaadin-checkbox-group-styles.js'; +import '../../src/vaadin-checkbox-group.js'; diff --git a/theme/material/vaadin-checkbox-styles.html b/theme/material/vaadin-checkbox-styles.html deleted file mode 100644 index de31195..0000000 --- a/theme/material/vaadin-checkbox-styles.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - diff --git a/theme/material/vaadin-checkbox-styles.js b/theme/material/vaadin-checkbox-styles.js new file mode 100644 index 0000000..26acb94 --- /dev/null +++ b/theme/material/vaadin-checkbox-styles.js @@ -0,0 +1,135 @@ +import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; +import '@vaadin/vaadin-material-styles/color.js'; + +registerStyles( + 'vaadin-checkbox', + css` + :host { + display: inline-block; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + outline: none; + -webkit-tap-highlight-color: transparent; + } + + [part='label']:not([empty]) { + margin: 3px 12px 3px 6px; + } + + [part='native-checkbox'] { + opacity: 0; + position: absolute; + } + + [part='checkbox'] { + display: inline-block; + width: 16px; + height: 16px; + flex: none; + margin: 4px; + position: relative; + border-radius: 2px; + box-shadow: inset 0 0 0 2px var(--material-secondary-text-color); + pointer-events: none; + line-height: 1.275; + background-color: transparent; + } + + /* Used for the ripple */ + [part='checkbox']::before { + /* Needed to align the checkbox nicely on the baseline */ + content: '\\2003'; + display: inline-block; + width: 100%; + height: 100%; + border-radius: 50%; + background-color: var(--material-disabled-text-color); + transform: scale(0); + opacity: 0; + transition: transform 0s 0.8s, opacity 0.8s; + will-change: transform, opacity; + } + + /* Used for the checkmark */ + [part='checkbox']::after { + content: ''; + display: inline-block; + width: 10px; + height: 19px; + border: 0 solid var(--material-background-color); + border-width: 3px 0 0 3px; + box-sizing: border-box; + transform-origin: 0 0; + position: absolute; + top: 12px; + left: 6px; + transform: scale(0) rotate(-135deg); + transition: transform 0.2s; + } + + :host([indeterminate]) [part='checkbox'], + :host([checked]) [part='checkbox'] { + background-color: var(--material-primary-color); + box-shadow: none; + } + + :host([checked]) [part='checkbox']::after { + transform: scale(0.55) rotate(-135deg); + } + + :host(:not([checked]):not([indeterminate]):not([disabled]):hover) [part='checkbox'] { + background-color: transparent; + } + + :host([focus-ring]) [part='checkbox']::before, + :host([active]) [part='checkbox']::before { + transition-duration: 0.08s, 0.01s; + transition-delay: 0s, 0s; + transform: scale(2.5); + opacity: 0.15; + } + + :host([checked]) [part='checkbox']::before { + background-color: var(--material-primary-color); + } + + :host([indeterminate]) [part='checkbox']::after { + transform: none; + opacity: 1; + top: 45%; + height: 10%; + left: 22%; + right: 22%; + width: auto; + border: 0; + background-color: var(--material-background-color); + transition: opacity 0.4s; + } + + :host([disabled]) { + pointer-events: none; + color: var(--material-disabled-text-color); + } + + :host([disabled]) ::slotted(*) { + color: inherit; + } + + :host([disabled]:not([checked]):not([indeterminate])) [part='checkbox'] { + box-shadow: inset 0 0 0 2px var(--material-disabled-color); + } + + :host([disabled][checked]) [part='checkbox'], + :host([disabled][indeterminate]) [part='checkbox'] { + background-color: var(--material-disabled-color); + } + + /* RTL specific styles */ + :host([dir='rtl']) [part='label']:not([empty]) { + margin: 3px 6px 3px 12px; + } + `, + { moduleId: 'material-checkbox' } +); diff --git a/theme/material/vaadin-checkbox.html b/theme/material/vaadin-checkbox.html deleted file mode 100644 index e6f67b9..0000000 --- a/theme/material/vaadin-checkbox.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/theme/material/vaadin-checkbox.js b/theme/material/vaadin-checkbox.js new file mode 100644 index 0000000..feb6434 --- /dev/null +++ b/theme/material/vaadin-checkbox.js @@ -0,0 +1,2 @@ +import './vaadin-checkbox-styles.js'; +import '../../src/vaadin-checkbox.js'; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..54289ba --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "lib": [ "esnext", "es2018", "dom" ], + "noEmit": true, + "strict": true + }, + "include": [ + "test/typings" + ] +} diff --git a/vaadin-checkbox-group.d.ts b/vaadin-checkbox-group.d.ts new file mode 100644 index 0000000..5658a6c --- /dev/null +++ b/vaadin-checkbox-group.d.ts @@ -0,0 +1 @@ +export * from './src/vaadin-checkbox-group.js'; diff --git a/vaadin-checkbox-group.html b/vaadin-checkbox-group.html deleted file mode 100644 index 0678bb7..0000000 --- a/vaadin-checkbox-group.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/vaadin-checkbox-group.js b/vaadin-checkbox-group.js new file mode 100644 index 0000000..5310485 --- /dev/null +++ b/vaadin-checkbox-group.js @@ -0,0 +1,2 @@ +import './theme/lumo/vaadin-checkbox-group.js'; +export * from './src/vaadin-checkbox-group.js'; diff --git a/vaadin-checkbox.d.ts b/vaadin-checkbox.d.ts new file mode 100644 index 0000000..9fe35d7 --- /dev/null +++ b/vaadin-checkbox.d.ts @@ -0,0 +1 @@ +export * from './src/vaadin-checkbox.js'; diff --git a/vaadin-checkbox.html b/vaadin-checkbox.html deleted file mode 100644 index 0aa306c..0000000 --- a/vaadin-checkbox.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/vaadin-checkbox.js b/vaadin-checkbox.js new file mode 100644 index 0000000..62c789e --- /dev/null +++ b/vaadin-checkbox.js @@ -0,0 +1,2 @@ +import './theme/lumo/vaadin-checkbox.js'; +export * from './src/vaadin-checkbox.js'; diff --git a/wct.conf.js b/wct.conf.js deleted file mode 100644 index 713f333..0000000 --- a/wct.conf.js +++ /dev/null @@ -1,68 +0,0 @@ -var envIndex = process.argv.indexOf('--env') + 1; -var env = envIndex ? process.argv[envIndex] : undefined; - -module.exports = { - testTimeout: 180 * 1000, - verbose: false, - plugins: { - local: { - browserOptions: { - chrome: [ - 'headless', - 'disable-gpu', - 'no-sandbox' - ] - } - }, - // MAGI REMOVE START - istanbul: { - dir: './coverage', - reporters: ['text-summary', 'lcov'], - include: [ - '**/vaadin-checkbox/src/*.html' - ], - exclude: [], - thresholds: { - global: { - statements: 99 - } - } - } - // MAGI REMOVE END - }, - - registerHooks: function(context) { - const saucelabsPlatformsMobile = [ - 'iOS Simulator/iphone@12.2', - 'iOS Simulator/iphone@10.3' - ]; - - const saucelabsPlatformsMicrosoft = [ - 'Windows 10/microsoftedge@18', - 'Windows 10/internet explorer@11' - ]; - - const saucelabsPlatformsDesktop = [ - 'macOS 10.13/safari@latest' - ]; - - const saucelabsPlatforms = [ - ...saucelabsPlatformsMobile, - ...saucelabsPlatformsMicrosoft, - ...saucelabsPlatformsDesktop - ]; - - const cronPlatforms = [ - 'iOS Simulator/ipad@12.2', - 'iOS Simulator/iphone@10.3', - 'Windows 10/chrome@latest', - 'Windows 10/firefox@latest' - ]; - - if (env === 'saucelabs') { - context.options.plugins.sauce.browsers = saucelabsPlatforms; - } else if (env === 'saucelabs-cron') { - context.options.plugins.sauce.browsers = cronPlatforms; - } - } -}; diff --git a/web-test-runner.config.js b/web-test-runner.config.js new file mode 100644 index 0000000..5e2330b --- /dev/null +++ b/web-test-runner.config.js @@ -0,0 +1,48 @@ +/* eslint-env node */ +const { createSauceLabsLauncher } = require('@web/test-runner-saucelabs'); + +const config = { + nodeResolve: true, + testsFinishTimeout: 60000, + coverageConfig: { + include: ['**/src/*'], + threshold: { + statements: 99, + branches: 86, + functions: 100, + lines: 99 + } + } +}; + +if (process.env.TEST_ENV === 'sauce') { + const sauceLabsLauncher = createSauceLabsLauncher({ + user: process.env.SAUCE_USERNAME, + key: process.env.SAUCE_ACCESS_KEY + }); + + const sharedCapabilities = { + 'sauce:options': { + name: 'vaadin-checkbox unit tests', + build: `${process.env.GITHUB_REF || 'local'} build ${process.env.GITHUB_RUN_NUMBER || ''}` + } + }; + + config.concurrency = 2; + config.browsers = [ + sauceLabsLauncher({ + ...sharedCapabilities, + browserName: 'firefox', + platform: 'Windows 10', + browserVersion: 'latest' + }), + sauceLabsLauncher({ + ...sharedCapabilities, + browserName: 'safari', + platform: 'macOS 10.15', + browserVersion: '13.1' + }) + ]; +} + +module.exports = config;