diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7536857a..f409fdf5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,6 +1,10 @@
name: toolkit-ci
-on: pull_request
+on:
+ push:
+ branches: main
+ pull_request:
+ branches: main
jobs:
test:
@@ -34,56 +38,6 @@ jobs:
run: yarn run test
working-directory: packages/components
- visual-test:
- runs-on: ubuntu-latest
- timeout-minutes: 10
- steps:
- - name: Checkout 🛎️
- uses: actions/checkout@v2
-
- - name: Setup Node 💾
- uses: actions/setup-node@v2
- with:
- node-version: '14'
-
- - name: Get yarn cache directory path
- id: yarn-cache-dir-path
- run: echo "::set-output name=dir::$(yarn cache dir)"
- - name: Setup yarn cache
- uses: actions/cache@v2
- id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
- with:
- path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
- key: yarn-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- yarn-
-
- - name: Install Dependencies 📥
- run: yarn install
-
- - name: Install Playwright Browsers
- run: yarn run playwright install --with-deps
- working-directory: packages/components
-
- - name: Run Visual Tests 🧪
- run: yarn run test:visual
- working-directory: packages/components
-
- - name: Update Snapshots
- if: ${{ failure() }}
- run: |
- mv test-results test-assets
- yarn run test:visual -u
- working-directory: packages/components
-
- - uses: actions/upload-artifact@v2
- if: ${{ failure() }}
- with:
- name: jupyter-ui-test
- path: |
- packages/components/test-assets/
- packages/components/src/**/*-snapshots/*
-
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
diff --git a/.github/workflows/visual-test.yml b/.github/workflows/visual-test.yml
new file mode 100644
index 00000000..fa54c0af
--- /dev/null
+++ b/.github/workflows/visual-test.yml
@@ -0,0 +1,58 @@
+name: Toolkit Visual Test
+
+on:
+ push:
+ branches: main
+ pull_request:
+ branches: main
+
+jobs:
+ visual-test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ steps:
+ - name: Checkout 🛎️
+ uses: actions/checkout@v2
+
+ - name: Setup Node 💾
+ uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+ - name: Setup yarn cache
+ uses: actions/cache@v2
+ id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ yarn-
+
+ - name: Install Dependencies 📥
+ run: yarn install
+
+ - name: Install Playwright Browsers
+ run: yarn run playwright install --with-deps
+ working-directory: packages/components
+
+ - name: Run Visual Tests 🧪
+ run: yarn run test:visual
+ working-directory: packages/components
+
+ - name: Update Snapshots
+ if: ${{ failure() }}
+ run: |
+ mv test-results test-assets
+ yarn run test:visual -u
+ working-directory: packages/components
+
+ - uses: actions/upload-artifact@v2
+ if: ${{ failure() }}
+ with:
+ name: jupyter-ui-test
+ path: |
+ packages/components/test-assets/
+ packages/components/src/**/*-snapshots/*
diff --git a/MANIFEST.in b/MANIFEST.in
index 11663305..24f638ab 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -17,7 +17,9 @@ include packages/components/package.json
include packages/components/jest.config.js
include packages/components/playwright.config.ts
include packages/components/rollup.config.js
+include packages/components/tsconfigbase.json
include packages/components/tsconfig.json
+include packages/components/tsconfig.storybook.json
graft packages/components/.storybook
graft packages/components/docs
graft packages/components/src
diff --git a/NOTICES b/NOTICES
index cd706c67..3b81c826 100644
--- a/NOTICES
+++ b/NOTICES
@@ -24,7 +24,7 @@ furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
@@ -58,28 +58,6 @@ PERFORMANCE OF THIS SOFTWARE.
---
-tslib 1.14.1 - 0BSD
-https://www.typescriptlang.org/
-
-Copyright (c) Microsoft Corporation.
-
-Copyright (c) Microsoft Corporation.
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-
----
-
----
-
uri-js 4.4.1 - BSD-2-Clause
https://github.com/garycourt/uri-js
@@ -102,397 +80,47 @@ The views and conclusions contained in the software and documentation are those
---
-@vscode/codicons 0.0.22 - CC-BY-4.0
-https://github.com/microsoft/vscode-codicons#readme
+@fortawesome/free-solid-svg-icons
+https://fontawesome.com
-Copyright (c) Microsoft Corporation.
+## Font Awesome Free License
+
+Font Awesome Free is free, open source, and GPL friendly. You can use it for
+commercial projects, open source projects, or really almost whatever you want.
+Full Font Awesome Free license: https://fontawesome.com/license/free.
+
+# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
+
+In the Font Awesome Free download, the CC BY 4.0 license applies to all icons
+packaged as SVG and JS file types.
+
+# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL)
+
+In the Font Awesome Free download, the SIL OFL license applies to all icons
+packaged as web and desktop font files.
+
+# Code: MIT License (https://opensource.org/licenses/MIT)
+
+In the Font Awesome Free download, the MIT license applies to all non-font and
+non-icon files.
+
+# Attribution
+
+Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
+Awesome Free files already contain embedded comments with sufficient
+attribution, so you shouldn't need to do anything additional when using these
+files normally.
+
+We've kept attribution comments terse, so we ask that you do not actively work
+to remove them from files, especially code. They're a great way for folks to
+learn about Font Awesome.
+
+# Brand Icons
-Attribution 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
- Considerations for licensors: Our public licenses are
- intended for use by those authorized to give the public
- permission to use material in ways otherwise restricted by
- copyright and certain other rights. Our licenses are
- irrevocable. Licensors should read and understand the terms
- and conditions of the license they choose before applying it.
- Licensors should also secure all rights necessary before
- applying our licenses so that the public can reuse the
- material as expected. Licensors should clearly mark any
- material not subject to the license. This includes other CC-
- licensed material, or material used under an exception or
- limitation to copyright. More considerations for licensors:
- wiki.creativecommons.org/Considerations_for_licensors
-
- Considerations for the public: By using one of our public
- licenses, a licensor grants the public permission to use the
- licensed material under specified terms and conditions. If
- the licensor's permission is not necessary for any reason--for
- example, because of any applicable exception or limitation to
- copyright--then that use is not regulated by the license. Our
- licenses grant only permissions under copyright and certain
- other rights that a licensor has authority to grant. Use of
- the licensed material may still be restricted for other
- reasons, including because others have copyright or other
- rights in the material. A licensor may make special requests,
- such as asking that all changes be marked or described.
- Although not required by our licenses, you are encouraged to
- respect those requests where reasonable. More_considerations
- for the public:
- wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution 4.0 International Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution 4.0 International Public License ("Public License"). To the
-extent this Public License may be interpreted as a contract, You are
-granted the Licensed Rights in consideration of Your acceptance of
-these terms and conditions, and the Licensor grants You such rights in
-consideration of benefits the Licensor receives from making the
-Licensed Material available under these terms and conditions.
-
-Section 1 -- Definitions.
-
-a. Adapted Material means material subject to Copyright and Similar
-Rights that is derived from or based upon the Licensed Material
-and in which the Licensed Material is translated, altered,
-arranged, transformed, or otherwise modified in a manner requiring
-permission under the Copyright and Similar Rights held by the
-Licensor. For purposes of this Public License, where the Licensed
-Material is a musical work, performance, or sound recording,
-Adapted Material is always produced where the Licensed Material is
-synched in timed relation with a moving image.
-
-b. Adapter's License means the license You apply to Your Copyright
-and Similar Rights in Your contributions to Adapted Material in
-accordance with the terms and conditions of this Public License.
-
-c. Copyright and Similar Rights means copyright and/or similar rights
-closely related to copyright including, without limitation,
-performance, broadcast, sound recording, and Sui Generis Database
-Rights, without regard to how the rights are labeled or
-categorized. For purposes of this Public License, the rights
-specified in Section 2(b)(1)-(2) are not Copyright and Similar
-Rights.
-
-d. Effective Technological Measures means those measures that, in the
-absence of proper authority, may not be circumvented under laws
-fulfilling obligations under Article 11 of the WIPO Copyright
-Treaty adopted on December 20, 1996, and/or similar international
-agreements.
-
-e. Exceptions and Limitations means fair use, fair dealing, and/or
-any other exception or limitation to Copyright and Similar Rights
-that applies to Your use of the Licensed Material.
-
-f. Licensed Material means the artistic or literary work, database,
-or other material to which the Licensor applied this Public
-License.
-
-g. Licensed Rights means the rights granted to You subject to the
-terms and conditions of this Public License, which are limited to
-all Copyright and Similar Rights that apply to Your use of the
-Licensed Material and that the Licensor has authority to license.
-
-h. Licensor means the individual(s) or entity(ies) granting rights
-under this Public License.
-
-i. Share means to provide material to the public by any means or
-process that requires permission under the Licensed Rights, such
-as reproduction, public display, public performance, distribution,
-dissemination, communication, or importation, and to make material
-available to the public including in ways that members of the
-public may access the material from a place and at a time
-individually chosen by them.
-
-j. Sui Generis Database Rights means rights other than copyright
-resulting from Directive 96/9/EC of the European Parliament and of
-the Council of 11 March 1996 on the legal protection of databases,
-as amended and/or succeeded, as well as other essentially
-equivalent rights anywhere in the world.
-
-k. You means the individual or entity exercising the Licensed Rights
-under this Public License. Your has a corresponding meaning.
-
-Section 2 -- Scope.
-
-a. License grant.
-
- 1. Subject to the terms and conditions of this Public License,
- the Licensor hereby grants You a worldwide, royalty-free,
- non-sublicensable, non-exclusive, irrevocable license to
- exercise the Licensed Rights in the Licensed Material to:
-
- a. reproduce and Share the Licensed Material, in whole or
- in part; and
-
- b. produce, reproduce, and Share Adapted Material.
-
- 2. Exceptions and Limitations. For the avoidance of doubt, where
- Exceptions and Limitations apply to Your use, this Public
- License does not apply, and You do not need to comply with
- its terms and conditions.
-
- 3. Term. The term of this Public License is specified in Section
- 6(a).
-
- 4. Media and formats; technical modifications allowed. The
- Licensor authorizes You to exercise the Licensed Rights in
- all media and formats whether now known or hereafter created,
- and to make technical modifications necessary to do so. The
- Licensor waives and/or agrees not to assert any right or
- authority to forbid You from making technical modifications
- necessary to exercise the Licensed Rights, including
- technical modifications necessary to circumvent Effective
- Technological Measures. For purposes of this Public License,
- simply making modifications authorized by this Section 2(a)
- (4) never produces Adapted Material.
-
- 5. Downstream recipients.
-
- a. Offer from the Licensor -- Licensed Material. Every
- recipient of the Licensed Material automatically
- receives an offer from the Licensor to exercise the
- Licensed Rights under the terms and conditions of this
- Public License.
-
- b. No downstream restrictions. You may not offer or impose
- any additional or different terms or conditions on, or
- apply any Effective Technological Measures to, the
- Licensed Material if doing so restricts exercise of the
- Licensed Rights by any recipient of the Licensed
- Material.
-
- 6. No endorsement. Nothing in this Public License constitutes or
- may be construed as permission to assert or imply that You
- are, or that Your use of the Licensed Material is, connected
- with, or sponsored, endorsed, or granted official status by,
- the Licensor or others designated to receive attribution as
- provided in Section 3(a)(1)(A)(i).
-
-b. Other rights.
-
- 1. Moral rights, such as the right of integrity, are not
- licensed under this Public License, nor are publicity,
- privacy, and/or other similar personality rights; however, to
- the extent possible, the Licensor waives and/or agrees not to
- assert any such rights held by the Licensor to the limited
- extent necessary to allow You to exercise the Licensed
- Rights, but not otherwise.
-
- 2. Patent and trademark rights are not licensed under this
- Public License.
-
- 3. To the extent possible, the Licensor waives any right to
- collect royalties from You for the exercise of the Licensed
- Rights, whether directly or through a collecting society
- under any voluntary or waivable statutory or compulsory
- licensing scheme. In all other cases the Licensor expressly
- reserves any right to collect such royalties.
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
-a. Attribution.
-
- 1. If You Share the Licensed Material (including in modified
- form), You must:
-
- a. retain the following if it is supplied by the Licensor
- with the Licensed Material:
-
- i. identification of the creator(s) of the Licensed
- Material and any others designated to receive
- attribution, in any reasonable manner requested by
- the Licensor (including by pseudonym if
- designated);
-
- ii. a copyright notice;
-
- iii. a notice that refers to this Public License;
-
- iv. a notice that refers to the disclaimer of
- warranties;
-
- v. a URI or hyperlink to the Licensed Material to the
- extent reasonably practicable;
-
- b. indicate if You modified the Licensed Material and
- retain an indication of any previous modifications; and
-
- c. indicate the Licensed Material is licensed under this
- Public License, and include the text of, or the URI or
- hyperlink to, this Public License.
-
- 2. You may satisfy the conditions in Section 3(a)(1) in any
- reasonable manner based on the medium, means, and context in
- which You Share the Licensed Material. For example, it may be
- reasonable to satisfy the conditions by providing a URI or
- hyperlink to a resource that includes the required
- information.
-
- 3. If requested by the Licensor, You must remove any of the
- information required by Section 3(a)(1)(A) to the extent
- reasonably practicable.
-
- 4. If You Share Adapted Material You produce, the Adapter's
- License You apply must not prevent recipients of the Adapted
- Material from complying with this Public License.
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
-a. for the avoidance of doubt, Section 2(a)(1) grants You the right
-to extract, reuse, reproduce, and Share all or a substantial
-portion of the contents of the database;
-
-b. if You include all or a substantial portion of the database
-contents in a database in which You have Sui Generis Database
-Rights, then the database in which You have Sui Generis Database
-Rights (but not its individual contents) is Adapted Material; and
-
-c. You must comply with the conditions in Section 3(a) if You Share
-all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
-a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
-EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
-AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
-ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
-IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
-WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
-PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
-ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
-KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
-ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
-b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
-TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
-NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
-INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
-COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
-USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
-ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
-DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
-IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
-c. The disclaimer of warranties and limitation of liability provided
-above shall be interpreted in a manner that, to the extent
-possible, most closely approximates an absolute disclaimer and
-waiver of all liability.
-
-Section 6 -- Term and Termination.
-
-a. This Public License applies for the term of the Copyright and
-Similar Rights licensed here. However, if You fail to comply with
-this Public License, then Your rights under this Public License
-terminate automatically.
-
-b. Where Your right to use the Licensed Material has terminated under
-Section 6(a), it reinstates:
-
- 1. automatically as of the date the violation is cured, provided
- it is cured within 30 days of Your discovery of the
- violation; or
-
- 2. upon express reinstatement by the Licensor.
-
- For the avoidance of doubt, this Section 6(b) does not affect any
- right the Licensor may have to seek remedies for Your violations
- of this Public License.
-
-c. For the avoidance of doubt, the Licensor may also offer the
-Licensed Material under separate terms or conditions or stop
-distributing the Licensed Material at any time; however, doing so
-will not terminate this Public License.
-
-d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
-License.
-
-Section 7 -- Other Terms and Conditions.
-
-a. The Licensor shall not be bound by any additional or different
-terms or conditions communicated by You unless expressly agreed.
-
-b. Any arrangements, understandings, or agreements regarding the
-Licensed Material not stated herein are separate from and
-independent of the terms and conditions of this Public License.
-
-Section 8 -- Interpretation.
-
-a. For the avoidance of doubt, this Public License does not, and
-shall not be interpreted to, reduce, limit, restrict, or impose
-conditions on any use of the Licensed Material that could lawfully
-be made without permission under this Public License.
-
-b. To the extent possible, if any provision of this Public License is
-deemed unenforceable, it shall be automatically reformed to the
-minimum extent necessary to make it enforceable. If the provision
-cannot be reformed, it shall be severed from this Public License
-without affecting the enforceability of the remaining terms and
-conditions.
-
-c. No term or condition of this Public License will be waived and no
-failure to comply consented to unless expressly agreed to by the
-Licensor.
-
-d. Nothing in this Public License constitutes or may be interpreted
-as a limitation upon, or waiver of, any privileges and immunities
-that apply to the Licensor or You, including from the legal
-processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public
-licenses. Notwithstanding, Creative Commons may elect to apply one of
-its public licenses to material it publishes and in those instances
-will be considered the “Licensor.” The text of the Creative Commons
-public licenses is dedicated to the public domain under the CC0 Public
-Domain Dedication. Except for the limited purpose of indicating that
-material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the
-public licenses.
-
-Creative Commons may be contacted at creativecommons.org.
+All brand icons are trademarks of their respective owners. The use of these
+trademarks does not indicate endorsement of the trademark holder by Font
+Awesome, nor vice versa. **Please do not use brand logos for any purpose except
+to represent the company, product, or service to which they refer.**
---
diff --git a/package.json b/package.json
index d19ba53d..292bb2a8 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"eslint-plugin-prettier": "^3.1.4",
"lerna": "^4.0.0",
"prettier": "^2.1.1",
+ "webpack": "^5.0.0",
"yarn": "^1.22.17"
},
"workspaces": {
diff --git a/packages/components/.storybook/babel.config.js b/packages/components/.storybook/babel.config.js
deleted file mode 100644
index b962a97e..00000000
--- a/packages/components/.storybook/babel.config.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- presets: ['@babel/preset-env', '@babel/preset-typescript'],
- plugins: [
- ['@babel/plugin-proposal-decorators', { legacy: true }],
- ['@babel/plugin-proposal-class-properties', { loose: true }],
- ['@babel/plugin-proposal-private-methods', { loose: true }],
- ['@babel/plugin-proposal-private-property-in-object', { loose: true }]
- ]
-};
diff --git a/packages/components/.storybook/customTheme.js b/packages/components/.storybook/customTheme.js
index 0cdc6318..b10a67ad 100644
--- a/packages/components/.storybook/customTheme.js
+++ b/packages/components/.storybook/customTheme.js
@@ -1,7 +1,7 @@
import { create } from '@storybook/theming/create';
export default create({
- base: 'light',
+ base: 'dark',
brandTitle: 'Jupyter UI Toolkit',
brandUrl: 'https://github.com/jupyterlab-contrib/jupyter-ui-toolkit'
});
diff --git a/packages/components/.storybook/main.js b/packages/components/.storybook/main.js
index a081ff9b..bc15e029 100644
--- a/packages/components/.storybook/main.js
+++ b/packages/components/.storybook/main.js
@@ -2,11 +2,7 @@ module.exports = {
core: {
builder: 'webpack5'
},
- stories: [
- '../src/**/*.stories.mdx',
- '../src/**/*.stories.@(js|jsx|ts|tsx)',
- '../docs/**/*.stories.mdx'
- ],
+ stories: ['../src/**/*.stories.ts'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
@@ -14,5 +10,21 @@ module.exports = {
],
features: {
postcss: false
+ },
+ webpackFinal: async config => {
+ config.module.rules.push({
+ test: /\.ts$/,
+ sideEffects: true,
+ use: [
+ {
+ loader: 'ts-loader',
+ options: {
+ configFile: 'tsconfig.storybook.json'
+ }
+ }
+ ]
+ });
+
+ return config;
}
};
diff --git a/packages/components/.storybook/preview-head.html b/packages/components/.storybook/preview-head.html
index 1001f6c7..19cc72b1 100644
--- a/packages/components/.storybook/preview-head.html
+++ b/packages/components/.storybook/preview-head.html
@@ -8,8 +8,19 @@
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol';
}
+
#root {
display: flex;
width: 100%;
}
-
+
+ /* For testing reaction to JupyterLab theme */
+ :root {
+ --jp-brand-color1: var(--md-blue-700);
+ --jp-border-width: 1px;
+ --jp-border-color1: var(--md-grey-400);
+ --jp-ui-font-size1: 13px;
+ --md-grey-400: #78909C;
+ --md-blue-700: #1976D2;
+ }
+
\ No newline at end of file
diff --git a/packages/components/.storybook/preview.js b/packages/components/.storybook/preview.js
index c1442106..1d136e45 100644
--- a/packages/components/.storybook/preview.js
+++ b/packages/components/.storybook/preview.js
@@ -13,7 +13,7 @@ export const parameters = {
enableShortcuts: false
},
docs: {
- theme: themes.light
+ theme: themes.dark
},
backgrounds: {
default: 'dark',
@@ -22,10 +22,6 @@ export const parameters = {
name: 'light',
value: '#f9f9f9'
},
- {
- name: 'grey',
- value: '#929396'
- },
{
name: 'dark',
value: '#252526'
@@ -33,3 +29,21 @@ export const parameters = {
]
}
};
+
+export const globalTypes = {
+ accent: {
+ name: 'Accent',
+ description: 'Theme accent color for components',
+ defaultValue: '#006CBE',
+ toolbar: {
+ icon: 'paintbrush',
+ // Array of plain string values or MenuItem shape (see below)
+ items: [
+ { value: '#006CBE', right: '🔵', title: 'blue' },
+ { value: '#DA1A5F', title: 'pink' }
+ ],
+ // Property that specifies if the name of the item will be displayed
+ showName: false
+ }
+ }
+};
diff --git a/packages/components/docs/api-report.md b/packages/components/docs/api-report.md
index 02f75349..1af94d00 100644
--- a/packages/components/docs/api-report.md
+++ b/packages/components/docs/api-report.md
@@ -68,17 +68,19 @@ export class Badge extends Badge_2 {
connectedCallback(): void;
}
-// @public
+// Warning: (ae-internal-missing-underscore) The name "Button" should be prefixed with an underscore because the declaration is marked as @internal
+//
+// @internal
export class Button extends Button_2 {
+ // @public
appearance: ButtonAppearance;
- // @internal
- attributeChangedCallback(attrName: string, oldVal: string, newVal: string): void;
- // @internal
connectedCallback(): void;
+ // @public
+ defaultSlottedContentChanged(oldValue: HTMLElement[], newValue: HTMLElement[]): void;
}
// @public
-export type ButtonAppearance = 'primary' | 'secondary' | 'icon';
+export type ButtonAppearance = 'accent' | 'neutral' | 'outline' | 'stealth';
// @public
export class Checkbox extends Checkbox_2 {
diff --git a/packages/components/package.json b/packages/components/package.json
index fe0e90fc..ce2f92f3 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -17,7 +17,8 @@
"sideEffects": false,
"scripts": {
"start": "start-storybook -p 6006",
- "build": "rollup -c && tsc -p ./tsconfig.json && yarn run doc",
+ "start:ci": "start-storybook -p 6006 --ci",
+ "build": "rollup -c && tsc -p ./tsconfig.json",
"build:docs": "build-storybook",
"deploy:docs": "yarn run build:docs && gh-pages -d storybook-static",
"doc": "api-extractor run --local",
@@ -30,14 +31,16 @@
"test:visual": "playwright test"
},
"dependencies": {
+ "@microsoft/fast-colors": "^5.1.4",
+ "@microsoft/fast-components": "^2.17.1",
"@microsoft/fast-element": "^1.6.0",
- "@microsoft/fast-foundation": "^2.21.0"
+ "@microsoft/fast-foundation": "^2.21.0",
+ "@storybook/addons": "^6.4.14",
+ "ts-loader": "^7.0.2"
},
"devDependencies": {
- "@babel/core": "^7.14.3",
- "@babel/plugin-proposal-decorators": "^7.14.2",
- "@babel/preset-env": "^7.14.2",
- "@babel/preset-typescript": "^7.13.0",
+ "@fortawesome/fontawesome-svg-core": "^1.2.36",
+ "@fortawesome/free-solid-svg-icons": "^5.15.4",
"@microsoft/api-extractor": "^7.18.9",
"@microsoft/eslint-config-fast-dna": "^1.2.0",
"@playwright/test": "^1.17.0",
@@ -54,7 +57,6 @@
"@storybook/theming": "^6.4.3",
"@types/jest": "^26.0.20",
"@typescript-eslint/eslint-plugin": "^4.8.1",
- "@vscode/codicons": "^0.0.22",
"babel-jest": "^27.2.4",
"babel-loader": "^8.2.2",
"babel-plugin-transform-class-properties": "^6.24.1",
diff --git a/packages/components/playwright.config.ts b/packages/components/playwright.config.ts
index 8758ded0..9e81033e 100644
--- a/packages/components/playwright.config.ts
+++ b/packages/components/playwright.config.ts
@@ -5,7 +5,7 @@ const config: PlaywrightTestConfig = {
retries: process.env.CI ? 2 : 0,
testMatch: '**/*.test.ts',
webServer: {
- command: 'yarn run start',
+ command: 'yarn run start:ci',
port: 6006,
timeout: 120 * 1000,
// It is safe to reuse the server for stories testing
@@ -13,7 +13,11 @@ const config: PlaywrightTestConfig = {
},
use: {
baseURL: process.env.TARGET_URL ?? 'http://localhost:6006',
- trace: 'on-first-retry'
+ trace: 'on-first-retry',
+ launchOptions: {
+ // Force slow motion to let storybook the time to update styles
+ slowMo: 30
+ }
},
projects: [
{
diff --git a/packages/components/src/badge/README.md b/packages/components/src/badge/README.md
deleted file mode 100644
index 40e727d1..00000000
--- a/packages/components/src/badge/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Jupyter Badge
-
-The `jp-badge` component is used to highlight an item, attract attention, and/or flag status.
-
-## Attributes
-
-None
-
-## Usage
-
-A `jp-badge` can only contain numbers to follow the conventions of the Jupyter design language.
-
-If a component that labels an item with a string is desired, see the `jp-tag` component.
-
-### Basic Usage
-
-[Interactive Storybook Example](https://jupyterlab-contrib.github.io/jupyter-ui-toolkit/?path=/story/library-badge--default)
-
-```html
-1
-```
diff --git a/packages/components/src/badge/badge.stories.ts b/packages/components/src/badge/badge.stories.ts
deleted file mode 100644
index 2938231f..00000000
--- a/packages/components/src/badge/badge.stories.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) Jupyter Development Team.
-// Copyright (c) Microsoft Corporation.
-// Distributed under the terms of the Modified BSD License.
-
-import { BadgeArgs, createBadge } from './fixtures/createBadge';
-
-export default {
- title: 'Library/Badge',
- argTypes: {
- label: { control: 'number' }
- },
- parameters: {
- actions: {
- disabled: true
- }
- }
-};
-
-const Template = ({ ...args }: BadgeArgs) => {
- return createBadge({ ...args });
-};
-
-export const Default: any = Template.bind({});
-Default.args = {
- label: '1'
-};
-Default.parameters = {
- docs: {
- source: {
- code: `1`
- }
- }
-};
diff --git a/packages/components/src/badge/badge.styles.ts b/packages/components/src/badge/badge.styles.ts
deleted file mode 100644
index f8e49608..00000000
--- a/packages/components/src/badge/badge.styles.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) Jupyter Development Team.
-// Copyright (c) Microsoft Corporation.
-// Distributed under the terms of the Modified BSD License.
-
-import { css, ElementStyles } from '@microsoft/fast-element';
-import {
- display,
- ElementDefinitionContext,
- FoundationElementDefinition
-} from '@microsoft/fast-foundation';
-import {
- badgeBackground,
- badgeForeground,
- borderWidth,
- buttonBorder,
- designUnit,
- fontFamily,
- typeRampMinus1FontSize,
- typeRampMinus1LineHeight
-} from '../design-tokens';
-
-export const badgeStyles = (
- context: ElementDefinitionContext,
- definition: FoundationElementDefinition
-): ElementStyles => css`
- ${display('inline-block')} :host {
- box-sizing: border-box;
- font-family: ${fontFamily};
- font-size: ${typeRampMinus1FontSize};
- line-height: ${typeRampMinus1LineHeight};
- }
- .control {
- align-items: center;
- background-color: ${badgeBackground};
- border: calc(${borderWidth} * 1px) solid ${buttonBorder};
- border-radius: 100px;
- box-sizing: border-box;
- color: ${badgeForeground};
- display: flex;
- height: calc(${designUnit} * 4px);
- justify-content: center;
- min-width: calc(${designUnit} * 4px);
- padding: 0 calc(${designUnit} * 1px);
- }
-`;
diff --git a/packages/components/src/badge/badge.test.ts b/packages/components/src/badge/badge.test.ts
deleted file mode 100644
index ea9c8c53..00000000
--- a/packages/components/src/badge/badge.test.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { test, expect } from '@playwright/test';
-
-test.describe('Badge', () => {
- test('Default', async ({ page }) => {
- await page.goto('/iframe.html?id=library-badge--default');
-
- expect(
- await page.locator('#root :nth-child(1)').first().screenshot()
- ).toMatchSnapshot('badge-default.png');
- });
-});
diff --git a/packages/components/src/badge/badge.test.ts-snapshots/badge-default-chromium-linux.png b/packages/components/src/badge/badge.test.ts-snapshots/badge-default-chromium-linux.png
deleted file mode 100644
index c9e589b7..00000000
Binary files a/packages/components/src/badge/badge.test.ts-snapshots/badge-default-chromium-linux.png and /dev/null differ
diff --git a/packages/components/src/badge/badge.test.ts-snapshots/badge-default-firefox-linux.png b/packages/components/src/badge/badge.test.ts-snapshots/badge-default-firefox-linux.png
deleted file mode 100644
index e29f9c93..00000000
Binary files a/packages/components/src/badge/badge.test.ts-snapshots/badge-default-firefox-linux.png and /dev/null differ
diff --git a/packages/components/src/badge/badge.test.ts-snapshots/badge-default-webkit-linux.png b/packages/components/src/badge/badge.test.ts-snapshots/badge-default-webkit-linux.png
deleted file mode 100644
index 72f6c2ed..00000000
Binary files a/packages/components/src/badge/badge.test.ts-snapshots/badge-default-webkit-linux.png and /dev/null differ
diff --git a/packages/components/src/badge/fixtures/createBadge.ts b/packages/components/src/badge/fixtures/createBadge.ts
deleted file mode 100644
index 1b76fb61..00000000
--- a/packages/components/src/badge/fixtures/createBadge.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) Jupyter Development Team.
-// Copyright (c) Microsoft Corporation.
-// Distributed under the terms of the Modified BSD License.
-
-import { Badge } from '../index';
-
-export type BadgeArgs = {
- label: string;
-};
-
-export function createBadge({ label }: BadgeArgs) {
- const badge = new Badge();
-
- if (label) {
- badge.textContent = label;
- }
-
- return badge;
-}
diff --git a/packages/components/src/badge/index.ts b/packages/components/src/badge/index.ts
deleted file mode 100644
index 1c5a0ea8..00000000
--- a/packages/components/src/badge/index.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) Jupyter Development Team.
-// Copyright (c) Microsoft Corporation.
-// Distributed under the terms of the Modified BSD License.
-
-import {
- Badge as FoundationBadge,
- badgeTemplate as template
-} from '@microsoft/fast-foundation';
-import { badgeStyles as styles } from './badge.styles';
-
-/**
- * The badge class.
- *
- * @public
- */
-export class Badge extends FoundationBadge {
- /**
- * Component lifecycle method that runs when the component is inserted
- * into the DOM.
- *
- * @internal
- */
- public connectedCallback(): void {
- super.connectedCallback();
-
- // This will override any usage of the circular attribute
- // inherited by the FAST Foundation Badge component so
- // that Jupyter Badges are always circular
- if (!this.circular) {
- this.circular = true;
- }
- }
-}
-
-/**
- * The badge component registration.
- *
- * @remarks
- * HTML Element: ``
- *
- * @public
- */
-export const jpBadge = Badge.compose({
- baseName: 'badge',
- template,
- styles
-});
diff --git a/packages/components/src/button/README.md b/packages/components/src/button/README.md
index 598dd228..b3f5c9fa 100644
--- a/packages/components/src/button/README.md
+++ b/packages/components/src/button/README.md
@@ -10,6 +10,7 @@ The `jp-button` is a web component implementation of a [button element](https://
| `aria-label` | string | Defines a label for buttons that screen readers can use. |
| `autofocus` | boolean | Determines if the element should receive document focus on page load. |
| `disabled` | boolean | Prevents the user from interacting with the button––it cannot be pressed or focused. |
+| `minimal` | boolean | Compact layout |
| `form` | string | See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes). |
| `formaction` | string | See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes). |
| `formenctype` | string | See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes). |
diff --git a/packages/components/src/button/button.stories.ts b/packages/components/src/button/button.stories.ts
index a350ba5e..93287be2 100644
--- a/packages/components/src/button/button.stories.ts
+++ b/packages/components/src/button/button.stories.ts
@@ -1,9 +1,8 @@
// Copyright (c) Jupyter Development Team.
-// Copyright (c) Microsoft Corporation.
// Distributed under the terms of the Modified BSD License.
import { action } from '@storybook/addon-actions';
-import { ButtonArgs, createButton } from './fixtures/createButton';
+import { getFaIcon, setTheme } from '../utilities/storybook';
export default {
title: 'Library/Button',
@@ -12,14 +11,13 @@ export default {
appearance: {
control: {
type: 'select',
- options: ['Primary', 'Secondary', 'Icon']
+ options: ['Accent', 'Error', 'Neutral', 'Outline', 'Stealth']
}
},
isDisabled: { control: 'boolean' },
isAutoFocused: { control: 'boolean' },
+ isMinimal: { control: 'boolean' },
startIcon: { control: 'boolean' },
- iconOnly: { control: 'boolean' },
- ariaLabel: { control: 'text' },
onClick: {
action: 'clicked',
table: {
@@ -29,39 +27,52 @@ export default {
}
};
-const Template = ({ ...args }: ButtonArgs) => {
- return createButton({ ...args });
+const Template = (
+ args,
+ { globals: { backgrounds, accent }, parameters }
+): HTMLElement => {
+ setTheme(accent, parameters.backgrounds, backgrounds);
+ const container = document.createElement('div');
+ container.insertAdjacentHTML(
+ 'afterbegin',
+ `${args.startIcon ? getFaIcon('plus', args.label ? 'start' : null) : ''}${
+ args.label ?? ''
+ }`
+ );
+
+ if (args.onClick) {
+ container.firstChild.addEventListener('click', args.onClick);
+ }
+ return container.firstChild as HTMLElement;
};
export const Default: any = Template.bind({});
Default.args = {
label: 'Button Text',
- appearance: 'Primary',
+ appearance: 'Accent',
isDisabled: false,
isAutoFocused: false,
+ isMinimal: false,
startIcon: false,
- iconOnly: false,
onClick: action('button-clicked')
};
-Default.parameters = {
- docs: {
- source: {
- code: `Button Text`
- }
- }
-};
-export const Secondary: any = Template.bind({});
-Secondary.args = {
+export const Error: any = Template.bind({});
+Error.args = {
...Default.args,
- appearance: 'Secondary'
+ appearance: 'Error'
};
-Secondary.parameters = {
- docs: {
- source: {
- code: `Button Text`
- }
- }
+
+export const Neutral: any = Template.bind({});
+Neutral.args = {
+ ...Default.args,
+ appearance: 'Neutral'
};
export const WithAutofocus: any = Template.bind({});
@@ -69,51 +80,22 @@ WithAutofocus.args = {
...Default.args,
isAutoFocused: true
};
-WithAutofocus.parameters = {
- docs: {
- source: {
- code: `Button Text`
- }
- }
-};
export const WithDisabled: any = Template.bind({});
WithDisabled.args = {
...Default.args,
isDisabled: true
};
-WithDisabled.parameters = {
- docs: {
- source: {
- code: `Button Text`
- }
- }
-};
export const WithStartIcon: any = Template.bind({});
WithStartIcon.args = {
...Default.args,
startIcon: true
};
-WithStartIcon.parameters = {
- docs: {
- source: {
- code: `\n\n\n\tButton Text\n\t\n`
- }
- }
-};
-export const WithIconOnly: any = Template.bind({});
-WithIconOnly.args = {
+export const IconOnly: any = Template.bind({});
+IconOnly.args = {
...Default.args,
- appearance: 'Icon',
- iconOnly: true,
- ariaLabel: 'Confirm'
-};
-WithIconOnly.parameters = {
- docs: {
- source: {
- code: `\n\n\n\t\n`
- }
- }
+ label: null,
+ startIcon: true
};
diff --git a/packages/components/src/button/button.styles.ts b/packages/components/src/button/button.styles.ts
index 12855491..56c1ff3a 100644
--- a/packages/components/src/button/button.styles.ts
+++ b/packages/components/src/button/button.styles.ts
@@ -1,56 +1,85 @@
-// Copyright (c) Jupyter Development Team.
-// Copyright (c) Microsoft Corporation.
-// Distributed under the terms of the Modified BSD License.
-
+import {
+ accentFillActive,
+ accentFillFocus,
+ accentFillHover,
+ accentFillRest,
+ bodyFont,
+ controlCornerRadius,
+ density,
+ designUnit,
+ disabledOpacity,
+ foregroundOnAccentActive,
+ foregroundOnAccentHover,
+ foregroundOnAccentRest,
+ neutralFillActive,
+ neutralFillFocus,
+ neutralFillHover,
+ neutralFillRest,
+ neutralFillStealthActive,
+ neutralFillStealthHover,
+ neutralFillStealthRest,
+ neutralForegroundRest,
+ strokeWidth,
+ typeRampBaseFontSize,
+ typeRampBaseLineHeight
+} from '@microsoft/fast-components';
import { css, ElementStyles } from '@microsoft/fast-element';
import {
ButtonOptions,
disabledCursor,
display,
ElementDefinitionContext,
- focusVisible
+ focusVisible,
+ forcedColorsStylesheetBehavior,
+ PropertyStyleSheetBehavior
} from '@microsoft/fast-foundation';
+import { SystemColors } from '@microsoft/fast-web-utilities';
import {
- borderWidth,
- buttonBorder,
- buttonIconBackground,
- buttonIconCornerRadius,
- buttonIconFocusBorderOffset,
- buttonIconHoverBackground,
- buttonIconPadding,
- buttonPaddingHorizontal,
- buttonPaddingVertical,
- buttonPrimaryBackground,
- buttonPrimaryForeground,
- buttonPrimaryHoverBackground,
- buttonSecondaryBackground,
- buttonSecondaryForeground,
- buttonSecondaryHoverBackground,
- cornerRadius,
- designUnit,
- disabledOpacity,
- focusBorder,
- fontFamily,
- foreground,
- typeRampBaseFontSize,
- typeRampBaseLineHeight
-} from '../design-tokens';
+ errorFillActive,
+ errorFillFocus,
+ errorFillHover,
+ errorFillRest,
+ foregroundOnErrorActive,
+ foregroundOnErrorHover,
+ foregroundOnErrorRest
+} from '../design-token';
+import { heightNumber } from '../styles';
+
+/**
+ * Behavior that will conditionally apply a stylesheet based on the elements
+ * appearance property
+ *
+ * @param value - The value of the appearance property
+ * @param styles - The styles to be applied when condition matches
+ *
+ * @internal
+ */
+function appearanceBehavior(value: string, styles: ElementStyles) {
+ return new PropertyStyleSheetBehavior('appearance', value, styles);
+}
+
+// TODO do we really want to use outline for focus, active, ... => this call for a minimal style for toolbar probably
+// outline force to use a padding so that the outline is not hidden by other elements.
/**
* @internal
*/
const BaseButtonStyles = css`
${display('inline-flex')} :host {
+ font-family: ${bodyFont};
outline: none;
- font-family: ${fontFamily};
font-size: ${typeRampBaseFontSize};
line-height: ${typeRampBaseLineHeight};
- color: ${buttonPrimaryForeground};
- background: ${buttonPrimaryBackground};
- border-radius: calc(${cornerRadius} * 1px);
- fill: currentColor;
+ height: calc(${heightNumber} * 1px);
+ min-width: calc(${heightNumber} * 1px);
+ background-color: ${neutralFillRest};
+ color: ${neutralForegroundRest};
+ border-radius: calc(${controlCornerRadius} * 1px);
+ fill: currentcolor;
cursor: pointer;
+ margin: calc((${designUnit} + ${density} + 2) * 1px);
}
+
.control {
background: transparent;
height: inherit;
@@ -59,131 +88,508 @@ const BaseButtonStyles = css`
display: inline-flex;
justify-content: center;
align-items: center;
- padding: ${buttonPaddingVertical} ${buttonPaddingHorizontal};
- white-space: wrap;
- outline: none;
+ padding: 0 calc((10 + (${designUnit} * 2 * ${density})) * 1px);
+ white-space: nowrap;
+ outline: 1px solid transparent;
+ outline-offset: calc((${designUnit} + ${density}) * 1px);
+ -moz-outline-radius: 0px;
text-decoration: none;
- border: calc(${borderWidth} * 1px) solid ${buttonBorder};
+ border: calc(${strokeWidth} * 1px) solid transparent;
color: inherit;
border-radius: inherit;
fill: inherit;
cursor: inherit;
font-family: inherit;
- max-width: 300px;
+ font-size: inherit;
+ line-height: inherit;
}
+
:host(:hover) {
- background: ${buttonPrimaryHoverBackground};
+ background-color: ${neutralFillHover};
}
+
+ :host(:hover) .control {
+ outline-color: ${neutralFillHover};
+ }
+
:host(:active) {
- background: ${buttonPrimaryBackground};
+ background-color: ${neutralFillActive};
}
- .control: ${focusVisible} {
- outline: calc(${borderWidth} * 1px) solid ${focusBorder};
- outline-offset: calc(${borderWidth} * 2px);
+
+ :host([minimal]) {
+ --density: -4;
+ }
+
+ :host([minimal]) .control {
+ padding: 1px;
}
+
+ :host(:active) .control {
+ outline-color: ${neutralFillActive};
+ }
+
+ :host .control:${focusVisible} {
+ outline-color: ${neutralFillFocus};
+ }
+
.control::-moz-focus-inner {
border: 0;
}
- :host([disabled]) {
- opacity: ${disabledOpacity};
- background: ${buttonPrimaryBackground};
- cursor: ${disabledCursor};
- }
- .content {
+
+ .start,
+ .end {
display: flex;
}
- .start {
- display: flex;
+
+ .control.icon-only {
+ padding: 0;
+ line-height: 0;
}
- ::slotted(svg),
- ::slotted(span) {
- width: calc(${designUnit} * 4px);
- height: calc(${designUnit} * 4px);
+
+ ::slotted(svg) {
+ ${
+ /* Glyph size and margin-left is temporary -
+ replace when adaptive typography is figured out */ ''
+ } width: 16px;
+ height: 16px;
+ pointer-events: none;
}
+
.start {
- margin-inline-end: 8px;
+ margin-inline-end: 11px;
}
-`;
+
+ .end {
+ margin-inline-start: 11px;
+ }
+`.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host .control {
+ background-color: ${SystemColors.ButtonFace};
+ border-color: ${SystemColors.ButtonText};
+ color: ${SystemColors.ButtonText};
+ fill: currentColor;
+ }
+
+ :host(:hover) .control {
+ forced-color-adjust: none;
+ background-color: ${SystemColors.Highlight};
+ color: ${SystemColors.HighlightText};
+ }
+
+ .control: ${focusVisible} {
+ forced-color-adjust: none;
+ background-color: ${SystemColors.Highlight};
+ outline-color: ${SystemColors.ButtonText};
+ color: ${SystemColors.HighlightText};
+ }
+
+ .control:hover,
+ :host([appearance='outline']) .control:hover {
+ outline-color: ${SystemColors.ButtonText};
+ }
+
+ :host([href]) .control {
+ border-color: ${SystemColors.LinkText};
+ color: ${SystemColors.LinkText};
+ }
+
+ :host([href]) .control:hover,
+ :host([href]) .control:${focusVisible} {
+ forced-color-adjust: none;
+ background: ${SystemColors.ButtonFace};
+ outline-color: ${SystemColors.LinkText};
+ color: ${SystemColors.LinkText};
+ fill: currentColor;
+ }
+ `
+ )
+);
/**
* @internal
*/
-const PrimaryButtonStyles = css`
- :host([appearance='primary']) {
- background: ${buttonPrimaryBackground};
- color: ${buttonPrimaryForeground};
+const AccentButtonStyles = css`
+ :host([appearance='accent']) {
+ background: ${accentFillRest};
+ color: ${foregroundOnAccentRest};
}
- :host([appearance='primary']:hover) {
- background: ${buttonPrimaryHoverBackground};
+
+ :host([appearance='accent']:hover) {
+ background: ${accentFillHover};
+ color: ${foregroundOnAccentHover};
}
- :host([appearance='primary']:active) .control:active {
- background: ${buttonPrimaryBackground};
+
+ :host([appearance='accent']:hover) .control {
+ outline-color: ${accentFillHover};
}
- :host([appearance='primary']) .control:${focusVisible} {
- outline: calc(${borderWidth} * 1px) solid ${focusBorder};
- outline-offset: calc(${borderWidth} * 2px);
+
+ :host([appearance='accent']:active) .control:active {
+ background: ${accentFillActive};
+ color: ${foregroundOnAccentActive};
+ outline-color: ${accentFillActive};
}
- :host([appearance='primary'][disabled]) {
- background: ${buttonPrimaryBackground};
+
+ :host([appearance="accent"]) .control:${focusVisible} {
+ outline-color: ${accentFillFocus};
}
-`;
+`.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='accent']) .control {
+ forced-color-adjust: none;
+ background: ${SystemColors.Highlight};
+ color: ${SystemColors.HighlightText};
+ }
+
+ :host([appearance='accent']) .control:hover,
+ :host([appearance='accent']:active) .control:active {
+ background: ${SystemColors.HighlightText};
+ outline-color: ${SystemColors.Highlight};
+ color: ${SystemColors.Highlight};
+ }
+
+ :host([appearance="accent"]) .control:${focusVisible} {
+ outline-color: ${SystemColors.Highlight};
+ }
+
+ :host([appearance='accent'][href]) .control {
+ background: ${SystemColors.LinkText};
+ color: ${SystemColors.HighlightText};
+ }
+
+ :host([appearance='accent'][href]) .control:hover {
+ background: ${SystemColors.ButtonFace};
+ outline-color: ${SystemColors.LinkText};
+ color: ${SystemColors.LinkText};
+ fill: currentColor;
+ }
+
+ :host([appearance="accent"][href]) .control:${focusVisible} {
+ outline-color: ${SystemColors.LinkText};
+ }
+ `
+ )
+);
/**
* @internal
*/
-const SecondaryButtonStyles = css`
- :host([appearance='secondary']) {
- background: ${buttonSecondaryBackground};
- color: ${buttonSecondaryForeground};
+const ErrorButtonStyles = css`
+ :host([appearance='error']) {
+ background: ${errorFillRest};
+ color: ${foregroundOnErrorRest};
}
- :host([appearance='secondary']:hover) {
- background: ${buttonSecondaryHoverBackground};
+
+ :host([appearance='error']:hover) {
+ background: ${errorFillHover};
+ color: ${foregroundOnErrorHover};
}
- :host([appearance='secondary']:active) .control:active {
- background: ${buttonSecondaryBackground};
+
+ :host([appearance='error']:hover) .control {
+ outline-color: ${errorFillHover};
}
- :host([appearance='secondary']) .control:${focusVisible} {
- outline: calc(${borderWidth} * 1px) solid ${focusBorder};
- outline-offset: calc(${borderWidth} * 2px);
+
+ :host([appearance='error']:active) .control:active {
+ background: ${errorFillActive};
+ color: ${foregroundOnErrorActive};
+ outline-color: ${errorFillActive};
}
- :host([appearance='secondary'][disabled]) {
- background: ${buttonSecondaryBackground};
+
+ :host([appearance="error"]) .control:${focusVisible} {
+ outline-color: ${errorFillFocus};
}
-`;
+`.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='error']) .control {
+ forced-color-adjust: none;
+ background: ${SystemColors.Highlight};
+ color: ${SystemColors.HighlightText};
+ }
+
+ :host([appearance='error']) .control:hover,
+ :host([appearance='error']:active) .control:active {
+ background: ${SystemColors.HighlightText};
+ outline-color: ${SystemColors.Highlight};
+ color: ${SystemColors.Highlight};
+ }
+
+ :host([appearance="error"]) .control:${focusVisible} {
+ outline-color: ${SystemColors.Highlight};
+ }
+
+ :host([appearance='error'][href]) .control {
+ background: ${SystemColors.LinkText};
+ color: ${SystemColors.HighlightText};
+ }
+
+ :host([appearance='error'][href]) .control:hover {
+ background: ${SystemColors.ButtonFace};
+ outline-color: ${SystemColors.LinkText};
+ color: ${SystemColors.LinkText};
+ fill: currentColor;
+ }
+
+ :host([appearance="error"][href]) .control:${focusVisible} {
+ outline-color: ${SystemColors.LinkText};
+ }
+ `
+ )
+);
/**
* @internal
*/
-const IconButtonStyles = css`
- :host([appearance='icon']) {
- background: ${buttonIconBackground};
- border-radius: ${buttonIconCornerRadius};
- color: ${foreground};
+const OutlineButtonStyles = css`
+ :host([appearance='outline']) {
+ background: transparent;
+ border-color: ${accentFillRest};
}
- :host([appearance='icon']:hover) {
- background: ${buttonIconHoverBackground};
+
+ :host([appearance='outline']:hover) {
+ border-color: ${accentFillHover};
+ }
+
+ :host([appearance='outline']:hover) .control {
+ outline-color: ${accentFillHover};
}
- :host([appearance='icon']) .control {
- padding: ${buttonIconPadding};
+
+ :host([appearance='outline']:active) {
+ border-color: ${accentFillActive};
}
- :host([appearance='icon']:active) .control:active {
- background: ${buttonIconHoverBackground};
+
+ :host([appearance='outline']:active) .control:active {
+ outline-color: ${accentFillActive};
}
- :host([appearance='icon']) .control:${focusVisible} {
- outline: calc(${borderWidth} * 1px) solid ${focusBorder};
- outline-offset: ${buttonIconFocusBorderOffset};
+
+ :host([appearance='outline']) .control {
+ border-color: inherit;
}
- :host([appearance='icon'][disabled]) {
- background: ${buttonIconBackground};
+
+ :host([appearance="outline"]) .control:${focusVisible} {
+ border-color: ${accentFillFocus};
+ outline-color: ${accentFillActive};
}
-`;
+`.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='outline']) .control {
+ border-color: ${SystemColors.ButtonText};
+ }
+ :host([appearance="outline"]) .control:${focusVisible} {
+ forced-color-adjust: none;
+ background-color: ${SystemColors.Highlight};
+ border-color: ${SystemColors.ButtonText};
+ color: ${SystemColors.HighlightText};
+ fill: currentColor;
+ }
+ :host([appearance='outline'][href]) .control {
+ background: ${SystemColors.ButtonFace};
+ border-color: ${SystemColors.LinkText};
+ color: ${SystemColors.LinkText};
+ fill: currentColor;
+ }
+ :host([appearance="outline"][href]) .control:hover,
+ :host([appearance="outline"][href]) .control:${focusVisible} {
+ forced-color-adjust: none;
+ border-color: ${SystemColors.LinkText};
+ box-shadow: 0 0 0 1px ${SystemColors.LinkText} inset;
+ }
+ `
+ )
+);
-export const buttonStyles = (
+/**
+ * @internal
+ */
+const StealthButtonStyles = css`
+ :host([appearance='stealth']) {
+ background: transparent;
+ }
+
+ :host([appearance='stealth']:hover) {
+ background: ${neutralFillStealthHover};
+ }
+
+ :host([appearance='stealth']:active) {
+ background: ${neutralFillStealthActive};
+ }
+`.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='stealth']),
+ :host([appearance='stealth']) .control {
+ forced-color-adjust: none;
+ background: ${SystemColors.ButtonFace};
+ outline-color: transparent;
+ color: ${SystemColors.ButtonText};
+ fill: currentColor;
+ }
+
+ :host([appearance='stealth']:hover) .control {
+ background: ${SystemColors.Highlight};
+ outline-color: ${SystemColors.Highlight};
+ color: ${SystemColors.HighlightText};
+ fill: currentColor;
+ }
+
+ :host([appearance="stealth"]:${focusVisible}) .control {
+ background: ${SystemColors.Highlight};
+ box-shadow: 0 0 0 1px ${SystemColors.Highlight};
+ color: ${SystemColors.HighlightText};
+ fill: currentColor;
+ }
+
+ :host([appearance='stealth'][href]) .control {
+ color: ${SystemColors.LinkText};
+ }
+
+ :host([appearance="stealth"][href]:hover) .control,
+ :host([appearance="stealth"][href]:${focusVisible}) .control {
+ background: ${SystemColors.LinkText};
+ outline-color: ${SystemColors.LinkText};
+ color: ${SystemColors.HighlightText};
+ fill: currentColor;
+ }
+
+ :host([appearance="stealth"][href]:${focusVisible}) .control {
+ forced-color-adjust: none;
+ box-shadow: 0 0 0 1px ${SystemColors.LinkText};
+ }
+ `
+ )
+);
+
+/**
+ * Styles for Button
+ * @public
+ */
+export const buttonStyles: (
context: ElementDefinitionContext,
definition: ButtonOptions
-): ElementStyles => css`
- ${BaseButtonStyles}
- ${PrimaryButtonStyles}
- ${SecondaryButtonStyles}
- ${IconButtonStyles}
-`;
+) => ElementStyles = (
+ context: ElementDefinitionContext,
+ definition: ButtonOptions
+) =>
+ css`
+ :host([disabled]),
+ :host([disabled]:hover),
+ :host([disabled]:active) {
+ opacity: ${disabledOpacity};
+ background-color: ${neutralFillRest};
+ cursor: ${disabledCursor};
+ }
+
+ ${BaseButtonStyles}
+ `.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([disabled]),
+ :host([disabled]) .control,
+ :host([disabled]:hover),
+ :host([disabled]:active) {
+ forced-color-adjust: none;
+ background-color: ${SystemColors.ButtonFace};
+ outline-color: ${SystemColors.GrayText};
+ color: ${SystemColors.GrayText};
+ cursor: ${disabledCursor};
+ opacity: 1;
+ }
+ `
+ ),
+ appearanceBehavior(
+ 'accent',
+ css`
+ :host([appearance='accent'][disabled]),
+ :host([appearance='accent'][disabled]:hover),
+ :host([appearance='accent'][disabled]:active) {
+ background: ${accentFillRest};
+ }
+
+ ${AccentButtonStyles}
+ `.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='accent'][disabled]) .control,
+ :host([appearance='accent'][disabled]) .control:hover {
+ background: ${SystemColors.ButtonFace};
+ border-color: ${SystemColors.GrayText};
+ color: ${SystemColors.GrayText};
+ }
+ `
+ )
+ )
+ ),
+ appearanceBehavior(
+ 'error',
+ css`
+ :host([appearance='error'][disabled]),
+ :host([appearance='error'][disabled]:hover),
+ :host([appearance='error'][disabled]:active) {
+ background: ${errorFillRest};
+ }
+
+ ${ErrorButtonStyles}
+ `.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='error'][disabled]) .control,
+ :host([appearance='error'][disabled]) .control:hover {
+ background: ${SystemColors.ButtonFace};
+ border-color: ${SystemColors.GrayText};
+ color: ${SystemColors.GrayText};
+ }
+ `
+ )
+ )
+ ),
+ appearanceBehavior(
+ 'outline',
+ css`
+ :host([appearance='outline'][disabled]),
+ :host([appearance='outline'][disabled]:hover),
+ :host([appearance='outline'][disabled]:active) {
+ background: transparent;
+ border-color: ${accentFillRest};
+ }
+
+ ${OutlineButtonStyles}
+ `.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='outline'][disabled]) .control {
+ border-color: ${SystemColors.GrayText};
+ }
+ `
+ )
+ )
+ ),
+ appearanceBehavior(
+ 'stealth',
+ css`
+ :host([appearance='stealth'][disabled]),
+ :host([appearance='stealth'][disabled]:hover),
+ :host([appearance='stealth'][disabled]:active) {
+ background: ${neutralFillStealthRest};
+ }
+
+ ${StealthButtonStyles}
+ `.withBehaviors(
+ forcedColorsStylesheetBehavior(
+ css`
+ :host([appearance='stealth'][disabled]) {
+ background: ${SystemColors.ButtonFace};
+ }
+
+ :host([appearance='stealth'][disabled]) .control {
+ background: ${SystemColors.ButtonFace};
+ border-color: transparent;
+ color: ${SystemColors.GrayText};
+ }
+ `
+ )
+ )
+ )
+ );
diff --git a/packages/components/src/button/button.test.ts b/packages/components/src/button/button.test.ts
index 7e437c4f..e48dba56 100644
--- a/packages/components/src/button/button.test.ts
+++ b/packages/components/src/button/button.test.ts
@@ -4,32 +4,56 @@ test.describe('Button', () => {
test('Default', async ({ page }) => {
await page.goto('/iframe.html?id=library-button--default');
- expect(
- await page.locator('#root :nth-child(1)').first().screenshot()
- ).toMatchSnapshot('button-default.png');
+ expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
+ 'button-default.png'
+ );
});
- test('Secondary', async ({ page }) => {
- await page.goto('/iframe.html?id=library-button--secondary');
+ test('Error', async ({ page }) => {
+ await page.goto('/iframe.html?id=library-button--error');
- expect(
- await page.locator('#root :nth-child(1)').first().screenshot()
- ).toMatchSnapshot('button-secondary.png');
+ expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
+ 'button-error.png'
+ );
+ });
+
+ test('Neutral', async ({ page }) => {
+ await page.goto('/iframe.html?id=library-button--neutral');
+
+ expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
+ 'button-neutral.png'
+ );
});
// test('With Autofocus', async ({ page }) => {
// await page.goto('/iframe.html?id=library-button--with-autofocus');
// expect(
- // await page.locator('#root :nth-child(1)').first().screenshot()
+ // await page.locator('jp-button').screenshot()
// ).toMatchSnapshot('button-with-autofocus.png');
// });
test('With Disabled', async ({ page }) => {
await page.goto('/iframe.html?id=library-button--with-disabled');
- expect(
- await page.locator('#root :nth-child(1)').first().screenshot()
- ).toMatchSnapshot('button-with-disabled.png');
+ expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
+ 'button-with-disabled.png'
+ );
+ });
+
+ test('With Start Icon', async ({ page }) => {
+ await page.goto('/iframe.html?id=library-button--with-start-icon');
+
+ expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
+ 'button-with-start-icon.png'
+ );
+ });
+
+ test('Icon Only', async ({ page }) => {
+ await page.goto('/iframe.html?id=library-button--icon-only');
+
+ expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
+ 'button-icon-only.png'
+ );
});
});
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-default-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-default-chromium-linux.png
index 9e2c7f8c..71aa7923 100644
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-default-chromium-linux.png and b/packages/components/src/button/button.test.ts-snapshots/button-default-chromium-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-default-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-default-firefox-linux.png
index 57428605..bdf18a12 100644
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-default-firefox-linux.png and b/packages/components/src/button/button.test.ts-snapshots/button-default-firefox-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-default-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-default-webkit-linux.png
index 3c18df1b..8fcc3ade 100644
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-default-webkit-linux.png and b/packages/components/src/button/button.test.ts-snapshots/button-default-webkit-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-error-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-error-chromium-linux.png
new file mode 100644
index 00000000..96fd6433
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-error-chromium-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-error-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-error-firefox-linux.png
new file mode 100644
index 00000000..a0bbd141
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-error-firefox-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-error-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-error-webkit-linux.png
new file mode 100644
index 00000000..464ec8d0
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-error-webkit-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-icon-only-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-icon-only-chromium-linux.png
new file mode 100644
index 00000000..ffefea36
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-icon-only-chromium-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-icon-only-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-icon-only-firefox-linux.png
new file mode 100644
index 00000000..c2a180a0
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-icon-only-firefox-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-icon-only-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-icon-only-webkit-linux.png
new file mode 100644
index 00000000..2e418ffd
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-icon-only-webkit-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-neutral-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-neutral-chromium-linux.png
new file mode 100644
index 00000000..9069c7e2
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-neutral-chromium-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-neutral-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-neutral-firefox-linux.png
new file mode 100644
index 00000000..395ccd8b
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-neutral-firefox-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-neutral-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-neutral-webkit-linux.png
new file mode 100644
index 00000000..9fec9c1e
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-neutral-webkit-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-secondary-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-secondary-chromium-linux.png
deleted file mode 100644
index 6f064f4d..00000000
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-secondary-chromium-linux.png and /dev/null differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-secondary-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-secondary-firefox-linux.png
deleted file mode 100644
index 8f4a50ce..00000000
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-secondary-firefox-linux.png and /dev/null differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-secondary-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-secondary-webkit-linux.png
deleted file mode 100644
index 4449b43b..00000000
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-secondary-webkit-linux.png and /dev/null differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-chromium-linux.png
deleted file mode 100644
index 9e2c7f8c..00000000
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-chromium-linux.png and /dev/null differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-firefox-linux.png
deleted file mode 100644
index a4bf42fc..00000000
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-firefox-linux.png and /dev/null differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-webkit-linux.png
deleted file mode 100644
index 8b779b69..00000000
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-with-autofocus-webkit-linux.png and /dev/null differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-chromium-linux.png
index b09f0d25..0f07c45a 100644
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-chromium-linux.png and b/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-chromium-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-firefox-linux.png
index 20999921..c9205a50 100644
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-firefox-linux.png and b/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-firefox-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-webkit-linux.png
index 086ced8e..2e1353b0 100644
Binary files a/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-webkit-linux.png and b/packages/components/src/button/button.test.ts-snapshots/button-with-disabled-webkit-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-chromium-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-chromium-linux.png
new file mode 100644
index 00000000..cfb5cdd0
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-chromium-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-firefox-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-firefox-linux.png
new file mode 100644
index 00000000..925dd254
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-firefox-linux.png differ
diff --git a/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-webkit-linux.png b/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-webkit-linux.png
new file mode 100644
index 00000000..faab24ab
Binary files /dev/null and b/packages/components/src/button/button.test.ts-snapshots/button-with-start-icon-webkit-linux.png differ
diff --git a/packages/components/src/button/fixtures/createButton.ts b/packages/components/src/button/fixtures/createButton.ts
deleted file mode 100644
index 6ec59325..00000000
--- a/packages/components/src/button/fixtures/createButton.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) Jupyter Development Team.
-// Copyright (c) Microsoft Corporation.
-// Distributed under the terms of the Modified BSD License.
-
-import { Button, ButtonAppearance } from '../index';
-import {
- createCodiconIcon,
- focusObserver
-} from '../../utilities/storybook/index';
-
-export type ButtonArgs = {
- label: string;
- appearance: ButtonAppearance;
- isDisabled: boolean;
- isAutoFocused: boolean;
- startIcon: boolean;
- iconOnly: boolean;
- ariaLabel: string;
- onClick: any;
-};
-
-export function createButton({
- label,
- appearance,
- isDisabled,
- isAutoFocused,
- startIcon,
- iconOnly,
- ariaLabel,
- onClick
-}: ButtonArgs) {
- const button = new Button();
-
- if (label && !iconOnly) {
- button.textContent = label;
- }
- if (appearance) {
- button.setAttribute('appearance', appearance.toLowerCase());
- }
- if (isDisabled) {
- button.setAttribute('disabled', '');
- }
- if (isAutoFocused) {
- button.setAttribute('autofocus', '');
- // Focus observer will force focus if button focus is lost after page load
- focusObserver(button);
- }
- if (startIcon) {
- const start = createCodiconIcon({
- iconName: 'add',
- slotName: 'start'
- });
- button.appendChild(start);
- }
- if (iconOnly) {
- const icon = createCodiconIcon({ iconName: 'check' });
- button.appendChild(icon);
- button.setAttribute('aria-label', ariaLabel);
- }
- button.addEventListener('click', onClick);
-
- return button;
-}
diff --git a/packages/components/src/button/index.ts b/packages/components/src/button/index.ts
index 7cdcfa91..7d5f884d 100644
--- a/packages/components/src/button/index.ts
+++ b/packages/components/src/button/index.ts
@@ -4,100 +4,93 @@
import { attr } from '@microsoft/fast-element';
import {
- ButtonOptions,
Button as FoundationButton,
buttonTemplate as template
} from '@microsoft/fast-foundation';
-import { buttonStyles as styles } from './button.styles';
+import { buttonStyles } from './button.styles';
/**
* Types of button appearance.
* @public
*/
-export type ButtonAppearance = 'primary' | 'secondary' | 'icon';
+export type ButtonAppearance =
+ | 'accent'
+ | 'error'
+ | 'neutral'
+ | 'outline'
+ | 'stealth';
/**
- * The button class.
- *
- * @public
+ * @internal
*/
export class Button extends FoundationButton {
/**
* The appearance the button should have.
*
* @public
+ * @remarks
+ * HTML Attribute: appearance
*/
- @attr public appearance: ButtonAppearance;
+ @attr
+ public appearance: ButtonAppearance;
/**
- * Component lifecycle method that runs when the component is inserted
- * into the DOM.
+ * Whether the button has a compact layout or not.
*
- * @internal
+ * @public
+ * @remarks
+ * HTML Attribute: minimal
*/
+ @attr({ attribute: 'minimal', mode: 'boolean' })
+ public minimal: boolean;
+
public connectedCallback(): void {
super.connectedCallback();
-
- // If the appearance property has not been set, set it to the
- // value of the appearance attribute.
if (!this.appearance) {
- const appearanceValue = this.getAttribute('appearance');
- this.appearance = appearanceValue as ButtonAppearance;
+ this.appearance = 'neutral';
}
}
/**
- * Component lifecycle method that runs when an attribute of the
- * element is changed.
- *
- * @param attrName - The attribute that was changed
- * @param oldVal - The old value of the attribute
- * @param newVal - The new value of the attribute
+ * Applies 'icon-only' class when there is only an SVG in the default slot
*
- * @internal
+ * @public
+ * @remarks
*/
- public attributeChangedCallback(
- attrName: string,
- oldVal: string,
- newVal: string
+ public defaultSlottedContentChanged(
+ oldValue: HTMLElement[],
+ newValue: HTMLElement[]
): void {
- // In the case when an icon only button is created add a default ARIA
- // label to the button since there is no longer button text to use
- // as the label
- if (attrName === 'appearance' && newVal === 'icon') {
- // Only set the ARIA label to the default text if an aria-label attribute
- // does not exist on the button
- const ariaLabelValue = this.getAttribute('aria-label');
- if (!ariaLabelValue) {
- this.ariaLabel = 'Icon Button';
- }
- }
-
- // In the case when the aria-label attribute has been defined on the
- // , this will programmatically propogate the value to
- // the